summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Färber <andreas.faerber@web.de>2010-09-18 12:02:09 +0200
committerAndreas Färber <andreas.faerber@web.de>2010-09-18 12:02:09 +0200
commit7a3d3257e59e2ff50910a58e6ee6857c6c4da703 (patch)
tree411c4b4cd82e56a0a2ad36c61335ce2a785a3212
downloadqemu-openhackware-7a3d3257e59e2ff50910a58e6ee6857c6c4da703.tar.gz
Import of openhackware-0.4.1
-rw-r--r--COPYING339
-rw-r--r--Changelog165
-rw-r--r--Makefile257
-rw-r--r--README128
-rw-r--r--TODO94
-rw-r--r--Timestamp1
-rw-r--r--src/bios.h580
-rw-r--r--src/bloc.c1236
-rw-r--r--src/boot.S100
-rw-r--r--src/boot.ld45
-rw-r--r--src/bootinfos.c282
-rw-r--r--src/char.c780
-rw-r--r--src/dev/bus/adb.h102
-rw-r--r--src/dev/char/char.h29
-rw-r--r--src/dev/char/kbd.c122
-rw-r--r--src/dev/char/kbd.h104
-rw-r--r--src/dev/char/kbdadb.c482
-rw-r--r--src/dev/char/pckbd.c214
-rw-r--r--src/libc/include/ctype.h113
-rw-r--r--src/libc/include/endian.h514
-rw-r--r--src/libc/include/errno.h62
-rw-r--r--src/libc/include/fcntl.h33
-rw-r--r--src/libc/include/stddef.h38
-rw-r--r--src/libc/include/stdint.h74
-rw-r--r--src/libc/include/stdio.h43
-rw-r--r--src/libc/include/stdlib.h50
-rw-r--r--src/libc/include/string.h90
-rw-r--r--src/libc/include/strings.h27
-rw-r--r--src/libc/include/unistd.h43
-rw-r--r--src/libc/src/errno.c25
-rw-r--r--src/libc/src/format.c467
-rw-r--r--src/libc/src/malloc.c730
-rw-r--r--src/libc/src/mem.c251
-rw-r--r--src/libc/src/str.c430
-rw-r--r--src/libexec/chrp.c404
-rw-r--r--src/libexec/core.c151
-rw-r--r--src/libexec/elf.c239
-rw-r--r--src/libexec/exec.h40
-rw-r--r--src/libexec/macho.c516
-rw-r--r--src/libexec/pef.c307
-rw-r--r--src/libexec/prep.c45
-rw-r--r--src/libexec/xcoff.c216
-rw-r--r--src/libfs/core.c562
-rw-r--r--src/libfs/ext2.c32
-rw-r--r--src/libfs/hfs.c2007
-rw-r--r--src/libfs/isofs.c32
-rw-r--r--src/libfs/libfs.h129
-rw-r--r--src/libfs/raw.c178
-rw-r--r--src/libpart/apple.c305
-rw-r--r--src/libpart/core.c289
-rw-r--r--src/libpart/isofs.c257
-rw-r--r--src/libpart/libpart.h66
-rw-r--r--src/libpart/prep.c216
-rw-r--r--src/main.c558
-rw-r--r--src/main.ld79
-rw-r--r--src/mm.c145
-rw-r--r--src/nvram.c450
-rw-r--r--src/of.c5235
-rw-r--r--src/pci.c2250
-rw-r--r--src/start.S379
-rw-r--r--src/vectors.S466
-rw-r--r--src/vectors.ld45
-rw-r--r--src/vga.c429
-rw-r--r--src/vgafont.h4627
64 files changed, 28704 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..e77696a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Changelog b/Changelog
new file mode 100644
index 0000000..a1b042d
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,165 @@
+#
+# <Changelog>
+#
+# Changelog for Open Hack'Ware.
+#
+# Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License V2
+# as published by the Free Software Foundation
+#
+# 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
+#
+2005-04-06:
+* Change 2nd MacIO ide controller IRQ, in coordination with Qemu patch.
+
+2005-03-18:
+* Added Mandrake 10.1 CHRP script CRC.
+
+2005-03-17:
+* Start bloc device / partition management APIs cleanup.
+* Fix PREP boot
+* Fix memory image boot
+
+2005-03-15:
+* Tested rock linux, then updated README
+
+2005-03-14:
+* Yet another fix for CHRP boot file load.
+* Add more CHRP boot scripts CRCs.
+* Make all debug printf be printed on the serial port (ie debug console).
+* Build 04-pre2 preview.
+
+2005-03-11:
+* Fix foolish license informations: this code is clearly distributed under
+ the GNU GPL V2.
+
+2005-03-06:
+* CHRP boot file loader:
+ - yet another boot file path fix
+ - add Debian sarge on hard-drive yaboot start script signature
+* enable FPU at startup (may compile with -msoft float as well...)
+
+2005-03-01:
+* Add dprintf/vdprintf routines for debug console.
+* Fix CHRP boot file path resolution
+* Fix OF PCI devices reg properties
+ (bug reported by Thayne Harbaugh <thayne@realmsys.com>)
+* Fix OF property with no value (value len is zero).
+* Update TODO list
+
+2005-02-18:
+* Merge HFS rework by Thayne Harbaugh <thayne@realmsys.com>
+* Merge generic and new ADB keyboard driver
+* Add '\b' support in VGA console.
+* Disable xcoff embedded binary support to make NetBSD start booting again.
+* Register VGA console when a PCI VGA device is found
+* Register and initialise CUDA when device is found
+
+2005-02-15:
+* Bugfix in toupper by Thayne Harbaugh <thayne@realmsys.com>
+
+2005-02-11:
+* Hack OF_serial_read to use console_read
+* Add '\r' support in vga_putchar.
+* Remove old console code and activate new one.
+* Register PC serial port.
+* Show OHW prompt after all hardware has been initialized.
+* New PC kbd code, reworked from Matthew Wood <mwood@realmsys.com>'s proposal
+
+2005-02-10:
+* Merge Motorola Raven PCI bridge support on PREP
+ by Thayne Harbaugh <thayne@realmsys.com>
+* Bugfix in pci code: pci_main was not initialized to NULL.
+
+2005-02-09:
+* Merge fixes reported by Thayne Harbaugh <thayne@realmsys.com>
+ and Matthew S. Wood <mwood@realmsys.com>:
+ - many typos
+ - bugfix in pci.c:pci_check_host (bad returned value)
+ - bugfix in of.c:OF_lds (debug message)
+ - Improve serial code + add serial_readb
+ - Add error message if parent node if NULL in of.c:OF_node_create
+ - Avoid duplication of properties if of.c:OF_blockdev_set_boot_device
+ is called twice
+ - Use console_read in of.c:OF_serial_read instead of using a harcoded
+ "answer" string.
+ - comment "Apple_patition_map" match
+ in libpart/apple.c:Apple_probe_partitions (was a mistake ?)
+ + more precise message if no bootable partition was found
+ - Never try to register multiple boot partitions (bloc.c:bd_set_boot_part)
+ - Do most of OF tree initialisation before parsing bloc devices (main.c:main)
+* Commit a TODO list.
+
+2005-02-08:
+* Update BIOS version (should have been done before...).
+* A few HFS fixes (still more needed)
+* new xcoff embedded file loader.
+* New OF "forth" function for Mac OS X 10.3
+* cosmetics & typos
+* update copyright infos.
+
+2004-12-20:
+* Great API and structure rework:
+ - add libc subset (to be completed)
+ - split part.c into libpart
+ - split fs.c into libfs
+ - split exec.c into libexec
+ - add preliminary version of memory management routines
+ - add more consistency checks (NULL pointers, ...)
+* partition management:
+ - Fixes in apple partition management with new API
+* filesystems support:
+ - Fixes in HFS/HFS+ support
+* boot file formats support:
+ - extract CHRP boot file format from HFS code + fixes
+ - add PEF file loader (untested)
+ - add Mach-O file loader.
+* OpenFirmware emulation:
+ - Fix some (of the) OF bugs
+ - Fix machine name in OF tree: "Qemu" wasn't recognized by OSes.
+* misc:
+ - avoid gcc compilation time warnings
+
+2004-07-14:
+* More sanity checks.
+* First version of character devices drivers.
+
+2004-07-07: version 0.3:
+* OpenFirmware emulation:
+ - Fix OF_lds and OF_sts
+ - Fix OF_env initialisation.
+ - Add more run-time checks in OF management.
+ - Fix OF naming scheme.
+ - Add OF methods arguments.
+ - Change Copyright string to make Mac OS 9 happy.
+ - New mmu_map method
+ - Fix serial_write & serial_read methods.
+ - Add block devices package.
+ - New OF_interpret hashes for yaboot support.
+* partition management:
+ - hide part_t structure.
+ - improve partitions registration
+* filesystems support:
+ - Fix inode cache management.
+ - Fix special inodes management.
+ - HFS support rework.
+* misc:
+ - keep OF private pointer in PCI IDE structures.
+ - change all xxx_DEBUG defines into DEBUG_xxx
+ - add missing copyright and license in pci.c
+
+2004-05-22:
+ - cleanup Makefile
+ - add COPYING
+ - fix license informations
+ - discard unwanted output sections in bootloaders linker scripts
+ - created Changelog \ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9dc19e2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,257 @@
+#
+# <Makefile>
+#
+# Makefile for Open Hack'Ware.
+#
+# Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License V2
+# as published by the Free Software Foundation
+#
+# 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
+#
+
+#DEBUG=1
+
+CROSS_COMPILE?=powerpc-linux-
+CC:= $(CROSS_COMPILE)gcc
+LD:= $(CROSS_COMPILE)ld
+OBJCOPY:= $(CROSS_COMPILE)objcopy
+MKDIR:= mkdir
+CAT:= cat
+TAR:= tar
+RM:= rm -rf --
+ECHO:= echo
+ifeq ("$(DEBUG)", "1")
+DEBUG:= $(ECHO)
+else
+DEBUG:= \#
+endif
+
+BUILD_DATE:= $(shell date -u +%F)
+BUILD_TIME:= $(shell date -u +%T)
+
+OBJDIR:= .objs
+DISTDIR:= .
+SRCDIR:= src
+
+CC_BASE:= $(shell $(CC) -print-search-dirs | grep install | sed -e 's/.*\ //')
+CFLAGS= -Wall -W -Werror -O2 -g -fno-builtin -fno-common -nostdinc -mregnames
+CFLAGS+= -DBUILD_DATE=$(BUILD_DATE) -DBUILD_TIME=$(BUILD_TIME)
+CFLAGS+= -I$(SRCDIR)/ -I$(SRCDIR)/libc/include -I$(CC_BASE)/include
+CFLAGS+= -I$(SRCDIR)/dev -I$(SRCDIR)/dev/block -I$(SRCDIR)/dev/char
+CFLAGS+= -I$(SRCDIR)/dev/bus
+LDFLAGS= -O2 -g -nostdlib
+
+BIOS_IMAGE_BITS:= 19
+BIOS_IMAGE_SIZE:= $(shell echo $$(( 1 << $(BIOS_IMAGE_BITS) )) )
+
+BOOT_SIZE := 0x00000200
+VECTORS_BASE := 0x00000000
+VECTORS_SIZE := $(shell echo $$(( 0x00004000 - $(BOOT_SIZE) )) )
+VECTORS_END := $(shell echo $$(( $(VECTORS_BASE) + $(VECTORS_SIZE) )) )
+BIOS_BASE := 0x05800000
+BIOS_SIZE := $(shell echo $$(( $(BIOS_IMAGE_SIZE) - $(BOOT_SIZE) - $(VECTORS_SIZE) )) )
+BIOS_END := $(shell echo $$(( $(BIOS_BASE) + $(BIOS_SIZE) )) )
+
+LOAD_IMAGE_BASE:= 0x04000000
+
+# boot.bin build options
+boot.o_CFLAGS:= -DBOOT_SIZE=$(BOOT_SIZE)
+boot.o_CFLAGS+= -DVECTORS_BASE=$(VECTORS_BASE) -DVECTORS_SIZE=$(VECTORS_SIZE)
+boot.o_CFLAGS+= -DBIOS_IMAGE_BITS=$(BIOS_IMAGE_BITS)
+boot.out_LDFLAGS+= -T $(SRCDIR)/boot.ld
+# vectors.bin build options
+vectors.o_CFLAGS:= -DBIOS_BASE=$(BIOS_BASE) -DBIOS_SIZE=$(BIOS_SIZE)
+vectors.out_LDFLAGS+= -T $(SRCDIR)/vectors.ld
+vectors.bin_OPTIONS:= --pad-to $(VECTORS_END)
+# main.bin build options
+main.o_CFLAGS:= -DLOAD_IMAGE_BASE=$(LOAD_IMAGE_BASE)
+main.out_LDFLAGS:= -T $(SRCDIR)/main.ld
+main.out_OBJS:= main.o bootinfos.o bloc.o pci.o of.o start.o nvram.o vga.o mm.o char.o
+main.out_OBJS:= $(addprefix $(OBJDIR)/, $(main.out_OBJS))
+# Pseudo-libc objects
+FORMAT_FUNCS:= _vprintf printf sprintf snprintf vprintf vsprintf vsnprintf
+FORMAT_FUNCS+= dprintf vdprintf
+MEM_FUNCS:= memcpy memccpy mempcpy memmove memcmove mempmove
+MEM_FUNCS+= memset memcmp memchr rawmemchr memrchr memmem
+STR_FUNCS:= strcpy strdup strndup stpcpy stpncpy strcat strncat
+STR_FUNCS+= strcmp strcasecmp strncmp strncasecmp strchr strchrnul strrchr
+STR_FUNCS+= basename dirname
+STR_FUNCS+= strlen strnlen
+MODULES:= format mem str
+format_OBJS:=$(addsuffix .o, $(FORMAT_FUNCS))
+mem_OBJS:=$(addsuffix .o, $(MEM_FUNCS))
+str_OBJS:=$(addsuffix .o, $(STR_FUNCS))
+pseudo_libc_OBJS:= malloc.o errno.o $(format_OBJS) $(mem_OBJS) $(str_OBJS)
+#pseudo_libc_OBJS:= errno.o $(format_OBJS) $(mem_OBJS) $(str_OBJS)
+main.out_OBJS+= $(addprefix $(OBJDIR)/, $(pseudo_libc_OBJS))
+# libexec objects
+libexec_OBJS:= core.o elf.o xcoff.o macho.o chrp.o prep.o pef.o
+main.out_OBJS+= $(addprefix $(OBJDIR)/exec_, $(libexec_OBJS))
+# libfs objects
+libfs_OBJS:= core.o raw.o ext2.o isofs.o hfs.o
+main.out_OBJS+= $(addprefix $(OBJDIR)/fs_, $(libfs_OBJS))
+# libpart objects
+libpart_OBJS:= core.o apple.o isofs.o prep.o
+main.out_OBJS+= $(addprefix $(OBJDIR)/part_, $(libpart_OBJS))
+# char devices drivers
+chardev_OBJS:= pckbd.o kbdadb.o kbd.o
+# bloc devices drivers
+blocdev_OBJS:=
+# devices drivers
+dev_OBJS:= $(addprefix bloc_, $(blocdev_OBJS))
+dev_OBJS+= $(addprefix char_, $(chardev_OBJS))
+main.out_OBJS+= $(addprefix $(OBJDIR)/dev_, $(dev_OBJS))
+
+CUR= $(notdir $@)
+CFLAGS+= $($(CUR)_CFLAGS)
+LDFLAGS+= $($(CUR)_LDFLAGS)
+
+BIN_TARGETS:= $(OBJDIR)/vectors.bin $(OBJDIR)/main.bin $(OBJDIR)/boot.bin
+TARGET:= ppc_rom.bin
+main.bin_OPTIONS:= --gap-fill 0xFF --pad-to $(BIOS_END)
+
+CURDIR:= $(shell basename `pwd`)
+SOURCES:= boot.S vectors.S start.S main.c of.c
+SOURCES+= vga.c vgafont.h bootinfos.c nvram.c file.c fs.c part.c bloc.c pci.c bios.h
+LD_SCRIPTS:= boot.ld vectors.ld main.ld
+MISC_FILES:= Makefile COPYING README Changelog Timestamp
+SVN_DIRS:= $(shell find . -type d -name .svn)
+TARBALL:= OpenHackWare.tar.bz2
+TARFILES:= $(addprefix $(SRCDIR)/, $(SOURCES) $(LD_SCRIPTS)) $(MISC_FILES)
+SVN_TARBALL:= OpenHackWare_svn.tar.bz2
+DISTFILE:= OpenHackWare_bin.tar.bz2
+
+#all: print
+all: $(OBJDIR) $(DISTDIR) $(addprefix $(DISTDIR)/, $(TARGET))
+
+dist: all $(CURDIR)/Timestamp
+ cd $(DISTDIR) && $(TAR) -cjf $(DISTFILE) $(DISTDIR)/$(TARGET) Timestamp
+
+print:
+ @$(DEBUG) "BOOT_SIZE = $(BOOT_SIZE)"
+ @$(DEBUG) "VECTORS_BASE = $(VECTORS_BASE)"
+ @$(DEBUG) "VECTORS_SIZE = $(VECTORS_SIZE)"
+ @$(DEBUG) "VECTORS_END = $(VECTORS_END)"
+ @$(DEBUG) "BIOS_BASE = $(BIOS_BASE)"
+ @$(DEBUG) "BIOS_SIZE = $(BIOS_SIZE)"
+ @$(DEBUG) "BIOS_END = $(BIOS_END)"
+
+$(OBJDIR) $(DISTDIR):
+ @$(MKDIR) $@
+
+$(DISTDIR)/$(TARGET): $(BIN_TARGETS)
+ $(CAT) $^ > $@
+
+$(OBJDIR)/%.bin: $(OBJDIR)/%.out
+ $(OBJCOPY) -O binary $($(notdir $@)_OPTIONS) $< $@
+
+$(OBJDIR)/%.out: $(OBJDIR)/%.o $(SRCDIR)/%.ld
+ $(LD) $(LDFLAGS) -o $@ $<
+
+$(OBJDIR)/main.out: $(main.out_OBJS) $(SRCDIR)/main.ld
+ $(LD) $(LDFLAGS) -o $@ $(main.out_OBJS)
+
+$(OBJDIR)/%.o: $(SRCDIR)/%.c $(SRCDIR)/bios.h
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+$(OBJDIR)/%.o: $(SRCDIR)/%.S $(SRCDIR)/bios.h
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -Wa,-mregnames -o $@ $<
+
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+# Pseudo libc objects
+$(OBJDIR)/%.o: $(SRCDIR)/libc/src/%.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+$(OBJDIR)/mem%.o: $(SRCDIR)/libc/src/mem.c
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+$(OBJDIR)/rawmemchr.o: $(SRCDIR)/libc/src/mem.c
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+$(OBJDIR)/str%.o: $(SRCDIR)/libc/src/str.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+$(OBJDIR)/stp%.o: $(SRCDIR)/libc/src/str.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+$(OBJDIR)/basename.o: $(SRCDIR)/libc/src/str.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+$(OBJDIR)/dirname.o: $(SRCDIR)/libc/src/str.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+$(OBJDIR)/%rintf.o: $(SRCDIR)/libc/src/format.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) $(CFLAGS) -D__USE_$(subst .o,,$(@F))__ -c -o $@ $<
+
+# libexec objects
+$(OBJDIR)/exec_%.o: $(SRCDIR)/libexec/%.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+# libfs objects
+$(OBJDIR)/fs_%.o: $(SRCDIR)/libfs/%.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+# libpart objects
+$(OBJDIR)/part_%.o: $(SRCDIR)/libpart/%.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+# Devices drivers
+$(OBJDIR)/dev_%.o: $(SRCDIR)/dev/%.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+# Char devices drivers
+$(OBJDIR)/dev_char_%.o: $(SRCDIR)/dev/char/%.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+# Bloc devices drivers
+$(OBJDIR)/dev_bloc_%.o: $(SRCDIR)/dev/bloc/%.c
+ @$(DEBUG) "CFLAGS = $(CFLAGS)"
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+# Other targets
+tarball: $(CURDIR)/Timestamp
+ cd .. && $(TAR) -cjf $(CURDIR)/$(TARBALL) \
+ $(addprefix $(CURDIR)/, $(TARFILES))
+
+svntarball: $(CURDIR)/Timestamp
+ cd .. && $(TAR) -cjf $(CURDIR)/$(SVN_TARBALL) \
+ $(addprefix $(CURDIR)/, $(TARFILES) $(SVN_DIRS))
+
+$(CURDIR)/Timestamp: force
+ @cd .. && echo "$(BUILD_DATE) at $(BUILD_TIME)" > $@
+
+clean:
+ $(RM) $(OBJDIR) $(addprefix $(DISTDIR)/, $(TARGETS))
+ $(RM) $(DISTFILE) $(CURDIR)/$(TARBALL)
+
+cleansrc: clean
+ $(RM) *~ src/*~ .*~ src/.*~
+
+# Keep all intermediary files
+.PRECIOUS: $(OBJDIR)/%.o $(OBJDIR)/%.out
+
+.PHONY: all dist print tarball clean cleansrc
+
+force:
diff --git a/README b/README
new file mode 100644
index 0000000..30e81cc
--- /dev/null
+++ b/README
@@ -0,0 +1,128 @@
+===============================================================================
+
+OpenHackWare started as a tiny BIOS that I wrote to launch Linux
+under Qemu-PPC for PREP emulation.
+Then I merged some work I some times ago, which was able to emulate
+some OpenFirmware functionalities to be able to launch some other
+Linux kernels.
+I then tried to improve it to be able to launch MacOSX.
+
+It's released under the GNU General Public License version 2
+
+===============================================================================
+STATUS:
+PowerMac emulation:
+* Linux:
+ - Debian:
+ x 3.0-r1:
+ install & install_safe crash at startup
+ install24 & install24_safe boot but installer crashes.
+ x same goes for 3.0-r4.
+ x same goes for woody.
+ x sarge_netinstall installs with some limitations:
+ if you don't have a DHCP server, expert installation type is needed
+ linux 2.6 framebuffer driver is buggy, so you'd better use a 2.4 kernel
+ top is buggy: it complains it can't read /proc/stat
+ => this seems to be a known propcps bug:
+ "old" top used with recent kernels misunderstand "/proc/stat" format.
+ mol does not display anything
+ + of course, Power3 & Power4 install crashes (unsupported opcodes).
+ - Gentoo:
+ x 1.2-r1 ISO CDROM boots and runs
+ x 1.4.1 live CDROM boots with no problem.
+ x 2004.1 & 2004.3 CROMs use Linux 2.6, then have frame-buffer problems.
+ - Mandrake
+ x 9.1 boots and installer starts
+ Seems to get stuck during some hardware probe
+ x 10.1 starts booting, using 2.6 kernel.
+ Seems to get stuck somewhere inside the kernel.
+ x 10.2 acts the same way.
+ - crux
+ x 1.3 boot but crashes: looks like an i386-only ISOFS bootable CDROM.
+ x 1.3.1 uses Linux 2.6. I guess I'm stuck during hardware probe or
+ it panics.
+ x 2.0 seems to react the same way as 1.3.1.
+ - knoppix
+ x 2003-07-13_4 boots but does not detect the hardware the right way:
+ it wants to use the VESA driver for X. If you are patient,
+ after a few tries, it will fallback to fbdev driver.
+ But then, the mouse is broken (uses the Microsoft serial protocol)
+ and the keyboard is set to german.
+ x k-mib-ppc-beta uses 2.6 kernel.
+ - gnoppix hoary boots kernel 2.6, then framebuffer is buggy
+ (colors are broken: should detect 15 bpp fb, but uses 16 bpp).
+ - sysrescue boots kernel 2.6 so framebuffer is buggy
+ (no output but the penguin).
+ - Fedora Core 3 uses 2.6 kernel then ...
+ ... seems to stay stuck into a small infinite loop inside the kernel.
+ - Fedora Core 4 does the same.
+ - unbuntu does not load: we don't find any bootable file on the HFS partition.
+ - yellow dog 4.0 boots with 2.6 kernel.
+ - rock linux: it boots and installs. Unfortunatelly, there seem to be some
+ bugs in this distribution: I did select the minimal installation,
+ then it forgot the "hfsutils" package and so yaboot did not install itself.
+* NetBSD:
+ - 1.5.2 fails to boot.
+ - 1.6.1, 1.6.2 & 2.0 boot-loader loads but stops
+ (missing available memory property).
+* OpenBSD:
+ - boot-loader cannot run because it's a gzipped ELF file.
+ (tried 3.4, 3.5 & 3.6 macppc CDROMs).
+* Darwin:
+ - Darwin 7.01 and gnuDarwin 2.3 beta dont run: boot-loader crashes:
+ seems to rely on special values in registers (or entry point is false...).
+ looks like Mach-O embedded in XCOFF (?).
+ - Darwin 6.02 and OpenDarwin 6.6.1, 6.6.2 & 20030212 load
+ but seem not to like the OF tree as it's shown then crash.
+ - Darwin 1.41, MacOS X 10.2 & gnuDarwin 2.3 boot
+ but fail to mount the boot device. Seems related to the OF tree.
+ - gnuDarwin 7.01 does not boot at all (cannot find the boot file).
+ - OpenDarwin 7.2.1 does not boot (no boot partition found).
+* MacOS:
+ - Mac OS X 10.2: fails to mount its root device.
+ - Mac OS X 10.3 crashes:
+ seems to try to use Altivec instructions. As my CDROM is one for G5,
+ this may be normal.
+ - Mac OS 9.2 installation CDROM starts to load then crashes.
+ - Ibook Restore CDROM loads & starts booting but crashes
+ - Ibook OS Restore CDROM does not boot (Mac OS X 10.2):
+ does not find any boot partition.
+ - Ibook hw check CDROM boots but crashes:
+ boot loader need its relocations to be resolved by OHW.
+ - IMac G5 hw check CDROM does not boot:
+ OHW is unable to find any boot file in the boot directory.
+* BeOS:
+ - not tested for now. Should not load, as fs may be ISOFS.
+
+PREP emulation:
+* Linux:
+ XXX: to be completed
+* Windows NT 4:
+ - XCoff file loader merges to be done for Microsoft format to be understood.
+* AIX:
+ - The PREP boot image is well located at startup but it seems there are
+ "magic" values to put in registers. Then, for now, it crashes.
+ Seeking for informations about this executable format (starting with
+ "AIXM").
+ Tested 4.3.3 and 5.1. I don't even know if they would run on a real PREP ;-)
+
+CHRP emulation:
+ TODO (no support in qemu).
+
+MVME emulation:
+ TODO (no support in qemu).
+
+Pegasos emulation:
+ TODO (no support in qemu).
+
+===============================================================================
+
+Known problems:
+
+---
+RedHat make 3.79 is fully buggy. You may have several problems trying to build
+OpenHackWare using it. You'd better update to make 3.80 or recompile it from
+regular sources (ie not RedHat sources). Please don't complain if you aren't
+able to build the BIOS using this package.
+
+===============================================================================
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..13b63f6
--- /dev/null
+++ b/TODO
@@ -0,0 +1,94 @@
+#
+# <TODO>
+#
+# TODO list for Open Hack'Ware.
+#
+# Copyright (C) 2005 Jocelyn Mayer (l_indien@magic.fr)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License V2
+# as published by the Free Software Foundation
+#
+# 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
+#
+
+This TODO list is still quite unordered.
+Any other ideas are welcome.
+
+* Features needed for 0.5 release:
+ - 2.6 Linux kernel boot for PMac & PREP targets
+ - 2.2 Linux kernel boot for PMac & PREP targets
+
+* Features needed for 1.0 release:
+ - Mac OS X boot for PMac target
+ - Mac OS 9 boot for PMac target
+ - NetBSD boot for PMac & PREP targets
+ - OpenBSD boot for PMac & PREP targets
+ - AIX boot for PREP target
+ - Windows NT boot for PREP target
+ - user should be able to tune the boot process:
+ x choose boot partition
+ x give special arguments to the bootloader
+
+* Short term fixes:
+ - ASAP: as soon as qemu floppy work again, check floppy boot process.
+ - 2.6 kernel boot.
+ - OSX / Darwin boot
+ - video output is mostly broken for PREP target
+ (reported by Bruce Beare (bbeare) <bbeare@cisco.com>)
+
+* Fixes:
+ - fix the OF tree.
+ - fix the bootinfos (seem buggy and are incomplete)
+ - check why OF_blockdev_set_boot_device may be called more than once.
+
+* Features to be tested:
+ - PEF loader
+
+* New features:
+ - User prompt is needed when multiple bootable partitions are found.
+ - in libfs
+ x ext2 support
+ x isofs support
+ x more filesystems ?
+ - in libpart
+ x Fix IBM PREP CDROMs boot for AIX & WinNT for PREP
+ x add more partition mappings (BSD slices and ?)
+ - in libexec
+ x Windows NT xcoff support (code exists but is to be merged and tested)
+ x Add dynamic linker (needed to boot Apple hardware check CDROMs)
+ - new libfilter:
+ x compression & encryption (gzip for OpenBSD boot, ...).
+ - in libc
+ x Add missing string and memory functions
+ x Add filename/URL manipulation routines (canonicalize, ...)
+ x nls support (code exists but isn't merged).
+ x Add hashed objects support with special cases for strings & unicode strings
+ (code exists, need to be tested and integrated).
+ - New architectures support (generic CHRP, MVME, pegasos, ...).
+ To be coordinated with Qemu improvments.
+
+* Future direction for OpenHackWare:
+ - Improve code split & structuration:
+ x split all device drivers
+ x make OF interface _really_ optional: currently, some devices won't be
+ registered/initialized if OF is not present.
+ For this to be, we should have an internal representation for all devices
+ and OF should become just an interface to this internal tree.
+ - Improve memory management.
+ - Add unitary tests for most library functions
+ - Improve exception vectors
+ - Add virtual devices support for RTAS (virtual SCSI & ethernet)
+ (preliminary code exists but is far from being usable).
+ - Use unicode for internal strings (UTF-8 or UTF-32 ?).
+ - Improve build system (current one is really ugly).
+ - Real forth support (preliminary code exists...).
+ - Accurate terminal emulation (some code exists).
+ - Add a generic device cache (related to improved memory management...).
diff --git a/Timestamp b/Timestamp
new file mode 100644
index 0000000..1fb967e
--- /dev/null
+++ b/Timestamp
@@ -0,0 +1 @@
+2005-04-06 at 21:44:49
diff --git a/src/bios.h b/src/bios.h
new file mode 100644
index 0000000..b420fff
--- /dev/null
+++ b/src/bios.h
@@ -0,0 +1,580 @@
+/*
+ * <bios.h>
+ *
+ * header for Open Hack'Ware
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+#if !defined (__BIOS_H__)
+#define __BIOS_H__
+
+#define USE_OPENFIRMWARE
+//#define DEBUG_BIOS 1
+
+#define BIOS_VERSION "0.4.1"
+
+#define DSISR 18
+#define DAR 19
+#define SRR0 26
+#define SRR1 27
+
+#define _tostring(s) #s
+#define stringify(s) _tostring(s)
+
+#if !defined (ASSEMBLY_CODE)
+
+#ifdef DEBUG_BIOS
+#define DPRINTF(fmt, args...) do { dprintf(fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do { } while (0)
+#endif
+#define ERROR(fmt, args...) do { printf("ERROR: " fmt , ##args); } while (0)
+#define MSG(fmt, args...) do { printf(fmt , ##args); } while (0)
+
+#define offsetof(_struct, field) \
+({ \
+ typeof(_struct) __tmp_struct; \
+ int __off; \
+ __off = (char *)(&__tmp_struct.field) - (char *)(&__tmp_struct); \
+ __off; \
+})
+
+#define unused __attribute__ (( unused))
+
+/* Useful macro in C code */
+#define MTSPR(num, value) \
+__asm__ __volatile__ ("mtspr " stringify(num) ", %0" :: "r"(value));
+
+/* Architectures */
+enum {
+ ARCH_PREP = 0,
+ ARCH_CHRP,
+ ARCH_MAC99,
+ ARCH_POP,
+};
+
+/* Hardware definition(s) */
+extern uint32_t isa_io_base;
+#define ISA_IO_BASE 0x80000000
+extern int arch;
+
+/*****************************************************************************/
+/* From start.S : BIOS start code and asm helpers */
+void transfer_handler (void *residual, void *load_addr,
+ void *OF_entry, void *bootinfos,
+ void *cmdline, void *not_used,
+ void *nip, void *stack_base);
+void bug (void);
+
+/* PPC helpers */
+uint32_t mfmsr (void);
+void mtmsr (uint32_t msr);
+uint32_t mfpvr (void);
+void mftb (uint32_t *tb);
+void MMU_on (void);
+void MMU_off (void);
+/* IO helpers */
+uint32_t inb (uint16_t port);
+void outb (uint16_t port, uint32_t val);
+uint32_t inw (uint16_t port);
+void outw (uint16_t port, uint32_t val);
+uint32_t inl (uint16_t port);
+void outl (uint16_t port, uint32_t val);
+void eieio (void);
+/* Misc helpers */
+uint16_t ldswap16 (uint16_t *addr);
+void stswap16 (void *addr, uint16_t val);
+uint32_t ldswap32 (uint32_t *addr);
+void stswap32 (void *addr, uint32_t val);
+void mul64 (uint32_t *ret, uint32_t a, uint32_t b);
+void add64 (uint32_t *ret, uint32_t *a, uint32_t *b);
+
+typedef struct jmp_buf {
+ uint32_t gpr[32];
+ uint32_t lr;
+ uint32_t ctr;
+ uint32_t xer;
+ uint32_t ccr;
+} jmp_buf;
+int setjmp (jmp_buf env);
+void longjmp (jmp_buf env);
+
+/*****************************************************************************/
+/* PCI BIOS */
+typedef struct pci_common_t pci_common_t;
+typedef struct pci_host_t pci_host_t;
+typedef struct pci_device_t pci_device_t;
+typedef struct pci_bridge_t pci_bridge_t;
+typedef struct pci_ops_t pci_ops_t;
+typedef union pci_u_t pci_u_t;
+
+typedef struct pci_dev_t pci_dev_t;
+struct pci_dev_t {
+ uint16_t vendor;
+ uint16_t product;
+ const unsigned char *type;
+ const unsigned char *name;
+ const unsigned char *model;
+ const unsigned char *compat;
+ int acells;
+ int scells;
+ int icells;
+ int (*config_cb)(pci_device_t *device);
+ const void *private;
+};
+
+pci_host_t *pci_init (void);
+void pci_get_mem_range (pci_host_t *host, uint32_t *start, uint32_t *len);
+
+/*****************************************************************************/
+/* nvram.c : NVRAM management routines */
+typedef struct nvram_t nvram_t;
+extern nvram_t *nvram;
+
+uint8_t NVRAM_read (nvram_t *nvram, uint32_t addr);
+void NVRAM_write (nvram_t *nvram, uint32_t addr, uint8_t value);
+uint16_t NVRAM_get_size (nvram_t *nvram);
+int NVRAM_format (nvram_t *nvram);
+nvram_t *NVRAM_get_config (uint32_t *RAM_size, int *boot_device,
+ void **boot_image, uint32_t *boot_size,
+ void **cmdline, uint32_t *cmdline_size,
+ void **ramdisk, uint32_t *ramdisk_size);
+
+/*****************************************************************************/
+/* bloc.c : bloc devices management */
+typedef struct pos_t {
+ uint32_t bloc;
+ uint32_t offset;
+} pos_t;
+
+typedef struct bloc_device_t bloc_device_t;
+typedef struct part_t part_t;
+typedef struct fs_t fs_t;
+
+bloc_device_t *bd_open (int device);
+int bd_seek (bloc_device_t *bd, uint32_t bloc, uint32_t pos);
+int bd_read (bloc_device_t *bd, void *buffer, int len);
+int bd_write (bloc_device_t *bd, const void *buffer, int len);
+#define _IOCTL(a, b) (((a) << 16) | (b))
+#define MEM_SET_ADDR _IOCTL('M', 0x00)
+#define MEM_SET_SIZE _IOCTL('M', 0x01)
+int bd_ioctl (bloc_device_t *bd, int func, void *args);
+uint32_t bd_seclen (bloc_device_t *bd);
+void bd_close (bloc_device_t *bd);
+uint32_t bd_seclen (bloc_device_t *bd);
+uint32_t bd_maxbloc (bloc_device_t *bd);
+void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum,
+ int *cyl, int *head, int *sect);
+uint32_t bd_CHS2sect (bloc_device_t *bd,
+ int cyl, int head, int sect);
+part_t *bd_probe (int boot_device);
+bloc_device_t *bd_get (int device);
+void bd_put (bloc_device_t *bd);
+void bd_set_boot_part (bloc_device_t *bd, part_t *partition);
+part_t **_bd_parts (bloc_device_t *bd);
+
+void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1,
+ uint32_t io_base2, uint32_t io_base3,
+ void *OF_private);
+void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1,
+ void *OF_private);
+
+/*****************************************************************************/
+/* part.c : partitions management */
+enum part_flags_t {
+ PART_TYPE_RAW = 0x0000,
+ PART_TYPE_PREP = 0x0001,
+ PART_TYPE_APPLE = 0x0002,
+ PART_TYPE_ISO9660 = 0x0004,
+ PART_FLAG_DUMMY = 0x0010,
+ PART_FLAG_DRIVER = 0x0020,
+ PART_FLAG_PATCH = 0x0040,
+ PART_FLAG_FS = 0x0080,
+ PART_FLAG_BOOT = 0x0100,
+};
+
+enum {
+ PART_PREP = 0x01,
+ PART_CHRP = 0x02,
+};
+
+part_t *part_open (bloc_device_t *bd,
+ uint32_t start, uint32_t size, uint32_t spb);
+int part_seek (part_t *part, uint32_t bloc, uint32_t pos);
+int part_read (part_t *part, void *buffer, int len);
+int part_write (part_t *part, const void *buffer, int len);
+void part_close (part_t *part);
+uint32_t part_blocsize (part_t *part);
+uint32_t part_flags (part_t *part);
+uint32_t part_size (part_t *part);
+fs_t *part_fs (part_t *part);
+
+part_t *part_get (bloc_device_t *bd, int partnum);
+part_t *part_probe (bloc_device_t *bd, int set_raw);
+int part_set_boot_file (part_t *part, uint32_t start, uint32_t offset,
+ uint32_t size);
+
+/*****************************************************************************/
+/* fs.c : file system management */
+typedef struct dir_t dir_t;
+typedef struct dirent_t dirent_t;
+typedef struct inode_t inode_t;
+
+struct dirent_t {
+ dir_t *dir;
+ inode_t *inode;
+ const unsigned char *dname;
+};
+
+enum {
+ INODE_TYPE_UNKNOWN = 0x00FF,
+ INODE_TYPE_DIR = 0x0000,
+ INODE_TYPE_FILE = 0x0001,
+ INODE_TYPE_OTHER = 0x0002,
+ INODE_TYPE_MASK = 0x00FF,
+ INODE_FLAG_EXEC = 0x0100,
+ INODE_FLAG_BOOT = 0x0200,
+ INODE_FLAG_MASK = 0xFF00,
+};
+
+/* probe a filesystem from a partition */
+fs_t *fs_probe (part_t *part, int set_raw);
+part_t *fs_part (fs_t *fs);
+/* Recurse thru directories */
+dir_t *fs_opendir (fs_t *fs, const unsigned char *name);
+dirent_t *fs_readdir (dir_t *dir);
+unsigned char *fs_get_path (dirent_t *dirent);
+void fs_closedir (dir_t *dir);
+/* Play with files */
+inode_t *fs_open (fs_t *fs, const unsigned char *name);
+int fs_seek (inode_t *inode, uint32_t bloc, uint32_t pos);
+int fs_read (inode_t *inode, void *buffer, int len);
+int fs_write (inode_t *inode, const void *buffer, unused int len);
+void fs_close (inode_t *inode);
+uint32_t fs_get_type (fs_t *fs);
+uint32_t fs_inode_get_type (inode_t *inode);
+uint32_t fs_inode_get_flags (inode_t *inode);
+part_t *fs_inode_get_part (inode_t *inode);
+
+/* Bootfile */
+unsigned char *fs_get_boot_dirname (fs_t *fs);
+inode_t *fs_get_bootfile (fs_t *fs);
+int fs_raw_set_bootfile (part_t *part,
+ uint32_t start_bloc, uint32_t start_offset,
+ uint32_t size_bloc, uint32_t size_offset);
+
+/*****************************************************************************/
+/* file.c : file management */
+#define DEFAULT_LOAD_DEST 0x00100000
+
+uint32_t file_seek (inode_t *file, uint32_t pos);
+
+/* Executable files loader */
+int bootfile_load (void **dest, void **entry, void **end,
+ part_t *part, int type, const unsigned char *fname,
+ uint32_t offset);
+
+/*****************************************************************************/
+/* char.c : char devices */
+typedef struct chardev_t chardev_t;
+typedef struct cops_t cops_t;
+
+struct cops_t {
+ int (*open)(void *private);
+ int (*close)(void *private);
+ int (*read)(void *private);
+ int (*write)(void *private, int c);
+ /* Won't implement seek for now */
+};
+
+enum {
+ CHARDEV_KBD = 0,
+ CHARDEV_MOUSE,
+ CHARDEV_SERIAL,
+ CHARDEV_DISPLAY,
+ CHARDEV_LAST,
+};
+
+int chardev_register (int type, cops_t *ops, void *private);
+int chardev_open (chardev_t *dev);
+int chardev_close (chardev_t *dev);
+int chardev_read (chardev_t *dev, void *buffer, int maxlen);
+int chardev_write (chardev_t *dev, const void *buffer, int maxlen);
+int chardev_type (chardev_t *dev);
+
+/* Console driver */
+int console_open (void);
+int console_read (void *buffer, int maxlen);
+int console_write (const void *buffer, int len);
+void console_close (void);
+
+/* PC serial port */
+#define SERIAL_OUT_PORT (0x03F8)
+int pc_serial_register (uint16_t base);
+
+/* CUDA host */
+typedef struct cuda_t cuda_t;
+cuda_t *cuda_init (uint32_t base);
+void cuda_reset (cuda_t *cuda);
+
+/*****************************************************************************/
+/* vga.c : VGA console */
+extern unsigned long vga_fb_phys_addr;
+extern int vga_fb_width;
+extern int vga_fb_height;
+extern int vga_fb_linesize;
+extern int vga_fb_bpp;
+extern int vga_fb_depth;
+void vga_prep_init(void);
+void vga_set_address (uint32_t address);
+void vga_set_mode(int width, int height, int depth);
+void vga_set_palette(int i, unsigned int rgba);
+#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define RGB(r, g, b) RGBA(r, g, b, 0xff)
+unsigned int vga_get_color(unsigned int rgba);
+
+void vga_draw_buf (const void *buf, int buf_linesize,
+ int posx, int posy, int width, int height);
+void vga_fill_rect (int posx, int posy, int width, int height, uint32_t color);
+void vga_bitblt(int xs, int ys, int xd, int yd, int w, int h);
+void vga_check_mode(int width, int height, int depth);
+
+/* text primitives */
+void vga_text_set_fgcol(unsigned int rgba);
+void vga_text_set_bgcol(unsigned int rgba);
+void vga_putcharxy(int x, int y, int ch,
+ unsigned int fgcol, unsigned int bgcol);
+void vga_putchar(int ch);
+void vga_puts(const char *s);
+
+/*****************************************************************************/
+/* bootinfos.c : build structures needed by kernels to boot */
+void prepare_bootinfos (void *p, uint32_t memsize,
+ void *cmdline, void *initrd, uint32_t initrd_size);
+void residual_build (void *p, uint32_t memsize,
+ uint32_t load_base, uint32_t load_size,
+ uint32_t last_alloc);
+
+/*****************************************************************************/
+/* of.c : Open-firmware emulation */
+#define OF_NAMELEN_MAX 1024
+#define OF_PROPLEN_MAX 256
+
+int OF_init (void);
+int OF_register_mb (const unsigned char *model, const unsigned char **compats);
+int OF_register_cpu (const unsigned char *name, int num, uint32_t pvr,
+ uint32_t min_freq, uint32_t max_freq, uint32_t bus_freq,
+ uint32_t tb_freq, uint32_t reset_io);
+#if 0
+int OF_register_translations (int nb, OF_transl_t *translations);
+#endif
+uint32_t OF_claim_virt (uint32_t virt, uint32_t size, int *range);
+int OF_register_memory (uint32_t memsize, uint32_t bios_size);
+int OF_register_bootargs (const unsigned char *bootargs);
+void *OF_register_pci_host (pci_dev_t *dev, uint16_t rev, uint32_t ccode,
+ uint32_t cfg_base, uint32_t cfg_len,
+ uint32_t mem_base, uint32_t mem_len,
+ uint32_t io_base, uint32_t io_len,
+ uint32_t rbase, uint32_t rlen,
+ uint16_t min_grant, uint16_t max_latency);
+void *OF_register_pci_bridge (void *parent, pci_dev_t *dev,
+ uint32_t cfg_base, uint32_t cfg_len,
+ uint8_t devfn, uint8_t rev, uint32_t ccode,
+ uint16_t min_grant, uint16_t max_latency);
+void *OF_register_pci_device (void *parent, pci_dev_t *dev,
+ uint8_t devfn, uint8_t rev, uint32_t ccode,
+ uint16_t min_grant, uint16_t max_latency);
+void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses);
+void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn,
+ uint32_t *regions, uint32_t *sizes);
+void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size,
+ void *private_data);
+int OF_register_bus (const unsigned char *name, uint32_t address,
+ const unsigned char *type);
+int OF_register_serial (const unsigned char *bus, const unsigned char *name,
+ uint32_t io_base, int irq);
+int OF_register_stdio (const unsigned char *dev_in,
+ const unsigned char *dev_out);
+void OF_vga_register (const unsigned char *name, uint32_t address,
+ int width, int height, int depth);
+void *OF_blockdev_register (void *parent, void *private,
+ const unsigned char *type,
+ const unsigned char *name, int devnum,
+ const char *alias);
+void OF_blockdev_set_boot_device (void *disk, int partnum,
+ const unsigned char *file);
+
+int OF_entry (void *p);
+int OF_client_entry (void *p);
+void RTAS_init (void);
+
+/*****************************************************************************/
+/* main.c : main BIOS code */
+/* Memory management */
+/* Memory areas */
+extern uint32_t _data_start, _data_end;
+extern uint32_t _OF_vars_start, _OF_vars_end;
+extern uint32_t _sdata_start, _sdata_end;
+extern uint32_t _ro_start, _ro_end;
+extern uint32_t _RTAS_start, _RTAS_end;
+extern uint32_t _RTAS_data_start, _RTAS_data_end;
+extern uint32_t _bss_start, _bss_end;
+extern uint32_t _ram_start;
+extern const unsigned char *BIOS_str;
+extern const unsigned char *copyright;
+void *mem_align (int align);
+void freep (void *p);
+
+/* Endian-safe memory read/write */
+static inline void put_be64 (void *addr, uint64_t l)
+{
+ *(uint64_t *)addr = l;
+}
+
+static inline uint64_t get_be64 (void *addr)
+{
+ return *(uint64_t *)addr;
+}
+
+static inline void put_le64 (void *addr, uint64_t l)
+{
+ uint32_t *p;
+
+ p = addr;
+ stswap32(p, l);
+ stswap32(p + 1, l >> 32);
+}
+
+static inline uint64_t get_le64 (void *addr)
+{
+ uint64_t val;
+ uint32_t *p;
+
+ p = addr;
+ val = ldswap32(p);
+ val |= (uint64_t)ldswap32(p + 1) << 32;
+
+ return val;
+}
+
+static inline void put_be32 (void *addr, uint32_t l)
+{
+ *(uint32_t *)addr = l;
+}
+
+static inline uint32_t get_be32 (void *addr)
+{
+ return *(uint32_t *)addr;
+}
+
+static inline void put_le32 (void *addr, uint32_t l)
+{
+ stswap32(addr, l);
+}
+
+static inline uint32_t get_le32 (void *addr)
+{
+ return ldswap32(addr);
+}
+
+static inline void put_be16 (void *addr, uint16_t l)
+{
+ *(uint16_t *)addr = l;
+}
+
+static inline uint16_t get_be16 (void *addr)
+{
+ return *(uint16_t *)addr;
+}
+
+static inline void put_le16 (void *addr, uint16_t l)
+{
+ stswap16(addr, l);
+}
+
+static inline uint16_t get_le16 (void *addr)
+{
+ return ldswap16(addr);
+}
+
+/* String functions */
+long strtol (const unsigned char *str, unsigned char **end, int base);
+
+int write_buf (const unsigned char *buf, int len);
+
+/* Misc */
+void usleep (uint32_t usec);
+void sleep (int sec);
+uint32_t crc32 (uint32_t crc, const uint8_t *p, int len);
+void set_loadinfo (void *load_base, uint32_t size);
+void set_check (int do_it);
+void check_location (const void *buf, const char *func, const char *name);
+
+static inline void pokeb (void *location, uint8_t val)
+{
+#ifdef DEBUG_BIOS
+ check_location(location, __func__, "location");
+#endif
+ *((uint8_t *)location) = val;
+}
+
+static inline uint8_t peekb (void *location)
+{
+#ifdef DEBUG_BIOS
+ check_location(location, __func__, "location");
+#endif
+ return *((uint8_t *)location);
+}
+
+static inline void pokew (void *location, uint16_t val)
+{
+#ifdef DEBUG_BIOS
+ check_location(location, __func__, "location");
+#endif
+ *((uint8_t *)location) = val;
+}
+
+static inline uint16_t peekw (void *location)
+{
+#ifdef DEBUG_BIOS
+ check_location(location, __func__, "location");
+#endif
+ return *((uint16_t *)location);
+}
+
+static inline void pokel (void *location, uint32_t val)
+{
+#ifdef DEBUG_BIOS
+ check_location(location, __func__, "location");
+#endif
+ *((uint32_t *)location) = val;
+}
+
+static inline uint32_t peekl (void *location)
+{
+#ifdef DEBUG_BIOS
+ check_location(location, __func__, "location");
+#endif
+ return *((uint32_t *)location);
+}
+
+/* Console */
+int cs_write (const unsigned char *buf, int len);
+
+#endif /* !defined (ASSEMBLY_CODE) */
+
+
+#endif /* !defined (__BIOS_H__) */
diff --git a/src/bloc.c b/src/bloc.c
new file mode 100644
index 0000000..6883ee0
--- /dev/null
+++ b/src/bloc.c
@@ -0,0 +1,1236 @@
+/*
+ * <bloc.c>
+ *
+ * Open Hack'Ware BIOS bloc devices management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+
+#undef DPRINTF
+#define DPRINTF(fmt, args...) do { } while (0)
+
+struct bloc_device_t {
+ int device;
+ /* Hardware */
+ uint32_t io_base;
+ int drv;
+ /* Geometry */
+ int heads;
+ int trks;
+ int sects;
+ int seclen;
+ /* Position */
+ int bloc;
+ int vbloc;
+ int vpos;
+ /* Access */
+ int (*init)(bloc_device_t *bd, int device);
+ int (*read_sector)(bloc_device_t *bd, void *buffer, int secnum);
+ int (*ioctl)(bloc_device_t *bd, int func, void *args);
+ /* buffer */
+ char *buffer;
+ /* Private data */
+ int tmp;
+ void *private;
+#ifdef USE_OPENFIRMWARE
+ void *OF_private;
+#endif
+ /* Partitions */
+ part_t *parts, *bparts;
+ part_t *boot_part;
+ /* Chain */
+ bloc_device_t *next;
+};
+
+static bloc_device_t *bd_list;
+
+static int fdc_initialize (bloc_device_t *bd, int device);
+static int fdc_read_sector (bloc_device_t *bd, void *buffer, int secnum);
+
+static int ide_initialize (bloc_device_t *bd, int device);
+static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum);
+
+static int mem_initialize (bloc_device_t *bd, int device);
+static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum);
+static int mem_ioctl (bloc_device_t *bd, int func, void *args);
+
+bloc_device_t *bd_open (int device)
+{
+ bloc_device_t *bd;
+ int num;
+
+ bd = bd_get(device);
+ if (bd != NULL)
+ return bd;
+ bd = malloc(sizeof(bloc_device_t));
+ if (bd == NULL)
+ return NULL;
+ bd->ioctl = NULL;
+ switch (device) {
+ case 'a':
+ num = 0;
+ bd->init = &fdc_initialize;
+ bd->read_sector = &fdc_read_sector;
+ break;
+ case 'b':
+ num = 1;
+ bd->init = &fdc_initialize;
+ bd->read_sector = &fdc_read_sector;
+ break;
+ case 'c':
+ num = 0;
+ bd->init = &ide_initialize;
+ bd->read_sector = &ide_read_sector;
+ break;
+ case 'd':
+ num = 1;
+ bd->init = &ide_initialize;
+ bd->read_sector = &ide_read_sector;
+ break;
+ case 'e':
+ num = 2;
+ bd->init = &ide_initialize;
+ bd->read_sector = &ide_read_sector;
+ break;
+ case 'f':
+ num = 3;
+ bd->init = &ide_initialize;
+ bd->read_sector = &ide_read_sector;
+ break;
+ case 'm':
+ num = 0;
+ bd->init = &mem_initialize;
+ bd->read_sector = &mem_read_sector;
+ bd->ioctl = &mem_ioctl;
+ break;
+ default:
+ return NULL;
+ }
+ bd->bloc = -1;
+ if ((*bd->init)(bd, num) < 0) {
+ free(bd);
+ return NULL;
+ }
+ bd->buffer = malloc(bd->seclen);
+ if (bd->buffer == NULL) {
+ free(bd);
+ return NULL;
+ }
+ bd->device = device;
+
+ return bd;
+}
+
+int bd_seek (bloc_device_t *bd, uint32_t bloc, uint32_t pos)
+{
+ uint32_t maxbloc;
+
+ maxbloc = bd_maxbloc(bd);
+ if (bloc > maxbloc) {
+ DPRINTF("%p bloc: %d maxbloc: %d C: %d H: %d S: %d\n",
+ bd, bloc, maxbloc, bd->trks, bd->heads, bd->sects);
+ return -1;
+ }
+ bd->vbloc = bloc;
+ bd->vpos = pos;
+ DPRINTF("%s: %p %08x %08x %08x %08x %08x\n", __func__, bd, bloc, pos,
+ bd->bloc, bd->vbloc, bd->vpos);
+
+ return 0;
+}
+
+int bd_read (bloc_device_t *bd, void *buffer, int len)
+{
+ int clen, total;
+
+ for (total = 0; len > 0; total += clen) {
+ if (bd->vbloc != bd->bloc) {
+ /* Do physical seek */
+#if 0
+ DPRINTF("Read sector %d\n", bd->vbloc);
+#endif
+ if ((*bd->read_sector)(bd, bd->buffer, bd->vbloc) < 0) {
+ printf("Error reading bloc %d\n", bd->vbloc);
+ return -1;
+ }
+ bd->bloc = bd->vbloc;
+ }
+ clen = bd->seclen - bd->vpos;
+ if (clen > len)
+ clen = len;
+ memcpy(buffer, bd->buffer + bd->vpos, clen);
+#if 0
+ DPRINTF("%s: %p copy %d bytes (%08x %08x %08x) %08x %08x %08x %08x\n",
+ __func__, bd, clen, bd->bloc, bd->vbloc, bd->vpos,
+ ((uint32_t *)buffer)[0], ((uint32_t *)buffer)[1],
+ ((uint32_t *)buffer)[2], ((uint32_t *)buffer)[3]);
+#endif
+ bd->vpos += clen;
+ if (bd->vpos == bd->seclen) {
+ bd->vbloc++;
+ bd->vpos = 0;
+ }
+ buffer += clen;
+ len -= clen;
+ }
+
+ return total;
+}
+
+int bd_write (unused bloc_device_t *bd,
+ unused const void *buffer, unused int len)
+{
+ return -1;
+}
+
+int bd_ioctl (bloc_device_t *bd, int func, void *args)
+{
+ if (bd->ioctl == NULL)
+ return -1;
+
+ return (*bd->ioctl)(bd, func, args);
+}
+
+void bd_close (unused bloc_device_t *bd)
+{
+}
+
+uint32_t bd_seclen (bloc_device_t *bd)
+{
+ return bd->seclen;
+}
+
+uint32_t bd_maxbloc (bloc_device_t *bd)
+{
+ return bd_CHS2sect(bd, bd->trks, 0, 1);
+}
+
+/* XXX: to be suppressed */
+void bd_set_boot_part (bloc_device_t *bd, part_t *partition)
+{
+ if (bd->boot_part == NULL) {
+ bd->boot_part = partition;
+ }
+}
+
+part_t **_bd_parts (bloc_device_t *bd)
+{
+ return &bd->parts;
+}
+
+part_t **_bd_bparts (bloc_device_t *bd)
+{
+ return &bd->bparts;
+}
+
+part_t *bd_probe (int boot_device)
+{
+ char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', };
+ bloc_device_t *bd, **cur;
+ part_t *boot_part, *tmp;
+ int i, force_raw;
+
+ boot_part = NULL;
+ /* Probe bloc devices */
+ for (i = 0; devices[i] != '\0'; i++) {
+ if (devices[i] == 'm' && boot_device != 'm')
+ break;
+ bd = bd_open(devices[i]);
+ if (bd != NULL) {
+ DPRINTF("New bloc device %c: %p\n", devices[i], bd);
+ for (cur = &bd_list; *cur != NULL; cur = &(*cur)->next)
+ continue;
+ *cur = bd;
+ } else {
+ DPRINTF("No bloc device %c\n", devices[i]);
+ }
+ }
+ /* Probe partitions for each bloc device found */
+ for (bd = bd_list; bd != NULL; bd = bd->next) {
+ dprintf("Probe partitions for device %c\n", bd->device);
+ if (bd->device == 'm')
+ force_raw = 1;
+ else
+ force_raw = 0;
+ tmp = part_probe(bd, force_raw);
+ if (boot_device == bd->device) {
+ boot_part = tmp;
+#if defined (USE_OPENFIRMWARE)
+ OF_blockdev_set_boot_device(bd->OF_private, 2, "\\\\ofwboot");
+#endif
+ }
+ }
+
+ return boot_part;
+}
+
+bloc_device_t *bd_get (int device)
+{
+ bloc_device_t *cur;
+
+ for (cur = bd_list; cur != NULL; cur = cur->next) {
+ if (cur->device == device) {
+ DPRINTF("%s: found device %c: %p\n", __func__, device, cur);
+ return cur;
+ }
+ }
+
+ return NULL;
+}
+
+void bd_put (unused bloc_device_t *bd)
+{
+}
+
+void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum,
+ int *cyl, int *head, int *sect)
+{
+ uint32_t tmp;
+
+ tmp = secnum / bd->sects;
+ *sect = secnum - (tmp * bd->sects) + 1;
+ *cyl = tmp / bd->heads;
+ *head = tmp - (*cyl * bd->heads);
+}
+
+uint32_t bd_CHS2sect (bloc_device_t *bd,
+ int cyl, int head, int sect)
+{
+ return (((cyl * bd->heads) + head) * bd->sects) + sect - 1;
+}
+
+/* Floppy driver */
+#define FDC_OUT_BASE (0x03F0)
+#define FDC_DOR_PORT (FDC_OUT_BASE + 0x0002)
+#define FDC_TAPE_PORT (FDC_OUT_BASE + 0x0003)
+#define FDC_MAIN_STATUS (FDC_OUT_BASE + 0x0004)
+#define FDC_WRITE_PORT (FDC_OUT_BASE + 0x0005)
+#define FDC_READ_PORT (FDC_OUT_BASE + 0x0005)
+
+static int fdc_read_data (uint8_t *addr, int len)
+{
+ uint8_t status;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ status = inb(FDC_MAIN_STATUS);
+ if ((status & 0xD0) != 0xD0) {
+#if 0
+ ERROR("fdc_read_data: read data status != READ_DATA: %0x\n",
+ status);
+#endif
+ return -1;
+ }
+ addr[i] = inb(FDC_READ_PORT);
+ }
+
+ return 0;
+}
+
+static inline int fdc_write_cmd (uint8_t cmd)
+{
+ uint8_t status;
+
+ status = inb(FDC_MAIN_STATUS);
+ if ((status & 0xC0) != 0x80) {
+#if 0
+ ERROR("fdc_write_cmd: read data status != WRITE_CMD: %0x\n",
+ status);
+#endif
+ return -1;
+ }
+ outb(FDC_WRITE_PORT, cmd);
+
+ return 0;
+}
+
+static int fdc_reset (void)
+{
+ uint8_t dor;
+
+ dor = inb(FDC_DOR_PORT);
+ /* Stop motors & enter reset */
+ dor &= ~0x34;
+ outb(FDC_DOR_PORT, dor);
+ usleep(1000);
+ /* leave reset state */
+ dor |= 0x04;
+ outb(FDC_DOR_PORT, dor);
+ usleep(1000);
+
+ return 0;
+}
+
+static int fdc_recalibrate (int drv)
+{
+ uint8_t data[2];
+
+ if (drv == 0)
+ data[0] = 0;
+ else
+ data[0] = 1;
+ if (fdc_write_cmd(0x07) < 0) {
+ ERROR("fdc_recalibrate != WRITE_CMD\n");
+ return -1;
+ }
+ if (fdc_write_cmd(data[0]) < 0) {
+ ERROR("fdc_recalibrate data\n");
+ return -1;
+ }
+ /* Wait for drive to go out of busy state */
+ while ((inb(FDC_MAIN_STATUS) & 0x0F) != 0x00)
+ continue;
+ /* Check command status */
+ if (fdc_write_cmd(0x08) < 0) {
+ ERROR("fdc_recalibrate != SENSE_INTERRUPT_STATUS\n");
+ return -1;
+ }
+ data[0] = inb(FDC_READ_PORT);
+ data[1] = inb(FDC_READ_PORT);
+ if (data[0] & 0xD0) {
+ /* recalibrate / seek failed */
+ return -1;
+ }
+ /* Status should be WRITE_CMD right now */
+ if ((inb(FDC_MAIN_STATUS) & 0xD0) != 0x80) {
+ ERROR("fdc_recalibrate status\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fdc_start_read (int drv, uint8_t hd, uint8_t trk, uint8_t sect,
+ int mt)
+{
+ uint8_t fdc_cmd[9], status;
+ int i;
+
+ fdc_cmd[0] = 0x66;
+ if (mt)
+ fdc_cmd[0] |= 0x80;
+ fdc_cmd[1] = 0x00;
+ if (hd)
+ fdc_cmd[1] |= 0x04;
+ if (drv)
+ fdc_cmd[1] |= 0x01;
+ fdc_cmd[2] = trk;
+ fdc_cmd[3] = hd;
+ fdc_cmd[4] = sect;
+ fdc_cmd[5] = 0x02;
+ fdc_cmd[6] = 0x12;
+ fdc_cmd[7] = 0x00;
+ fdc_cmd[8] = 0x00;
+ for (i = 0; i < (int)sizeof(fdc_cmd); i++) {
+ status = inb(FDC_MAIN_STATUS);
+ if ((status & 0xC0) != 0x80) {
+ ERROR("fdc_start_read: write command status != WRITE_CMD: %0x\n",
+ status);
+ return -1;
+ }
+ outb(FDC_WRITE_PORT, fdc_cmd[i]);
+ }
+ status = inb(FDC_MAIN_STATUS);
+ if ((status & 0xD0) != 0xD0) {
+ ERROR("fdc_read_sector: status != READ_DATA: %0x\n", status);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* FDC driver entry points */
+static int fdc_initialize (bloc_device_t *bd, int device)
+{
+ uint8_t fifo[10];
+#if 0
+ uint32_t tape;
+#endif
+ int status;
+
+ if (device > 1)
+ return -1;
+ DPRINTF("Init FDC drive %d\n", device);
+ /* Manage 1.44 MB disks only, for now */
+ bd->drv = device;
+ bd->heads = 2;
+ bd->trks = 80;
+ bd->sects = 18;
+ bd->seclen = 512;
+ bd->tmp = -1;
+ fdc_reset();
+ /* Dump registers */
+ if (fdc_write_cmd(0x0E) < 0) {
+#if 0
+ ERROR("fdc_reset: DUMP_REGISTER != WRITE_CMD\n");
+#endif
+ return -1;
+ }
+ if (fdc_read_data(fifo, 10) < 0) {
+ ERROR("fdc_reset: DUMP_REGISTER data\n");
+ return -1;
+ }
+ /* SPECIFY: be sure we're not in DMA mode */
+ if (fdc_write_cmd(0x03) < 0) {
+ ERROR("fdc_reset: SPECIFY != WRITE_CMD\n");
+ return -1;
+ }
+ if (fdc_write_cmd(fifo[4]) < 0 || fdc_write_cmd(fifo[5] | 0x01)) {
+ ERROR("fdc_reset: SPECIFY data\n");
+ return -1;
+ }
+ /* Status should be WRITE_CMD right now */
+ status = inb(FDC_MAIN_STATUS);
+ if ((status & 0xD0) != 0x80) {
+ ERROR("fdc_initialise: read data status != WRITE_CMD: %0x\n",
+ status);
+ return -1;
+ }
+ /* RECALIBRATE */
+ if (fdc_recalibrate(device) < 0) {
+ printf("fd%c: no floppy inserted\n", 'a' + device);
+ return -1;
+ }
+ printf("fd%c initialized\n", 'a' + device);
+
+ return 0;
+}
+
+static int fdc_read_sector (bloc_device_t *bd, void *buffer, int secnum)
+{
+ int head, cyl, sect;
+ int need_restart;
+
+#if DEBUG_BIOS > 1
+ printf("Read fdc sector: %d at: %0x\n", secnum, (uint32_t)buffer);
+ bd_sect2CHS(bd, secnum, &cyl, &head, &sect);
+ printf("cur: %d hd: %d trk: %d sect: %d\n", bd->bloc, head, cyl, sect);
+#endif
+ if (secnum != bd->tmp) {
+ if (fdc_reset() < 0 || fdc_recalibrate(bd->drv) < 0)
+ return -1;
+ need_restart = 1;
+ } else {
+ need_restart = 0;
+ }
+ bd_sect2CHS(bd, secnum, &cyl, &head, &sect);
+ if (need_restart == 1 || (head == 0 && sect == 1)) {
+ if (need_restart == 0) {
+ /* Read the status */
+ uint8_t tmp[7];
+
+ while (fdc_read_data(tmp, 1) == 0)
+ continue;
+ }
+#if !defined (DEBUG_BIOS)
+ printf(".");
+#endif
+ if (fdc_start_read(bd->drv, head, cyl, sect, 1) < 0)
+ return -1;
+ bd->bloc = secnum;
+ bd->tmp = secnum;
+ }
+ if (fdc_read_data(buffer, bd->seclen) < 0)
+ return -1;
+ bd->tmp++;
+
+ return bd->seclen;
+}
+
+/* SCSI subset */
+/* SPC: primary commands, common to all devices */
+static int spc_inquiry_req (void *buffer, int maxlen)
+{
+ uint8_t *p;
+
+ p = buffer;
+ p[0] = 0x12;
+ /* No page code */
+ p[1] = 0x00;
+ p[2] = 0x00;
+ p[3] = maxlen >> 8;
+ p[4] = maxlen;
+ p[5] = 0x00;
+
+ return 6;
+}
+
+static int spc_inquiry_treat (void *buffer, int len)
+{
+ const uint8_t *p;
+
+ if (len < 36)
+ return -1;
+ p = buffer;
+ if ((p[0] >> 5) != 0) {
+ ERROR("Logical unit not ready\n");
+ return -1;
+ }
+
+ return p[0] & 0x1F;
+}
+
+static int spc_test_unit_ready_req (void *buffer)
+{
+ uint8_t *p;
+
+ p = buffer;
+ p[0] = 0x00;
+ p[1] = 0x00;
+ p[2] = 0x00;
+ p[3] = 0x00;
+ p[4] = 0x00;
+ p[5] = 0x00;
+
+ return 6;
+}
+
+/* MMC: multimedia commands */
+static int mmc_read_capacity_req (void *buffer)
+{
+ uint8_t *p;
+
+ p = buffer;
+ p[0] = 0x25;
+ p[1] = 0x00;
+ p[2] = 0x00;
+ p[3] = 0x00;
+ p[4] = 0x00;
+ p[5] = 0x00;
+ p[6] = 0x00;
+ p[7] = 0x00;
+ p[8] = 0x00;
+ p[9] = 0x00;
+
+ return 10;
+}
+
+static int mmc_read_capacity_treat (uint32_t *size, uint32_t *ssize,
+ const void *buffer, int len)
+{
+ const uint8_t *p;
+
+ if (len != 8)
+ return -1;
+ p = buffer;
+ /* Only handle CDROM address mode for now */
+ *size = ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) + 1;
+ *ssize = ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]);
+
+ return 0;
+}
+
+static int mmc_read12_req (void *buffer, uint32_t LBA, uint32_t size)
+{
+ uint8_t *p;
+
+ p = buffer;
+ p[0] = 0xA8;
+ p[1] = 0x00;
+ p[2] = LBA >> 24;
+ p[3] = LBA >> 16;
+ p[4] = LBA >> 8;
+ p[5] = LBA;
+ p[6] = size >> 24;
+ p[7] = size >> 16;
+ p[8] = size >> 8;
+ p[9] = size;
+ p[10] = 0x00;
+ p[11] = 0x00;
+
+ return 12;
+}
+
+/* IDE disk driver */
+static uint32_t ide_base[2] = { 0x1F0, 0x170, };
+static uint32_t ide_base2[2] = { 0x3F6, 0x376, };
+
+typedef struct ide_ops_t {
+ uint8_t (*port_read)(bloc_device_t *bd, int port);
+ void (*port_write)(bloc_device_t *bd, int port, uint8_t value);
+ uint32_t (*data_readl)(bloc_device_t *bd);
+ void (*data_writel)(bloc_device_t *bd, uint32_t val);
+ void (*control_write)(bloc_device_t *bd, uint32_t val);
+ uint32_t base[4];
+#ifdef USE_OPENFIRMWARE
+ void *OF_private[2];
+#endif
+} ide_ops_t;
+
+/* IDE ISA access */
+static uint8_t ide_isa_port_read (bloc_device_t *bd, int port)
+{
+ return inb(bd->io_base + port);
+}
+
+static void ide_isa_port_write (bloc_device_t *bd, int port, uint8_t value)
+{
+ outb(bd->io_base + port, value);
+}
+
+static uint32_t ide_isa_data_readl (bloc_device_t *bd)
+{
+ return inl(bd->io_base);
+}
+
+static void ide_isa_data_writel (bloc_device_t *bd, uint32_t val)
+{
+ return outl(bd->io_base, val);
+}
+
+static void ide_isa_control_write (bloc_device_t *bd, uint32_t val)
+{
+ outb(bd->tmp, val);
+}
+
+static ide_ops_t ide_isa_ops = {
+ &ide_isa_port_read,
+ &ide_isa_port_write,
+ &ide_isa_data_readl,
+ &ide_isa_data_writel,
+ &ide_isa_control_write,
+ { 0, },
+#ifdef USE_OPENFIRMWARE
+ { NULL, },
+#endif
+};
+
+static ide_ops_t *ide_pci_ops;
+
+/* IDE PCI access for pc */
+static uint8_t ide_pci_port_read (bloc_device_t *bd, int port)
+{
+ eieio();
+
+ return *(uint8_t *)(bd->io_base + port);
+}
+
+static void ide_pci_port_write (bloc_device_t *bd, int port, uint8_t value)
+{
+ *(uint8_t *)(bd->io_base + port) = value;
+ eieio();
+}
+
+static uint32_t ide_pci_data_readl (bloc_device_t *bd)
+{
+ eieio();
+
+ return *((uint32_t *)bd->io_base);
+}
+
+static void ide_pci_data_writel (bloc_device_t *bd, uint32_t val)
+{
+ *(uint32_t *)(bd->io_base) = val;
+ eieio();
+}
+
+static void ide_pci_control_write (bloc_device_t *bd, uint32_t val)
+{
+ *((uint8_t *)bd->tmp) = val;
+ eieio();
+}
+
+static ide_ops_t ide_pci_pc_ops = {
+ &ide_pci_port_read,
+ &ide_pci_port_write,
+ &ide_pci_data_readl,
+ &ide_pci_data_writel,
+ &ide_pci_control_write,
+ { 0, },
+#ifdef USE_OPENFIRMWARE
+ { NULL, },
+#endif
+};
+
+void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1,
+ uint32_t io_base2, uint32_t io_base3,
+ unused void *OF_private)
+{
+ if (ide_pci_ops == NULL) {
+ ide_pci_ops = malloc(sizeof(ide_ops_t));
+ if (ide_pci_ops == NULL)
+ return;
+ memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t));
+ }
+ if ((io_base0 != 0 || io_base1 != 0) &&
+ ide_pci_ops->base[0] == 0 && ide_pci_ops->base[1] == 0) {
+ ide_pci_ops->base[0] = io_base0;
+ ide_pci_ops->base[1] = io_base1;
+#ifdef USE_OPENFIRMWARE
+ ide_pci_ops->OF_private[0] = OF_private;
+#endif
+ }
+ if ((io_base2 != 0 || io_base3 != 0) &&
+ ide_pci_ops->base[2] == 0 && ide_pci_ops->base[3] == 0) {
+ ide_pci_ops->base[2] = io_base2;
+ ide_pci_ops->base[3] = io_base3;
+#ifdef USE_OPENFIRMWARE
+ ide_pci_ops->OF_private[1] = OF_private;
+#endif
+ }
+}
+
+/* IDE PCI access for pmac */
+static uint8_t ide_pmac_port_read (bloc_device_t *bd, int port)
+{
+ uint32_t addr;
+
+ if (port != 8)
+ addr = bd->io_base + (port << 4);
+ else
+ addr = bd->io_base + 0x160;
+ eieio();
+
+ return *((uint8_t *)addr);
+}
+
+static void ide_pmac_port_write (bloc_device_t *bd, int port, uint8_t value)
+{
+ uint32_t addr;
+
+ if (port != 8)
+ addr = bd->io_base + (port << 4);
+ else
+ addr = bd->io_base + 0x160;
+ *((uint8_t *)addr) = value;
+ eieio();
+}
+
+static uint32_t ide_pmac_data_readl (bloc_device_t *bd)
+{
+ eieio();
+ return ldswap32((uint32_t *)bd->io_base);
+ // return *((uint32_t *)bd->io_base);
+}
+
+static void ide_pmac_data_writel (bloc_device_t *bd, uint32_t val)
+{
+ // *((uint32_t *)bd->io_base) = val;
+ stswap32((uint32_t *)bd->io_base, val);
+ eieio();
+}
+
+static void ide_pmac_control_write (bloc_device_t *bd, uint32_t val)
+{
+ ide_pmac_port_write(bd, 8, val);
+}
+
+static ide_ops_t ide_pmac_ops = {
+ &ide_pmac_port_read,
+ &ide_pmac_port_write,
+ &ide_pmac_data_readl,
+ &ide_pmac_data_writel,
+ &ide_pmac_control_write,
+ { 0, },
+#ifdef USE_OPENFIRMWARE
+ { NULL, },
+#endif
+};
+
+void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1,
+ unused void *OF_private)
+{
+ if (ide_pci_ops == NULL) {
+ ide_pci_ops = malloc(sizeof(ide_ops_t));
+ if (ide_pci_ops == NULL)
+ return;
+ memcpy(ide_pci_ops, &ide_pmac_ops, sizeof(ide_ops_t));
+ }
+ if (io_base0 != 0 && ide_pci_ops->base[0] == 0) {
+ ide_pci_ops->base[0] = io_base0;
+#ifdef USE_OPENFIRMWARE
+ ide_pci_ops->OF_private[0] = OF_private;
+#endif
+ }
+ if (io_base1 != 0 && ide_pci_ops->base[1] == 0) {
+ ide_pci_ops->base[1] = io_base1;
+#ifdef USE_OPENFIRMWARE
+ ide_pci_ops->OF_private[1] = OF_private;
+#endif
+ }
+}
+
+static inline uint8_t ide_port_read (bloc_device_t *bd, int port)
+{
+ ide_ops_t *ops = bd->private;
+
+ return ops->port_read(bd, port);
+}
+
+static inline void ide_port_write (bloc_device_t *bd, int port, uint8_t value)
+{
+ ide_ops_t *ops = bd->private;
+
+ ops->port_write(bd, port, value);
+}
+
+static inline uint32_t ide_data_readl (bloc_device_t *bd)
+{
+ ide_ops_t *ops = bd->private;
+
+ return ops->data_readl(bd);
+}
+
+static inline void ide_data_writel (bloc_device_t *bd, uint32_t val)
+{
+ ide_ops_t *ops = bd->private;
+
+ return ops->data_writel(bd, val);
+}
+
+static inline void ide_control_write (bloc_device_t *bd, uint32_t val)
+{
+ ide_ops_t *ops = bd->private;
+
+ return ops->control_write(bd, val);
+}
+
+static int ide_reset (bloc_device_t *bd)
+{
+ int status, is_cdrom, lcyl;
+
+ ide_control_write(bd, 0x04);
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x90) {
+ return -1;
+ }
+ ide_control_write(bd, 0x00);
+ if (bd->drv == 0)
+ ide_port_write(bd, 0x06, 0xa0);
+ else
+ ide_port_write(bd, 0x06, 0xb0);
+
+ lcyl = ide_port_read(bd, 0x04);
+ switch (lcyl) {
+ case 0x00:
+ /* IDE drive */
+ is_cdrom = 0;
+ break;
+ case 0x14:
+ /* ATAPI device */
+ is_cdrom = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ return is_cdrom;
+}
+
+static void atapi_pad_req (void *buffer, int len);
+static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum);
+
+static int ide_initialize (bloc_device_t *bd, int device)
+{
+#ifdef USE_OPENFIRMWARE
+ void *OF_parent;
+#endif
+ const unsigned char *devname, *devtype, *alias;
+ uint32_t atapi_buffer[9];
+ uint32_t size;
+ int status, base, is_cdrom, len, i;
+
+ if (device > 1)
+ base = 1;
+ else
+ base = 0;
+ if (ide_pci_ops != NULL) {
+ bd->private = ide_pci_ops;
+ bd->io_base = ide_pci_ops->base[base];
+ bd->tmp = ide_pci_ops->base[2 + base];
+ if (bd->io_base == 0x00000000 || bd->io_base == 0xFFFFFFFF) {
+ ERROR("No IDE drive %c\n", device);
+ return -1;
+ }
+ } else {
+ bd->private = &ide_isa_ops;
+ bd->io_base = ide_base[base];
+ bd->tmp = ide_base2[base];
+ }
+ bd->drv = device & 1;
+ DPRINTF("Init IDE drive %d-%d (%d)\n", base, bd->drv, device);
+ is_cdrom = ide_reset(bd);
+ printf("ide%d: drive %d: ",
+ (device >> 1), bd->drv);
+ switch(is_cdrom) {
+ case 0:
+ printf("Hard Disk\n");
+ devname = "disk";
+ devtype = "hd";
+ alias = "hd";
+ break;
+ case 1:
+ printf("CD-ROM\n");
+ devname = "cdrom";
+ devtype = "cdrom";
+ alias = "cd";
+ break;
+ default:
+ printf("none\n");
+ devname = NULL;
+ devtype = NULL;
+ alias = NULL;
+ break;
+ }
+ if (is_cdrom < 0)
+ return -1;
+#ifdef USE_OPENFIRMWARE
+ /* Register disk into OF tree */
+ OF_parent = ide_pci_ops->OF_private[base];
+ if (OF_parent != NULL) {
+ bd->OF_private = OF_blockdev_register(OF_parent, bd, devtype,
+ devname, bd->drv, alias);
+ }
+#endif
+ /* Select drive */
+ if (bd->drv == 0)
+ ide_port_write(bd, 0x06, 0x40);
+ else
+ ide_port_write(bd, 0x06, 0x50);
+ /* WIN_DEVICE_RESET */
+ ide_port_write(bd, 0x07, 0x08);
+ status = ide_port_read(bd, 0x07);
+ if (is_cdrom) {
+ if (status != 0x00) {
+ ERROR("WIN_DEVICE_RESET : status %0x != 0x00 (is_cdrom: %d)\n",
+ status, is_cdrom);
+ return -1;
+ }
+ /* TEST_UNIT_READY */
+ DPRINTF("TEST_UNIT_READY\n");
+ len = spc_test_unit_ready_req(&atapi_buffer);
+ atapi_pad_req(&atapi_buffer, len);
+ ide_port_write(bd, 0x07, 0xA0);
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x08) {
+ ERROR("ATAPI TEST_UNIT_READY : status %0x != 0x08\n", status);
+ return -1;
+ }
+ for (i = 0; i < 3; i++) {
+ ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
+ }
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x40) {
+ ERROR("ATAPI TEST_UNIT_READY : status %0x != 0x40\n", status);
+ return -1;
+ }
+ /* INQUIRY */
+ DPRINTF("INQUIRY\n");
+ len = spc_inquiry_req(&atapi_buffer, 36);
+ atapi_pad_req(&atapi_buffer, len);
+ ide_port_write(bd, 0x07, 0xA0);
+ for (i = 0; i < 3; i++)
+ ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x48) {
+ ERROR("ATAPI INQUIRY : status %0x != 0x48\n", status);
+ return -1;
+ }
+ for (i = 0; i < 9; i++)
+ stswap32(&atapi_buffer[i], ide_data_readl(bd));
+ if (spc_inquiry_treat(&atapi_buffer, 36) != 0x05) {
+ ERROR("Only ATAPI CDROMs are handled for now\n");
+ return -1;
+ }
+ /* READ_CAPACITY */
+ DPRINTF("READ_CAPACITY\n");
+ len = mmc_read_capacity_req(&atapi_buffer);
+ atapi_pad_req(&atapi_buffer, len);
+ ide_port_write(bd, 0x07, 0xA0);
+ for (i = 0; i < 3; i++)
+ ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x48) {
+ ERROR("ATAPI READ_CAPACITY : status %0x != 0x48\n", status);
+ return -1;
+ }
+ for (i = 0; i < 2; i++)
+ stswap32(&atapi_buffer[i], ide_data_readl(bd));
+ if (mmc_read_capacity_treat(&size, &bd->seclen,
+ &atapi_buffer, 8) != 0) {
+ ERROR("Error retrieving ATAPI CDROM capacity\n");
+ return -1;
+ }
+ bd->read_sector = &atapi_read_sector;
+ DPRINTF("ATAPI: size=%d ssize=%d\n", size, bd->seclen);
+ } else {
+ if (status != 0x41) {
+ ERROR("WIN_DEVICE_RESET : status %0x != 0x41 (is_cdrom: %d)\n",
+ status, is_cdrom);
+ return -1;
+ }
+ /* WIN_READ_NATIVE_MAX */
+ ide_port_write(bd, 0x07, 0xF8);
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x40) {
+ ERROR("WIN_READ_NATIVE_MAX : status %0x != 0x40\n", status);
+ return -1;
+ }
+ /* Retrieve parameters */
+ size = (ide_port_read(bd, 0x06) & ~0xF0) << 24;
+ size |= ide_port_read(bd, 0x05) << 16;
+ size |= ide_port_read(bd, 0x04) << 8;
+ size |= ide_port_read(bd, 0x03);
+ bd->seclen = 512;
+ }
+ bd->heads = 16;
+ bd->sects = 64;
+ bd->trks = (size + (16 * 64 - 1)) >> 10;
+
+ return 0;
+}
+
+static void atapi_pad_req (void *buffer, int len)
+{
+ uint8_t *p;
+
+ p = buffer;
+ memset(p + len, 0, 12 - len);
+}
+
+static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum)
+{
+ uint32_t atapi_buffer[4];
+ uint8_t *p;
+ uint32_t status, value;
+ int i, len;
+
+ /* select drive */
+ if (bd->drv == 0)
+ ide_port_write(bd, 0x06, 0x40);
+ else
+ ide_port_write(bd, 0x06, 0x50);
+ len = mmc_read12_req(atapi_buffer, secnum, 1);
+ atapi_pad_req(&atapi_buffer, len);
+ ide_port_write(bd, 0x07, 0xA0);
+ for (i = 0; i < 3; i++)
+ ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x48) {
+ ERROR("ATAPI READ12 : status %0x != 0x48\n", status);
+ return -1;
+ }
+ p = buffer;
+ for (i = 0; i < bd->seclen; i += 4) {
+ value = ide_data_readl(bd);
+ *p++ = value;
+ *p++ = value >> 8;
+ *p++ = value >> 16;
+ *p++ = value >> 24;
+ }
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x40) {
+ ERROR("ATAPI READ12 done : status %0x != 0x48\n", status);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum)
+{
+ uint32_t value;
+ uint8_t *p;
+ int status;
+ int i;
+
+ bd->drv &= 1;
+ // printf("ide_read_sector: drv %d secnum %d buf %p\n", bd->drv, secnum, buffer);
+ /* select drive & set highest bytes */
+ if (bd->drv == 0)
+ ide_port_write(bd, 0x06, 0x40 | (secnum >> 24));
+ else
+ ide_port_write(bd, 0x06, 0x50 | (secnum >> 24));
+ /* Set hcyl */
+ ide_port_write(bd, 0x05, secnum >> 16);
+ /* Set lcyl */
+ ide_port_write(bd, 0x04, secnum >> 8);
+ /* Set sect */
+ ide_port_write(bd, 0x03, secnum);
+ /* Read 1 sector */
+ ide_port_write(bd, 0x02, 1);
+ /* WIN_READ */
+ ide_port_write(bd, 0x07, 0x20);
+ status = ide_port_read(bd, 0x07);
+ // DPRINTF("ide_read_sector: try %d\n", secnum);
+ if (status != 0x58) {
+ ERROR("ide_read_sector: %d status %0x != 0x58\n", secnum, status);
+ return -1;
+ }
+ /* Get data */
+ p = buffer;
+ for (i = 0; i < bd->seclen; i += 4) {
+ value = ide_data_readl(bd);
+ *p++ = value;
+ *p++ = value >> 8;
+ *p++ = value >> 16;
+ *p++ = value >> 24;
+ }
+ status = ide_port_read(bd, 0x07);
+ if (status != 0x50) {
+ ERROR("ide_read_sector 6: status %0x != 0x50\n", status);
+ return -1;
+ }
+
+ return bd->seclen;
+}
+
+/* Memory image access driver */
+static int mem_initialize (bloc_device_t *bd, int device)
+{
+ bd->seclen = 512;
+ bd->private = NULL;
+ bd->heads = 1;
+ bd->sects = 1;
+ bd->trks = 1;
+
+ return device == 'm';
+}
+
+static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum)
+{
+ if (buffer != (char *)bd->private + (bd->seclen * secnum)) {
+ memmove(buffer,
+ (char *)bd->private + (bd->seclen * secnum), bd->seclen);
+ }
+
+ return bd->seclen;
+}
+
+static int mem_ioctl (bloc_device_t *bd, int func, void *args)
+{
+ uint32_t *u32;
+ int ret;
+
+ switch (func) {
+ case MEM_SET_ADDR:
+ bd->private = args;
+ ret = 0;
+ break;
+ case MEM_SET_SIZE:
+ u32 = args;
+ bd->trks = (*u32 + bd->seclen - 1) / bd->seclen + 1;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
diff --git a/src/boot.S b/src/boot.S
new file mode 100644
index 0000000..0519b7e
--- /dev/null
+++ b/src/boot.S
@@ -0,0 +1,100 @@
+/*
+ * <boot.S>
+ *
+ * First stage BIOS loader for Open Hack'Ware.
+ *
+ * Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/*
+ * setup one RAM bank then
+ * relocate the one page BIOS second stage into RAM.
+ *
+ * We consider that we know nothing about the CPU state
+ * at the time we enter this code.
+ *
+ */
+
+#define ASSEMBLY_CODE
+#include "bios.h"
+
+.section .rom, "ax"
+.align 2
+_boot_start:
+ /* Minimal setup */
+ li r0, 0 ;
+ /* r11 is _boot_start address */
+ mflr r11 ;
+ addi r11, r11, (_boot_start - _start - 4) ;
+ /* Disable MMU and interruptions */
+ addi r12, r11, (_boot_no_mmu - _boot_start) ;
+ mtspr SRR0, r12 ;
+ mfmsr r12 ;
+ lis r13, 0x0004 ;
+ ori r13, r13, 0xEF71 ;
+ andc r15, r12, r13 ;
+ mtspr SRR1, r12 ;
+ rfi ;
+_boot_no_mmu:
+ /* TODO: initialize physical RAM (we need at least one page)
+ * before doing anything else.
+ * This may be machine dependent code.
+ */
+_boot_copy:
+ /* Copy the second stage bootloader into RAM
+ * We may need a tiny driver if we need to boot from special device
+ * (ie disc-on-chip, ...)
+ */
+ lis r12, (VECTORS_SIZE / 4)@h ;
+ ori r12, r12, (VECTORS_SIZE / 4)@l ;
+ mtctr r12 ;
+ clrrwi r12, r11, BIOS_IMAGE_BITS ;
+ addis r3, r12, VECTORS_SIZE@h ;
+ addi r3, r3, VECTORS_SIZE@l ;
+ subi r12, r12, 4 ;
+ lis r13, VECTORS_BASE@h ;
+ ori r13, r13, VECTORS_BASE@l ;
+ mtlr r13 ;
+ subi r13, r13, 4 ;
+_boot_copy_loop:
+ lwzu r14, 4(r12) ;
+ stwu r14, 4(r13) ;
+ bdnz _boot_copy_loop ;
+ /* Synchronize the whole execution context */
+ addi r12, r11, (_boot_sync - _boot_start) ;
+ mtspr SRR0, r12 ;
+ mfmsr r12 ;
+ mtspr SRR1, r12 ;
+ rfi ;
+_boot_sync:
+ /* All done, jump into the loaded code */
+ blrl ;
+ /* If we ever return, reboot */
+ b _start ;
+
+.space BOOT_SIZE - 4 - (. - _boot_start), 0xFF
+/* Reset entry point */
+ . = 0x1FC
+_start:
+ bl _boot_start ;
diff --git a/src/boot.ld b/src/boot.ld
new file mode 100644
index 0000000..916fd94
--- /dev/null
+++ b/src/boot.ld
@@ -0,0 +1,45 @@
+/*
+ * <boot.ld>
+ *
+ * First stage BIOS loader for Open Hack'Ware linker script.
+ *
+ * Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+OUTPUT_ARCH(powerpc)
+
+MEMORY
+{
+ /* NOTE: some old ld do not support wrapping to zero,
+ so we set a dummy address different from 0xFFFFFE00 */
+ rom (rx) : ORIGIN = 0xEFFFFE00, LENGTH = 512
+}
+
+SECTIONS
+{
+ .rom : { *(.rom) } > rom
+ /DISCARD/ : { *(.text) }
+ /DISCARD/ : { *(.rodata) }
+ /DISCARD/ : { *(.data) }
+ /DISCARD/ : { *(.bss) }
+ /DISCARD/ : { *(.sbss) }
+ /DISCARD/ : { *(.sdata) }
+ /DISCARD/ : { *(.sdata2) }
+ /DISCARD/ : { *(.stab) }
+ /DISCARD/ : { *(.stabstr) }
+ /DISCARD/ : { *(.comment) }
+ /DISCARD/ : { *(.note) }
+}
diff --git a/src/bootinfos.c b/src/bootinfos.c
new file mode 100644
index 0000000..60f85a6
--- /dev/null
+++ b/src/bootinfos.c
@@ -0,0 +1,282 @@
+/*
+ * <bootinfos.c>
+ *
+ * Generate boot informations (bootinfos for Linux and residual data).
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include "bios.h"
+
+#define BI_FIRST 0x1010 /* first record - marker */
+#define BI_LAST 0x1011 /* last record - marker */
+#define BI_CMD_LINE 0x1012
+#define BI_BOOTLOADER_ID 0x1013
+#define BI_INITRD 0x1014
+#define BI_SYSMAP 0x1015
+#define BI_MACHTYPE 0x1016
+#define BI_MEMSIZE 0x1017
+#define BI_BOARD_INFO 0x1018
+
+static inline void put_long (void *addr, uint32_t l)
+{
+ char *pos = addr;
+ pos[0] = (l >> 24) & 0xFF;
+ pos[1] = (l >> 16) & 0xFF;
+ pos[2] = (l >> 8) & 0xFF;
+ pos[3] = l & 0xFF;
+}
+
+static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size,
+ void *data)
+{
+ char *pos = addr;
+
+ put_long(pos, tag);
+ pos += 4;
+ put_long(pos, size + 8);
+ pos += 4;
+ memcpy(pos, data, size);
+ pos += size;
+
+ return pos;
+}
+
+void prepare_bootinfos (void *p, uint32_t memsize,
+ void *cmdline, void *initrd, uint32_t initrd_size)
+{
+ uint32_t tmpi[2];
+
+ /* BI_FIRST */
+ p = set_bootinfo_tag(p, BI_FIRST, 0, NULL);
+ /* BI_CMD_LINE */
+ if (cmdline != 0) {
+ p = set_bootinfo_tag(p, BI_CMD_LINE, strlen(cmdline), cmdline);
+ } else {
+ p = set_bootinfo_tag(p, BI_CMD_LINE, 0, NULL);
+ }
+ /* BI_MEM_SIZE */
+ p = set_bootinfo_tag(p, BI_MEMSIZE, 4, &memsize);
+ /* BI_INITRD */
+ tmpi[0] = (uint32_t)initrd;
+ tmpi[1] = initrd_size;
+ p = set_bootinfo_tag(p, BI_INITRD, 8, tmpi);
+ /* BI_LAST */
+ p = set_bootinfo_tag(p, BI_LAST, 0, 0);
+}
+
+/* Residual data */
+#define MAX_CPUS 16
+#define MAX_SEGS 64
+#define MAX_MEMS 64
+#define MAX_DEVS 256
+
+typedef struct vital_t {
+ /* Motherboard dependents */
+ uint8_t model[32];
+ uint8_t serial[64];
+ uint16_t version;
+ uint16_t revision;
+ uint32_t firmware;
+ uint32_t NVRAM_size;
+ uint32_t nSIMMslots;
+ uint32_t nISAslots;
+ uint32_t nPCIslots;
+ uint32_t nPCMCIAslots;
+ uint32_t nMCAslots;
+ uint32_t nEISAslots;
+ uint32_t CPUHz;
+ uint32_t busHz;
+ uint32_t PCIHz;
+ uint32_t TBdiv;
+ /* CPU infos */
+ uint32_t wwidth;
+ uint32_t page_size;
+ uint32_t ChBlocSize;
+ uint32_t GrSize;
+ /* Cache and TLBs */
+ uint32_t cache_size;
+ uint32_t cache_type;
+ uint32_t cache_assoc;
+ uint32_t cache_lnsize;
+ uint32_t Icache_size;
+ uint32_t Icache_assoc;
+ uint32_t Icache_lnsize;
+ uint32_t Dcache_size;
+ uint32_t Dcache_assoc;
+ uint32_t Dcache_lnsize;
+ uint32_t TLB_size;
+ uint32_t TLB_type;
+ uint32_t TLB_assoc;
+ uint32_t ITLB_size;
+ uint32_t ITLB_assoc;
+ uint32_t DTLB_size;
+ uint32_t DTLB_assoc;
+ void *ext_vital;
+} vital_t;
+
+typedef struct PPC_CPU_t {
+ uint32_t pvr;
+ uint32_t serial;
+ uint32_t L2_size;
+ uint32_t L2_assoc;
+} PPC_CPU_t;
+
+typedef struct map_t {
+ uint32_t usage;
+ uint32_t base;
+ uint32_t count;
+} map_t;
+
+typedef struct PPC_mem_t {
+ uint32_t size;
+} PPC_mem_t;
+
+typedef struct PPC_device_t {
+ uint32_t busID;
+ uint32_t devID;
+ uint32_t serial;
+ uint32_t flags;
+ uint32_t type;
+ uint32_t subtype;
+ uint32_t interface;
+ uint32_t spare;
+} PPC_device_t;
+
+typedef struct residual_t {
+ uint32_t length;
+ uint16_t version;
+ uint16_t revision;
+ vital_t vital;
+ uint32_t nCPUs;
+ PPC_CPU_t CPUs[MAX_CPUS];
+ uint32_t max_mem;
+ uint32_t good_mem;
+ uint32_t nmaps;
+ map_t maps[MAX_SEGS];
+ uint32_t nmems;
+ PPC_mem_t memories[MAX_MEMS];
+ uint32_t ndevices;
+ PPC_device_t devices[MAX_DEVS];
+ /* TOFIX: No PNP devices */
+} residual_t;
+
+void residual_build (void *p, uint32_t memsize,
+ uint32_t load_base, uint32_t load_size,
+ uint32_t last_alloc)
+{
+ const unsigned char model[] = "Qemu\0PPC\0";
+ residual_t *res = p;
+ int i;
+
+ if (res == NULL)
+ return;
+ res->length = sizeof(residual_t);
+ res->version = 1;
+ res->revision = 0;
+ memcpy(res->vital.model, model, sizeof(model));
+ res->vital.version = 1;
+ res->vital.revision = 0;
+ res->vital.firmware = 0x1D1;
+ res->vital.NVRAM_size = 0x2000;
+ res->vital.nSIMMslots = 1;
+ res->vital.nISAslots = 0;
+ res->vital.nPCIslots = 0;
+ res->vital.nPCMCIAslots = 0;
+ res->vital.nMCAslots = 0;
+ res->vital.nEISAslots = 0;
+ res->vital.CPUHz = 200 * 1000 * 1000;
+ res->vital.busHz = 100 * 1000 * 1000;
+ res->vital.PCIHz = 33 * 1000 * 1000;
+ res->vital.TBdiv = 1000;
+ res->vital.wwidth = 32;
+ res->vital.page_size = 4096;
+ res->vital.ChBlocSize = 32;
+ res->vital.GrSize = 32;
+ res->vital.cache_size = 0;
+ res->vital.cache_type = 0; /* No cache */
+ res->vital.cache_assoc = 8; /* Same as 601 */
+ res->vital.cache_lnsize = 32;
+ res->vital.Icache_size = 0;
+ res->vital.Icache_assoc = 8;
+ res->vital.Icache_lnsize = 32;
+ res->vital.Dcache_size = 0;
+ res->vital.Dcache_assoc = 8;
+ res->vital.Dcache_lnsize = 32;
+ res->vital.TLB_size = 0;
+ res->vital.TLB_type = 0; /* None */
+ res->vital.TLB_assoc = 2;
+ res->vital.ITLB_size = 0;
+ res->vital.ITLB_assoc = 2;
+ res->vital.DTLB_size = 0;
+ res->vital.DTLB_assoc = 2;
+ res->vital.ext_vital = NULL;
+ res->nCPUs = 1;
+ res->CPUs[0].pvr = mfpvr();
+ res->CPUs[0].serial = 0;
+ res->CPUs[0].L2_size = 0;
+ res->CPUs[0].L2_assoc = 8;
+ /* Memory infos */
+ res->max_mem = memsize;
+ res->good_mem = memsize;
+ /* Memory mappings */
+ /* First segment: firmware */
+ last_alloc = (last_alloc + 4095) & ~4095;
+ res->maps[0].usage = 0x0007;
+ res->maps[0].base = 0x00000000;
+ res->maps[0].count = last_alloc >> 12;
+ i = 1;
+ if (last_alloc != load_base) {
+ /* Free memory between firmware and boot image */
+ res->maps[1].usage = 0x0010;
+ res->maps[1].base = last_alloc >> 12;
+ res->maps[1].count = (load_base - last_alloc) >> 12;
+ i++;
+ }
+ /* Boot image */
+ load_size = (load_size + 4095) & ~4095;
+ res->maps[i].usage = 0x0008;
+ res->maps[i].base = load_base >> 12;
+ res->maps[i].count = load_size >> 12;
+ i++;
+ /* Free memory */
+ res->maps[i].usage = 0x0010;
+ res->maps[i].base = (load_base + load_size) >> 12;
+ res->maps[i].count = (memsize >> 12) - res->maps[i].base;
+ i++;
+ /* ISA IO region : 8MB */
+ res->maps[i].usage = 0x0040;
+ res->maps[i].base = 0x80000000 >> 12;
+ res->maps[i].count = 0x00800000 >> 12;
+ i++;
+ /* System registers : 8MB */
+ res->maps[i].usage = 0x0200;
+ res->maps[i].base = 0xBF800000 >> 12;
+ res->maps[i].count = 0x00800000 >> 12;
+ i++;
+ /* System ROM : 64 kB */
+ res->maps[i].usage = 0x2000;
+ res->maps[i].base = 0xFFFF0000 >> 12;
+ res->maps[i].count = 0x00010000 >> 12;
+ i++;
+ res->nmaps = i;
+ /* Memory SIMMs */
+ res->nmems = 1;
+ res->memories[0].size = memsize;
+ /* Describe no devices */
+ res->ndevices = 0;
+}
diff --git a/src/char.c b/src/char.c
new file mode 100644
index 0000000..4e74ac6
--- /dev/null
+++ b/src/char.c
@@ -0,0 +1,780 @@
+/*
+ * <char.c>
+ *
+ * Open Hack'Ware BIOS character devices drivers.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * cuda driver: Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "adb.h"
+
+//#define DEBUG_CHARDEV
+//#define DEBUG_CUDA
+//#define DEBUG_ADB
+
+#ifdef DEBUG_CHARDEV
+#define CHARDEV_DPRINTF(fmt, args...) \
+do { dprintf("CHARDEV - %s: " fmt, __func__ , ##args); } while (0)
+#else
+#define CHARDEV_DPRINTF(fmt, args...) do { } while (0)
+#endif
+
+/* Generic character device API */
+struct chardev_t {
+ chardev_t *next;
+ int type;
+ cops_t *ops;
+ void *private;
+};
+
+static chardev_t *char_devices;
+
+int chardev_register (int type, cops_t *ops, void *private)
+{
+ chardev_t *dev, **cur;
+
+ CHARDEV_DPRINTF("Register char device of type %d\n", type);
+ if (type > CHARDEV_LAST)
+ return -1;
+ dev = malloc(sizeof(chardev_t));
+ if (dev == NULL)
+ return -1;
+ dev->type = type;
+ dev->ops = ops;
+ dev->private = private;
+ for (cur = &char_devices; *cur != NULL; cur = &((*cur)->next))
+ continue;
+ *cur = dev;
+
+ return 0;
+}
+
+int chardev_open (chardev_t *dev)
+{
+ if (dev->ops == NULL)
+ return -1;
+ if (dev->ops->open == NULL)
+ return 0;
+
+ return (*dev->ops->open)(dev->private);
+}
+
+int chardev_close (chardev_t *dev)
+{
+ if (dev->ops == NULL)
+ return -1;
+ if (dev->ops->close == NULL)
+ return 0;
+
+ return (*dev->ops->close)(dev->private);
+}
+
+int chardev_read (chardev_t *dev, void *buffer, int maxlen)
+{
+ unsigned char *p;
+ int len;
+ int c;
+
+ if (dev->ops == NULL || dev->ops->read == NULL)
+ return -1;
+
+ p = buffer;
+ for (len = 0; len < maxlen; len++) {
+ c = (*dev->ops->read)(dev->private);
+ if (c < 0)
+ break;
+ *p++ = c;
+ }
+
+ return len;
+}
+
+int chardev_write (chardev_t *dev, const void *buffer, int maxlen)
+{
+ const unsigned char *p;
+ int len;
+ int c;
+
+ if (dev->ops == NULL || dev->ops->write == NULL)
+ return -1;
+
+ p = buffer;
+ for (len = 0; len < maxlen; len++) {
+ c = *p++;
+ if ((*dev->ops->write)(dev->private, c) < 0)
+ break;
+ }
+
+ return len;
+}
+
+int chardev_type (chardev_t *dev)
+{
+ return dev->type;
+}
+
+/* Console driver */
+static chardev_t *console_in_devs[17], *console_out_devs[17];
+static int console_last_in;
+
+int console_open (void)
+{
+ chardev_t *cur;
+ int i, j, n, register_outd;
+
+ i = 0;
+ j = 0;
+ n = 0;
+ /* Check all character devices and register those which are usable
+ * as IO for the console
+ */
+ CHARDEV_DPRINTF("enter\n");
+ for (cur = char_devices; cur != NULL; cur = cur->next, n++) {
+ register_outd = 0;
+ switch (cur->type) {
+ case CHARDEV_SERIAL:
+ CHARDEV_DPRINTF("one serial port\n");
+ register_outd = 1;
+ /* No break here */
+ case CHARDEV_KBD:
+ CHARDEV_DPRINTF("one input port %d %d\n", n, i);
+ if (i < 16 && chardev_open(cur) == 0) {
+ console_in_devs[i++] = cur;
+ }
+ if (!register_outd)
+ break;
+ /* No break here */
+ case CHARDEV_DISPLAY:
+ CHARDEV_DPRINTF("one output port %d %d\n", n, j);
+ if (j < 16 && chardev_open(cur) == 0) {
+ console_out_devs[j++] = cur;
+ }
+ break;
+ default:
+ CHARDEV_DPRINTF("Skip device %d\n", n);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int console_read (void *buffer, int maxlen)
+{
+ chardev_t *cur;
+ int i, in;
+
+ CHARDEV_DPRINTF("enter\n");
+ /* Get data from the first in device responding to us */
+ cur = console_in_devs[console_last_in];
+ for (i = console_last_in;;) {
+ CHARDEV_DPRINTF("read from device %d\n", i);
+ in = chardev_read(cur, buffer, maxlen);
+ if (in > 0) {
+ console_last_in = i;
+#if 0
+ printf("Read %d chars '%c'...\n", in, *((char *)buffer));
+#endif
+ return in;
+ }
+ cur = console_in_devs[++i];
+ if (cur == NULL) {
+ i = 0;
+ cur = console_in_devs[0];
+ }
+ if (i == console_last_in || cur == NULL)
+ break;
+ }
+ console_last_in = i;
+ CHARDEV_DPRINTF("out\n");
+
+ return 0;
+}
+
+int console_write (const void *buffer, int len)
+{
+ chardev_t *cur;
+ int i, out, max;
+
+ /* Write data to all devices */
+ max = 0;
+ for (i = 0; i < 16; i++) {
+ cur = console_out_devs[i];
+ if (cur == NULL)
+ break;
+ out = chardev_write(cur, buffer, len);
+ if (out > max)
+ max = out;
+ }
+
+ return max;
+}
+
+void console_close (void)
+{
+ chardev_t *cur;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ cur = console_out_devs[i];
+ if (cur == NULL)
+ break;
+ chardev_close(cur);
+ console_out_devs[i] = NULL;
+ }
+}
+
+/* PC serial port "driver" */
+#define PC_SERIAL_LSR_OFFSET (5)
+typedef struct pc_serial_t {
+ uint16_t base;
+} pc_serial_t;
+
+static int pc_serial_open (unused void *private)
+{
+ return 0;
+}
+
+static int pc_serial_writeb (void *private, int data)
+{
+ pc_serial_t *serial = private;
+
+ /* Wait for the FIFO to be ready to accept more chars.
+ * Note: this is completely buggy and would never work on real hardware,
+ * as the serial port (especialy the FIFO) has not been programmed
+ * anywhere before !
+ */
+ if (!(inb(serial->base + PC_SERIAL_LSR_OFFSET) & 0x20))
+ usleep(100);
+ outb(serial->base, data);
+
+ return 0;
+}
+
+static int pc_serial_readb (void *private)
+{
+ pc_serial_t *serial = private;
+
+ if (!(inb(serial->base + PC_SERIAL_LSR_OFFSET) & 0x01))
+ return -1;
+
+ return inb(serial->base);
+}
+
+static int pc_serial_close (unused void *private)
+{
+ return 0;
+}
+
+static cops_t pc_serial_ops = {
+ .open = &pc_serial_open,
+ .read = &pc_serial_readb,
+ .write = &pc_serial_writeb,
+ .close = &pc_serial_close,
+};
+
+/* XXX: debug stuff only ! (TOFIX with a generic debug console) */
+int serial_write (const void *buffer, int len)
+{
+ const char *p;
+
+ for (p = buffer; len > 0; len--) {
+ if (!(inb(0x3F8 + PC_SERIAL_LSR_OFFSET) & 0x20))
+ usleep(100);
+ outb(0x3F8, *p++);
+ }
+
+ return 0;
+}
+
+int pc_serial_register (uint16_t base)
+{
+ pc_serial_t *serial;
+
+ serial = malloc(sizeof(pc_serial_t));
+ if (serial == NULL)
+ return -1;
+ serial->base = base;
+ /* XXX: TODO: initialize the serial port (FIFO, speed, ...) */
+
+ return chardev_register(CHARDEV_SERIAL, &pc_serial_ops, serial);
+}
+
+/* VGA console device */
+static int vga_cons_open (unused void *private)
+{
+ return 0;
+}
+
+static int vga_cons_writeb (unused void *private, int data)
+{
+ vga_putchar(data);
+
+ return 0;
+}
+
+static int vga_cons_close (unused void *private)
+{
+ return 0;
+}
+
+static cops_t vga_cons_ops = {
+ .open = &vga_cons_open,
+ .read = NULL,
+ .write = &vga_cons_writeb,
+ .close = &vga_cons_close,
+};
+
+int vga_console_register (void)
+{
+ return chardev_register(CHARDEV_DISPLAY, &vga_cons_ops, NULL);
+}
+
+/* Macintosh via-cuda driver */
+#ifdef DEBUG_CUDA
+#define CUDA_DPRINTF(fmt, args...) \
+do { dprintf("CUDA - %s: " fmt, __func__ , ##args); } while (0)
+#else
+#define CUDA_DPRINTF(fmt, args...) do { } while (0)
+#endif
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS 0x200 /* skip between registers */
+#define B 0 /* B-side data */
+#define A RS /* A-side data */
+#define DIRB (2*RS) /* B-side direction (1=output) */
+#define DIRA (3*RS) /* A-side direction (1=output) */
+#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
+#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
+#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
+#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
+#define SR (10*RS) /* Shift register */
+#define ACR (11*RS) /* Auxiliary control register */
+#define PCR (12*RS) /* Peripheral control register */
+#define IFR (13*RS) /* Interrupt flag register */
+#define IER (14*RS) /* Interrupt enable register */
+#define ANH (15*RS) /* A-side data, no handshake */
+
+/* Bits in B data register: all active low */
+#define TREQ 0x08 /* Transfer request (input) */
+#define TACK 0x10 /* Transfer acknowledge (output) */
+#define TIP 0x20 /* Transfer in progress (output) */
+
+/* Bits in ACR */
+#define SR_CTRL 0x1c /* Shift register control bits */
+#define SR_EXT 0x0c /* Shift on external clock */
+#define SR_OUT 0x10 /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET 0x80 /* set bits in IER */
+#define IER_CLR 0 /* clear bits in IER */
+#define SR_INT 0x04 /* Shift register full/empty */
+
+#define CUDA_BUF_SIZE 16
+
+#define ADB_PACKET 0
+#define CUDA_PACKET 1
+
+struct cuda_t {
+ uint32_t base;
+ adb_bus_t *adb_bus;
+};
+
+static uint8_t cuda_readb (cuda_t *dev, int reg)
+{
+ return *(volatile uint8_t *)(dev->base + reg);
+}
+
+static void cuda_writeb (cuda_t *dev, int reg, uint8_t val)
+{
+ *(volatile uint8_t *)(dev->base + reg) = val;
+}
+
+static void cuda_wait_irq (cuda_t *dev)
+{
+ int val;
+
+ CUDA_DPRINTF("\n");
+ for(;;) {
+ val = cuda_readb(dev, IFR);
+ cuda_writeb(dev, IFR, val & 0x7f);
+ if (val & SR_INT)
+ break;
+ }
+}
+
+static int cuda_request (cuda_t *dev, uint8_t pkt_type, const uint8_t *buf,
+ int buf_len, uint8_t *obuf)
+{
+ int i, obuf_len, val;
+
+ cuda_writeb(dev, ACR, cuda_readb(dev, ACR) | SR_OUT);
+ cuda_writeb(dev, SR, pkt_type);
+ cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP);
+ if (buf) {
+ CUDA_DPRINTF("Send buf len: %d\n", buf_len);
+ /* send 'buf' */
+ for(i = 0; i < buf_len; i++) {
+ cuda_wait_irq(dev);
+ cuda_writeb(dev, SR, buf[i]);
+ cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK);
+ }
+ }
+ cuda_wait_irq(dev);
+ cuda_writeb(dev, ACR, cuda_readb(dev, ACR) & ~SR_OUT);
+ cuda_readb(dev, SR);
+ cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK);
+
+ obuf_len = 0;
+ if (obuf) {
+ cuda_wait_irq(dev);
+ cuda_readb(dev, SR);
+ cuda_writeb(dev, B, cuda_readb(dev, B) & ~TIP);
+ for(;;) {
+ cuda_wait_irq(dev);
+ val = cuda_readb(dev, SR);
+ if (obuf_len < CUDA_BUF_SIZE)
+ obuf[obuf_len++] = val;
+ if (cuda_readb(dev, B) & TREQ)
+ break;
+ cuda_writeb(dev, B, cuda_readb(dev, B) ^ TACK);
+ }
+ cuda_writeb(dev, B, cuda_readb(dev, B) | TIP | TACK);
+
+ cuda_wait_irq(dev);
+ cuda_readb(dev, SR);
+ }
+ CUDA_DPRINTF("Got len: %d\n", obuf_len);
+
+ return obuf_len;
+}
+
+#if 0
+void cuda_test(void)
+{
+ int keycode;
+ printf("cuda test:\n");
+ cuda_init(0x80400000 + 0x16000);
+ for(;;) {
+ keycode = adb_read_key();
+ if (keycode >= 0)
+ printf("keycode=%x\n", keycode);
+ }
+}
+#endif
+
+/* Cuda ADB glue */
+static int cuda_adb_req (void *host, const uint8_t *snd_buf, int len,
+ uint8_t *rcv_buf)
+{
+ uint8_t buffer[CUDA_BUF_SIZE], *pos;
+
+ CUDA_DPRINTF("len: %d %02x\n", len, snd_buf[0]);
+ len = cuda_request(host, ADB_PACKET, snd_buf, len, buffer);
+ if (len > 1 && buffer[0] == ADB_PACKET) {
+ pos = buffer + 2;
+ len -= 2;
+ } else {
+ pos = buffer + 1;
+ len = -1;
+ }
+ memcpy(rcv_buf, pos, len);
+
+ return len;
+}
+
+cuda_t *cuda_init (uint32_t base)
+{
+ cuda_t *cuda;
+
+ CUDA_DPRINTF(" base=%08x\n", base);
+ cuda = malloc(sizeof(cuda_t));
+ if (cuda == NULL)
+ return NULL;
+ cuda->base = base;
+ cuda_writeb(cuda, B, cuda_readb(cuda, B) | TREQ | TIP);
+#if 0
+ {
+ int len;
+
+ /* enable auto poll */
+ buf[0] = 0x01;
+ buf[1] = 1;
+ len = cuda_request(cuda, CUDA_PACKET, buf, 2, obuf);
+ if (len != 2 || obuf[0] != CUDA_PACKET || obuf[1] != 1) {
+ printf("cuda: invalid reply for auto poll request");
+ free(cuda);
+ return NULL;
+ }
+ }
+#endif
+ cuda->adb_bus = adb_bus_new(cuda, &cuda_adb_req);
+ if (cuda->adb_bus == NULL) {
+ free(cuda);
+ return NULL;
+ }
+ adb_bus_init(cuda->adb_bus);
+
+ return cuda;
+}
+
+void cuda_reset (cuda_t *cuda)
+{
+ adb_bus_reset(cuda->adb_bus);
+}
+
+/* ADB generic driver */
+#ifdef DEBUG_ADB
+#define ADB_DPRINTF(fmt, args...) \
+do { dprintf("ADB - %s: " fmt, __func__ , ##args); } while (0)
+#else
+#define ADB_DPRINTF(fmt, args...) do { } while (0)
+#endif
+
+int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg,
+ uint8_t *buf, int len)
+{
+ uint8_t adb_send[ADB_BUF_SIZE], adb_rcv[ADB_BUF_SIZE];
+
+ ADB_DPRINTF("cmd: %d reg: %d len: %d\n", cmd, reg, len);
+ if (dev->bus == NULL || dev->bus->req == NULL) {
+ ADB_DPRINTF("ERROR: invalid bus !\n");
+ bug();
+ }
+ /* Sanity checks */
+ if (cmd != ADB_LISTEN && len != 0) {
+ /* No buffer transmitted but for LISTEN command */
+ ADB_DPRINTF("in buffer for cmd %d\n", cmd);
+ return -1;
+ }
+ if (cmd == ADB_LISTEN && ((len < 2 || len > 8) || buf == NULL)) {
+ /* Need a buffer with a regular register size for LISTEN command */
+ ADB_DPRINTF("no/invalid buffer for ADB_LISTEN (%d)\n", len);
+ return -1;
+ }
+ if ((cmd == ADB_TALK || cmd == ADB_LISTEN) && reg > 3) {
+ /* Need a valid register number for LISTEN and TALK commands */
+ ADB_DPRINTF("invalid reg for TALK/LISTEN command (%d %d)\n", cmd, reg);
+ return -1;
+ }
+ switch (cmd) {
+ case ADB_SEND_RESET:
+ adb_send[0] = ADB_SEND_RESET;
+ break;
+ case ADB_FLUSH:
+ adb_send[0] = (dev->addr << 4) | ADB_FLUSH;
+ break;
+ case ADB_LISTEN:
+ memcpy(adb_send + 1, buf, len);
+ /* No break here */
+ case ADB_TALK:
+ adb_send[0] = (dev->addr << 4) | cmd | reg;
+ break;
+ }
+ memset(adb_rcv, 0, ADB_BUF_SIZE);
+ len = (*dev->bus->req)(dev->bus->host, adb_send, len + 1, adb_rcv);
+#ifdef DEBUG_ADB
+ printf("%x %x %x %x\n", adb_rcv[0], adb_rcv[1], adb_rcv[2], adb_rcv[3]);
+#endif
+ switch (len) {
+ case 0:
+ /* No data */
+ break;
+ case 2 ... 8:
+ /* Register transmitted */
+ if (buf != NULL)
+ memcpy(buf, adb_rcv, len);
+ break;
+ default:
+ /* Should never happen */
+ ADB_DPRINTF("Cmd %d returned %d bytes !\n", cmd, len);
+ return -1;
+ }
+ ADB_DPRINTF("retlen: %d\n", len);
+
+ return len;
+}
+
+void adb_bus_reset (adb_bus_t *bus)
+{
+ adb_reset(bus);
+}
+
+adb_bus_t *adb_bus_new (void *host,
+ int (*req)(void *host, const uint8_t *snd_buf,
+ int len, uint8_t *rcv_buf))
+{
+ adb_bus_t *new;
+
+ new = malloc(sizeof(adb_bus_t));
+ if (new == NULL)
+ return NULL;
+ new->host = host;
+ new->req = req;
+
+ return new;
+}
+
+/* ADB */
+void *adb_kbd_new (void *private);
+
+static int adb_mouse_open (void *private);
+static int adb_mouse_close (void *private);
+static int adb_mouse_read (void *private);
+
+static cops_t adb_mouse_ops = {
+ &adb_mouse_open,
+ &adb_mouse_close,
+ &adb_mouse_read,
+ NULL,
+};
+
+/* Check and relocate all ADB devices as suggested in
+ * ADB_manager Apple documentation
+ */
+int adb_bus_init (adb_bus_t *bus)
+{
+ uint8_t buffer[ADB_BUF_SIZE];
+ uint8_t adb_addresses[16] =
+ { 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, 0, };
+ adb_dev_t tmp_device, **cur;
+ int address;
+ int reloc = 0, next_free = 7;
+ int keep;
+
+ /* Reset the bus */
+ ADB_DPRINTF("\n");
+ adb_reset(bus);
+ cur = &bus->devices;
+ memset(&tmp_device, 0, sizeof(adb_dev_t));
+ tmp_device.bus = bus;
+ for (address = 1; address < 8 && adb_addresses[reloc] > 0;) {
+ if (address == ADB_RES) {
+ /* Reserved */
+ address++;
+ continue;
+ }
+ ADB_DPRINTF("Check device on ADB address %d\n", address);
+ tmp_device.addr = address;
+ switch (adb_reg_get(&tmp_device, 3, buffer)) {
+ case 0:
+ ADB_DPRINTF("No device on ADB address %d\n", address);
+ /* Register this address as free */
+ if (adb_addresses[next_free] != 0)
+ adb_addresses[next_free++] = address;
+ /* Check next ADB address */
+ address++;
+ break;
+ case 2:
+ /* One device answered :
+ * make it available and relocate it to a free address
+ */
+ if (buffer[0] == ADB_CHADDR) {
+ /* device self test failed */
+ ADB_DPRINTF("device on ADB address %d self-test failed "
+ "%02x %02x %02x\n", address,
+ buffer[0], buffer[1], buffer[2]);
+ keep = 0;
+ } else {
+ ADB_DPRINTF("device on ADB address %d self-test OK\n",
+ address);
+ keep = 1;
+ }
+ ADB_DPRINTF("Relocate device on ADB address %d to %d (%d)\n",
+ address, adb_addresses[reloc], reloc);
+ buffer[0] = ((buffer[0] & 0x40) & ~0x90) | adb_addresses[reloc];
+ if (keep == 1)
+ buffer[0] |= 0x20;
+ buffer[1] = ADB_CHADDR_NOCOLL;
+ if (adb_reg_set(&tmp_device, 3, buffer, 2) < 0) {
+ ADB_DPRINTF("ADB device relocation failed\n");
+ return -1;
+ }
+ if (keep == 1) {
+ *cur = malloc(sizeof(adb_dev_t));
+ if (*cur == NULL) {
+ return -1;
+ }
+ (*cur)->type = address;
+ (*cur)->bus = bus;
+ (*cur)->addr = adb_addresses[reloc++];
+ /* Flush buffers */
+ adb_flush(*cur);
+ switch ((*cur)->type) {
+ case ADB_PROTECT:
+ ADB_DPRINTF("Found one protected device\n");
+ break;
+ case ADB_KEYBD:
+ ADB_DPRINTF("Found one keyboard\n");
+ adb_kbd_new(*cur);
+ break;
+ case ADB_MOUSE:
+ ADB_DPRINTF("Found one mouse\n");
+ chardev_register(CHARDEV_MOUSE, &adb_mouse_ops, *cur);
+ break;
+ case ADB_ABS:
+ ADB_DPRINTF("Found one absolute positioning device\n");
+ break;
+ case ADB_MODEM:
+ ADB_DPRINTF("Found one modem\n");
+ break;
+ case ADB_RES:
+ ADB_DPRINTF("Found one ADB res device\n");
+ break;
+ case ADB_MISC:
+ ADB_DPRINTF("Found one ADB misc device\n");
+ break;
+ }
+ cur = &((*cur)->next);
+ }
+ break;
+ case 1:
+ case 3 ... 7:
+ /* SHOULD NOT HAPPEN : register 3 is always two bytes long */
+ ADB_DPRINTF("Invalid returned len for ADB register 3\n");
+ return -1;
+ case -1:
+ /* ADB ERROR */
+ ADB_DPRINTF("error gettting ADB register 3\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* ADB mouse chardev interface (TODO) */
+static int adb_mouse_open (unused void *private)
+{
+ return 0;
+}
+
+static int adb_mouse_close (unused void *private)
+{
+ return 0;
+}
+
+static int adb_mouse_read (unused void *private)
+{
+ return -1;
+}
diff --git a/src/dev/bus/adb.h b/src/dev/bus/adb.h
new file mode 100644
index 0000000..e48b120
--- /dev/null
+++ b/src/dev/bus/adb.h
@@ -0,0 +1,102 @@
+/*
+ * ADB bus definitions for Open Hack'Ware
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined(__OHW_ADB_H__)
+#define __OHW_ADB_H__
+
+typedef struct adb_bus_t adb_bus_t;
+typedef struct adb_dev_t adb_dev_t;
+
+#define ADB_BUF_SIZE 8
+struct adb_bus_t {
+ void *host;
+ int (*req)(void *host, const uint8_t *snd_buf, int len, uint8_t *rcv_buf);
+ adb_dev_t *devices;
+};
+
+struct adb_dev_t {
+ adb_dev_t *next;
+ adb_bus_t *bus;
+ uint8_t addr;
+ uint8_t type;
+ uint32_t state;
+};
+
+#define ADB_BUF_SIZE 8
+
+/* ADB commands */
+enum {
+ ADB_SEND_RESET = 0x00,
+ ADB_FLUSH = 0x01,
+ ADB_LISTEN = 0x08,
+ ADB_TALK = 0x0C,
+};
+/* ADB default IDs before relocation */
+enum {
+ ADB_PROTECT = 0x01,
+ ADB_KEYBD = 0x02,
+ ADB_MOUSE = 0x03,
+ ADB_ABS = 0x04,
+ ADB_MODEM = 0x05,
+ ADB_RES = 0x06,
+ ADB_MISC = 0x07,
+};
+/* ADB special device handlers IDs */
+enum {
+ ADB_CHADDR = 0x00,
+ ADB_CHADDR_ACTIV = 0xFD,
+ ADB_CHADDR_NOCOLL = 0xFE,
+ ADB_SELF_TEST = 0xFF,
+};
+
+int adb_cmd (adb_dev_t *dev, uint8_t cmd, uint8_t reg,
+ uint8_t *buf, int len);
+void adb_bus_reset (adb_bus_t *bus);
+adb_bus_t *adb_bus_new (void *host,
+ int (*req)(void *host, const uint8_t *snd_buf,
+ int len, uint8_t *rcv_buf));
+int adb_bus_init (adb_bus_t *bus);
+
+static inline int adb_reset (adb_bus_t *bus)
+{
+ adb_dev_t fake_device;
+
+ memset(&fake_device, 0, sizeof(adb_dev_t));
+ fake_device.bus = bus;
+
+ return adb_cmd(&fake_device, ADB_SEND_RESET, 0, NULL, 0);
+}
+
+static inline int adb_flush (adb_dev_t *dev)
+{
+ return adb_cmd(dev, ADB_FLUSH, 0, NULL, 0);
+}
+
+static inline int adb_reg_get (adb_dev_t *dev, uint8_t reg, uint8_t *buf)
+{
+ return adb_cmd(dev, ADB_TALK, reg, buf, 0);
+}
+
+static inline int adb_reg_set (adb_dev_t *dev, uint8_t reg,
+ uint8_t *buf, int len)
+{
+ return adb_cmd(dev, ADB_LISTEN, reg, buf, len);
+}
+
+#endif /* !defined(__OHW_ADB_H__) */
diff --git a/src/dev/char/char.h b/src/dev/char/char.h
new file mode 100644
index 0000000..14f17e7
--- /dev/null
+++ b/src/dev/char/char.h
@@ -0,0 +1,29 @@
+/*
+ * <char.h>
+ *
+ * Open Hack'Ware BIOS misc char devices definitions.
+ *
+ * Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_DEV_CHAR_H__)
+#define __OHW_DEV_CHAR_H__
+
+/* Keyboard devices registration */
+int pckbd_register (void);
+void *adb_kbd_new (void *private);
+
+#endif /* !defined (__OHW_DEV_CHAR_H__) */
diff --git a/src/dev/char/kbd.c b/src/dev/char/kbd.c
new file mode 100644
index 0000000..78f5204
--- /dev/null
+++ b/src/dev/char/kbd.c
@@ -0,0 +1,122 @@
+/*
+ * <kbd.c>
+ *
+ * Open Hack'Ware BIOS generic keyboard input translation.
+ *
+ * Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "kbd.h"
+
+//#define DEBUG_KBD
+#ifdef DEBUG_KBD
+#define KBD_DPRINTF(fmt, args...) \
+do { dprintf("KBD - %s: " fmt, __func__ , ##args); } while (0)
+#else
+#define KBD_DPRINTF(fmt, args...) do { } while (0)
+#endif
+
+void *kbd_new (int len)
+{
+ kbd_t *kbd;
+
+ if (len < (int)sizeof(kbd_t)) {
+ kbd = NULL;
+ } else {
+ kbd = malloc(len);
+ if (kbd != NULL)
+ memset(kbd, 0, len);
+ }
+
+ return kbd;
+}
+
+int kbd_set_keymap (kbd_t *kbd, int nb_keys, keymap_t *keymap)
+{
+ kbd->nb_keys = nb_keys;
+ kbd->keymap = keymap;
+
+ return 0;
+}
+
+int kbd_translate_key (kbd_t *kbd, int keycode, int up_down)
+{
+ keymap_t *keyt;
+ int mod_state, key, type;
+ int ret;
+
+ ret = -1;
+ /* Get key table */
+ if (keycode < kbd->nb_keys) {
+ keyt = &kbd->keymap[keycode];
+ /* Get modifier state */
+ mod_state = (kbd->mod_state | (kbd->mod_state >> 8)) & 0xFF;
+ /* Adjust with lock */
+ if (keyt->lck_shift >= 0) {
+ if ((kbd->mod_state >> (16 + keyt->lck_shift)) & 0x01) {
+ KBD_DPRINTF("adjust with lock %02x => %02x (%d %08x)\n",
+ mod_state,
+ mod_state ^ ((kbd->mod_state >>
+ (16 + keyt->lck_shift)) &
+ 0x01),
+ keyt->lck_shift, kbd->mod_state);
+ }
+ mod_state ^= (kbd->mod_state >> (16 + keyt->lck_shift)) & 0x01;
+ }
+ key = keyt->trans[mod_state];
+ type = key & 0xFF000000;
+ key &= ~0xFF000000;
+ switch (type) {
+ case KBD_TYPE_REGULAR:
+ if (!up_down) {
+ /* We don't care about up events on "normal" keys */
+ ret = key;
+ }
+ break;
+ case KBD_TYPE_LOCK:
+ if (!up_down) {
+ kbd->mod_state ^= key;
+ ret = -2;
+ KBD_DPRINTF("Change modifier type %d key %04x %s => %08x\n",
+ type, key, up_down ? "up" : "down",
+ kbd->mod_state);
+ }
+ break;
+ case KBD_TYPE_LMOD:
+ case KBD_TYPE_RMOD:
+ if (up_down)
+ kbd->mod_state &= ~key;
+ else
+ kbd->mod_state |= key;
+ KBD_DPRINTF("Change modifier type %d key %04x %s => %08x\n",
+ type, key, up_down ? "up" : "down", kbd->mod_state);
+ ret = -2; /* The caller may know the key was a modifier */
+ break;
+ default:
+ KBD_DPRINTF("Unknown key: keycode=%02x mod_state=%02x (%08x)\n",
+ keycode, mod_state, kbd->mod_state);
+ break;
+ }
+ } else {
+ KBD_DPRINTF("Unmanaged key: keycode=%02x mod_state %08x\n",
+ keycode, kbd->mod_state);
+ }
+
+ return ret;
+}
diff --git a/src/dev/char/kbd.h b/src/dev/char/kbd.h
new file mode 100644
index 0000000..3a56609
--- /dev/null
+++ b/src/dev/char/kbd.h
@@ -0,0 +1,104 @@
+/*
+ * <kbd.h>
+ *
+ * Open Hack'Ware BIOS generic keyboard management definitions.
+ *
+ * Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_KBD_H__)
+#define __OHW_KBD_H__
+
+typedef struct kbd_t kbd_t;
+typedef struct keymap_t keymap_t;
+struct kbd_t {
+ uint32_t mod_state;
+ /* Modifier state
+ * 0x00 kk ll rr
+ * | | | |
+ * Not used for now -+ | | |
+ * Locks ---------------+ | |
+ * Left modifiers ---------+ |
+ * Right modifiers -----------+
+ */
+ int nb_keys;
+ keymap_t *keymap;
+};
+
+/* Modifiers */
+typedef enum {
+ KBD_MOD_SHIFT = 0x01,
+ KBD_MOD_CTRL = 0x02,
+ KBD_MOD_ALT = 0x04,
+ KBD_MOD_CMD = 0x08,
+ KBD_MOD_OPT = 0x10,
+} kbd_modifiers;
+
+/* Locks */
+typedef enum {
+ KBD_LCK_CAPS = 0x01,
+ KBD_LCK_NUM = 0x02,
+ KBD_LCK_SCROLL = 0x04,
+} kbd_locks;
+
+/* Lock shifts */
+typedef enum {
+ KBD_SH_NONE = -1,
+ KBD_SH_CAPS = 0,
+ KBD_SH_NUML = 1,
+ KBD_SH_SCRL = 2,
+} kbd_lck_shifts;
+
+enum {
+ KBD_TYPE_REGULAR = 0 << 24,
+ KBD_TYPE_LMOD = 1 << 24,
+ KBD_TYPE_RMOD = 2 << 24,
+ KBD_TYPE_LOCK = 3 << 24,
+};
+
+#define KBD_MOD_MAP(mod) \
+KBD_SH_NONE, { (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \
+ (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \
+ (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), \
+ (mod), (mod), (mod), (mod), (mod), (mod), (mod), (mod), }
+#define KBD_MOD_MAP_LSHIFT KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_SHIFT)
+#define KBD_MOD_MAP_RSHIFT KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_SHIFT << 8))
+#define KBD_MOD_MAP_LCTRL KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_CTRL)
+#define KBD_MOD_MAP_RCTRL KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_CTRL << 8))
+#define KBD_MOD_MAP_LALT KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_ALT)
+#define KBD_MOD_MAP_RALT KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_ALT << 8))
+#define KBD_MOD_MAP_LCMD KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_CMD)
+#define KBD_MOD_MAP_RCMD KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_CMD << 8))
+#define KBD_MOD_MAP_LOPT KBD_MOD_MAP(KBD_TYPE_LMOD | KBD_MOD_OPT)
+#define KBD_MOD_MAP_ROPT KBD_MOD_MAP(KBD_TYPE_RMOD | (KBD_MOD_OPT << 8))
+#define KBD_MOD_MAP_CAPS KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_CAPS << 16))
+#define KBD_MOD_MAP_NUML KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_NUML << 16))
+#define KBD_MOD_MAP_SCROLL KBD_MOD_MAP(KBD_TYPE_LOCK | (KBD_LCK_SCRL << 16))
+#define KBD_MAP_NONE KBD_MOD_MAP(-1)
+
+/* Keymap definition */
+struct keymap_t {
+ /* Set the lock which applies to this key (if any) */
+ int lck_shift;
+ /* Key translations */
+ uint32_t trans[32];
+};
+
+void *kbd_new (int len);
+int kbd_set_keymap (kbd_t *kbd, int nb_keys, keymap_t *keymap);
+int kbd_translate_key (kbd_t *kbd, int keycode, int up_down);
+
+#endif /* !defined (__OHW_KBD_H__) */
diff --git a/src/dev/char/kbdadb.c b/src/dev/char/kbdadb.c
new file mode 100644
index 0000000..4f7dd37
--- /dev/null
+++ b/src/dev/char/kbdadb.c
@@ -0,0 +1,482 @@
+/*
+ * <adbkbd.c>
+ *
+ * Open Hack'Ware BIOS ADB keyboard support.
+ *
+ * Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "adb.h"
+#include "kbd.h"
+
+#ifdef DEBUG_ADB
+#define ADB_DPRINTF(fmt, args...) \
+do { dprintf("ADB - %s: " fmt, __func__ , ##args); } while (0)
+#else
+#define ADB_DPRINTF(fmt, args...) do { } while (0)
+#endif
+
+/* ADB US keyboard translation map
+ * XXX: for now, only shift modifier is defined
+ */
+static keymap_t ADB_kbd_us[] = {
+ /* 0x00 */
+ { KBD_SH_CAPS, { 0x61, 0x41, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x73, 0x53, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x64, 0x44, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x66, 0x46, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x68, 0x48, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x67, 0x47, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x7A, 0x5A, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x78, 0x58, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x08 */
+ { KBD_SH_CAPS, { 0x63, 0x43, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x76, 0x56, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x60, 0x40, -1, -1, -1, -1, -1, -1, /* ? */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x62, 0x42, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x71, 0x51, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x77, 0x57, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x65, 0x45, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x72, 0x52, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x10 */
+ { KBD_SH_CAPS, { 0x79, 0x59, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x74, 0x54, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x31, 0x21, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x32, 0x40, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x33, 0x23, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x34, 0x24, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x36, 0x5E, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x35, 0x25, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x18 */
+ { KBD_SH_CAPS, { 0x3D, 0x2B, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x39, 0x28, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x37, 0x26, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x2D, 0x5F, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x38, 0x2A, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x30, 0x29, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x5D, 0x7D, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x6F, 0x4F, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x20 */
+ { KBD_SH_CAPS, { 0x75, 0x55, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x5B, 0x7B, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x69, 0x49, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x70, 0x50, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MOD_MAP(0x0D), },
+ { KBD_SH_CAPS, { 0x6C, 0x4C, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x6A, 0x4A, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x27, 0x22, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x28 */
+ { KBD_SH_CAPS, { 0x6B, 0x4B, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x3B, 0x3A, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x5C, 0x7C, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x2C, 0x3C, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x2F, 0x3F, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x6E, 0x4E, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x6D, 0x4D, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_CAPS, { 0x2E, 0x3E, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x30 : tab */
+ { KBD_MOD_MAP(0x09), },
+ /* 0x31 : space */
+ { KBD_MOD_MAP(0x20), },
+ /* 0x32 : '<' '>' */
+ { KBD_SH_CAPS, { 0x3C, 0x3E, -1, -1, -1, -1, -1, -1, /* ? */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x33 : backspace */
+ { KBD_MOD_MAP(0x08), },
+ { KBD_MAP_NONE, },
+ /* 0x35 : ESC */
+ { KBD_MOD_MAP(0x1B), },
+ /* 0x36 : control */
+ { KBD_MOD_MAP_LCTRL, },
+ /* 0x37 : command */
+ { KBD_MOD_MAP_LCMD, },
+ /* 0x38 : left shift */
+ { KBD_MOD_MAP_LSHIFT, },
+ /* 0x39 : caps-lock */
+ { KBD_MOD_MAP_CAPS, },
+ /* 0x3A : option */
+ { KBD_MOD_MAP_LOPT, },
+ /* 0x3B : left */
+ { KBD_MAP_NONE, },
+ /* 0x3C : right */
+ { KBD_MAP_NONE, },
+ /* 0x3D : down */
+ { KBD_MAP_NONE, },
+ /* 0x3E : up */
+ { KBD_MAP_NONE, },
+ { KBD_MAP_NONE, },
+ /* 0x40 */
+ { KBD_MAP_NONE, },
+ { KBD_SH_NUML, { 0x7F, 0x2E, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MAP_NONE, },
+ { KBD_SH_NONE, { 0x2A, 0x2A, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MAP_NONE, },
+ { KBD_SH_NONE, { 0x2B, 0x2B, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MAP_NONE, },
+ { KBD_MOD_MAP(0x7F), },
+ /* 0x48 */
+ { KBD_MAP_NONE, },
+ { KBD_MAP_NONE, },
+ { KBD_MAP_NONE, },
+ { KBD_SH_NONE, { 0x2F, 0x2F, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MOD_MAP(0x0D), },
+ { KBD_MAP_NONE, },
+ { KBD_SH_NONE, { 0x2D, 0x2D, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MAP_NONE, },
+ /* 0x50 */
+ { KBD_MAP_NONE, },
+ { KBD_SH_NONE, { 0x3D, 0x3D, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x30, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x31, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x32, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x33, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x34, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x35, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ /* 0x58 */
+ { KBD_SH_NUML, { -1, 0x36, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x37, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MAP_NONE, },
+ { KBD_SH_NUML, { -1, 0x38, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_SH_NUML, { -1, 0x39, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { KBD_MAP_NONE, },
+ { KBD_MOD_MAP(0x2F), },
+ { KBD_MAP_NONE, },
+ /* 0x60 : F5 */
+ { KBD_MAP_NONE, },
+ /* 0x61 : F6 */
+ { KBD_MAP_NONE, },
+ /* 0x62 : F7 */
+ { KBD_MAP_NONE, },
+ /* 0x63 : F3 */
+ { KBD_MAP_NONE, },
+ /* 0x64 : F8 */
+ { KBD_MAP_NONE, },
+ /* 0x65 : F9 */
+ { KBD_MAP_NONE, },
+ { KBD_MAP_NONE, },
+ /* 0x67 : F11 */
+ { KBD_MAP_NONE, },
+ /* 0x68 */
+ { KBD_MAP_NONE, },
+ /* 0x69 : F13 */
+ { KBD_MAP_NONE, },
+ { KBD_MAP_NONE, },
+ /* 0x6B : F14 */
+ { KBD_MAP_NONE, },
+ { KBD_MAP_NONE, },
+ /* 0x6D : F10 */
+ { KBD_MAP_NONE, },
+ { KBD_MAP_NONE, },
+ /* 0x6F : F12 */
+ { KBD_MAP_NONE, },
+ /* 0x70 */
+ { KBD_MAP_NONE, },
+ /* 0x71 : F15 */
+ { KBD_MAP_NONE, },
+ /* 0x72 : help */
+ { KBD_MAP_NONE, },
+ /* 0x73 : home */
+ { KBD_MAP_NONE, },
+ /* 0x74 : page up */
+ { KBD_MAP_NONE, },
+ /* 0x75 : del */
+ { KBD_MAP_NONE, },
+ /* 0x76 : F4 */
+ { KBD_MAP_NONE, },
+ /* 0x77 : end */
+ { KBD_MAP_NONE, },
+ /* 0x78 : F2 */
+ { KBD_MAP_NONE, },
+ /* 0x79 : page down */
+ { KBD_MAP_NONE, },
+ /* 0x7A : F1 */
+ { KBD_MAP_NONE, },
+ /* 0x7B : right shift */
+ { KBD_MOD_MAP_RSHIFT, },
+ /* 0x7C : right option */
+ { KBD_MOD_MAP_ROPT, },
+ /* 0x7D : right control */
+ { KBD_MOD_MAP_RCTRL, },
+ { KBD_MAP_NONE, },
+ /* 0x7F : power */
+ { KBD_MAP_NONE, },
+};
+
+typedef struct adb_kbd_t adb_kbd_t;
+struct adb_kbd_t {
+ kbd_t kbd;
+ int next_key;
+};
+
+static int adb_kbd_open (unused void *private)
+{
+ return 0;
+}
+
+static int adb_kbd_close (unused void *private)
+{
+ return 0;
+}
+
+static int adb_kbd_read (void *private)
+{
+ uint8_t buffer[ADB_BUF_SIZE];
+ adb_dev_t *dev = private;
+ adb_kbd_t *kbd;
+ int key;
+ int ret;
+
+ kbd = (void *)dev->state;
+ ADB_DPRINTF("enter\n");
+ /* Get saved state */
+ ret = -1;
+ for (key = -1; key == -1; ) {
+ if (kbd->next_key != -1) {
+ key = kbd->next_key;
+ kbd->next_key = -1;
+ } else {
+ if (adb_reg_get(dev, 0, buffer) != 2) {
+ goto out;
+ }
+ kbd->next_key = buffer[1] == 0xFF ? -1 : buffer[1];
+ key = buffer[0];
+ }
+ ret = kbd_translate_key(&kbd->kbd, key & 0x7F, key >> 7);
+ ADB_DPRINTF("Translated %d (%02x) into %d (%02x)\n",
+ key, key, ret, ret);
+ }
+ out:
+
+ return ret;
+}
+
+static cops_t adb_kbd_ops = {
+ &adb_kbd_open,
+ &adb_kbd_close,
+ &adb_kbd_read,
+ NULL,
+};
+
+void *adb_kbd_new (void *private)
+{
+ adb_kbd_t *kbd;
+ adb_dev_t *dev = private;
+
+ kbd = kbd_new(sizeof(adb_kbd_t));
+ if (kbd != NULL) {
+ kbd_set_keymap(&kbd->kbd,
+ sizeof(ADB_kbd_us) / sizeof(keymap_t), ADB_kbd_us);
+ kbd->next_key = -1;
+ dev->state = (int32_t)kbd;
+ chardev_register(CHARDEV_KBD, &adb_kbd_ops, private);
+ }
+
+ return kbd;
+}
diff --git a/src/dev/char/pckbd.c b/src/dev/char/pckbd.c
new file mode 100644
index 0000000..45b5a67
--- /dev/null
+++ b/src/dev/char/pckbd.c
@@ -0,0 +1,214 @@
+/*
+ * <pckbd.c>
+ *
+ * Open Hack'Ware BIOS PC keyboard driver.
+ *
+ * Copyright (c) 2005 Jocelyn Mayer
+ *
+ * This code is a rework (mostly simplification) from code
+ * proposed by Matthew Wood <mwood@realmsys.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+
+/* IO definitions */
+#define PCKBD_IO_BASE 0x60
+#define PCKBD_COMMAND_OFFSET 0x4
+#define PCKBD_STATUS_OFFSET 0x4
+
+/* Indexes for keyboard state */
+#define SHIFT 0x1
+#define CTRL 0x2
+#define ALT 0x4
+
+/* Scan codes */
+#define L_SHIFT 0x2a
+#define R_SHIFT 0x36
+#define L_CTRL 0x1d
+/* XXX: R_CTRL ? */
+#define L_ALT 0x38
+/* XXX: missing capslock */
+/* XXX: TODO: add keypad/numlock ... (pc105 kbd) */
+
+typedef struct kbdmap_t kbdmap_t;
+struct kbdmap_t {
+ char translate[8];
+};
+
+typedef struct pckbd_t pckbd_t;
+struct pckbd_t {
+ int modifiers;
+ kbdmap_t *map;
+ int maplen;
+ int io_base;
+};
+
+/* XXX: should not be here cause it's locale dependent */
+static kbdmap_t pc_map_us[] = {
+ /* 0x00 */
+ { { -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { { 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, }, },
+ { { '1', '!', -1, -1, '1', '!', -1, -1, }, },
+ { { '2', '\'', '\'', -1, -1, '2', '\'', '\'', }, },
+ { { '3', '#', -1, -1, '3', '#', -1, -1, }, },
+ { { '4', '$', -1, -1, '4', '$', -1, -1, }, },
+ { { '5', '%', -1, -1, '5', '%', -1, -1, }, },
+ { { '6', '^', -1, -1, '6', '^', -1, -1, }, },
+ /* 0x08 */
+ { { '7', '&', -1, -1, '7', '&', -1, -1, }, },
+ { { '8', '*', -1, -1, '8', '*', -1, -1, }, },
+ { { '9', '(', -1, -1, '9', '(', -1, -1, }, },
+ { { '0', ')', -1, -1, '0', ')', -1, -1, }, },
+ { { '-', '_', -1, -1, '-', '_', -1, -1, }, },
+ { { '=', '+', -1, -1, '=', '+', -1, -1, }, },
+ { { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, }, },
+ { { 0x2a, -1, -1, -1, 0x2a, -1, -1, -1, }, },
+ /* 0x10 */
+ { { 'q', 'Q', -1, -1, 'q', 'Q', -1, -1, }, },
+ { { 'w', 'W', -1, -1, 'w', 'W', -1, -1, }, },
+ { { 'e', 'E', -1, -1, 'e', 'E', -1, -1, }, },
+ { { 'r', 'R', -1, -1, 'r', 'R', -1, -1, }, },
+ { { 't', 'T', -1, -1, 't', 'T', -1, -1, }, },
+ { { 'y', 'Y', -1, -1, 'y', 'Y', -1, -1, }, },
+ { { 'u', 'U', -1, -1, 'u', 'U', -1, -1, }, },
+ { { 'i', 'I', -1, -1, 'i', 'I', -1, -1, }, },
+ /* 0x18 */
+ { { 'o', 'O', -1, -1, 'o', 'O', -1, -1, }, },
+ { { 'p', 'P', -1, -1, 'p', 'P', -1, -1, }, },
+ { { '[', '{', 0x1b, 0x1b, '[', '{', 0x1b, 0x1b, }, },
+ { { ']', '}', -1, -1, ']', '}', -1, -1, }, },
+ { { 0x0d, 0x0d, '\r', '\r', 0x0d, 0x0d, '\r', '\r', }, },
+ { { -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { { 'a', 'A', -1, -1, 'a', 'A', -1, -1, }, },
+ { { 's', 'S', -1, -1, 's', 'S', -1, -1, }, },
+ /* 0x20 */
+ { { 'd', 'D', -1, -1, 'd', 'D', -1, -1, }, },
+ { { 'f', 'F', -1, -1, 'f', 'F', -1, -1, }, },
+ { { 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, }, },
+ { { 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, }, },
+ { { 'j', 'J', '\r', '\r', 'j', 'J', '\r', '\r', }, },
+ { { 'k', 'K', -1, -1, 'k', 'K', -1, -1, }, },
+ { { 'l', 'L', -1, -1, 'l', 'L', -1, -1, }, },
+ { { ';', ':', -1, -1, ';', ':', -1, -1, }, },
+ /* 0x28 */
+ { { '\'', '"', -1, -1, '\'', '"', -1, -1, }, },
+ { { '`', '~', -1, -1, '`', '~', -1, -1, }, },
+ { { 0x02, -1, -1, -1, -1, -1, -1, -1, }, },
+ { { '\\', '|', -1, -1, '\\', '|', -1, -1, }, },
+ { { 'z', 'Z', -1, -1, 'z', 'Z', -1, -1, }, },
+ { { 'x', 'X', -1, -1, 'x', 'X', -1, -1, }, },
+ { { 'c', 'C', -1, -1, 'c', 'C', -1, -1, }, },
+ { { 'v', 'V', 0x16, 0x16, 'v', 'V', -1, -1, }, },
+ /* 0x30 */
+ { { 'b', 'B', -1, -1, 'b', 'B', -1, -1, }, },
+ { { 'n', 'N', -1, -1, 'n', 'N', -1, -1, }, },
+ { { 'm', 'M', 0x0d, 0x0d, 'm', 'M', 0x0d, 0x0d, }, },
+ { { ',', '<', -1, -1, ',', '<', -1, -1, }, },
+ { { '.', '>', -1, -1, '.', '>', -1, -1, }, },
+ { { '/', '?', -1, -1, '/', '?', -1, -1, }, },
+ { { -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { { '*', '*', -1, -1, '*', '*', -1, -1, }, },
+ /* 0x38 */
+ { { -1, -1, -1, -1, -1, -1, -1, -1, }, },
+ { { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }, },
+};
+
+static int pckbd_open (unused void *private)
+{
+ return 0;
+}
+
+static int pckbd_close (unused void *private)
+{
+ return 0;
+}
+
+static int pckbd_readb (void *private)
+{
+ pckbd_t *kbd = private;
+ int status, key, up, mod;
+ int ret;
+
+ for (ret = -1; ret < 0; ) {
+ status = inb(kbd->io_base + PCKBD_STATUS_OFFSET);
+ if (!(status & 1)) {
+ /* No more data available */
+ break;
+ }
+ key = inb(kbd->io_base);
+ up = (key & 0x80) != 0;
+ key &= ~0x80;
+ switch (key) {
+ case 0:
+ break;
+ case L_ALT:
+ mod = ALT;
+ goto set_modifiers;
+ case L_SHIFT:
+ case R_SHIFT:
+ mod = SHIFT;
+ goto set_modifiers;
+ case L_CTRL:
+#if 0 /* XXX: missing definition */
+ case R_CTRL:
+#endif
+ mod = CTRL;
+ set_modifiers:
+ if (up)
+ kbd->modifiers &= ~mod;
+ else
+ kbd->modifiers |= mod;
+ break;
+ default:
+ /* We don't care about up events or unknown keys */
+ if (!up && key < kbd->maplen)
+ ret = kbd->map[key].translate[kbd->modifiers];
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static cops_t pckbd_ops = {
+ &pckbd_open,
+ &pckbd_close,
+ &pckbd_readb,
+ NULL,
+};
+
+int pckbd_register (void)
+{
+ pckbd_t *kbd;
+
+ kbd = malloc(sizeof(pckbd_t));
+ if (kbd == NULL)
+ return -1;
+ memset(kbd, 0, sizeof(pckbd_t));
+ /* Set IO base */
+ /* XXX: should be a parameter... */
+ kbd->io_base = PCKBD_IO_BASE;
+ /* Set default keymap */
+ kbd->map = pc_map_us;
+ kbd->maplen = sizeof(pc_map_us) / sizeof(kbdmap_t);
+ /* Reset modifiers state */
+ kbd->modifiers = 0x00;
+ chardev_register(CHARDEV_KBD, &pckbd_ops, kbd);
+
+ return 0;
+}
diff --git a/src/libc/include/ctype.h b/src/libc/include/ctype.h
new file mode 100644
index 0000000..09309c1
--- /dev/null
+++ b/src/libc/include/ctype.h
@@ -0,0 +1,113 @@
+/*
+ * <ctype.h>
+ *
+ * Open Hack'Ware BIOS POSIX like ctype definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_CTYPE_H__)
+#define __OHW_CTYPE_H__
+
+/* Beware that those routines only support ASCII */
+static inline int islower (int c)
+{
+ return c >= 'a' && c <= 'z';
+}
+
+static inline int isupper (int c)
+{
+ return c >= 'A' && c <= 'Z';
+}
+
+static inline int isalpha (int c)
+{
+ return islower(c) || isupper(c);
+}
+
+static inline int isdigit (int c)
+{
+ return c >= '0' && c <= '9';
+}
+
+static inline int isalnum (int c)
+{
+ return isalpha(c) || isdigit(c);
+}
+
+static inline int isxdigit (int c)
+{
+ return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+}
+
+static inline int isspace (int c)
+{
+ return c == ' ' || c == '\f' || c == '\n' || c == '\r' ||
+ c == '\t' || c == '\v';
+}
+
+static inline int isgraph (int c)
+{
+ return (c >= 0x21 && c <= 0x7E) || (c >= 0xA1 && c <= 0xFF);
+}
+
+static inline int isprint (int c)
+{
+ return isgraph(c) && c != ' ';
+}
+
+static inline int ispunct (int c)
+{
+ return isprint(c) && !isalpha(c) && !isspace(c);
+}
+
+static inline int isblank (int c)
+{
+ return c == ' ' || c == '\t';
+}
+
+static inline int iscntrl (int c)
+{
+ return !isprint(c);
+}
+
+static inline int isascii (int c)
+{
+ return (c & 0x80) == 0;
+}
+
+static inline int tolower (int c)
+{
+ if (isupper(c))
+ c |= 0x20;
+
+ return c;
+}
+
+static inline int toupper (int c)
+{
+ if (islower(c))
+ c &= ~0x20;
+
+ return c;
+}
+
+static inline int toascii (int c)
+{
+ return c & ~0x80;
+}
+
+#endif /* !defined (__OHW_CTYPE_H__) */
diff --git a/src/libc/include/endian.h b/src/libc/include/endian.h
new file mode 100644
index 0000000..87fc546
--- /dev/null
+++ b/src/libc/include/endian.h
@@ -0,0 +1,514 @@
+/*
+ * <endian.h>
+ *
+ * Open Hack'Ware BIOS: provides all common endianness conversions functions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+/*
+ * This file provides:
+ * void cpu_to_be16p (uint16_t *outp, uint16_t in);
+ * void cpu_to_be32p (uint32_t *outp, uint32_t in);
+ * void cpu_to_be64p (uint64_t *outp, uint64_t in);
+ * void cpu_to_le16p (uint16_t *outp, uint16_t in);
+ * void cpu_to_le32p (uint32_t *outp, uint32_t in);
+ * void cpu_to_le64p (uint64_t *outp, uint64_t in);
+ * void endian_to_cpu16p (uint16_t *outp, uint16_t in, endian_t endian);
+ * void endian_to_cpu32p (uint32_t *outp, uint32_t in, endian_t endian);
+ * void endian_to_cpu64p (uint64_t *outp, uint64_t in, endian_t endian);
+ * void cpu16_to_endianp (uint16_t *outp, uint16_t in, endian_t endian);
+ * void cpu32_to_endianp (uint32_t *outp, uint32_t in, endian_t endian);
+ * void cpu64_to_endianp (uint64_t *outp, uint64_t in, endian_t endian);
+ *
+ */
+
+#if !defined (__OHW_ENDIAN_H__)
+#define __OHW_ENDIAN_H__
+
+#include <stdint.h>
+
+typedef enum endian_t endian_t;
+enum endian_t {
+ ENDIAN_1234 = 0,
+ ENDIAN_4321,
+ ENDIAN_3412,
+ ENDIAN_2143,
+};
+
+/* Generic endian conversion functions */
+static inline void generic_cpu_swap16p (uint16_t *outp, uint16_t in)
+{
+ *outp = ((in & 0xFF00) >> 8) | ((in & 0x00FF) << 8);
+}
+
+static inline void generic_cpu_swap32p (uint32_t *outp, uint32_t in)
+{
+ *outp = ((in & 0xFF000000) >> 24) | ((in & 0x00FF0000) >> 8) |
+ ((in & 0x0000FF00) << 8) | ((in & 0x000000FF) << 24);
+}
+
+static inline void generic_cpu_swap64p (uint64_t *outp, uint64_t in)
+{
+ *outp = ((in & 0xFF00000000000000ULL) >> 56) |
+ ((in & 0x00FF000000000000ULL) >> 40) |
+ ((in & 0x0000FF0000000000ULL) >> 24) |
+ ((in & 0x000000FF00000000ULL) >> 8) |
+ ((in & 0x00000000FF000000ULL) << 8) |
+ ((in & 0x0000000000FF0000ULL) << 24) |
+ ((in & 0x000000000000FF00ULL) << 40) |
+ ((in & 0x00000000000000FFULL) << 56);
+}
+
+static inline void generic_cpu_swap64p_32 (uint64_t *outp, uint64_t in)
+{
+ uint32_t *_outp = (uint32_t *)outp;
+
+ generic_cpu_swap32p(_outp, in);
+ generic_cpu_swap32p(_outp + 1, in >> 32);
+}
+
+#if defined (__i386__)
+
+#define __CPU_ENDIAN_4321__
+#define __CPU_LENGTH_32__
+
+#elif defined (__x86_64__)
+
+#define __CPU_ENDIAN_4321__
+#define __CPU_LENGTH_64__
+
+#elif defined (__powerpc__)
+
+#define __CPU_ENDIAN_1234__
+#define __CPU_LENGTH_32__
+
+#define __HAVE_CPU_SWAP16P__
+static inline void cpu_swap16p (uint16_t *outp, uint16_t in)
+{
+ __asm__ __volatile__ ("sthbrx %4, 0(%3)");
+}
+
+#define __HAVE_CPU_SWAP32P__
+static inline void cpu_swap32p (uint32_t *outp, uint32_t in)
+{
+ __asm__ __volatile__ ("stwbrx %4, 0(%3)");
+}
+
+#define __HAVE_CPU_SWAP64P__
+static inline void cpu_swap64p (uint64_t *outp, uint64_t in)
+{
+ return generic_cpu_swap64p_32(outp, in);
+}
+
+#else
+
+#error "unsupported CPU architecture"
+
+#endif
+
+/* Use generic swap function if no cpu specific were provided */
+#if !defined (__HAVE_CPU_SWAP16P__)
+static inline void cpu_swap16p (uint16_t *outp, uint16_t in)
+{
+ generic_cpu_swap16p(outp, in);
+}
+#endif
+
+#if !defined (__HAVE_CPU_SWAP32P__)
+static inline void cpu_swap32p (uint32_t *outp, uint32_t in)
+{
+ generic_cpu_swap32p(outp, in);
+}
+#endif
+
+#if !defined (__HAVE_CPU_SWAP64P__)
+static inline void cpu_swap64p (uint64_t *outp, uint64_t in)
+{
+#if defined (__CPU_LENGTH_64__)
+ generic_cpu_swap64p(outp, in);
+#elif defined (__CPU_LENGTH_32__)
+ generic_cpu_swap64p_32(outp, in);
+#else
+#error "Don't know how to make 64 bits swapping on this arch"
+#endif
+}
+#endif
+
+static inline void cpu_nswap16p (uint16_t *outp, uint16_t in)
+{
+ *outp = in;
+}
+
+static inline void cpu_nswap32p (uint32_t *outp, uint32_t in)
+{
+ *outp = in;
+}
+
+static inline void cpu_nswap64p (uint64_t *outp, uint64_t in)
+{
+ *outp = in;
+}
+
+static inline void _endian_be16_p (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ switch (endian) {
+ case ENDIAN_4321:
+ case ENDIAN_2143:
+ cpu_swap16p(outp, in);
+ break;
+ case ENDIAN_1234:
+ case ENDIAN_3412:
+ cpu_nswap16p(outp, in);
+ break;
+ }
+}
+
+static inline void _endian_be32_p (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ switch (endian) {
+ case ENDIAN_4321:
+ cpu_swap32p(outp, in);
+ break;
+ case ENDIAN_1234:
+ cpu_nswap32p(outp, in);
+ break;
+ case ENDIAN_2143:
+ /* TODO */
+ break;
+ case ENDIAN_3412:
+ /* TODO */
+ break;
+ }
+}
+
+static inline void _endian_be64_p (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ switch (endian) {
+ case ENDIAN_4321:
+ cpu_swap64p(outp, in);
+ break;
+ case ENDIAN_1234:
+ cpu_nswap64p(outp, in);
+ break;
+ case ENDIAN_2143:
+ /* TODO */
+ break;
+ case ENDIAN_3412:
+ /* TODO */
+ break;
+ }
+}
+
+static inline void _endian_le16_p (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ switch (endian) {
+ case ENDIAN_4321:
+ case ENDIAN_2143:
+ cpu_nswap16p(outp, in);
+ break;
+ case ENDIAN_1234:
+ case ENDIAN_3412:
+ cpu_swap16p(outp, in);
+ break;
+ }
+}
+
+static inline void _endian_le32_p (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ switch (endian) {
+ case ENDIAN_4321:
+ cpu_nswap32p(outp, in);
+ break;
+ case ENDIAN_1234:
+ cpu_swap32p(outp, in);
+ break;
+ case ENDIAN_2143:
+ /* TODO */
+ break;
+ case ENDIAN_3412:
+ /* TODO */
+ break;
+ }
+}
+
+static inline void _endian_le64_p (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ switch (endian) {
+ case ENDIAN_4321:
+ cpu_nswap64p(outp, in);
+ break;
+ case ENDIAN_1234:
+ cpu_swap64p(outp, in);
+ break;
+ case ENDIAN_2143:
+ /* TODO */
+ break;
+ case ENDIAN_3412:
+ /* TODO */
+ break;
+ }
+}
+
+static inline void endian_to_be16p (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ _endian_be16_p(outp, in, endian);
+}
+
+static inline void endian_to_be32p (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ _endian_be32_p(outp, in, endian);
+}
+
+static inline void endian_to_be64p (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ _endian_be64_p(outp, in, endian);
+}
+
+static inline void endian_to_le16p (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ _endian_le16_p(outp, in, endian);
+}
+
+static inline void endian_to_le32p (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ _endian_le32_p(outp, in, endian);
+}
+
+static inline void endian_to_le64p (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ _endian_le64_p(outp, in, endian);
+}
+
+static inline void be16_to_endianp (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ _endian_be16_p(outp, in, endian);
+}
+
+static inline void be32_to_endianp (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ _endian_be32_p(outp, in, endian);
+}
+
+static inline void be64_to_endianp (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ _endian_be64_p(outp, in, endian);
+}
+
+static inline void le16_to_endianp (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ _endian_le16_p(outp, in, endian);
+}
+
+static inline void le32_to_endianp (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ _endian_le32_p(outp, in, endian);
+}
+
+static inline void le64_to_endianp (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ _endian_le64_p(outp, in, endian);
+}
+
+#if defined (__CPU_ENDIAN_4321__)
+
+static inline void cpu_to_be16p (uint16_t *outp, uint16_t in)
+{
+ cpu_swap16p(outp, in);
+}
+
+static inline void cpu_to_be32p (uint32_t *outp, uint32_t in)
+{
+ cpu_swap32p(outp, in);
+}
+
+static inline void cpu_to_be64p (uint64_t *outp, uint64_t in)
+{
+ cpu_swap64p(outp, in);
+}
+
+static inline void cpu_to_le16p (uint16_t *outp, uint16_t in)
+{
+ cpu_nswap16p(outp, in);
+}
+
+static inline void cpu_to_le32p (uint32_t *outp, uint32_t in)
+{
+ cpu_nswap32p(outp, in);
+}
+
+static inline void cpu_to_le64p (uint64_t *outp, uint64_t in)
+{
+ cpu_nswap64p(outp, in);
+}
+
+static inline void be16_to_cpup (uint16_t *outp, uint16_t in)
+{
+ cpu_swap16p(outp, in);
+}
+
+static inline void be32_to_cpup (uint32_t *outp, uint32_t in)
+{
+ cpu_swap32p(outp, in);
+}
+
+static inline void be64_to_cpup (uint64_t *outp, uint64_t in)
+{
+ cpu_swap64p(outp, in);
+}
+
+static inline void le16_to_cpup (uint16_t *outp, uint16_t in)
+{
+ cpu_nswap16p(outp, in);
+}
+
+static inline void le32_to_cpup (uint32_t *outp, uint32_t in)
+{
+ cpu_nswap32p(outp, in);
+}
+
+static inline void le64_to_cpup (uint64_t *outp, uint64_t in)
+{
+ cpu_nswap64p(outp, in);
+}
+
+static inline void endian_to_cpu16p (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ endian_to_le16p(outp, in, endian);
+}
+
+static inline void endian_to_cpu32p (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ endian_to_le32p(outp, in, endian);
+}
+
+static inline void endian_to_cpu64p (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ endian_to_le64p(outp, in, endian);
+}
+
+static inline void cpu16_to_endianp (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ le16_to_endianp(outp, in, endian);
+}
+
+static inline void cpu32_to_endianp (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ le32_to_endianp(outp, in, endian);
+}
+
+static inline void cpu64_to_endianp (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ le64_to_endianp(outp, in, endian);
+}
+
+#elif defined (__CPU_ENDIAN_1234__)
+
+static inline void cpu_to_be16p (uint16_t *outp, uint16_t in)
+{
+ cpu_nswap16p(outp, in);
+}
+
+static inline void cpu_to_be32p (uint32_t *outp, uint32_t in)
+{
+ cpu_nswap32p(outp, in);
+}
+
+static inline void cpu_to_be64p (uint64_t *outp, uint64_t in)
+{
+ cpu_nswap64p(outp, in);
+}
+
+static inline void cpu_to_le16p (uint16_t *outp, uint16_t in)
+{
+ cpu_swap16p(outp, in);
+}
+
+static inline void cpu_to_le32p (uint32_t *outp, uint32_t in)
+{
+ cpu_swap32p(outp, in);
+}
+
+static inline void cpu_to_le64p (uint64_t *outp, uint64_t in)
+{
+ cpu_swap64p(outp, in);
+}
+
+static inline void endian_to_cpu16p (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ endian_to_be16p(outp, in, endian);
+}
+
+static inline void endian_to_cpu32p (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ endian_to_be32p(outp, in, endian);
+}
+
+static inline void endian_to_cpu64p (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ endian_to_be64p(outp, in, endian);
+}
+
+static inline void cpu16_to_endianp (uint16_t *outp, uint16_t in,
+ endian_t endian)
+{
+ be16_to_endianp(outp, in, endian);
+}
+
+static inline void cpu32_to_endianp (uint32_t *outp, uint32_t in,
+ endian_t endian)
+{
+ be32_to_endianp(outp, in, endian);
+}
+
+static inline void cpu64_to_endianp (uint64_t *outp, uint64_t in,
+ endian_t endian)
+{
+ be64_to_endianp(outp, in, endian);
+}
+
+#else /* 2143 / 3412 */
+/* TODO */
+#error "TODO"
+#endif
+
+#endif /* !defined (__OHW_ENDIAN_H__) */
diff --git a/src/libc/include/errno.h b/src/libc/include/errno.h
new file mode 100644
index 0000000..f6242a5
--- /dev/null
+++ b/src/libc/include/errno.h
@@ -0,0 +1,62 @@
+/*
+ * <errno.h>
+ *
+ * Open Hack'Ware BIOS errno management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+#if !defined (__OHW_ERRNO_H__)
+#define __OHW_ERRNO_H__
+
+struct task {
+ int errno;
+};
+
+extern struct task cur_task;
+
+void *get_current_stack (void);
+
+static inline int *errno_location (void)
+{
+ /* XXX: to fix */
+#if 0
+ struct task *taskp;
+
+ taskp = get_current_stack();
+
+ return &taskp->errno;
+#else
+ return &cur_task.errno;
+#endif
+}
+
+static inline void set_errno (int errnum)
+{
+ *(errno_location()) = errnum;
+}
+
+static inline int get_errno (void)
+{
+ return *(errno_location());
+}
+
+#define errno get_errno()
+
+enum {
+ ENOMEM,
+};
+
+#endif /* !defined (__OHW_ERRNO_H__) */
diff --git a/src/libc/include/fcntl.h b/src/libc/include/fcntl.h
new file mode 100644
index 0000000..d55c477
--- /dev/null
+++ b/src/libc/include/fcntl.h
@@ -0,0 +1,33 @@
+/*
+ * <fcntl.h>
+ *
+ * Open Hack'Ware BIOS: subset of POSIX fcntl definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_FCNTL_H__)
+#define __OHW_FCNTL_H__
+
+enum {
+ O_RDONLY = 0x0001,
+ O_WRONLY = 0x0002,
+ O_RDWR = 0x0003,
+ O_CREAT = 0x0010,
+ O_EXCL = 0x0020,
+};
+
+#endif /* !defined (__OHW_FCNTL_H__) */
diff --git a/src/libc/include/stddef.h b/src/libc/include/stddef.h
new file mode 100644
index 0000000..0e973eb
--- /dev/null
+++ b/src/libc/include/stddef.h
@@ -0,0 +1,38 @@
+/*
+ * <stddef.h>
+ *
+ * Open Hack'Ware BIOS: subset of POSIX standard definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_STDDEF_H__)
+#define __OHW_STDDEF_H__
+
+#include <stdint.h>
+
+typedef signed long ptrdiff_t;
+typedef unsigned long size_t;
+typedef signed long ssize_t;
+typedef signed long off_t;
+
+/* We use unicode UCS-4 as the standard character set */
+typedef uint32_t wchar_t;
+
+/* XXX: to be moveed elsewhere */
+typedef uint32_t mode_t;
+
+#endif /* !defined (__OHW_STDDEF_H__) */
diff --git a/src/libc/include/stdint.h b/src/libc/include/stdint.h
new file mode 100644
index 0000000..1bf62b4
--- /dev/null
+++ b/src/libc/include/stdint.h
@@ -0,0 +1,74 @@
+/*
+ * <stdint.h>
+ *
+ * Open Hack'Ware BIOS: arch dependent basic types
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_STDINT_H__)
+#define __OHW_STDINT_H__
+
+#if defined (__i386__)
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+
+#elif defined (__x86_64__)
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef unsigned long uint64_t;
+typedef signed long int64_t;
+
+#elif defined (__powerpc__)
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef unsigned long long uint64_t;
+typedef signed long long int64_t;
+
+#elif defined (__powerpc64__)
+
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef unsigned short uint16_t;
+typedef signed short int16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef unsigned long uint64_t;
+typedef signed long int64_t;
+#else
+
+#error "unsupported CPU architecture"
+
+#endif
+
+#endif /* !defined (__OHW_STDINT_H__) */
diff --git a/src/libc/include/stdio.h b/src/libc/include/stdio.h
new file mode 100644
index 0000000..f6bca86
--- /dev/null
+++ b/src/libc/include/stdio.h
@@ -0,0 +1,43 @@
+/*
+ * <stdio.h>
+ *
+ * Open Hack'Ware BIOS: subset of POSIX stdio definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_STDIO_H__)
+#define __OHW_STDIO_H__
+
+/* va_list is defined here */
+#include <stdarg.h>
+/* size_t is defined here */
+#include <stddef.h>
+
+#define EOF ((int)-1)
+
+int printf (const char *format, ...);
+int dprintf (const char *format, ...);
+int sprintf (char *str, const char *format, ...);
+int snprintf (char *str, size_t size, const char *format, ...);
+int vprintf (const char *format, va_list ap);
+int vdprintf (const char *format, va_list ap);
+int vsprintf (char *str, const char *format, va_list ap);
+int vsnprintf (char *str, size_t size, const char *format, va_list ap);
+
+int rename (const char *oldpath, const char *newpath);
+
+#endif /* !defined (__OHW_STDIO_H__) */
diff --git a/src/libc/include/stdlib.h b/src/libc/include/stdlib.h
new file mode 100644
index 0000000..d0fab6c
--- /dev/null
+++ b/src/libc/include/stdlib.h
@@ -0,0 +1,50 @@
+/*
+ * <stdlib.h>
+ *
+ * Open Hack'Ware BIOS: subset of POSIX stdlib definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_STDLIB_H__)
+#define __OHW_STDLIB_H__
+
+#define NULL ((void *)0)
+
+/* size_t is declared here */
+#include <stddef.h>
+
+void *malloc (size_t size);
+void free (void *ptr);
+void *realloc (void *ptr, size_t size);
+
+/* memset is declared here */
+#include <string.h>
+
+static inline void *calloc (size_t nmemb, size_t size)
+{
+ void *ret;
+
+ ret = malloc(nmemb * size);
+ if (ret != NULL)
+ memset(ret, 0, nmemb * size);
+
+ return ret;
+}
+
+int mkstemp (char *template);
+
+#endif /* !defined (__OHW_STDLIB_H__) */
diff --git a/src/libc/include/string.h b/src/libc/include/string.h
new file mode 100644
index 0000000..a2c4e0e
--- /dev/null
+++ b/src/libc/include/string.h
@@ -0,0 +1,90 @@
+/*
+ * <string.h>
+ *
+ * Open Hack'Ware BIOS: subset of POSIX string definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_STRING_H__)
+#define __OHW_STRING_H__
+
+/* size_t is declared here */
+#include <stddef.h>
+
+void *memcpy (void *dest, const void *src, size_t n);
+void *memccpy (void *dest, const void *src, int c, size_t n);
+void *mempcpy (void *dest, const void *src, size_t n);
+void *memmove (void *dest, const void *src, size_t n);
+void *memcmove (void *dest, const void *src, int c, size_t n);
+void *mempmove (void *dest, const void *src, size_t n);
+void *memset (void *s, int c, size_t n);
+int memcmp (const void *s1, const void *s2, size_t n);
+void *memchr (const void *s, int c, size_t n);
+void *rawmemchr (const void *s, int c);
+void *memrchr (const void *s, int c, size_t n);
+void *memmem (const void *haystack, size_t haystacklen,
+ const void *needle, size_t neddlelen);
+void *strcpy (char *dest, const char *src);
+void *strncpy (char *dest, const char *src, size_t n);
+char *strdup (const char *s);
+char *strndup (const char *s, size_t n);
+void *stpcpy (char *dest, const char *src);
+void *stpncpy (char *dest, const char *src, size_t n);
+char *strcat (char *dest, const char *src);
+char *strncat (char *dest, const char *src, size_t n);
+int strcmp (const char *s1, const char *s2);
+int strcasecmp (const char *s1, const char *s2);
+int strncmp (const char *s1, const char *s2, size_t n);
+int strncasecmp (const char *s1, const char *s2, size_t n);
+char *strchr (const char *s, int c);
+char *strchrnul (const char *s, int c);
+char *strrchr (const char *s, int c);
+char *strstr (const char *haystack, const char *needle);
+char *strcasestr (const char *haystack, const char *needle);
+#if 0 // TODO
+size_t strspn (const char *s, const char *accept);
+size_t strcspn (const char *s, const char *reject);
+char *strpbrk (const char *s, const char *accept);
+char *strtok (char *s, const char *delim);
+char *strtok_r (char *s, const char *delim, char **ptrptr);
+char *strsep (char **stringp, const char *delim);
+#endif // TODO
+char *basename (char *path);
+char *dirname (char *path);
+size_t strlen (const char *s);
+size_t strnlen (const char *s, size_t maxlen);
+
+#if 0
+static inline int ffs (int value)
+{
+ int tmp;
+
+ __asm__ __volatile__ ("cntlzw %0, %1" : "=r" (tmp) : "r" (value));
+
+ return 32 - tmp;
+}
+#endif
+
+static inline int ffs (int value)
+{
+ return __builtin_ffs(value);
+}
+
+int ffsl (long i);
+int ffsll (long long i);
+
+#endif /* !defined (__OHW_STRING_H__) */
diff --git a/src/libc/include/strings.h b/src/libc/include/strings.h
new file mode 100644
index 0000000..64c2cfd
--- /dev/null
+++ b/src/libc/include/strings.h
@@ -0,0 +1,27 @@
+/*
+ * <strings.h>
+ *
+ * Open Hack'Ware BIOS: Fake header for POSIX compatibility
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_STRINGS_H__)
+#define __OHW_STRINGS_H__
+
+#include <string.h>
+
+#endif /* !defined (__OHW_STRINGS_H__) */
diff --git a/src/libc/include/unistd.h b/src/libc/include/unistd.h
new file mode 100644
index 0000000..4199a03
--- /dev/null
+++ b/src/libc/include/unistd.h
@@ -0,0 +1,43 @@
+/*
+ * <unistd.h>
+ *
+ * Open Hack'Ware BIOS: subset of POSIX unistd definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_UNISTD_H__)
+#define __OHW_UNISTD_H__
+
+/* size_t is defined here */
+/* mode_t is defined here (SHOULD NOT !) */
+/* off_t is defined here */
+#include <stddef.h>
+
+int open (const char *pathname, int flags, mode_t mode);
+int close (int fd);
+ssize_t read (int fd, void *buf, size_t count);
+ssize_t write (int fd, const void *buf, size_t count);
+enum {
+ SEEK_SET = 0x01,
+ SEEK_CUR = 0x02,
+ SEEK_END = 0x03,
+};
+off_t lseek (int fd, off_t offset, int whence);
+int truncate (const char *path, off_t length);
+int ftruncate (int fd, off_t length);
+
+#endif /* !defined (__OHW_UNISTD_H__) */
diff --git a/src/libc/src/errno.c b/src/libc/src/errno.c
new file mode 100644
index 0000000..3417998
--- /dev/null
+++ b/src/libc/src/errno.c
@@ -0,0 +1,25 @@
+/*
+ * <errno.c>
+ *
+ * Open Hack'Ware BIOS: errno management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include "errno.h"
+
+/* XXX: to fix */
+struct task cur_task;
diff --git a/src/libc/src/format.c b/src/libc/src/format.c
new file mode 100644
index 0000000..f62d5dc
--- /dev/null
+++ b/src/libc/src/format.c
@@ -0,0 +1,467 @@
+/*
+ * <format.c>
+ *
+ * Open Hack'Ware BIOS: formated output functions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+/* functions prototypes are here */
+#include <stdio.h>
+/* va_list is defined here */
+#include <stdarg.h>
+/* size_t is defined here */
+#include <stddef.h>
+/* NULL is defined here */
+#include <stdlib.h>
+/* write is defined here */
+#include <unistd.h>
+/* memcpy is defined here */
+/* memset is defined here */
+/* strlen is defined here */
+#include <string.h>
+
+#define unused __attribute__ (( unused ))
+int console_write (const void *buffer, int len);
+/* XXX: this is a hack to be fixed */
+int serial_write (const void *buffer, int len);
+#define debug_write serial_write
+
+/* Low level output fonctions */
+typedef size_t (*outf_t)(void *private, const unsigned char *buf, size_t len);
+
+/* output to fd */
+#if defined (__USE__vprintf__)
+size_t outfd (void *private, const unsigned char *buf, size_t len)
+{
+ int *fd = private;
+
+ if (*fd == 1 || *fd == 2)
+ return console_write(buf, len);
+
+ return write(*fd, buf, len);
+}
+
+size_t outf_dbg (void *private, const unsigned char *buf, size_t len)
+{
+ int *fd = private;
+
+ if (*fd == 1 || *fd == 2)
+ return debug_write(buf, len);
+
+ return write(*fd, buf, len);
+}
+
+/* output to buffer */
+size_t outbuf (void *private, const unsigned char *buf, size_t len)
+{
+ unsigned char **dst = private;
+
+ memcpy(*dst, buf, len);
+ (*dst) += len;
+ (*dst)[0] = '\0';
+
+ return len;
+}
+
+/* misc formatted output functions */
+/* out one character */
+static size_t outc (outf_t outf, void *private,
+ unsigned int value, size_t maxlen)
+{
+ unsigned char buffer;
+
+ if (maxlen < 1)
+ return 0;
+ buffer = value;
+ if ((*outf)(private, &buffer, 1) == (size_t)-1)
+ return -1;
+
+ return 1;
+}
+
+/* out one int in decimal */
+static size_t outdecs (outf_t outf, void *private,
+ int value, size_t fill, size_t maxlen)
+{
+ unsigned char buffer[12];
+ size_t pos, len;
+ int sign;
+
+ buffer[11] = '\0';
+ pos = 10;
+ if (value == 0) {
+ sign = 0;
+ buffer[pos--] = '0';
+ } else {
+ if (value < 0) {
+ sign = -1;
+ value = -value;
+ } else {
+ sign = 1;
+ }
+ for (; value != 0; pos--) {
+ buffer[pos] = (value % 10) + '0';
+ value = value / 10;
+ }
+ }
+ if (fill != 0)
+ fill -= pos - 10;
+ for (; fill != 0 && pos != 0; fill--) {
+ buffer[pos--] = '0';
+ }
+ if (sign == -1)
+ buffer[pos--] = '-';
+ len = 10 - pos;
+ if (len > maxlen)
+ len = maxlen;
+ if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1)
+ return -1;
+
+ return len;
+}
+
+/* out one unsigned int as decimal */
+static size_t outdecu (outf_t outf, void *private,
+ unsigned int value, size_t fill, size_t maxlen)
+{
+ unsigned char buffer[11];
+ size_t pos, len;
+
+ buffer[10] = '\0';
+ pos = 9;
+ if (value == 0) {
+ buffer[pos--] = '0';
+ } else {
+ for (; value != 0; pos--) {
+ buffer[pos] = (value % 10) + '0';
+ value = value / 10;
+ }
+ }
+ if (fill != 0)
+ fill -= pos - 9;
+ for (; fill != 0 && pos != (size_t)-1; fill--) {
+ buffer[pos--] = '0';
+ }
+ len = 9 - pos;
+ if (len > maxlen)
+ len = maxlen;
+ if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1)
+ return -1;
+
+ return len;
+}
+
+/* out one unsigned int as hexadecimal */
+static size_t outhex (outf_t outf, void *private,
+ unsigned int value, size_t fill, size_t maxlen)
+{
+ unsigned char buffer[9];
+ size_t pos, len;
+ int d;
+
+ buffer[8] = '\0';
+ pos = 7;
+ if (value == 0) {
+ buffer[pos--] = '0';
+ } else {
+ for (; value != 0; pos--) {
+ d = value & 0xF;
+ if (d > 9)
+ d += 'a' - '0' - 10;
+ buffer[pos] = d + '0';
+ value = value >> 4;
+ }
+ }
+ if (fill > 0)
+ fill -= pos - 7;
+ for (; fill != 0 && pos != (size_t)-1; fill--) {
+ buffer[pos--] = '0';
+ }
+ len = 7 - pos;
+ if (len > maxlen)
+ len = maxlen;
+ if ((*outf)(private, buffer + pos + 1, len) == (size_t)-1)
+ return -1;
+
+ return len;
+}
+
+static size_t outstr (outf_t outf, void *private,
+ const unsigned char *str, unused size_t fill,
+ size_t maxlen)
+{
+#define TMPBUF_LEN 256
+#if 0
+ unsigned char tmpbuf[TMPBUF_LEN];
+ size_t len, totlen, tmp;
+#else
+ size_t len, totlen;
+#endif
+
+ if (str == NULL) {
+ /* Avoid crash if given a NULL string */
+ str = "<null>";
+ }
+ len = strlen(str);
+ totlen = 0;
+#if 0
+ if (len < fill) {
+ memset(tmpbuf, ' ', TMPBUF_LEN);
+ fill -= len;
+ for (; fill > 0; fill -= tmp) {
+ tmp = fill;
+ if (tmp > TMPBUF_LEN)
+ tmp = TMPBUF_LEN;
+ totlen += tmp;
+ if (totlen > maxlen) {
+ tmp = maxlen - totlen;
+ totlen = maxlen;
+ }
+ (*outf)(private, tmpbuf, tmp);
+ }
+ }
+#endif
+ totlen += len;
+ if (totlen > maxlen) {
+ len = maxlen - totlen;
+ totlen = maxlen;
+ }
+ if ((*outf)(private, str, len) == (size_t)-1)
+ return -1;
+
+ return totlen;
+}
+
+int _vprintf(outf_t outf, void *private, size_t maxlen,
+ const unsigned char *format, va_list ap)
+{
+ const unsigned char *p, *str;
+ size_t maxfill, totlen, len, tmp;
+ int cur;
+
+ cur = 0;
+ str = format;
+ for (totlen = 0; totlen != maxlen;) {
+ for (p = str; (*p != '%' || cur > 6) && *p != '\0'; p++)
+ continue;
+ len = p - str;
+ if (len + totlen > maxlen)
+ len = maxlen - totlen;
+ tmp = (*outf)(private, str, p - str);
+ if (tmp == (size_t)-1)
+ return -1;
+ totlen += tmp;
+ if (*p == '\0')
+ break;
+ maxfill = -2;
+ str = p;
+ next:
+ p++;
+ switch (*p) {
+ case '\0':
+ /* Invalid format */
+ goto invalid;
+ case '0':
+ if (maxfill >= (size_t)-2) {
+ maxfill = -1;
+ goto next;
+ }
+ /* No break here */
+ case '1' ... '9':
+ switch (maxfill) {
+ case -2:
+ /* Invalid format */
+ goto invalid;
+ case -1:
+ maxfill = *p - '0';
+ break;
+ default:
+ maxfill = (maxfill * 10) + *p - '0';
+ break;
+ }
+ goto next;
+ case 'l':
+ /* Ignore it */
+ goto next;
+ case 'h':
+ /* Ignore it */
+ goto next;
+ case 'd':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outdecs(outf, private,
+ va_arg(ap, int), maxfill, maxlen - totlen);
+ break;
+ case 'u':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outdecu(outf, private,
+ va_arg(ap, unsigned int), maxfill, maxlen - totlen);
+ break;
+ case 'x':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outhex(outf, private,
+ va_arg(ap, unsigned int), maxfill, maxlen - totlen);
+ break;
+ case 'p':
+ if (p != str + 1) {
+ /* Invalid format */
+ goto invalid;
+ } else {
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ tmp = outhex(outf, private, va_arg(ap, unsigned int),
+ maxfill, maxlen - totlen);
+ }
+ break;
+ case 'c':
+ if (p != str + 1) {
+ /* Invalid format */
+ goto invalid;
+ } else {
+ tmp = outc(outf, private,
+ va_arg(ap, int), maxlen - totlen);
+ }
+ break;
+ case 's':
+ if (maxfill == (size_t)-2 || maxfill == (size_t)(-1))
+ maxfill = 0;
+ str = va_arg(ap, const unsigned char *);
+ tmp = outstr(outf, private, str, maxfill, maxlen - totlen);
+ break;
+ case '%':
+ if (p != str + 1) {
+ /* Invalid format */
+ goto invalid;
+ } else {
+ tmp = outc(outf, private, '%', maxlen - totlen);
+ }
+ default:
+ invalid:
+ /* Invalid format : display the raw string */
+ len = p - str + 1;
+ if (len + totlen > maxlen)
+ len = maxlen - totlen;
+ tmp = (*outf)(private, str, len);
+ break;
+ }
+ if (tmp == (size_t)-1)
+ return -1;
+ totlen += tmp;
+ str = p + 1;
+ }
+
+ return 0;
+}
+#else /* defined (__USE__vprintf__) */
+size_t outfd (void *private, const unsigned char *buf, size_t len);
+size_t outf_dbg (void *private, const unsigned char *buf, size_t len);
+size_t outbuf (void *private, const unsigned char *buf, size_t len);
+int _vprintf(outf_t outf, void *private, size_t maxlen,
+ const unsigned char *format, va_list ap);
+#endif /* defined (__USE__vprintf__) */
+
+#if defined (__USE_printf__)
+int printf (const char *format, ...)
+{
+ va_list ap;
+ int fd = 1;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outfd, &fd, -1, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_printf__) */
+
+#if defined (__USE_dprintf__)
+int dprintf (const char *format, ...)
+{
+ va_list ap;
+ int fd = 1;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outf_dbg, &fd, -1, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_dprintf__) */
+
+#if defined (__USE_sprintf__)
+int sprintf (char *str, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outbuf, &str, -1, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_sprintf__) */
+
+#if defined (__USE_snprintf__)
+int snprintf (char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = _vprintf(&outbuf, &str, size, format, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif /* defined (__USE_snprintf__) */
+
+#if defined (__USE_vprintf__)
+int vprintf (const char *format, va_list ap)
+{
+ int fd = 1;
+
+ return _vprintf(&outfd, &fd, -1, format, ap);
+}
+#endif /* defined (__USE_vprintf__) */
+
+#if defined (__USE_vdprintf__)
+int vdprintf (const char *format, va_list ap)
+{
+ int fd = 1;
+
+ return _vprintf(&outf_dbg, &fd, -1, format, ap);
+}
+#endif /* defined (__USE_vdprintf__) */
+
+#if defined (__USE_vsprintf__)
+int vsprintf (char *str, const char *format, va_list ap)
+{
+ return _vprintf(&outbuf, &str, -1, format, ap);
+}
+#endif /* defined (__USE_vsprintf__) */
+
+#if defined (__USE_vsnprintf__)
+int vsnprintf (char *str, size_t size, const char *format, va_list ap)
+{
+ return _vprintf(&outbuf, &str, size, format, ap);
+}
+#endif /* defined (__USE_vsnprintf__) */
diff --git a/src/libc/src/malloc.c b/src/libc/src/malloc.c
new file mode 100644
index 0000000..19eb2b2
--- /dev/null
+++ b/src/libc/src/malloc.c
@@ -0,0 +1,730 @@
+/*
+ * <malloc.c>
+ *
+ * Open Hack'Ware BIOS: memory management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+/* functions prototypes are here */
+/* NULL is declared here */
+#include <stdlib.h>
+/* memcpy is defined here */
+#include <string.h>
+/* set_errno is defined here */
+#include <errno.h>
+
+//#define DEBUG_MEMOPS
+#if defined (DEBUG_MEMOPS)
+#define MEMOPS_PRINTF(fmt, args...) do { dprintf(fmt , ##args); } while (0)
+#else
+#define MEMOPS_PRINTF(fmt, args...) do { } while (0)
+#endif
+
+#define unused __attribute__ (( unused ))
+
+/* XXX: TODO: put this elsewhere */
+void *page_get (int nb_pages);
+void page_put (void *addr, int nb_pages);
+
+/* XXX: TOTO: put this elsewhere */
+#if defined (__i386__)
+#define NATURAL_ALIGN_BITS 2
+#define PAGE_BITS 12
+#define __32_BITS 1
+#elif defined (__powerpc__)
+#define NATURAL_ALIGN_BITS 2
+#define PAGE_BITS 12
+#define __32_BITS 1
+#elif defined (__x86_64__)
+#define NATURAL_ALIGN_BITS 3
+#define PAGE_BITS 12
+#else
+#error "Unsupported architecture"
+#endif
+#define PAGE_SIZE (1 << PAGE_BITS)
+#define PAGE(addr) ((void *)((unsigned long)(addr) & ~(PAGE_SIZE - 1)))
+
+
+#define MIN_ELEM_BITS (NATURAL_ALIGN_BITS + 1)
+#define MIN_ELEM_SIZE (1 << (MIN_ELEM_BITS))
+#define MAX_ELEM_BITS (PAGE_BITS)
+#define MAX_ELEM_SIZE (1 << (MAX_ELEM_BITS - 1))
+#define POOL_MAX ((MAX_ELEM_BITS) - (MIN_ELEM_BITS))
+#define CACHE_MAX 16
+
+typedef struct free_slot_t free_slot_t;
+struct free_slot_t {
+ struct free_slot_t *next;
+};
+
+typedef struct page_descr_t page_descr_t;
+struct page_descr_t {
+ struct page_descr_t *next;
+ struct page_descr_t *prev;
+ void *addr;
+ unsigned long nb;
+};
+
+/*
+ * This points to the first descriptor page where stand:
+ * - 1 descriptor for this page.
+ * - 1 decriptor pages list head.
+ * - POOL_MAX pool descriptors list heads.
+ * - CACHE_MAX page cache entries list heads.
+ */
+static void *malloc_base;
+
+/* Shared functions */
+static inline page_descr_t *main_descr_get (void)
+{
+ return (page_descr_t *)malloc_base + 1;
+}
+
+static inline page_descr_t *pool_head_get (int pool_idx)
+{
+ return main_descr_get() + 1 + pool_idx;
+}
+
+static inline page_descr_t *cache_head_get (int cache_idx)
+{
+ return pool_head_get(POOL_MAX) + 1 + cache_idx;
+}
+
+static void free_slots_init (void *page, int incr, int size)
+{
+ free_slot_t *slot, *next;
+
+ for (slot = page;
+ slot < (free_slot_t *)((char *)page + size); slot = next) {
+ next = (void *)((char *)slot + incr);
+ slot->next = next;
+ }
+ slot = (void *)((char *)slot - incr);
+ slot->next = NULL;
+}
+
+static page_descr_t *descr_find_free (page_descr_t *head_descr,
+ page_descr_t *skip_descr)
+{
+ page_descr_t *cur_descr, *best;
+ unsigned long max_used;
+
+ /* Try to always return the page with the less free slots to reduce
+ * memory fragmentation.
+ */
+ max_used = 0;
+ best = NULL;
+ for (cur_descr = head_descr->next;
+ cur_descr != head_descr; cur_descr = cur_descr->next) {
+ if (cur_descr != skip_descr && cur_descr->addr != NULL &&
+ cur_descr->nb >= max_used) {
+ max_used = cur_descr->nb;
+ best = cur_descr;
+ }
+ }
+
+ return best;
+}
+
+/* Page descriptors management */
+static void page_descr_free (page_descr_t *head_descr)
+{
+ head_descr->next->prev = head_descr->prev;
+ head_descr->prev->next = head_descr->next;
+ page_put(head_descr, 1);
+}
+
+static page_descr_t *page_descr_get (void)
+{
+ page_descr_t *main_descr, *head_descr, *page_descr;
+ free_slot_t *first_free;
+
+ main_descr = main_descr_get();
+ head_descr = main_descr->addr;
+ first_free = head_descr->addr;
+ if (first_free == NULL) {
+ /* Find a page with free descriptors */
+ head_descr = descr_find_free(main_descr, NULL);
+ if (head_descr != NULL) {
+ /* Get the first free slot */
+ first_free = head_descr->addr;
+ } else {
+ /* Allocate a new page */
+ head_descr = page_get(1);
+ if (head_descr == NULL) {
+ MEMOPS_PRINTF("%s: cannot get new head descriptor\n",
+ __func__);
+ return NULL;
+ }
+ /* Initialise free slots */
+ free_slots_init(head_descr, sizeof(page_descr_t), PAGE_SIZE);
+ /* Initialise page head descriptor */
+ head_descr->addr = head_descr + 1;
+ head_descr->nb = 0;
+ head_descr->next = main_descr;
+ head_descr->prev = main_descr->prev;
+ /* Update main descriptor */
+ main_descr->prev->next = head_descr;
+ main_descr->prev = head_descr;
+ main_descr->nb++;
+ first_free = head_descr->addr;
+ }
+ main_descr->addr = head_descr;
+ }
+ head_descr->addr = first_free->next;
+ if (head_descr->nb == 0)
+ main_descr->nb--;
+ head_descr->nb++;
+ page_descr = (page_descr_t *)first_free;
+ page_descr->prev = NULL;
+ page_descr->next = NULL;
+ page_descr->addr = NULL;
+ page_descr->nb = 0;
+
+ return page_descr;
+}
+
+static void page_descr_put (page_descr_t *page_descr)
+{
+ page_descr_t *main_descr, *head_descr, *next_descr, *free_descr;
+ free_slot_t *first_free, *next_free;
+
+ head_descr = PAGE(page_descr);
+ /* Mark this descriptor as free */
+ next_free = head_descr->addr;
+ first_free = (free_slot_t *)page_descr;
+ first_free->next = next_free;
+ /* Update page descriptor */
+ head_descr->addr = first_free;
+ head_descr->nb--;
+ main_descr = main_descr_get();
+ if (head_descr->nb == 0) {
+ /* Try to free this page */
+ if (main_descr->addr == head_descr ||
+ main_descr->addr == NULL ||
+ main_descr->nb > 0)
+ free_descr = descr_find_free(main_descr, head_descr);
+ else
+ free_descr = main_descr->addr;
+ if (free_descr != NULL) {
+ /* Update main descriptor */
+ page_descr_free(head_descr);
+ main_descr->addr = free_descr;
+ } else {
+ main_descr->addr = head_descr;
+ main_descr->nb++;
+ }
+ } else if (next_free == NULL) {
+ free_descr = head_descr;
+ for (head_descr = main_descr->next;
+ main_descr->nb > 0 && head_descr != main_descr;
+ head_descr = next_descr) {
+ next_descr = head_descr->next;
+ if (head_descr->nb == 0) {
+ if (main_descr->addr == head_descr)
+ main_descr->addr = NULL;
+ page_descr_free(head_descr);
+ main_descr->nb--;
+ }
+ }
+ if (main_descr->addr == NULL)
+ main_descr->addr = free_descr;
+ }
+}
+
+/* Page cache management */
+static inline unsigned long cache_idx (void *addr)
+{
+ return ((unsigned long)addr >> PAGE_BITS) & (CACHE_MAX - 1);
+}
+
+static inline unsigned long page_cache_pool_idx (page_descr_t *cache_descr)
+{
+ return (cache_descr->nb & 0xF);
+}
+
+static inline page_descr_t *page_cache_page_descr (page_descr_t *cache_descr)
+{
+ return (page_descr_t *)(cache_descr->nb & ~0xF);
+}
+
+static int page_cache_add_page (page_descr_t *page_descr, int pool_idx)
+{
+ page_descr_t *main_descr, *cache_head, *cache_descr;
+
+ main_descr = main_descr_get();
+ cache_head = cache_head_get(cache_idx(page_descr->addr));
+ cache_descr = page_descr_get();
+ if (cache_descr == NULL) {
+ MEMOPS_PRINTF("%s: cannot get cache page\n", __func__);
+ return -1;
+ }
+ cache_descr->nb = pool_idx | (unsigned long)page_descr;
+ cache_descr->prev = cache_head;
+ cache_descr->next = cache_head->next;
+ cache_descr->addr = page_descr->addr;
+ cache_head->next->prev = cache_descr;
+ cache_head->next = cache_descr;
+
+ return 0;
+}
+
+static page_descr_t *page_cache_get_descr (void *addr)
+{
+ page_descr_t *main_descr, *cache_head, *cache_descr;
+
+ main_descr = main_descr_get();
+ cache_head = cache_head_get(cache_idx(addr));
+ for (cache_descr = cache_head->next;
+ cache_descr != cache_head; cache_descr = cache_descr->next) {
+ if (cache_descr->addr == addr) {
+ return cache_descr;
+ }
+ }
+ MEMOPS_PRINTF("%s: cannot get cache page descr\n", __func__);
+
+ return NULL;
+}
+
+static void page_cache_remove_descr (page_descr_t *cache_descr)
+{
+ cache_descr->next->prev = cache_descr->prev;
+ cache_descr->prev->next = cache_descr->next;
+ page_descr_put(cache_descr);
+}
+
+/* Allocation by pool (size <= PAGE_SIZE / 2) */
+static void pool_descr_free (page_descr_t *cache_descr,
+ page_descr_t *pool_descr)
+{
+ page_put(PAGE(pool_descr->addr), 1);
+ page_cache_remove_descr(cache_descr);
+ pool_descr->next->prev = pool_descr->prev;
+ pool_descr->prev->next = pool_descr->next;
+ page_descr_put(pool_descr);
+}
+
+static void *pool_malloc (int pool_idx)
+{
+ page_descr_t *main_descr, *pool_head, *pool_descr;
+ free_slot_t *first_free, *next_free;
+
+ main_descr = main_descr_get();
+ pool_head = pool_head_get(pool_idx);
+ pool_descr = pool_head->addr;
+ if (pool_descr == NULL || pool_descr->addr == NULL) {
+ pool_descr = descr_find_free(pool_head, NULL);
+ if (pool_descr == NULL) {
+ pool_descr = page_descr_get();
+ if (pool_descr == NULL) {
+ MEMOPS_PRINTF("%s: cannot get pool descr\n", __func__);
+ return NULL;
+ }
+ pool_descr->addr = page_get(1);
+ if (pool_descr->addr == NULL) {
+ MEMOPS_PRINTF("%s: cannot allocate new page\n", __func__);
+ page_descr_put(pool_descr);
+ return NULL;
+ }
+ if (page_cache_add_page(pool_descr, pool_idx) < 0) {
+ MEMOPS_PRINTF("%s: cannot add new page to cache\n", __func__);
+ page_put(pool_descr->addr, 1);
+ page_descr_put(pool_descr);
+ return NULL;
+ }
+ free_slots_init(pool_descr->addr,
+ 1 << (MIN_ELEM_BITS + pool_idx), PAGE_SIZE);
+ pool_descr->nb = 0;
+ pool_descr->prev = pool_head->prev;
+ pool_descr->next = pool_head;
+ pool_head->prev->next = pool_descr;
+ pool_head->prev = pool_descr;
+ pool_head->nb++;
+ }
+ pool_head->addr = pool_descr;
+ }
+ first_free = pool_descr->addr;
+ next_free = first_free->next;
+ // memset(first_free, 0, 1 << (MIN_ELEM_BITS + pool_idx));
+ pool_descr->addr = next_free;
+ if (pool_descr->nb == 0)
+ pool_head->nb--;
+ pool_descr->nb++;
+
+ return first_free;
+}
+
+unused static void pool_free (page_descr_t *cache_descr, void *area)
+{
+ page_descr_t *pool_head, *pool_descr, *pool_next, *free_pool;
+ free_slot_t *first_free, *next_free;
+ unsigned long size, pool_idx;
+
+ pool_descr = page_cache_page_descr(cache_descr);
+ first_free = area;
+ next_free = pool_descr->addr;
+ pool_idx = page_cache_pool_idx(cache_descr);
+ size = 1 << (MIN_ELEM_BITS + pool_idx);
+ first_free->next = next_free;
+ pool_descr->addr = first_free;
+ pool_descr->nb--;
+ pool_head = pool_head_get(pool_idx);
+ if (pool_descr->nb == 0) {
+ if (pool_head->addr == pool_descr ||
+ pool_head->addr == NULL ||
+ pool_head->nb > 0)
+ free_pool = descr_find_free(pool_head, pool_descr);
+ else
+ free_pool = pool_head->addr;
+ if (free_pool != NULL) {
+ /* Free page & descriptor */
+ pool_descr_free(cache_descr, pool_descr);
+ pool_head->addr = free_pool;
+ } else {
+ pool_head->addr = pool_descr;
+ pool_head->nb++;
+ }
+ } else if (next_free == NULL) {
+ free_pool = pool_descr;
+ for (pool_descr = pool_head->next;
+ pool_head->nb > 0 && pool_descr != pool_head;
+ pool_descr = pool_next) {
+ pool_next = pool_descr->next;
+ if (pool_descr->nb == 0) {
+ if (pool_head->addr == pool_descr)
+ pool_head->addr = NULL;
+ cache_descr = page_cache_get_descr(PAGE(pool_descr->addr));
+ if (cache_descr != NULL) {
+ pool_descr_free(cache_descr, pool_descr);
+ pool_head->nb--;
+ } else {
+ /* Incoherency: what to do ? */
+ }
+ }
+ }
+ if (pool_head->addr == NULL)
+ pool_head->addr = free_pool;
+ }
+}
+
+/* Big area management (size > PAGE_SIZE / 2) */
+static void *big_malloc (int nb_pages)
+{
+ page_descr_t *main_descr, *pool_head, *pool_descr;
+
+ main_descr = main_descr_get();
+ pool_head = pool_head_get(POOL_MAX);
+ pool_descr = page_descr_get();
+ if (pool_descr == NULL) {
+ MEMOPS_PRINTF("%s: cannot get pool descr\n", __func__);
+ return NULL;
+ }
+ pool_descr->addr = page_get(nb_pages);
+ if (pool_descr->addr == NULL) {
+ page_descr_put(pool_descr);
+ MEMOPS_PRINTF("%s: cannot get page\n", __func__);
+ return NULL;
+ }
+ if (page_cache_add_page(pool_descr, POOL_MAX) < 0) {
+ page_put(pool_descr->addr, nb_pages);
+ page_descr_put(pool_descr);
+ MEMOPS_PRINTF("%s: cannot get add page to cache\n", __func__);
+ return NULL;
+ }
+ pool_descr->prev = pool_head->prev;
+ pool_descr->next = pool_head;
+ pool_descr->nb = nb_pages;
+ pool_head->prev->next = pool_descr;
+ pool_head->prev = pool_descr;
+
+ return pool_descr->addr;
+}
+
+static void big_free (page_descr_t *cache_descr)
+{
+ page_descr_t *pool_descr;
+
+ pool_descr = page_cache_page_descr(cache_descr);
+ if (pool_descr->addr != NULL && pool_descr->nb != 0) {
+ page_put(pool_descr->addr, pool_descr->nb);
+ pool_descr->next->prev = pool_descr->prev;
+ pool_descr->prev->next = pool_descr->next;
+ page_descr_put(pool_descr);
+ page_cache_remove_descr(cache_descr);
+ } else {
+ MEMOPS_PRINTF("%s: ERROR %p %d\n",
+ __func__, pool_descr->addr, (int)pool_descr->nb);
+ }
+}
+
+unused static void *big_realloc (page_descr_t *cache_descr, int new_size)
+{
+ void *new_area;
+ page_descr_t *pool_descr;
+ unsigned long new_nb;
+
+ pool_descr = page_cache_page_descr(cache_descr);
+ new_nb = (new_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ if (new_nb == pool_descr->nb) {
+ new_area = cache_descr->addr;
+ } else {
+ new_area = big_malloc(new_size);
+ memcpy(new_area, cache_descr->addr, pool_descr->nb * PAGE_SIZE);
+ big_free(cache_descr);
+ }
+
+ return new_area;
+}
+
+/* Global entry points */
+int page_descrs_init (void)
+{
+ page_descr_t *main_descr, *page_descr, *pool_head, *cache_head;
+ int i;
+
+ /* Allocate first descriptor page */
+ malloc_base = page_get(1);
+ if (malloc_base == NULL) {
+ set_errno(ENOMEM);
+ MEMOPS_PRINTF("%s: cannot get main descriptor\n", __func__);
+ return -1;
+ }
+ /* Init free slots in this page */
+ free_slots_init(malloc_base, sizeof(page_descr_t), PAGE_SIZE);
+ /* Init main descriptor */
+ page_descr = malloc_base;
+ main_descr = main_descr_get();
+ main_descr->addr = page_descr;
+ main_descr->nb = 0;
+ main_descr->next = page_descr;
+ main_descr->prev = page_descr;
+ page_descr->nb = 1;
+ page_descr->addr = page_descr + 2;
+ page_descr->next = main_descr;
+ page_descr->prev = main_descr;
+ /* Init pool lists heads */
+ for (i = 0; i <= POOL_MAX; i++) {
+ pool_head = page_descr_get();
+ if (pool_head == NULL) {
+ page_put(malloc_base, 1);
+ malloc_base = NULL;
+ MEMOPS_PRINTF("%s: cannot get pool descriptor %d\n", __func__, i);
+ return -1;
+ }
+ pool_head->prev = pool_head;
+ pool_head->next = pool_head;
+ pool_head->addr = NULL;
+ }
+ /* Init page caches lists heads */
+ for (i = 0; i < CACHE_MAX; i++) {
+ cache_head = page_descr_get();
+ if (cache_head == NULL) {
+ page_put(malloc_base, 1);
+ malloc_base = NULL;
+ MEMOPS_PRINTF("%s: cannot get page cache descriptor %d\n",
+ __func__, i);
+ return -1;
+ }
+ cache_head->prev = cache_head;
+ cache_head->next = cache_head;
+ }
+
+ return 0;
+}
+
+static inline int get_pool_idx (size_t size)
+{
+ int pool_idx;
+
+ pool_idx = 0;
+ for (size /= MIN_ELEM_SIZE; size != 0; size = size / 2)
+ pool_idx++;
+
+ return pool_idx;
+}
+
+#if 1
+void *malloc (size_t size)
+{
+ void *ret;
+ int pool_idx;
+
+ if (malloc_base == NULL || size == 0) {
+ ret = NULL;
+ } else if (size >= MAX_ELEM_SIZE) {
+ ret = big_malloc((size + PAGE_SIZE - 1) / PAGE_SIZE);
+ } else {
+ if (size <= MIN_ELEM_SIZE)
+ pool_idx = 0;
+ else {
+ pool_idx = get_pool_idx(size);
+ }
+ ret = pool_malloc(pool_idx);
+ }
+ if (ret != NULL)
+ memset(ret, 0, size);
+#if 0
+ memory_dump();
+ printf("%s(%d) => %p\n", __func__, size, ret);
+#endif
+
+ return ret;
+}
+#endif
+
+#if 0
+void free (void *area)
+{
+ page_descr_t *cache_descr;
+ int pool_idx;
+
+ if (malloc_base == NULL || area == NULL)
+ return;
+ cache_descr = page_cache_get_descr(PAGE(area));
+ if (cache_descr != NULL) {
+ pool_idx = page_cache_pool_idx(cache_descr);
+ if (pool_idx == POOL_MAX) {
+ big_free(cache_descr);
+ } else {
+ pool_free(cache_descr, area);
+ }
+ } else {
+ /* Given area is not valid */
+ MEMOPS_PRINTF("ERROR: area to free not found: %p\n", area);
+ }
+}
+#endif
+
+#if 0
+void *realloc (void *area, size_t new_size)
+{
+ void *new_area;
+ page_descr_t *pool_descr, *cache_descr;
+ size_t size;
+ int pool_idx, new_pool_idx;
+
+ if (malloc_base == NULL || new_size == 0) {
+ free(area);
+ return NULL;
+ }
+ if (area == NULL)
+ return malloc(new_size);
+ cache_descr = page_cache_get_descr(PAGE(area));
+ if (cache_descr == NULL) {
+ /* Given area is not valid */
+ return NULL;
+ }
+ pool_idx = page_cache_pool_idx(cache_descr);
+ if (new_size >= MAX_ELEM_SIZE) {
+ new_pool_idx = POOL_MAX;
+ if (pool_idx == POOL_MAX)
+ return big_realloc(cache_descr, new_size);
+ } else {
+ if (new_size <= MIN_ELEM_SIZE)
+ new_pool_idx = 0;
+ else
+ new_pool_idx = get_pool_idx(size);
+ if (pool_idx == new_pool_idx)
+ return area;
+ }
+ /* Common case: alloc, copy & free */
+ if (new_pool_idx == POOL_MAX)
+ new_area = big_malloc((new_size + PAGE_SIZE - 1) / PAGE_SIZE);
+ else
+ new_area = pool_malloc(new_pool_idx);
+ if (new_area == NULL)
+ return NULL;
+ if (pool_idx == POOL_MAX) {
+ pool_descr = page_cache_page_descr(cache_descr);
+ size = pool_descr->nb * PAGE_SIZE;
+ } else {
+ size = MIN_ELEM_SIZE << pool_idx;
+ }
+ memcpy(new_area, area, size);
+ if (pool_idx == POOL_MAX)
+ big_free(cache_descr);
+ else
+ pool_free(cache_descr, area);
+
+ return new_area;
+}
+#endif
+
+void memory_dump (void)
+{
+#if defined (DEBUG_MEMOPS)
+ page_descr_t *main_descr, *page_descr;
+ page_descr_t *pool_head, *pool_descr, *cache_head, *cache_descr;
+ int i, n;
+
+ main_descr = main_descr_get();
+ /* Dump descriptor pages */
+ printf("Descriptor pages dump: %p max=%d %d pages with no alloc descrs\n",
+ main_descr, (int)(PAGE_SIZE / sizeof(page_descr_t)), (int)main_descr->nb);
+ n = 0;
+ for (page_descr = main_descr->next;
+ page_descr != main_descr; page_descr = page_descr->next) {
+ printf("Descr %d : %p %p used: %d\n",
+ n, page_descr, page_descr->addr, (int)page_descr->nb);
+ n++;
+ }
+ /* Dump pool areas pages */
+ for (i = 0; i < POOL_MAX; i++) {
+ n = 0;
+ pool_head = pool_head_get(i);
+ printf("Pool %d %p\n", i, pool_head);
+ for (pool_descr = pool_head->next;
+ pool_descr != pool_head; pool_descr = pool_descr->next) {
+ printf("Pool %d descr %d : %p %p used: %d size %d free: %p %p\n",
+ i, n, pool_descr, PAGE(pool_descr->addr), (int)pool_descr->nb,
+ 1 << (MIN_ELEM_BITS + i), pool_descr->addr,
+ ((free_slot_t *)pool_descr->addr)->next);
+ n++;
+ }
+ printf(" => %d pages allocated\n", n);
+ }
+#if 0
+ /* Dump big area pages */
+ printf("Pool %d\n", POOL_MAX);
+ n = 0;
+ pool_head = pool_head_get(POOL_MAX);
+ for (pool_descr = pool_head->next;
+ pool_descr != pool_head; pool_descr = pool_descr->next) {
+ printf("Pool %d descr %d : %p nb pages: %d\n",
+ POOL_MAX, n, pool_descr->addr, (int)pool_descr->nb);
+ n++;
+ }
+ printf(" => %d pages allocated\n", n);
+ /* Dump page cache */
+ for (i = 0; i < CACHE_MAX; i++) {
+ printf("Page cache 0x____%x___\n", i);
+ n = 0;
+ cache_head = cache_head_get(i);
+ for (cache_descr = cache_head->next;
+ cache_descr != cache_head; cache_descr = cache_descr->next) {
+ pool_descr = page_cache_page_descr(cache_descr);
+ printf("Cache %d descr %d : %p pool: %d descr: %p %p %d\n",
+ i, n, cache_descr->addr,
+ (int)page_cache_pool_idx(cache_descr),
+ pool_descr, pool_descr->addr, (int)pool_descr->nb);
+ n++;
+ }
+ printf(" => %d pages allocated\n", n);
+ }
+#endif
+#endif
+}
diff --git a/src/libc/src/mem.c b/src/libc/src/mem.c
new file mode 100644
index 0000000..a75ff85
--- /dev/null
+++ b/src/libc/src/mem.c
@@ -0,0 +1,251 @@
+/*
+ * <mem.c>
+ *
+ * Open Hack'Ware BIOS: mem<xxx> functions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+/* functions prototypes are here */
+#include <string.h>
+/* NULL is declared here */
+#include <stdlib.h>
+
+/* mem___ functions */
+#if defined (__USE_memcpy__)
+void *memcpy (void *dest, const void *src, size_t n)
+{
+ const char *p;
+ char *q;
+
+ p = src;
+ q = dest;
+ for (; n != 0; n--)
+ *q++ = *p++;
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_memccpy__)
+void *memccpy (void *dest, const void *src, int c, size_t n)
+{
+ const char *p;
+ char *q, *r;
+
+ p = src;
+ q = dest;
+ r = NULL;
+ for (; n != 0; n--, q++) {
+ *q = *p++;
+ if (*q == c) {
+ r = q;
+ break;
+ }
+ }
+
+ return r;
+}
+#endif
+
+#if defined (__USE_mempcpy__)
+/* GNU extension */
+void *mempcpy (void *dest, const void *src, size_t n)
+{
+ const char *p;
+ char *q;
+
+ p = src;
+ q = dest;
+ for (; n != 0; n--)
+ *q++ = *p++;
+
+ return q;
+}
+#endif
+
+#if defined (__USE_memmove__)
+void *memmove (void *dest, const void *src, size_t n)
+{
+ const char *p;
+ char *q;
+
+ p = src;
+ q = dest;
+ if (dest <= src) {
+ for (; n != 0; n--)
+ *q++ = *p++;
+ } else {
+ p += n;
+ q += n;
+ for (; n != 0; n--)
+ *--q = *--p;
+ }
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_memcmove__)
+/* OHW extension */
+void *memcmove (void *dest, const void *src, int c, size_t n)
+{
+ const char *p;
+ char *q, *r;
+
+ p = src;
+ q = dest;
+ r = NULL;
+ if (dest <= src) {
+ for (; n != 0; n--, q++) {
+ *q++ = *p++;
+ if (*q == c) {
+ r = q;
+ break;
+ }
+ }
+ } else {
+ p += n;
+ q += n;
+ for (; n != 0; n--, q--) {
+ *--q = *--p;
+ if (*q == c) {
+ r = q;
+ break;
+ }
+ }
+ }
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_mempmove__)
+/* OHW extension */
+void *mempmove (void *dest, const void *src, size_t n)
+{
+ const char *p;
+ char *q, *r;
+
+ p = src;
+ q = dest;
+ r = q + n;
+ if (dest <= src) {
+ for (; n != 0; n--)
+ *q++ = *p++;
+ } else {
+ p += n;
+ q = r;
+ for (; n != 0; n--)
+ *--q = *--p;
+ }
+
+ return r;
+}
+#endif
+
+#if defined (__USE_memset__)
+void *memset (void *s, int c, size_t n)
+{
+ char *p;
+
+ for (p = s; n != 0; n--)
+ *p++ = c;
+
+ return s;
+}
+#endif
+
+#if defined (__USE_memcmp__)
+int memcmp (const void *s1, const void *s2, size_t n)
+{
+ const char *p, *q;
+ int ret;
+
+ p = s1;
+ q = s2;
+ for (ret = 0; n != 0 && ret == 0; n--)
+ ret = *p++ - *q++;
+
+ return ret;
+}
+#endif
+
+#if defined (__USE_memchr__)
+void *memchr (const void *s, int c, size_t n)
+{
+ const char *p, *r;
+
+ r = NULL;
+ for (p = s; n != 0; n--, p++) {
+ if (*p == c) {
+ r = p;
+ break;
+ }
+ }
+
+ return (void *)r;
+}
+#endif
+
+#if defined (__USE_rawmemchr__)
+/* GNU extension */
+void *rawmemchr (const void *s, int c)
+{
+ const char *p;
+
+ for (p = s; *p != c; p++)
+ continue;
+
+ return (void *)p;
+}
+#endif
+
+#if defined (__USE_memrchr__)
+void *memrchr (const void *s, int c, size_t n)
+{
+ const char *p, *r;
+
+ r = NULL;
+ for (p = s + n; n != 0; n--, p--) {
+ if (*p == c) {
+ r = p;
+ break;
+ }
+ }
+
+ return (void *)r;
+}
+#endif
+
+#if defined (__USE_memmem__)
+/* GNU extension */
+void *memmem (const void *haystack, size_t haystacklen,
+ const void *needle, size_t neddlelen)
+{
+ const char *p, *r;
+
+ r = NULL;
+ for (p = haystack; haystacklen > neddlelen; haystacklen--, p++) {
+ if (memcmp(p, needle, neddlelen) == 0) {
+ r = p;
+ break;
+ }
+ }
+
+ return (void *)r;
+}
+#endif
diff --git a/src/libc/src/str.c b/src/libc/src/str.c
new file mode 100644
index 0000000..24548fa
--- /dev/null
+++ b/src/libc/src/str.c
@@ -0,0 +1,430 @@
+/*
+ * <str.c>
+ *
+ * Open Hack'Ware BIOS: str<xxx> functions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+/* functions prototypes are here */
+#include <string.h>
+/* NULL is defined here */
+/* malloc is defined here */
+#include <stdlib.h>
+/* toupper is defined here */
+#include <ctype.h>
+
+/* str___ functions */
+#if defined (__USE_strcpy__)
+void *strcpy (char *dest, const char *src)
+{
+ char *q;
+
+ q = dest;
+ for (; ; q++) {
+ *q = *src++;
+ if (*q == '\0')
+ break;
+ }
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_strncpy__)
+void *strncpy (char *dest, const char *src, size_t n)
+{
+ char *q;
+
+ q = dest;
+ for (; n != 0; n--, q++) {
+ *q = *src++;
+ if (*q == '\0')
+ break;
+ }
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_strdup__)
+char *strdup (const char *s)
+{
+ char *dest;
+ size_t len;
+
+ len = strlen(s) + 1;
+ dest = malloc(len);
+ if (dest != NULL)
+ memcpy(dest, s, len);
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_strndup__)
+/* GNU extension */
+char *strndup (const char *s, size_t n)
+{
+ char *dest;
+ size_t len;
+
+ len = strlen(s) + 1;
+ if (len > n)
+ len = n;
+ dest = malloc(len);
+ if (dest != NULL) {
+ memcpy(dest, s, len - 1);
+ dest[len - 1] = '\0';
+ }
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_stpcpy__)
+void *stpcpy (char *dest, const char *src)
+{
+ char *q;
+
+ q = dest;
+ for (; ; q++) {
+ *q = *src++;
+ if (*q == '\0')
+ break;
+ }
+
+ return q;
+}
+#endif
+
+#if defined (__USE_stpncpy__)
+void *stpncpy (char *dest, const char *src, size_t n)
+{
+ char *q;
+
+ q = dest;
+ for (; n != 0; n--, q++) {
+ *q = *src++;
+ if (*q == '\0')
+ break;
+ }
+
+ return q;
+}
+#endif
+
+#if defined (__USE_strcat__)
+char *strcat (char *dest, const char *src)
+{
+ char *q;
+
+ for (q = dest + strlen(dest); ; q++) {
+ *q = *src++;
+ if (*q == '\0')
+ break;
+ }
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_strncat__)
+char *strncat (char *dest, const char *src, size_t n)
+{
+ char *q;
+
+ for (q = dest + strlen(dest); n != 0; n--, q++) {
+ *q = *src++;
+ if (*q == '\0')
+ break;
+ }
+
+ return dest;
+}
+#endif
+
+#if defined (__USE_strcmp__)
+int strcmp (const char *s1, const char *s2)
+{
+ int ret;
+
+ for (ret = 0; ret == 0; s1++) {
+ ret = *s1 - *s2++;
+ if (*s1 == '\0')
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined (__USE_strcasecmp__)
+int strcasecmp (const char *s1, const char *s2)
+{
+ int ret;
+
+ for (ret = 0; ret == 0; s1++) {
+ ret = toupper(*s1) - toupper(*s2++);
+ if (*s1 == '\0')
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined (__USE_strncmp__)
+int strncmp (const char *s1, const char *s2, size_t n)
+{
+ int ret;
+
+ for (ret = 0; ret == 0 && n != 0; n--, s1++) {
+ ret = *s1 - *s2++;
+ if (*s1 == '\0')
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined (__USE_strncasecmp__)
+int strncasecmp (const char *s1, const char *s2, size_t n)
+{
+ int ret;
+
+ for (ret = 0; ret == 0 && n != 0; n--, s1++) {
+ ret = toupper(*s1) - toupper(*s2++);
+ if (*s1 == '\0')
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined (__USE_strchr__)
+char *strchr (const char *s, int c)
+{
+ const char *r;
+
+ for (r = NULL; *s != '\0'; s++) {
+ if (*s == c) {
+ r = s;
+ break;
+ }
+ }
+
+ return (char *)r;
+}
+#endif
+
+#if defined (__USE_strchrnul__)
+/* GNU extension */
+char *strchrnul (const char *s, int c)
+{
+ for (; *s != '\0' && *s != c; s++)
+ continue;
+
+ return (char *)s;
+}
+#endif
+
+#if defined (__USE_strrchr__)
+char *strrchr (const char *s, int c)
+{
+ const char *p, *r;
+
+ r = NULL;
+ for (p = s + strlen(s); p != s; p--) {
+ if (*p == c) {
+ r = p;
+ break;
+ }
+ }
+
+ return (char *)r;
+}
+#endif
+
+#if defined (__USE_strstr__)
+char *strstr (const char *haystack, const char *needle)
+{
+ const char *r;
+ size_t hlen, nlen;
+
+ if (*needle == '\0')
+ return (char *)haystack;
+ r = NULL;
+ hlen = strlen(haystack);
+ nlen = strlen(needle);
+ for (; hlen > nlen; hlen--, haystack++) {
+ if (memcmp(haystack, needle, nlen) == 0) {
+ r = haystack;
+ break;
+ }
+ }
+
+ return (char *)r;
+}
+#endif
+
+#if defined (__USE_strcasestr__)
+char *strcasestr (const char *haystack, const char *needle)
+{
+ const char *p, *q, *r;
+ size_t hlen, nlen, n;
+
+ if (*needle == '\0')
+ return (char *)haystack;
+ r = NULL;
+ hlen = strlen(haystack);
+ nlen = strlen(needle);
+ for (; hlen > nlen; hlen--, haystack++) {
+ p = haystack;
+ q = needle;
+ for (n = nlen; n != 0; n--) {
+ if (toupper(*p++) != toupper(*q++))
+ break;
+ }
+ if (n == 0) {
+ r = haystack;
+ break;
+ }
+ }
+
+ return (char *)r;
+}
+#endif
+
+#if defined (__USE_strspn__)
+#error "TODO"
+size_t strspn (const char *s, const char *accept)
+{
+}
+#endif
+
+#if defined (__USE_strcspn__)
+#error "TODO"
+size_t strcspn (const char *s, const char *reject)
+{
+}
+#endif
+
+#if defined (__USE_strpbrk__)
+#error "TODO"
+char *strpbrk (const char *s, const char *accept)
+{
+}
+#endif
+
+#if defined (__USE_strtok__)
+#error "TODO"
+char *strtok (char *s, const char *delim)
+{
+}
+#endif
+
+#if defined (__USE_strtok_r__)
+#error "TODO"
+char *strtok_r (char *s, const char *delim, char **ptrptr)
+{
+}
+#endif
+
+#if defined (__USE_strsep__)
+#error "TODO"
+char *strsep (char **stringp, const char *delim)
+{
+}
+#endif
+
+#if defined (__USE_basename__)
+char *basename (char *path)
+{
+ char *sl;
+ size_t len;
+
+ if (path == NULL || (len = strlen(path)) == 0)
+ return strdup(".");
+ sl = path + len - 1;
+ if (*sl == '/')
+ sl--;
+ for (; sl != path; sl--) {
+ if (*sl == '/')
+ break;
+ }
+
+ return strdup(sl + 1);
+}
+#endif
+
+#if defined (__USE_dirname__)
+char *dirname (char *path)
+{
+ char *sl, *ret;
+ size_t len;
+
+ if (path == NULL || (len = strlen(path)) == 0) {
+ ret = strdup(".");
+ } else {
+ sl = path + len - 1;
+ if (*sl == '/')
+ sl--;
+ for (; sl != path; sl--) {
+ if (*sl == '/')
+ break;
+ }
+ len = sl - path;
+ if (len == 0) {
+ ret = strdup(".");
+ } else {
+ ret = malloc(len + 1);
+ if (ret != NULL) {
+ memcpy(path, ret, len);
+ path[len] = '\0';
+ }
+ }
+ }
+
+ return ret;
+}
+#endif
+
+#if defined (__USE_strlen__)
+size_t strlen (const char *s)
+{
+ size_t len;
+
+ for (len = 0; *s != '\0'; len++)
+ s++;
+
+ return len;
+}
+#endif
+
+#if defined (__USE_strnlen__)
+size_t strnlen (const char *s, size_t maxlen)
+{
+ size_t len;
+
+ for (len = 0; maxlen != 0 && *s != '\0'; maxlen--, len++)
+ s++;
+
+ return len;
+}
+#endif
diff --git a/src/libexec/chrp.c b/src/libexec/chrp.c
new file mode 100644
index 0000000..9a2be2e
--- /dev/null
+++ b/src/libexec/chrp.c
@@ -0,0 +1,404 @@
+/*
+ * <chrp.c>
+ *
+ * Open Hack'Ware BIOS CHRP boot file loader
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "bios.h"
+#include "exec.h"
+#include "libfs/libfs.h"
+
+/* Simple XML parser */
+typedef struct XML_tag_t XML_tag_t;
+struct XML_tag_t {
+ unsigned char *name;
+ XML_tag_t *up;
+ int dlen;
+ void *data;
+};
+
+enum {
+ CHRP_TAG_UNKNOWN = 0,
+ CHRP_TAG_CHRP_BOOT,
+ CHRP_TAG_COMPATIBLE,
+ CHRP_TAG_DESCRIPTION,
+ CHRP_TAG_BOOT_SCRIPT,
+ CHRP_TAG_OS_BADGE_ICONS,
+ CHRP_TAG_ICON,
+ CHRP_TAG_BITMAP,
+ CHRP_TAG_LICENSE,
+};
+
+enum {
+ CHRP_SCRIPT_IGNORE = 0,
+ CHRP_SCRIPT_LOAD_BOOT,
+ CHRP_SCRIPT_EMBEDDED,
+};
+
+enum {
+ XML_STATE_OUT = 0,
+ XML_STATE_TAG,
+ XML_STATE_DATA,
+};
+
+static int XML_get_type (const unsigned char *name)
+{
+ int ret;
+
+ if (strcmp(name, "CHRP-BOOT") == 0)
+ ret = CHRP_TAG_CHRP_BOOT;
+ else if (strcmp(name, "COMPATIBLE") == 0)
+ ret = CHRP_TAG_COMPATIBLE;
+ else if (strcmp(name, "DESCRIPTION") == 0)
+ ret = CHRP_TAG_DESCRIPTION;
+ else if (strcmp(name, "BOOT-SCRIPT") == 0)
+ ret = CHRP_TAG_BOOT_SCRIPT;
+ else if (strcmp(name, "OS-BADGE-ICONS") == 0)
+ ret = CHRP_TAG_OS_BADGE_ICONS;
+ else if (strcmp(name, "ICON") == 0)
+ ret = CHRP_TAG_ICON;
+ else if (strcmp(name, "BITMAP") == 0)
+ ret = CHRP_TAG_BITMAP;
+ else if (strcmp(name, "LICENSE") == 0)
+ ret = CHRP_TAG_LICENSE;
+ else
+ ret = CHRP_TAG_UNKNOWN;
+
+ return ret;
+}
+
+static unsigned char *strfind (const unsigned char *buf, const unsigned char *str)
+{
+ const unsigned char *pos;
+ int len = strlen(str);
+
+ // DPRINTF("Look for '%s' in \n'%s'\n", str, buf);
+ for (pos = buf; *pos != '\0'; pos++) {
+ if (memcmp(pos, str, len) == 0)
+ return (unsigned char *)pos;
+ }
+
+ return NULL;
+}
+
+int exec_load_chrp (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+#define TMPNAME_LEN 512
+ unsigned char tmpname[TMPNAME_LEN], *tmpp, *buf, *pos, *endc, c;
+ XML_tag_t *tag, *tmp, *first;
+ part_t *part;
+ inode_t *inode;
+ int state;
+ int script_type = CHRP_SCRIPT_IGNORE;
+ uint32_t crc, offset = 0;
+ int ret, rel = 0;
+
+ buf = malloc(16384);
+ /* Check the file head */
+ file_seek(file, loffset);
+ fs_read(file, buf, 11);
+ if (memcmp(buf, "<CHRP-BOOT>", 11) != 0) {
+ ERROR("Not an Apple CHRP boot file !\n");
+ return -2;
+ }
+ /* Re-seek at start of the file and start parsing it */
+ file_seek(file, loffset);
+ pos = buf;
+ tag = NULL;
+ first = NULL;
+ ret = -1;
+ fs_read(file, &c, 1);
+ offset++;
+ for (state = XML_STATE_TAG; state != XML_STATE_OUT;) {
+ /* Get next char */
+ fs_read(file, &c, 1);
+ offset++;
+ if ((state == XML_STATE_TAG && c != '>') ||
+ (state == XML_STATE_DATA && c != '<')) {
+ *pos++ = c;
+ continue;
+ }
+ *pos++ = '\0';
+ switch (state) {
+ case XML_STATE_TAG:
+ if (*buf == '/') {
+ if (tag == NULL || strcmp(buf + 1, tag->name) != 0) {
+ ERROR("XML error: open name: '%s' close name: '%s'\n",
+ buf + 1, tag->name);
+ goto out;
+ }
+ DPRINTF("Close tag: '%s'\n", tag->name);
+ switch (XML_get_type(tag->name)) {
+ case CHRP_TAG_CHRP_BOOT:
+ /* Nothing to do */
+ break;
+ case CHRP_TAG_COMPATIBLE:
+ /* Won't check... */
+ pos = tag->data;
+ if (*(char *)tag->data == 0x0d) {
+ pos++;
+ }
+ DPRINTF("Compatible: '%s'\n", pos);
+ break;
+ case CHRP_TAG_DESCRIPTION:
+ pos = tag->data;
+ if (*(char *)tag->data == 0x0d) {
+ pos++;
+ }
+ DPRINTF("Description: '%s'\n", pos);
+ break;
+ case CHRP_TAG_BOOT_SCRIPT:
+ /* Here is the interresting part... */
+ crc = crc32(0, tag->data, tag->dlen);
+#if 0
+ DPRINTF("Forth script: %08x\n%s\n",
+ crc, (char *)tag->data);
+#endif
+ switch (crc) {
+ case 0x5464F92C:
+ /* Mandrake 9.1 CD1 boot script */
+ case 0x4BC74ECF:
+ /* Mandrake 10.1 & 10.2 CD1 boot script */
+ case 0x5B265246:
+ /* Gentoo 1.2-r1 */
+ /* Gentoo 2004.1 minimal install CD */
+ /* Gentoo 1.4 live CDROM */
+ /* Knopix PPC beta-pre12 */
+ case 0x75420D8A:
+ /* Debian woody */
+ /* Debian 3.0r1 */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0x633e4c9c:
+ /* Debian Sarge */
+ case 0xbe3abf60:
+ /* Debian Sarge, installed on a hard disk drive */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0x07b86bfe:
+ /* Linux Fedora Core 3 */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0x9ccdf371:
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0xEF423926:
+ /* OpenBSD 3.4 */
+ case 0x68e4f265:
+ /* OpenBSD 3.5 */
+ case 0x3b7ea9e1:
+ /* OpenBSD 3.6 */
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+ case 0xB7981DBC:
+ /* iBook 2 hw test CDROM */
+#if 1
+ script_type = CHRP_SCRIPT_LOAD_BOOT;
+ goto do_script;
+#endif
+
+ case 0xEA06C1A7:
+ /* MacOS 9.2 boot script:
+ * the XCOFF loader is embedded in the file...
+ */
+ case 0x53A95958:
+ /* iBook 2 restore CD (MacOS X 10.2) */
+ script_type = CHRP_SCRIPT_EMBEDDED;
+ pos = strfind(tag->data, "elf-offset");
+ if (pos != NULL) {
+ /* Go backward until we get the value */
+ for (--pos; *pos < '0' || *pos > '9'; pos--)
+ continue;
+ for (; *pos >= '0' && *pos <= '9'; pos--)
+ continue;
+ offset = strtol(pos, NULL, 16);
+ goto do_script;
+ }
+ ERROR("Didn't find boot file offset\n");
+ goto out;
+ case 0x8d5acb86:
+ /* Darwin-7.01
+ * The executable file is embedded after the script
+ */
+ script_type = CHRP_SCRIPT_EMBEDDED;
+ DPRINTF("Boot file embedded at the end of boot script\n");
+ break;
+ default:
+ ERROR("XML error: unknown Forth script: %08x\n%s\n",
+ crc, (char *)tag->data);
+ goto out;
+ }
+ break;
+
+ do_script:
+ switch (script_type) {
+ case CHRP_SCRIPT_LOAD_BOOT:
+ pos = strfind(tag->data, "boot");
+ if (pos != NULL) {
+ /* Eat everything until file name */
+ for (pos += 4; *pos != ','; pos++)
+ continue;
+ /* Eat ',' */
+ for (++pos; isspace(*pos) || *pos == '"'; pos++)
+ continue;
+ /* Find file name end */
+ redo:
+ for (endc = pos;
+ *endc != ' ' && *endc != '"' &&
+ *endc != '\n' && *endc != '\r';
+ endc++) {
+ if (*endc == '\\')
+ *endc = '/';
+ }
+ if (memcmp(pos, "ofwboot", 7) == 0) {
+ for (pos = endc + 1; *pos == ' '; pos++)
+ continue;
+ goto redo;
+ }
+ *endc = '\0';
+ }
+ DPRINTF("Real boot file is: '%s'\n", pos);
+ part = fs_inode_get_part(file);
+ /* check if it's a path or just a file */
+ tmpp = pos;
+ if ((pos[0] == '/' && pos[1] == '/') ||
+ pos[0] != '/') {
+ unsigned char *bootdir;
+ bootdir = fs_get_boot_dirname(part_fs(part));
+ if (bootdir == NULL) {
+ ERROR("Cannot get boot directory name\n");
+ bug();
+ }
+ snprintf(tmpname, TMPNAME_LEN,
+ "%s/%s", bootdir, pos);
+ tmpname[TMPNAME_LEN - 1] = '\0';
+ rel++;
+ pos = tmpname;
+ DPRINTF("'%s' => '%s'\n", bootdir, pos);
+ }
+ retry:
+ inode = fs_open(part_fs(part), pos);
+ if (inode == NULL) {
+ ERROR("Real boot inode '%s' not found\n", pos);
+ /* Try in root directory */
+ if (rel == 1) {
+ for (; *tmpp == '/'; tmpp++)
+ continue;
+ snprintf(tmpname, TMPNAME_LEN, "/%s", tmpp);
+ tmpname[TMPNAME_LEN - 1] = '\0';
+ rel++;
+ goto retry;
+ }
+
+ bug();
+ }
+ ret = _bootfile_load(inode, dest, entry, end, 0, -1);
+ fs_close(inode);
+ goto out;
+ case CHRP_SCRIPT_EMBEDDED:
+ DPRINTF("Exec offset: %d %08x\n", offset, offset);
+ ret = 0;
+ goto out;
+ case CHRP_SCRIPT_IGNORE:
+ break;
+ }
+ break;
+ case CHRP_TAG_OS_BADGE_ICONS:
+ case CHRP_TAG_ICON:
+ /* Ignore it */
+ break;
+ case CHRP_TAG_BITMAP:
+ /* Ignore it */
+ break;
+ case CHRP_TAG_LICENSE:
+ /* Ignore it */
+ pos = tag->data;
+ if (*(char *)tag->data == 0x0d) {
+ pos++;
+ }
+ DPRINTF("License: '%s'\n", pos);
+ break;
+ default:
+ ERROR("XML error: unknown tag: '%s'\n", tag->name);
+ goto out;
+ }
+ tmp = tag->up;
+ if (tmp == NULL)
+ state = XML_STATE_OUT;
+ else
+ state = XML_STATE_DATA;
+ free(tag->name);
+ free(tag->data);
+ free(tag);
+ tag = tmp;
+ } else {
+ tmp = malloc(sizeof(XML_tag_t));
+ if (tmp == NULL) {
+ ERROR("Cannot allocate new tag\n");
+ goto out;
+ }
+ tmp->up = tag;
+ /* Ignore tag attributes */
+ pos = strchr(buf, ' ');
+ if (pos != NULL)
+ *pos = '\0';
+ tmp->name = strdup(buf);
+ tag = tmp;
+ if (first == NULL)
+ first = tag;
+ DPRINTF("Open tag '%s'\n", tag->name);
+ state = XML_STATE_DATA;
+ }
+ break;
+ case XML_STATE_DATA:
+ if (tag->data == NULL) {
+ tag->dlen = pos - buf;
+ tag->data = malloc(tag->dlen);
+ memcpy(tag->data, buf, tag->dlen);
+ }
+ state = XML_STATE_TAG;
+ break;
+ }
+ pos = buf;
+ }
+ ret = 0;
+ fs_read(file, &c, 1);
+ fs_read(file, &c, 1);
+ offset += 2;
+ out:
+#if 1
+ for (; tag != NULL; tag = tmp) {
+ tmp = tag->up;
+ free(tag->name);
+ free(tag->data);
+ free(tag);
+ }
+#endif
+ if (ret == 0 && script_type == CHRP_SCRIPT_EMBEDDED) {
+ DPRINTF("Load embedded file from offset %d (%d => %d)\n",
+ offset, loffset, loffset + offset);
+ ret = _bootfile_load(file, dest, entry, end, loffset + offset, -1);
+ }
+ DPRINTF("Done\n");
+
+ return ret;
+}
diff --git a/src/libexec/core.c b/src/libexec/core.c
new file mode 100644
index 0000000..222a29a
--- /dev/null
+++ b/src/libexec/core.c
@@ -0,0 +1,151 @@
+/*
+ * <file.c>
+ *
+ * Open Hack'Ware BIOS executable file loader
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "exec.h"
+
+/*****************************************************************************/
+uint32_t file_seek (inode_t *file, uint32_t pos)
+{
+ uint32_t blocsize, bloc, offset;
+
+ if (file == NULL)
+ return -1;
+ blocsize = part_blocsize(fs_inode_get_part(file));
+ bloc = pos / blocsize;
+ offset = pos % blocsize;
+
+ return fs_seek(file, bloc, offset);
+}
+
+/*****************************************************************************/
+/* Executable file loaders */
+
+enum {
+ FILE_TYPE_ELF = 0,
+ FILE_TYPE_XCOFF,
+ FILE_TYPE_MACHO,
+ FILE_TYPE_PEF,
+ FILE_TYPE_CHRP,
+ FILE_TYPE_PREP,
+ FILE_TYPE_FLAT,
+};
+
+uint32_t fs_inode_get_size (inode_t *inode);
+unsigned int part_get_entry (part_t *part);
+/*****************************************************************************/
+/* Generic boot file loader */
+int _bootfile_load (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset, int type)
+{
+ int (*do_load)(inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+ uint32_t size;
+ int ret;
+ int i;
+
+ if (type == -1)
+ i = 0;
+ else
+ i = type;
+ for (;; i++) {
+ switch (i) {
+ case FILE_TYPE_ELF:
+ do_load = &exec_load_elf;
+ break;
+ case FILE_TYPE_XCOFF:
+ do_load = &exec_load_xcoff;
+ break;
+ case FILE_TYPE_MACHO:
+ do_load = &exec_load_macho;
+ break;
+ case FILE_TYPE_PEF:
+ do_load = &exec_load_pef;
+ break;
+ case FILE_TYPE_CHRP:
+ do_load = &exec_load_chrp;
+ break;
+ case FILE_TYPE_PREP:
+ do_load = &exec_load_prep;
+ break;
+ default:
+ if (*dest == NULL)
+ *dest = (void *)DEFAULT_LOAD_DEST;
+ if (*entry == NULL) {
+ if (part_get_entry(fs_inode_get_part(file)) != 0 || 1) {
+ *entry = (char *)*dest +
+ part_get_entry(fs_inode_get_part(file));
+ dprintf("dest %p entry %08x => %p\n",
+ *dest, part_get_entry(fs_inode_get_part(file)),
+ *entry);
+ } else {
+ *entry = *dest + 0xC;
+ }
+ }
+ size = fs_inode_get_size(file);
+ *end = (char *)*dest + size - loffset;
+ printf("Load raw file into memory at %p %d (%08x) %d (%08x)\n",
+ *dest, size, size, loffset, loffset);
+ file_seek(file, loffset);
+ set_loadinfo(*dest, size);
+ if ((uint32_t)fs_read(file, *dest, size) != size) {
+ ERROR("Error loading file...\n");
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+ goto out;
+ }
+ DPRINTF("Check file type %d at offset %d %p\n", i, loffset, do_load);
+ ret = (*do_load)(file, dest, entry, end, loffset);
+ if (ret >= -1 || type == i) {
+ if (type == i)
+ ret = -2;
+ break;
+ }
+ }
+ out:
+
+ return ret;
+}
+
+int bootfile_load (void **dest, void **entry, void **end,
+ part_t *part, int type, const unsigned char *fname,
+ uint32_t loffset)
+{
+ inode_t *file;
+ int ret;
+
+ DPRINTF("Load file '%s' %p %p type: %d offset: %0x => %d %p\n",
+ fname, part, part_fs(part), type, loffset, part_blocsize(part), *dest);
+ if (fname == NULL)
+ file = fs_get_bootfile(part_fs(part));
+ else
+ file = fs_open(part_fs(part), fname);
+ if (file == NULL)
+ return -1;
+ ret = _bootfile_load(file, dest, entry, end, loffset, type);
+ fs_close(file);
+
+ return ret;
+}
diff --git a/src/libexec/elf.c b/src/libexec/elf.c
new file mode 100644
index 0000000..ae9f8e0
--- /dev/null
+++ b/src/libexec/elf.c
@@ -0,0 +1,239 @@
+/*
+ * <elf.c>
+ *
+ * Open Hack'Ware BIOS ELF executable file loader
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "exec.h"
+
+uint32_t fs_inode_get_size (inode_t *inode);
+
+/* ELF executable loader */
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Word;
+typedef uint32_t Elf32_Off;
+typedef uint32_t Elf32_Addr;
+
+#define EI_NIDENT 16
+
+typedef struct elf32_hdr_t {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr_t;
+
+typedef struct elf32_phdr_t {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr_t;
+
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_OSABI 7
+#define EI_PAD 8
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+
+#define ELFCLASSNONE 0 /* EI_CLASS */
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFCLASSNUM 3
+
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_NONE 0 /* e_version, EI_VERSION */
+#define EV_CURRENT 1
+#define EV_NUM 2
+
+/* These constants define the different elf file types */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* These constants define the various ELF target machines */
+#define EM_NONE 0
+#define EM_M32 1
+#define EM_SPARC 2
+#define EM_386 3
+#define EM_68K 4
+#define EM_88K 5
+#define EM_486 6 /* Perhaps disused */
+#define EM_860 7
+#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
+#define EM_PARISC 15 /* HPPA */
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC64 */
+#define EM_SH 42 /* SuperH */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+#define EM_IA_64 50 /* HP/Intel IA-64 */
+#define EM_X86_64 62 /* AMD x86-64 */
+#define EM_S390 22 /* IBM S/390 */
+#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
+#define EM_V850 87 /* NEC v850 */
+#define EM_H8_300H 47 /* Hitachi H8/300H */
+#define EM_H8S 48 /* Hitachi H8S */
+/*
+ * This is an interim value that we will use until the committee comes
+ * up with a final number.
+ */
+#define EM_ALPHA 0x9026
+/* Bogus old v850 magic number, used by old tools. */
+#define EM_CYGNUS_V850 0x9080
+/*
+ * This is the old interim value for S/390 architecture
+ */
+#define EM_S390_OLD 0xA390
+
+int exec_load_elf (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+ Elf32_Ehdr_t ehdr;
+ Elf32_Phdr_t phdr;
+ void *address, *first, *last;
+ uint32_t offset, fsize, msize;
+ int i;
+
+ file_seek(file, loffset);
+ if (fs_read(file, &ehdr, sizeof(Elf32_Ehdr_t)) < 0) {
+ ERROR("Cannot load first bloc of file...\n");
+ return -1;
+ }
+ DPRINTF("Check ELF file\n");
+ /* Check ident */
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr.e_ident[EI_MAG3] != ELFMAG3) {
+ DPRINTF("Not an ELF file %0x\n", *(uint32_t *)ehdr.e_ident);
+ return -2;
+ }
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
+ ERROR("Not a 32 bits ELF file\n");
+ return -2;
+ }
+ if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
+ ERROR("Not a big-endian ELF file\n");
+ return -2;
+ }
+ if (ehdr.e_ident[EI_VERSION] != EV_CURRENT /*||
+ ehdr->e_version != EV_CURRENT*/) {
+ ERROR("Invalid ELF executable version %d %08x\n",
+ ehdr.e_ident[EI_VERSION], ehdr.e_version);
+ return -2;
+ }
+ if (ehdr.e_type != ET_EXEC) {
+ ERROR("Not an executable ELF file\n");
+ return -2;
+ }
+ if (ehdr.e_machine != EM_PPC) {
+ ERROR("Not a PPC ELF executable\n");
+ return -2;
+ }
+ /* All right, seems to be a regular ELF program for PPC */
+ *entry = (void *)ehdr.e_entry;
+ DPRINTF("ELF file found entry = %p\n", *entry);
+ last = NULL;
+ first = last - 4;
+ fsize = msize = 0;
+ offset = ehdr.e_phoff;
+ for (i = 0; i < ehdr.e_phnum; i++) {
+#if 0
+ if (offset > fs_inode_get_size(file)) {
+ ERROR("ELF program header %d offset > file size %d %d\n", i,
+ offset, fs_inode_get_size(file));
+ return -1;
+ }
+#endif
+ DPRINTF("Load program header %d from %08x\n", i, offset);
+ file_seek(file, offset + loffset);
+ if (fs_read(file, &phdr, sizeof(Elf32_Phdr_t)) < 0) {
+ ERROR("Cannot load ELF program header %d...\n", i);
+ return -1;
+ }
+ DPRINTF("Load program header %d %08x %08x %08x %08x\n", i,
+ phdr.p_offset, phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz);
+#if 0
+ if (phdr.p_offset > fs_inode_get_size(file)) {
+ ERROR("ELF program %d offset > file size %d %d\n",
+ i, phdr.p_offset, fs_inode_get_size(file));
+ return -1;
+ }
+#endif
+ /* As we won't remap memory, load it at it's virtual address (!) */
+ address = (void *)phdr.p_vaddr;
+ if (address < first)
+ first = address;
+ fsize = phdr.p_filesz;
+ msize = phdr.p_memsz;
+ if (address + msize > last)
+ last = address + msize;
+ file_seek(file, phdr.p_offset + loffset);
+ set_loadinfo((void *)first, last - first);
+ if (fs_read(file, address, fsize) < 0) {
+ ERROR("Cannot load ELF program %d...\n", i);
+ return -1;
+ }
+ if (msize > fsize) {
+ memset(address + fsize, 0, msize - fsize);
+ }
+ offset += ehdr.e_phentsize;
+ }
+ *dest = (void *)first;
+ *end = (void *)last;
+ DPRINTF("ELF file loaded at %p => %p fsize %08x msize %08x "
+ "(%08x %08x)\n", *dest, *entry, fsize, msize,
+ *(uint32_t *)entry, *((uint32_t *)entry + 1));
+
+ return 0;
+}
diff --git a/src/libexec/exec.h b/src/libexec/exec.h
new file mode 100644
index 0000000..46f138f
--- /dev/null
+++ b/src/libexec/exec.h
@@ -0,0 +1,40 @@
+/*
+ * <exec.h>
+ *
+ * Open Hack'Ware BIOS: executable files loader definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined(__OHW_EXEC_H__)
+#define __OHW_EXEC_H__
+
+int _bootfile_load (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset, int type);
+int exec_load_elf (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_macho (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_pef (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_prep (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+int exec_load_chrp (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset);
+
+#endif /* !defined(__OHW_EXEC_H__) */
diff --git a/src/libexec/macho.c b/src/libexec/macho.c
new file mode 100644
index 0000000..ea55892
--- /dev/null
+++ b/src/libexec/macho.c
@@ -0,0 +1,516 @@
+/*
+ * <macho.c>
+ *
+ * Open Hack'Ware BIOS MACH-O executable file loader
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "exec.h"
+
+/* MACH-O executable loader */
+/* FAT definitions */
+/* CPU type definitions */
+typedef enum cpu_type_t {
+ CPU_TYPE_ANY = -1,
+ CPU_TYPE_VAX = 1,
+ CPU_TYPE_MC680x0 = 6,
+ CPU_TYPE_I386 = 7,
+ CPU_TYPE_MIPS = 8,
+ CPU_TYPE_MC98000 = 10,
+ CPU_TYPE_HPPA = 11,
+ CPU_TYPE_ARM = 12,
+ CPU_TYPE_MC88000 = 13,
+ CPU_TYPE_SPARC = 14,
+ CPU_TYPE_I860 = 15,
+ CPU_TYPE_ALPHA = 16,
+ CPU_TYPE_POWERPC = 18,
+} cpu_type_t;
+
+/* Any CPU */
+typedef enum cpu_subtype_any_t {
+ CPU_SUBTYPE_MULTIPLE = -1,
+ CPU_SUBTYPE_LITTLE_ENDIAN = 0,
+ CPU_SUBTYPE_BIG_ENDIAN = 1,
+} cpu_subtype_any_t;
+
+/* PowerPC */
+typedef enum cpu_subtype_ppc_t {
+ CPU_SUBTYPE_PPC_ALL = 0,
+ CPU_SUBTYPE_PPC_601 = 1,
+ CPU_SUBTYPE_PPC_602 = 2,
+ CPU_SUBTYPE_PPC_603 = 3,
+ CPU_SUBTYPE_PPC_603e = 4,
+ CPU_SUBTYPE_PPC_603ev = 5,
+ CPU_SUBTYPE_PPC_604 = 6,
+ CPU_SUBTYPE_PPC_604e = 7,
+ CPU_SUBTYPE_PPC_620 = 8,
+ CPU_SUBTYPE_PPC_750 = 9,
+ CPU_SUBTYPE_PPC_7400 = 10,
+ CPU_SUBTYPE_PPC_7450 = 11,
+} cpu_subtype_ppc_t;
+
+/* Fat header definition */
+#define FAT_MAGIC 0xCAFEBABE
+
+typedef struct fat_head_t {
+ uint32_t magic;
+ uint32_t nfat_arch;
+} fat_head_t;
+
+typedef struct fat_arch_t {
+ cpu_type_t cpu_type;
+ cpu_subtype_ppc_t cpu_subtype;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t align;
+} fat_arch_t;
+
+/* Mach-O binary definitions */
+#define MACH_O_MAGIC 0xFEEDFACE
+
+typedef enum filetype_t {
+ MH_OBJECT = 0x1,
+ MH_EXECUTE = 0x2,
+ MH_FVMLIB = 0x3,
+ MH_CORE = 0x4,
+ MH_PRELOAD = 0x5,
+ MH_DYLIB = 0x6,
+ MH_DYLINKER = 0x7,
+ MH_BUNDLE = 0x8,
+} filetype_t;
+
+enum {
+ MH_NOUNDEFS = 0x01,
+ MH_INCRLINK = 0x02,
+ MH_DYLDLINK = 0x04,
+ MH_BINDATLOAD = 0x08,
+ MH_PREBOUND = 0x10,
+};
+
+typedef struct mach_head_t {
+ uint32_t magic;
+ cpu_type_t cpu_type;
+ cpu_subtype_ppc_t subtype;
+ filetype_t file_type;
+ uint32_t nb_cmds;
+ uint32_t cmds_size;
+ uint32_t flags;
+} mach_head_t;
+
+typedef enum load_cmd_t {
+ LC_SEGMENT = 0x01,
+ LC_SYMTAB = 0x02,
+ LC_SYMSEG = 0x03,
+ LC_THREAD = 0x04,
+ LC_UNIXTHREAD = 0x05,
+ LC_LOADFVMLIB = 0x06,
+ LC_IDFVMLIB = 0x07,
+ LC_IDENT = 0x08,
+ LC_FVMFILE = 0x09,
+ LC_PREPAGE = 0x0A,
+ LC_DYSYMTAB = 0x0B,
+ LC_LOAD_DYLIB = 0x0C,
+ LC_ID_DYLIB = 0x0D,
+ LC_LOAD_DYLINKER = 0x0E,
+ LC_ID_DYLINKER = 0x0F,
+ LC_PREBOUND_DYLIB = 0x10,
+} load_cmd_t;
+
+typedef struct mach_load_cmd_t {
+ load_cmd_t cmd;
+ uint32_t cmd_size;
+} mach_load_cmd_t;
+
+typedef struct mach_string_t {
+ uint32_t offset;
+} mach_string_t;
+
+enum {
+ SG_HIGHVM = 0x1,
+ SG_FVMLIB = 0x2,
+ SG_NORELOC = 0x4,
+};
+
+typedef struct mach_segment_t {
+ unsigned char segname[16];
+ uint32_t vmaddr;
+ uint32_t vmsize;
+ uint32_t file_offset;
+ uint32_t file_size;
+ uint32_t max_prot;
+ uint32_t init_prot;
+ uint32_t nsects;
+ uint32_t flags;
+} mach_segment_t;
+
+enum {
+ SECTION_TYPE = 0xFF,
+ S_REGULAR = 0x0,
+ S_ZEROFILL = 0x1,
+ S_CSTRING_LITERALS = 0x2,
+ S_4BYTE_LITERALS = 0x3,
+ S_8BYTE_LITERALS = 0x4,
+ S_LITERAL_POINTERS = 0x5,
+ S_NON_LAZY_SYMBOL_POINTERS = 0x6,
+ S_LAZY_SYMBOL_POINTERS = 0x7,
+ S_SYMBOL_STUBS = 0x8,
+ S_MOD_INIT_FUNC_POINTERS = 0x9,
+};
+
+enum {
+ S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
+ S_ATTR_SOME_INSTRUCTIONS = 0x00000400,
+ S_ATTR_EXT_RELOC = 0x00000200,
+ S_ATTR_LOC_RELOC = 0x00000100,
+};
+
+typedef struct mach_section_t {
+ unsigned char sectname[16];
+ unsigned char segname[16];
+ uint32_t vmaddr;
+ uint32_t size;
+ uint32_t offset;
+ uint32_t align;
+ uint32_t reloc_offset;
+ uint32_t nreloc;
+ uint32_t flags;
+ uint32_t res1;
+ uint32_t res2;
+} mach_section_t;
+
+typedef struct mach_symtab_t {
+ uint32_t offset;
+ uint32_t nsyms;
+ uint32_t str_offset;
+ uint32_t str_size;
+} mach_symtab_t;
+
+typedef struct mach_symseg_t {
+ uint32_t offset;
+ uint32_t size;
+} mach_symseg_t;
+
+typedef struct mach_unixth_t {
+ uint32_t flavor;
+ uint32_t count;
+ /* This is supposed to be a stack.
+ * Let's assume it's less than 1kB (arbitrary !)
+ */
+ uint32_t data[256];
+} mach_unixth_t;
+
+typedef struct mach_fvmlib_t {
+ uint32_t str_offset;
+ uint32_t minor_version;
+ uint32_t header_addr;
+} mach_fvmlib_t;
+
+typedef struct mach_fvmfile_t {
+ uint32_t str_offset;
+ uint32_t vmaddr;
+} mach_fvmfile_t;
+
+typedef struct mach_dysymtab_t {
+ uint32_t ilocal_syms;
+ uint32_t nlocal_syms;
+ uint32_t iext_syms;
+ uint32_t next_syms;
+ uint32_t iundef_syms;
+ uint32_t nundef_syms;
+ uint32_t toc_offset;
+ uint32_t ntoc;
+ uint32_t modtab_offset;
+ uint32_t nmodtab;
+ uint32_t extsym_offset;
+ uint32_t nextsym;
+ uint32_t indirect_offset;
+ uint32_t nindirect;
+ uint32_t ext_reloc_offset;
+ uint32_t next_reloc;
+ uint32_t local_reloc_offset;
+ uint32_t nlocal_reloc;
+} mach_dysymtab_t;
+
+typedef struct mach_dylib_t {
+ uint32_t str_offset;
+ uint32_t timestamp;
+ uint32_t cur_version;
+ uint32_t compat_version;
+} mach_dylib_t;
+
+typedef struct mach_prebound_t {
+ uint32_t str_offset;
+ uint32_t nb_modules;
+ unsigned char linked_modules[256];
+} mach_prebound_t;
+
+int exec_load_macho (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+ mach_head_t mhdr;
+ mach_load_cmd_t lcmd;
+ fat_head_t fhdr;
+ fat_arch_t fahdr;
+ void *address, *first, *last;
+ uint32_t k, j, best, offset;
+ int entry_set;
+
+ /* Probe FAT */
+ file_seek(file, loffset);
+ if (fs_read(file, &fhdr, sizeof(fat_head_t)) < 0) {
+ ERROR("Cannot load fat header...\n");
+ return -1;
+ }
+ fhdr.magic = get_be32(&fhdr.magic);
+ if (fhdr.magic != FAT_MAGIC)
+ goto macho_probe;
+ fhdr.nfat_arch = get_be32(&fhdr.nfat_arch);
+ DPRINTF("FAT file: %d archs\n", fhdr.nfat_arch);
+ /* Find the best architecture */
+ best = -1;
+ offset = 0;
+ for (k = 0; k < fhdr.nfat_arch; k++) {
+ if (fs_read(file, &fahdr, sizeof(fat_arch_t)) < 0) {
+ ERROR("Cannot load fat arch header\n");
+ return -1;
+ }
+ fahdr.cpu_type = get_be32(&fahdr.cpu_type);
+ if (fahdr.cpu_type != CPU_TYPE_POWERPC)
+ continue;
+ fahdr.cpu_subtype = get_be32(&fahdr.cpu_subtype);
+ fahdr.offset = get_be32(&fahdr.offset);
+ fahdr.size = get_be32(&fahdr.size);
+ fahdr.align = get_be32(&fahdr.align);
+ switch (fahdr.cpu_subtype) {
+ case CPU_SUBTYPE_PPC_750:
+ best = k;
+ offset = fahdr.offset;
+ goto fat_cpu_ok;
+ case CPU_SUBTYPE_PPC_ALL:
+ if (best == (uint32_t)-1) {
+ offset = fahdr.offset;
+ best = k;
+ }
+ break;
+ case CPU_SUBTYPE_PPC_603:
+ case CPU_SUBTYPE_PPC_603e:
+ case CPU_SUBTYPE_PPC_603ev:
+ case CPU_SUBTYPE_PPC_604:
+ case CPU_SUBTYPE_PPC_604e:
+ best = k;
+ offset = fahdr.offset;
+ break;
+ default:
+ break;
+ }
+ }
+ if (best == (uint32_t)-1) {
+ ERROR("No matching PPC FAT arch\n");
+ return -1;
+ }
+ DPRINTF("Use FAT arch %d at %08x %08x\n", best, offset, loffset);
+ fat_cpu_ok:
+ loffset += offset;
+
+ /* Probe macho */
+ macho_probe:
+ file_seek(file, loffset);
+ if (fs_read(file, &mhdr, sizeof(mach_head_t)) < 0) {
+ ERROR("Cannot load MACH-O header...\n");
+ return -1;
+ }
+ mhdr.magic = get_be32(&mhdr.magic);
+ if (mhdr.magic != MACH_O_MAGIC) {
+ ERROR("Not a MACH-O file\n");
+ return -2;
+ }
+ mhdr.cpu_type = get_be32(&mhdr.cpu_type);
+ mhdr.subtype = get_be32(&mhdr.subtype);
+ mhdr.file_type = get_be32(&mhdr.file_type);
+ mhdr.nb_cmds = get_be32(&mhdr.nb_cmds);
+ mhdr.cmds_size = get_be32(&mhdr.cmds_size);
+ mhdr.flags = get_be32(&mhdr.flags);
+ DPRINTF("MACHO-O file cpu %d %d file type %08x %d cmds size %08x flags "
+ "%08x\n", mhdr.cpu_type, mhdr.subtype, mhdr.file_type,
+ mhdr.nb_cmds, mhdr.cmds_size, mhdr.flags);
+ offset = sizeof(mach_head_t);
+ first = (void *)-1;
+ last = NULL;
+ entry_set = 0;
+ for (k = 0; k < mhdr.nb_cmds; k++) {
+ file_seek(file, loffset + offset);
+ if (fs_read(file, &lcmd, sizeof(mach_load_cmd_t)) < 0) {
+ ERROR("Unable to load MACH-O cmd %d\n", k);
+ return -1;
+ }
+ lcmd.cmd = get_be32(&lcmd.cmd);
+ lcmd.cmd_size = get_be32(&lcmd.cmd_size);
+ DPRINTF("Cmd %d : %08x size %08x (%08x %08x)\n", k, lcmd.cmd,
+ lcmd.cmd_size, offset, offset + loffset);
+ switch (lcmd.cmd) {
+ case LC_SEGMENT:
+ /* To be loaded for execution */
+ {
+ mach_segment_t segment;
+ mach_section_t section;
+ uint32_t pos;
+
+ pos = offset + sizeof(mach_load_cmd_t);
+ if (fs_read(file, &segment, sizeof(mach_segment_t)) < 0) {
+ ERROR("Cannot load MACH-O segment\n");
+ return -1;
+ }
+ pos += sizeof(mach_segment_t);
+ segment.vmaddr = get_be32(&segment.vmaddr);
+ segment.vmsize = get_be32(&segment.vmsize);
+ segment.file_offset = get_be32(&segment.file_offset);
+ segment.file_size = get_be32(&segment.file_size);
+ segment.max_prot = get_be32(&segment.max_prot);
+ segment.init_prot = get_be32(&segment.init_prot);
+ segment.nsects = get_be32(&segment.nsects);
+ segment.flags = get_be32(&segment.flags);
+ DPRINTF("MACH-O segment addr %08x size %08x off %08x fsize "
+ "%08x ns %d fl %08x\n", segment.vmaddr, segment.vmsize,
+ segment.file_offset, segment.file_size,
+ segment.nsects, segment.flags);
+ for (j = 0; j < segment.nsects; j++) {
+ file_seek(file, loffset + pos);
+ if (fs_read(file, &section, sizeof(mach_section_t)) < 0) {
+ ERROR("Cannot load MACH-O section\n");
+ return -1;
+ }
+ pos += sizeof(mach_section_t);
+ section.vmaddr = get_be32(&section.vmaddr);
+ section.size = get_be32(&section.size);
+ section.offset = get_be32(&section.offset);
+ section.align = get_be32(&section.align);
+ section.reloc_offset = get_be32(&section.reloc_offset);
+ section.nreloc = get_be32(&section.nreloc);
+ section.flags = get_be32(&section.flags);
+ section.res1 = get_be32(&section.res1);
+ section.res2 = get_be32(&section.res2);
+ DPRINTF("MACH-O section vmaddr %08x size %08x off %08x "
+ "flags %08x\n", section.vmaddr, section.size,
+ section.offset, section.flags);
+ switch (section.flags & SECTION_TYPE) {
+ case S_REGULAR:
+ case S_CSTRING_LITERALS:
+ case S_4BYTE_LITERALS:
+ case S_8BYTE_LITERALS:
+ case S_LITERAL_POINTERS:
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ case S_LAZY_SYMBOL_POINTERS:
+ case S_SYMBOL_STUBS:
+ case S_MOD_INIT_FUNC_POINTERS:
+ DPRINTF("Load section of type %d from %08x to %08x"
+ " %08x\n", section.flags, section.offset,
+ section.vmaddr, section.size);
+ file_seek(file, section.offset + loffset);
+ address = (void *)section.vmaddr;
+ if (address < first && address != NULL)
+ first = address;
+ if (address + section.size > last)
+ last = address + section.size;
+ if (fs_read(file, address, section.size) < 0) {
+ ERROR("Cannot load MACH-O section %d %d...\n",
+ k, j);
+ return -1;
+ }
+ break;
+ case S_ZEROFILL:
+ DPRINTF("Fill zero section to %08x %08x\n",
+ section.vmaddr, section.size);
+ address = (void *)section.vmaddr;
+ if (address < first && address != NULL)
+ first = address;
+ if (address + section.size > last)
+ last = address + section.size;
+ memset(address, 0, section.size);
+ break;
+ default:
+ ERROR("Unknown MACH-O section type: %d\n",
+ section.flags);
+ return -1;
+ }
+ }
+ }
+ break;
+ case LC_SYMTAB:
+ /* Don't care */
+ break;
+ case LC_SYMSEG:
+ /* Don't care */
+ break;
+ case LC_UNIXTHREAD:
+ /* To be loaded for execution */
+ {
+ mach_unixth_t unixth;
+
+ if (fs_read(file, &unixth, sizeof(mach_unixth_t)) < 0) {
+ ERROR("Cannot load MACH-O UNIX thread\n");
+ return -1;
+ }
+ DPRINTF("Set entry point to %08x\n", unixth.data[0]);
+ *entry = (void *)unixth.data[0];
+ entry_set = 1;
+ }
+ break;
+ case LC_THREAD:
+ break;
+ case LC_LOADFVMLIB:
+ break;
+ case LC_IDFVMLIB:
+ break;
+ case LC_IDENT:
+ break;
+ case LC_FVMFILE:
+ break;
+ case LC_PREPAGE:
+ printf("Prepage command\n");
+ break;
+ case LC_DYSYMTAB:
+ break;
+ case LC_LOAD_DYLIB:
+ break;
+ case LC_ID_DYLIB:
+ break;
+ case LC_LOAD_DYLINKER:
+ /* To be loaded for execution */
+ break;
+ case LC_ID_DYLINKER:
+ break;
+ case LC_PREBOUND_DYLIB:
+ break;
+ case 0x17:
+ /* ? */
+ break;
+ default:
+ printf("unknown MACH-O command (%d %d)\n", k, lcmd.cmd);
+ return -1;
+ }
+ offset += lcmd.cmd_size;
+ }
+ *dest = first;
+ *end = last;
+ // if (entry_set == 0)
+ *entry = *dest;
+
+ return 0;
+}
diff --git a/src/libexec/pef.c b/src/libexec/pef.c
new file mode 100644
index 0000000..2c58014
--- /dev/null
+++ b/src/libexec/pef.c
@@ -0,0 +1,307 @@
+/*
+ * <pef.c>
+ *
+ * Open Hack'Ware BIOS Classic MacOS executable file loader
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "exec.h"
+
+/* PEF (old MacOS executable format) */
+typedef struct PEF_container_t PEF_container_t;
+struct PEF_container_t {
+ uint32_t tag1;
+ uint32_t tag2;
+ uint32_t arch;
+ uint32_t version;
+ uint32_t timestamp;
+ uint32_t oldDefVersion;
+ uint32_t oldImpVersion;
+ uint32_t currentVersion;
+ uint16_t nb_sections;
+ uint16_t nb_inst_sections;
+ uint32_t pad;
+} __attribute__ (( packed ));
+
+typedef struct PEF_section_t PEF_section_t;
+struct PEF_section_t {
+ int32_t name_offset;
+ uint32_t address;
+ uint32_t total_size;
+ uint32_t unpacked_size;
+ uint32_t packed_size;
+ uint32_t container_offset;
+ uint8_t section_kind;
+ uint8_t share_kind;
+ uint8_t align;
+ uint8_t pad;
+} __attribute__ (( packed ));
+
+typedef struct PEF_loader_t PEF_loader_t;
+struct PEF_loader_t {
+ int32_t main_section;
+ uint32_t main_offset;
+ int32_t init_section;
+ uint32_t init_offset;
+ int32_t term_section;
+ uint32_t term_offset;
+ uint32_t nb_import_libs;
+ uint32_t nb_import_symbols;
+ uint32_t nb_reloc_sections;
+ uint32_t reloc_instr_offset;
+ uint32_t loader_strings_offset;
+ uint32_t export_hash_offset;
+ uint32_t export_hashtable_power;
+ uint32_t nb_export_symbols;
+} __attribute__ (( packed ));
+
+enum {
+ PEF_SECTION_CODE = 0,
+ PEF_SECTION_UNPDATA = 1,
+ PEF_SECTION_INIDATA = 2,
+ PEF_SECTION_CONSTANT = 3,
+ PEF_SECTION_LOADER = 4,
+ PEF_SECTION_DEBUG = 5,
+ PEF_SECTION_EXEC = 6,
+ PEF_SECTION_EXCP = 7,
+ PEF_SECTION_TRACE = 8,
+};
+
+enum {
+ PEF_SHARE_PROCESS = 1,
+ PEF_SHARE_GLOBAL = 4,
+ PEF_SHARE_PROTECTED = 5,
+};
+
+int exec_load_pef (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+ PEF_container_t container;
+ PEF_section_t section;
+ PEF_loader_t loader;
+ void *first, *last, *addr, **sections;
+ uint32_t pos, padsize, size, lpos, main_offset;
+ uint8_t opcode;
+ int nb_sections, nb_inst_sections, main_section, i, n;
+
+ file_seek(file, loffset);
+ if (fs_read(file, &container, sizeof(PEF_container_t)) < 0) {
+ ERROR("Cannot load container header\n");
+ return -1;
+ }
+ pos = sizeof(PEF_container_t);
+ /* Check tags and architecture */
+ if (memcmp(&container.tag1, "Joy!", 4) != 0) {
+ DPRINTF("No joy, no PEF\n");
+ return -2;
+ }
+ if (memcmp(&container.tag2, "peff", 4) != 0) {
+ DPRINTF("No PEFF file\n");
+ return -2;
+ }
+ if (memcmp(&container.arch, "pwpc", 4) != 0) {
+ DPRINTF("PEFF file not for PPC\n");
+ return -2;
+ }
+ if (get_be32(&container.version) != 1) {
+ DPRINTF("Unknown PEFF container version\n");
+ return -2;
+ }
+ nb_sections = get_be32(&container.nb_sections);
+ sections = malloc(nb_sections * sizeof(void *));
+ if (sections == NULL) {
+ ERROR("Cannot allocate sections\n");
+ return -1;
+ }
+ nb_inst_sections = get_be32(&container.nb_inst_sections);
+ first = (void *)0xFFFFFFFF;
+ last = NULL;
+ main_section = -1;
+ main_offset = 0;
+ for (i = 0, n = 0; i < nb_sections; i++) {
+ file_seek(file, loffset + pos);
+ if (fs_read(file, &section, sizeof(PEF_section_t)) < 0) {
+ ERROR("Cannot read section %d\n", i);
+ return -1;
+ }
+ pos += sizeof(PEF_section_t);
+ addr = (void *)get_be32(&section.address);
+ sections[i] = addr;
+ if (addr < first)
+ first = addr;
+ size = get_be32(&section.total_size);
+ lpos = get_be32(&section.container_offset);
+ file_seek(file, loffset + lpos);
+ switch (section.section_kind) {
+ case PEF_SECTION_CODE:
+ case PEF_SECTION_UNPDATA:
+ /* Load as raw data */
+ padsize = get_be32(&section.unpacked_size) - size;
+ file_seek(file, loffset + lpos);
+ if (fs_read(file, addr, size) < 0) {
+ ERROR("Cannot load section %d\n", i);
+ return -1;
+ }
+ addr = (char *)addr + size;
+ memset(addr, 0, padsize);
+ addr = (char *)addr + padsize;
+ break;
+ case PEF_SECTION_INIDATA:
+ case PEF_SECTION_CONSTANT:
+ case PEF_SECTION_EXEC:
+ /* Load as compressed data */
+ for (;;) {
+ void *ref;
+ uint32_t total;
+ uint8_t bsize, csize, count, j;
+
+ if (fs_read(file, &opcode, 1) < 0) {
+ ERROR("Cannot get opcode\n");
+ return -1;
+ }
+ bsize = opcode & 0x1F;
+ switch (opcode >> 5) {
+ case 0x0:
+ /* Initialize size bytes to zero */
+ memset(addr, 0, bsize);
+ addr = (char *)addr + bsize;
+ total = bsize;
+ break;
+ case 0x1:
+ /* Copy bloc */
+ if (fs_read(file, addr, bsize) < 0) {
+ ERROR("Cannot copy bloc\n");
+ return -1;
+ }
+ addr = (char *)addr + bsize;
+ total = bsize;
+ break;
+ case 0x2:
+ /* Repeat bloc */
+ if (fs_read(file, &count, 1) < 0) {
+ ERROR("Cannot read bloc size\n");
+ return -1;
+ }
+ total = 0;
+ if (count == 0) {
+ break;
+ }
+ if (fs_read(file, addr, bsize) < 0) {
+ ERROR("Cannot read repeat bloc\n");
+ return -1;
+ }
+ ref = addr;
+ addr = (char *)addr + bsize;
+ for (j = 1; j < count; j++) {
+ memcpy(addr, ref, bsize);
+ total += bsize;
+ addr = (char *)addr + bsize;
+ }
+ break;
+ case 0x3:
+ /* Interleave repeat bloc with bloc copy */
+ if (fs_read(file, &csize, 1) < 0 ||
+ fs_read(file, &count, 1) < 0) {
+ ERROR("Cannot read repeat params\n");
+ return -1;
+ }
+ ref = addr;
+ if (fs_read(file, addr, bsize) < 0) {
+ ERROR("Cannot read common data\n");
+ return -1;
+ }
+ addr = (char *)addr + bsize;
+ total = bsize;
+ for (j = 0; j < count; j++) {
+ if (fs_read(file, addr, csize) < 0) {
+ ERROR("Cannot read custom data\n");
+ return -1;
+ }
+ addr = (char *)addr + csize;
+ memcpy(addr, ref, bsize);
+ addr = (char *)addr + bsize;
+ total += csize + bsize;
+ }
+ break;
+ case 0x4:
+ /* Interleave repeat bloc with zero */
+ if (fs_read(file, &csize, 1) < 0 ||
+ fs_read(file, &count, 1) < 0) {
+ ERROR("Cannot read repeat params\n");
+ return -1;
+ }
+ total = 0;
+ for (j = 0; j < count; j++) {
+ memset(addr, 0, bsize);
+ addr = (char *)addr + bsize;
+ if (fs_read(file, addr, csize) < 0) {
+ ERROR("Cannot read repeat data\n");
+ return -1;
+ }
+ addr = (char *)addr + csize;
+ total += csize + bsize;
+ }
+ memset(addr, 0, bsize);
+ addr = (char *)addr + bsize;
+ total += bsize;
+ break;
+ default:
+ ERROR("Unknown opcode\n");
+ return -1;
+ }
+ if (addr > last)
+ last = addr;
+ if (total >= size)
+ break;
+ size -= total;
+ }
+ break;
+ case PEF_SECTION_LOADER:
+ /* find entry point */
+ if (fs_read(file, &loader, sizeof(PEF_loader_t)) < 0) {
+ ERROR("Cannot read loader header\n");
+ return -1;
+ }
+ main_section = get_be32(&loader.main_section);
+ main_offset = get_be32(&loader.main_offset);
+ if (main_section >= nb_sections) {
+ ERROR("Invalid main section\n");
+ return -1;
+ }
+ break;
+ case PEF_SECTION_DEBUG:
+ case PEF_SECTION_EXCP:
+ case PEF_SECTION_TRACE:
+ break;
+ default:
+ return -2;
+ }
+ }
+ *dest = first;
+ *end = last;
+ if (main_section == -1) {
+ *entry = first;
+ } else {
+ *entry = (char *)sections[main_section] + main_offset;
+ }
+ free(sections);
+
+ return 0;
+}
diff --git a/src/libexec/prep.c b/src/libexec/prep.c
new file mode 100644
index 0000000..15b6ea6
--- /dev/null
+++ b/src/libexec/prep.c
@@ -0,0 +1,45 @@
+/*
+ * <prep.c>
+ *
+ * Open Hack'Ware BIOS PREP executable file loader
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "exec.h"
+
+/* PREP boot loader */
+int exec_load_prep (inode_t *file, unused void **dest,
+ unused void **entry, unused void **end,
+ unused uint32_t loffset)
+{
+ unsigned char buffer[512];
+
+ file_seek(file, loffset);
+ if (fs_read(file, buffer, 512) < 0) {
+ ERROR("Cannot load first bloc of file...\n");
+ return -2;
+ }
+ if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) {
+ DPRINTF("Not a PREP file\n");
+ return -2;
+ }
+
+ return -2;
+}
diff --git a/src/libexec/xcoff.c b/src/libexec/xcoff.c
new file mode 100644
index 0000000..a9a6da4
--- /dev/null
+++ b/src/libexec/xcoff.c
@@ -0,0 +1,216 @@
+/*
+ * <xcoff.c>
+ *
+ * Open Hack'Ware BIOS XCOFF executable file loader
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "exec.h"
+
+uint32_t fs_inode_get_size (inode_t *inode);
+
+/* XCOFF executable loader */
+typedef struct COFF_filehdr_t {
+ uint16_t f_magic; /* magic number */
+ uint16_t f_nscns; /* number of sections */
+ uint32_t f_timdat; /* time & date stamp */
+ uint32_t f_symptr; /* file pointer to symtab */
+ uint32_t f_nsyms; /* number of symtab entries */
+ uint16_t f_opthdr; /* sizeof(optional hdr) */
+ uint16_t f_flags; /* flags */
+} COFF_filehdr_t;
+
+/* IBM RS/6000 */
+#define U802WRMAGIC 0730 /* writeable text segments **chh** */
+#define U802ROMAGIC 0735 /* readonly sharable text segments */
+#define U802TOCMAGIC 0737 /* readonly text segments and TOC */
+
+/*
+ * Bits for f_flags:
+ *
+ * F_RELFLG relocation info stripped from file
+ * F_EXEC file is executable (i.e. no unresolved external
+ * references)
+ * F_LNNO line numbers stripped from file
+ * F_LSYMS local symbols stripped from file
+ * F_MINMAL this is a minimal object file (".m") output of fextract
+ * F_UPDATE this is a fully bound update file, output of ogen
+ * F_SWABD this file has had its bytes swabbed (in names)
+ * F_AR16WR this file has the byte ordering of an AR16WR
+ * (e.g. 11/70) machine
+ * F_AR32WR this file has the byte ordering of an AR32WR machine
+ * (e.g. vax and iNTEL 386)
+ * F_AR32W this file has the byte ordering of an AR32W machine
+ * (e.g. 3b,maxi)
+ * F_PATCH file contains "patch" list in optional header
+ * F_NODF (minimal file only) no decision functions for
+ * replaced functions
+ */
+
+#define COFF_F_RELFLG 0000001
+#define COFF_F_EXEC 0000002
+#define COFF_F_LNNO 0000004
+#define COFF_F_LSYMS 0000010
+#define COFF_F_MINMAL 0000020
+#define COFF_F_UPDATE 0000040
+#define COFF_F_SWABD 0000100
+#define COFF_F_AR16WR 0000200
+#define COFF_F_AR32WR 0000400
+#define COFF_F_AR32W 0001000
+#define COFF_F_PATCH 0002000
+#define COFF_F_NODF 0002000
+
+typedef struct COFF_aouthdr_t {
+ uint16_t magic; /* type of file */
+ uint16_t vstamp; /* version stamp */
+ uint32_t tsize; /* text size in bytes, padded to FW bdry */
+ uint32_t dsize; /* initialized data " " */
+ uint32_t bsize; /* uninitialized data " " */
+ uint32_t entry; /* entry pt. */
+ uint32_t text_start; /* base of text used for this file */
+ uint32_t data_start; /* base of data used for this file */
+ uint32_t o_toc; /* address of TOC */
+ uint16_t o_snentry; /* section number of entry point */
+ uint16_t o_sntext; /* section number of .text section */
+ uint16_t o_sndata; /* section number of .data section */
+ uint16_t o_sntoc; /* section number of TOC */
+ uint16_t o_snloader; /* section number of .loader section */
+ uint16_t o_snbss; /* section number of .bss section */
+ uint16_t o_algntext; /* .text alignment */
+ uint16_t o_algndata; /* .data alignment */
+ uint16_t o_modtype; /* module type (??) */
+ uint16_t o_cputype; /* cpu type */
+ uint32_t o_maxstack; /* max stack size (??) */
+ uint32_t o_maxdata; /* max data size (??) */
+ char o_resv2[12]; /* reserved */
+} COFF_aouthdr_t;
+
+#define AOUT_MAGIC 0x010b
+
+typedef struct COFF_scnhdr_t {
+ char s_name[8]; /* section name */
+ uint32_t s_paddr; /* physical address, aliased s_nlib */
+ uint32_t s_vaddr; /* virtual address */
+ uint32_t s_size; /* section size */
+ uint32_t s_scnptr; /* file ptr to raw data for section */
+ uint32_t s_relptr; /* file ptr to relocation */
+ uint32_t s_lnnoptr; /* file ptr to line numbers */
+ uint16_t s_nreloc; /* number of relocation entries */
+ uint16_t s_nlnno; /* number of line number entries */
+ uint32_t s_flags; /* flags */
+} COFF_scnhdr_t;
+
+int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end,
+ uint32_t loffset)
+{
+ COFF_filehdr_t fhdr;
+ COFF_aouthdr_t ahdr;
+ COFF_scnhdr_t shdr;
+ void *first, *last;
+ uint32_t offset;
+ int i;
+
+ file_seek(file, loffset);
+ if (fs_read(file, &fhdr, sizeof(COFF_filehdr_t)) < 0) {
+ ERROR("Cannot load first bloc of file...\n");
+ return -1;
+ }
+ if (fhdr.f_magic != U802WRMAGIC && fhdr.f_magic != U802ROMAGIC &&
+ fhdr.f_magic != U802TOCMAGIC && fhdr.f_magic != 0x01DF) {
+ DPRINTF("Not a XCOFF file %02x %08x\n", fhdr.f_magic,
+ *(uint32_t *)&fhdr.f_magic);
+ return -2;
+ }
+ if (fhdr.f_magic != 0x01DF && (fhdr.f_flags & COFF_F_EXEC) == 0) {
+ ERROR("Not an executable XCOFF file %02x\n", fhdr.f_flags);
+ return -2;
+ }
+ if (fhdr.f_opthdr != sizeof(COFF_aouthdr_t)) {
+ ERROR("AOUT optional error size missmactch in XCOFF file\n");
+ return -2;
+ }
+ if (fs_read(file, &ahdr, sizeof(COFF_aouthdr_t)) < 0) {
+ ERROR("Cannot load XCOFF AOUT header...\n");
+ return -1;
+ }
+ if (ahdr.magic != AOUT_MAGIC) {
+ ERROR("Invalid AOUT optional header\n");
+ return -2;
+ }
+#if 0 // XXX: buggy: this makes NetBSD fail to boot
+ if (fhdr.f_magic == 0x01DF) {
+ /* Load embedded file */
+ return _bootfile_load(file, dest, entry, end, loffset +
+ sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t) +
+ (fhdr.f_nscns * sizeof(COFF_scnhdr_t)),
+ -1);
+ }
+#endif
+ *entry = (void *)ahdr.entry + 0xC;
+ last = NULL;
+ first = last - 4;
+ offset = sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t);
+ DPRINTF("XCOFF file with %d sections entry:%p\n", fhdr.f_nscns, *entry);
+ for (i = 0; i < fhdr.f_nscns; i++) {
+ DPRINTF("Read next header (%0x)\n", offset);
+ file_seek(file, offset + loffset);
+ if (fs_read(file, &shdr, sizeof(COFF_scnhdr_t)) < 0) {
+ ERROR("Cannot load section header %d...\n", i);
+ return -1;
+ }
+ if (strcmp(shdr.s_name, ".text") == 0 ||
+ strcmp(shdr.s_name, ".data") == 0) {
+ if ((void *)shdr.s_vaddr < first)
+ first = (void *)shdr.s_vaddr;
+ if ((void *)shdr.s_vaddr > last)
+ last = (void *)shdr.s_vaddr;
+ DPRINTF("Load '%s' section from %0x %0x to %0x (%0x)\n",
+ shdr.s_name, offset, shdr.s_scnptr,
+ shdr.s_vaddr, shdr.s_size);
+#if 0
+ if (shdr.s_scnptr + shdr.s_size > fs_inode_get_size(file)) {
+ ERROR("Section %d data offset > file size\n", i);
+ return -1;
+ }
+#endif
+ file_seek(file, shdr.s_scnptr + loffset);
+ set_loadinfo((void *)first, last - first);
+ if (fs_read(file, (void *)shdr.s_vaddr, shdr.s_size) < 0) {
+ ERROR("Cannot load section %d...\n", i);
+ return -1;
+ }
+ } else if (strcmp(shdr.s_name, ".bss") == 0) {
+ if ((void *)shdr.s_vaddr < first)
+ first = (void *)shdr.s_vaddr;
+ if ((void *)shdr.s_vaddr > last)
+ last = (void *)shdr.s_vaddr;
+ DPRINTF("Erase '%s' section at %0x size: %0x\n",
+ shdr.s_name, shdr.s_vaddr, shdr.s_size);
+ memset((void *)shdr.s_vaddr, 0, shdr.s_size);
+ } else {
+ DPRINTF("Skip '%s' section\n", shdr.s_name);
+ }
+ offset += sizeof(COFF_scnhdr_t);
+ }
+ *dest = first;
+ *end = last;
+
+ return 0;
+}
diff --git a/src/libfs/core.c b/src/libfs/core.c
new file mode 100644
index 0000000..9743a64
--- /dev/null
+++ b/src/libfs/core.c
@@ -0,0 +1,562 @@
+/*
+ * <fs.c>
+ *
+ * Open Hack'Ware BIOS file systems management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "libfs.h"
+#undef FS_DPRINTF
+#define FS_DPRINTF(fmt, args...) do { } while (0)
+
+static int special_file_get_type (const unsigned char *name)
+{
+ int ret;
+
+ if (strcmp(name, "root") == 0)
+ ret = FILE_ROOT;
+ else if (strcmp(name, "boot") == 0)
+ ret = FILE_BOOT;
+ else if (strcmp(name, "bootdir") == 0)
+ ret = FILE_BOOTDIR;
+ else
+ ret = FILE_UNKNOWN;
+
+ return ret;
+}
+
+void fs_cache_add_inode (inode_t *parent, inode_t *inode)
+{
+ inode_t **cur;
+
+ if (parent == NULL || inode == NULL)
+ return;
+ FS_DPRINTF("Add inode '%s' to '%s' cache\n", inode->name, parent->name);
+ for (cur = &parent->child; *cur != NULL; cur = &((*cur)->next)) {
+ if (strcmp((*cur)->name, inode->name) == 0) {
+ return;
+ }
+ }
+ *cur = inode;
+}
+
+static inode_t *fs_cache_get_inode (inode_t *parent,
+ const unsigned char *name)
+{
+ inode_t *cur, *rec;
+ int dec;
+
+ FS_DPRINTF("Look for '%s' into '%s' cache\n", name, parent->name);
+ if (name == NULL || parent == NULL)
+ return NULL;
+ if (name[0] == '/' && name[1] == '\0')
+ return parent->fs->root;
+ if (is_special_file(name))
+ dec = strlen(FS_SPECIAL) + 2;
+ else
+ dec = 0;
+ for (cur = parent->child; cur != NULL; cur = cur->next) {
+ if (strcmp(cur->name + dec, name + dec) == 0) {
+ cur->refcount++;
+ for (rec = parent; rec != NULL; rec = rec->parent)
+ rec->refcount++;
+ break;
+ }
+ }
+ cur = NULL;
+
+ return cur;
+}
+
+static void fs_cache_put_inode (inode_t *inode)
+{
+ void (*put_inode)(inode_t *inode);
+ inode_t *cur, **upd;
+
+ if (inode != NULL && --inode->refcount == 0) {
+ if (inode->parent == NULL)
+ return;
+ fs_cache_put_inode(inode->parent);
+ upd = &inode->parent->child;
+ for (cur = *upd; cur != NULL; cur = cur->next) {
+ if (cur == inode) {
+ (*upd) = cur->next;
+ put_inode = inode->fs->fs_ops->put_inode;
+ (*put_inode)(cur);
+ FS_DPRINTF("Free inode '%s' from '%s' cache\n",
+ inode->name, inode->parent->name);
+ free(cur);
+ return;
+ }
+ upd = &cur;
+ }
+ FS_ERROR("didn't find inode in list !\n");
+ }
+}
+
+static inode_t *fs_get_inode (inode_t *parent, const unsigned char *name)
+{
+ inode_t *(*get_inode)(inode_t *parent, const unsigned char *name);
+ inode_t *cur;
+
+ if (parent == NULL) {
+ FS_ERROR("Invalide inode '%s' (NULL)\n", name);
+ return NULL;
+ } else {
+ if (fs_inode_get_type(parent) != INODE_TYPE_DIR) {
+ FS_ERROR("Try to recurse in a non-directory inode (%d)\n",
+ parent->flags);
+ return NULL;
+ }
+ }
+ if (is_special_file(name)) {
+ int type;
+ /* Special files */
+ FS_DPRINTF("look for special file '%s'\n",
+ name + strlen(FS_SPECIAL) + 2);
+ type = special_file_get_type(name + strlen(FS_SPECIAL) + 2);
+ if (type == FILE_UNKNOWN) {
+ FS_ERROR("Unknown special file '%s'\n",
+ name + strlen(FS_SPECIAL) + 2);
+ return NULL;
+ }
+ cur = (*parent->fs->fs_ops->get_special_inode)(parent->fs, type);
+ FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
+ parent->fs->bootfile, parent->fs->bootfile->name,
+ &parent->fs->bootfile,
+ parent->fs->bootdir, parent->fs->bootdir->name,
+ &parent->fs->bootdir);
+ switch (type) {
+ case FILE_ROOT:
+ parent->fs->root = cur;
+ cur->parent = NULL;
+ cur->fs = parent->fs;
+ cur->name = strdup("");
+ return cur;
+ case FILE_BOOT:
+ parent->fs->bootfile = cur;
+ break;
+ case FILE_BOOTDIR:
+ parent->fs->bootdir = cur;
+ break;
+ }
+#if 0
+ parent = cur->parent;
+#else
+ cur->fs = parent->fs;
+ return cur;
+#endif
+ } else {
+ FS_DPRINTF("look for file '%s' in %p '%s'\n", name, parent,
+ parent->name);
+ DPRINTF("look for file '%s' in %p '%s'\n", name, parent,
+ parent->name);
+ cur = fs_cache_get_inode(parent, name);
+ if (cur != NULL) {
+ FS_DPRINTF("found inode '%s' %p in cache\n", name, cur);
+ DPRINTF("found inode '%s' %p in cache\n", name, cur);
+ return cur;
+ }
+ get_inode = parent->fs->fs_ops->get_inode;
+ cur = (*get_inode)(parent, name);
+ cur->name = strdup(name);
+ }
+ if (cur != NULL) {
+ cur->parent = parent;
+ cur->fs = parent->fs;
+ fs_cache_add_inode(parent, cur);
+ FS_DPRINTF("Inode '%s' in '%s': %d blocs size %d %d\n",
+ name, parent->name, cur->nb_blocs, cur->size.bloc,
+ cur->size.offset);
+ DPRINTF("Inode '%s' in '%s': %d blocs size %d %d\n",
+ name, parent->name, cur->nb_blocs, cur->size.bloc,
+ cur->size.offset);
+ } else {
+ FS_ERROR("Inode '%s' not found in '%s'\n", name, parent->name);
+ }
+
+ return cur;
+}
+
+static inline void fs_put_inode (inode_t *inode)
+{
+ fs_cache_put_inode(inode);
+}
+
+static inode_t *_fs_walk (inode_t *parent, const unsigned char *name)
+{
+ unsigned char tmpname[MAXNAME_LEN], *sl;
+ inode_t *new, *subdir;
+
+ FS_DPRINTF("'%s' %p\n", name, parent);
+ DPRINTF("'%s' %p\n", name, parent);
+ for (; *name == '/'; name++)
+ continue;
+ DPRINTF("'%s' %p\n", name, parent);
+ strcpy(tmpname, name);
+ sl = strchr(tmpname, '/');
+ if (sl != NULL) {
+ *sl = '\0';
+ subdir = fs_get_inode(parent, tmpname);
+ if (subdir == NULL)
+ return NULL;
+ new = _fs_walk(subdir, sl + 1);
+ } else {
+ new = fs_get_inode(parent, tmpname);
+ }
+
+ return new;
+}
+
+static inode_t *fs_walk (inode_t *parent, const unsigned char *name)
+{
+ unsigned char tmpname[MAXNAME_LEN];
+ int len;
+
+ FS_DPRINTF("'%s' %p\n", name, parent);
+ DPRINTF("'%s' %p %p\n", name, parent, parent->fs->root);
+ len = strlen(name);
+ memcpy(tmpname, name, len + 1);
+ if (tmpname[len - 1] == '/')
+ tmpname[--len] = '\0';
+ if (parent == parent->fs->root && tmpname[0] == '\0')
+ return parent->fs->root;
+
+ return _fs_walk(parent, tmpname);
+}
+
+static unsigned char *fs_inode_get_path (inode_t *inode)
+{
+ unsigned char tmpname[MAXNAME_LEN], *pname;
+ int len;
+ inode_t *parent;
+
+ parent = inode->parent;
+ if (parent == NULL || (inode->name[0] == '/' && inode->name[1] == '\0')) {
+ FS_DPRINTF("Reached root node '/'\n");
+ return strdup("/");
+ }
+ FS_DPRINTF("Recurse to root '%s'...\n", inode->name);
+ pname = fs_inode_get_path(parent);
+ FS_DPRINTF("'%s' '%s'\n", pname, inode->name);
+ len = strlen(pname);
+ memcpy(tmpname, pname, len);
+ if (tmpname[len - 1] != '/')
+ tmpname[len++] = '/';
+ strcpy(tmpname + len, inode->name);
+ free(pname);
+ FS_DPRINTF(" => '%s'\n", tmpname);
+
+ return strdup(tmpname);
+}
+
+static inline uint32_t fs_map_bloc (inode_t *inode, uint32_t bloc)
+{
+ FS_DPRINTF("%s: inode %p bloc %d %p %p %p\n", __func__, inode, bloc,
+ inode->fs, inode->fs->fs_ops, inode->fs->fs_ops->map_bloc);
+ return (*inode->fs->fs_ops->map_bloc)(inode, bloc);
+}
+
+fs_t *fs_probe (part_t *part, int set_raw)
+{
+ fs_t *new;
+ inode_t fake_inode;
+ fs_ops_t *fs_ops = NULL;
+ unsigned char *name = NULL;
+ void *private = NULL;
+ uint32_t size = 0;
+ int type = FS_TYPE_UNKNOWN;
+
+ FS_DPRINTF("\n");
+ if (set_raw == 2) {
+ DPRINTF("Check raw only\n");
+ goto raw_only;
+ }
+ DPRINTF("Probe ext2\n");
+ type = fs_ext2_probe(part, &size, &fs_ops, &name, &private);
+ if (type == FS_TYPE_UNKNOWN) {
+ DPRINTF("Probe isofs\n");
+ type = fs_isofs_probe(part, &size, &fs_ops, &name, &private);
+ if (type == FS_TYPE_UNKNOWN) {
+ DPRINTF("Probe HFS\n");
+ type = fs_hfs_probe(part, &size, &fs_ops, &name, &private);
+ if (set_raw) {
+ DPRINTF("Probe raw\n");
+ raw_only:
+ type = fs_raw_probe(part, &size, &fs_ops, &name, &private);
+ }
+ if (type == FS_TYPE_UNKNOWN) {
+ FS_ERROR("FS not identified\n");
+ return NULL;
+ }
+ }
+ }
+ if (fs_ops == NULL || size == 0) {
+ FS_ERROR("Missing param: %p %d\n", fs_ops, size);
+ return NULL;
+ }
+ new = malloc(sizeof(fs_t));
+ if (new == NULL)
+ return NULL;
+ new->type = type;
+ new->part = part;
+ new->size = size;
+ new->fs_ops = fs_ops;
+ new->name = name;
+ new->private = private;
+ /* Get root inode */
+ memset(&fake_inode, 0, sizeof(inode_t));
+ fake_inode.name = "fake_root";
+ fake_inode.fs = new;
+ fake_inode.refcount = 1;
+ fs_get_inode(&fake_inode, "\0" FS_SPECIAL "\0root");
+ if (new->root == NULL) {
+ FS_ERROR("Didn't find root inode\n");
+ free(new);
+ return NULL;
+ }
+ FS_DPRINTF("fs: %p root: %p root fs: %p\n", new, new->root, new->root->fs);
+ FS_DPRINTF("OK\n");
+
+ return new;
+}
+
+dir_t *fs_opendir (fs_t *fs, const unsigned char *name)
+{
+ inode_t *inode;
+ dir_t *new;
+
+ FS_DPRINTF("'%s'\n", name);
+ inode = fs_walk(fs->root, name);
+ if (inode == NULL)
+ return NULL;
+ new = malloc(sizeof(dir_t));
+ new->inode = inode;
+
+ return new;
+}
+
+dirent_t *fs_readdir (dir_t *dir)
+{
+ void (*put_inode)(inode_t *inode);
+ inode_t *inode;
+
+ inode = fs_get_inode(dir->inode, NULL);
+ if (inode == NULL)
+ return NULL;
+ if (dir->cur == NULL) {
+ dir->cur = malloc(sizeof(dirent_t));
+ dir->cur->dir = dir;
+ } else {
+ put_inode = dir->inode->fs->fs_ops->put_inode;
+ (*put_inode)(dir->cur->inode);
+ }
+ dir->cur->inode = inode;
+ dir->cur->dname = inode->name;
+
+ return dir->cur;
+}
+
+unsigned char *fs_get_path (dirent_t *dirent)
+{
+ return fs_inode_get_path(dirent->inode);
+}
+
+void fs_closedir (dir_t *dir)
+{
+ void (*put_inode)(inode_t *inode);
+
+ if (dir->cur != NULL) {
+ put_inode = dir->inode->fs->fs_ops->put_inode;
+ (*put_inode)(dir->cur->inode);
+ free(dir->cur);
+ }
+ free(dir);
+}
+
+inode_t *fs_open (fs_t *fs, const unsigned char *name)
+{
+ inode_t *inode;
+
+ FS_DPRINTF("'%s'\n", name);
+ inode = fs_walk(fs->root, name);
+ if (inode != NULL)
+ fs_seek(inode, 0, 0);
+
+ return inode;
+}
+
+int fs_seek (inode_t *inode, uint32_t bloc, uint32_t pos)
+{
+ if (inode == NULL || inode->fs == NULL) {
+ ERROR("%s: no inode / fs ! %p %p\n", __func__, inode,
+ inode == NULL ? NULL : inode->fs);
+ return -1;
+ }
+ FS_DPRINTF("%08x %08x\n", bloc, pos);
+ if (part_seek(inode->fs->part, fs_map_bloc(inode, bloc), pos) == -1)
+ return -1;
+ inode->vbloc = bloc;
+ inode->vpos = pos;
+
+ return 0;
+}
+
+int fs_read (inode_t *inode, void *buffer, int len)
+{
+ uint32_t bsize, total;
+ int done, tmp;
+
+ bsize = part_blocsize(inode->fs->part);
+ total = 0;
+ if (fs_seek(inode, inode->vbloc, inode->vpos) < 0)
+ return -1;
+ for (; len != 0; len -= done) {
+ tmp = bsize - inode->vpos;
+ if (len < tmp)
+ tmp = len;
+ done = part_read(inode->fs->part, buffer, tmp);
+ if (done < 0)
+ return -1;
+ inode->vpos += done;
+ if (inode->vpos >= bsize) {
+ inode->vbloc++;
+ inode->vpos -= bsize;
+ }
+ buffer += done;
+ total += done;
+ }
+
+ return total;
+}
+
+int fs_write (inode_t *inode, const void *buffer, unused int len)
+{
+ uint32_t bsize, total;
+ int done, tmp;
+
+ bsize = part_blocsize(inode->fs->part);
+ total = 0;
+ for (; len != 0; len -= done) {
+ tmp = bsize - inode->vpos;
+ if (len < tmp)
+ tmp = len;
+ done = part_write(inode->fs->part, buffer, tmp);
+ if (done < 0)
+ return -1;
+ inode->vpos += done;
+ if (inode->vpos >= bsize) {
+ inode->vbloc++;
+ inode->vpos -= bsize;
+ if (fs_seek(inode, inode->vbloc, inode->vpos) < 0)
+ return -1;
+ }
+ buffer += done;
+ total += done;
+ }
+
+ return total;
+}
+
+void fs_close (inode_t *inode)
+{
+ fs_put_inode(inode);
+}
+
+uint32_t fs_inode_get_type (inode_t *inode)
+{
+ return inode->flags & INODE_TYPE_MASK;
+}
+
+uint32_t fs_inode_get_flags (inode_t *inode)
+{
+ return inode->flags & INODE_FLAG_MASK;
+}
+
+uint32_t fs_inode_get_size (inode_t *inode)
+{
+ DPRINTF("%s: (%d * %d) + %d\n", __func__, inode->size.bloc,
+ part_blocsize(inode->fs->part), inode->size.offset);
+ return (inode->size.bloc * part_blocsize(inode->fs->part)) +
+ inode->size.offset;
+}
+
+part_t *fs_part (fs_t *fs)
+{
+ return fs->part;
+}
+
+uint32_t fs_get_type (fs_t *fs)
+{
+ return fs->type;
+}
+
+part_t *fs_inode_get_part (inode_t *inode)
+{
+ return inode->fs->part;
+}
+
+inode_t *fs_get_bootdir (fs_t *fs)
+{
+ FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
+ if (fs->bootdir == NULL) {
+ fs->bootdir = fs_get_inode(fs->root, "\0" FS_SPECIAL "\0bootdir");
+ }
+ FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
+ FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
+ fs->bootfile, fs->bootfile->name, &fs->bootfile,
+ fs->bootdir, fs->bootdir->name, &fs->bootdir);
+
+ return fs->bootdir;
+}
+unsigned char *fs_get_boot_dirname (fs_t *fs)
+{
+ if (fs->bootdir == NULL) {
+ fs_get_bootdir(fs);
+ if (fs->bootdir == NULL)
+ return NULL;
+ }
+ FS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n",
+ fs->bootfile, fs->bootfile->name,
+ fs->bootdir, fs->bootdir->name);
+
+ return fs_inode_get_path(fs->bootdir);
+}
+
+inode_t *fs_get_bootfile (fs_t *fs)
+{
+ FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
+ FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
+ fs->bootfile, fs->bootfile->name, &fs->bootfile,
+ fs->bootdir, fs->bootdir->name, &fs->bootdir);
+ if (fs->bootfile == NULL) {
+ if (fs->bootdir == NULL)
+ fs_get_bootdir(fs);
+ if (fs->bootdir == NULL)
+ return NULL;
+ fs->bootfile = fs_get_inode(fs->bootdir, "\0" FS_SPECIAL "\0boot");
+ }
+ FS_DPRINTF("fs: %p root: %p root fs: %p\n", fs, fs->root, fs->root->fs);
+ FS_DPRINTF("boot file: %p '%s' %p boot dir: %p '%s' %p\n",
+ fs->bootfile, fs->bootfile->name, &fs->bootfile,
+ fs->bootdir, fs->bootdir->name, &fs->bootdir);
+
+ return fs->bootfile;
+}
diff --git a/src/libfs/ext2.c b/src/libfs/ext2.c
new file mode 100644
index 0000000..122f408
--- /dev/null
+++ b/src/libfs/ext2.c
@@ -0,0 +1,32 @@
+/*
+ * <ext2.c>
+ *
+ * Open Hack'Ware BIOS ext2 file system management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include "bios.h"
+#include "libfs.h"
+
+/* ext2 filesystem */
+int fs_ext2_probe (unused part_t *part, unused uint32_t *size,
+ unused fs_ops_t **fs_ops, unused unsigned char **name,
+ unused void **private)
+{
+ return -1;
+}
diff --git a/src/libfs/hfs.c b/src/libfs/hfs.c
new file mode 100644
index 0000000..b2420eb
--- /dev/null
+++ b/src/libfs/hfs.c
@@ -0,0 +1,2007 @@
+/*
+ * <hfs.c>
+ *
+ * Open Hack'Ware BIOS HFS file system management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ *
+ * Major rework and debug by Thayne Harbaugh <thayne@realmsys.com>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "libfs.h"
+
+//#define DEBUG_HFS 1
+
+/* HFS / HFSplus */
+#if defined (DEBUG_HFS)
+#define HFS_DPRINTF(fmt, args...) \
+do { dprintf("%s: " fmt, __func__ , ##args); } while (0)
+#else
+#define HFS_DPRINTF(fmt, args...) \
+do { } while (0)
+#endif
+#define HFS_ERROR(fmt, args...) \
+do { dprintf("HFS ERROR in %s: " fmt, __func__ , ##args); } while (0)
+
+/* HFS/HFS+ common definitions */
+#define HFS_SECTOR_SIZE 512
+#define HFS_VOLHEAD_SECTOR 2
+#define HFS_NODE_SIZE 0x200
+
+/* HFS signature */
+#define HFS_VOLHEAD_SIG 0x4244
+/* HFS+ signature */
+#define HFSPLUS_VOLHEAD_SIG 0x482b
+
+/* HFS+ filesystem support */
+/* Files CNID */
+enum {
+ HFS_ROOT_PARENT = 1, /* Parent of root folder */
+ HFS_ROOT_FOLDER = 2, /* root folder */
+ HFS_EXTENT_FILE = 3, /* file extents file */
+ HFS_CATALOG_FILE = 4, /* catalog file */
+ HFS_BBLOCS_FILE = 5, /* badblocks file */
+ HFS_ALLOC_FILE = 6, /* allocation file (HFSplus) */
+ HFS_STARTUP_FILE = 7, /* startup file (HFSplus) */
+ HFS_ATTR_FILE = 8, /* attribute file (HFSplus) */
+ HFS_BEXTENT_FILE = 15, /* file extents temporary file */
+ HFS_FIRST_USERID = 16,
+};
+
+typedef uint32_t HFS_cnid_t;
+
+static inline HFS_cnid_t HFS_get_cnid (HFS_cnid_t *cnidp)
+{
+ return get_be32(cnidp);
+}
+
+typedef uint16_t HFSP_unichr_t;
+
+static inline HFSP_unichr_t HFSP_get_unichr (HFSP_unichr_t *chrp)
+{
+ return get_be16(chrp);
+}
+
+/* A single contiguous area of a file */
+typedef struct HFSP_extent_t HFSP_extent_t;
+struct HFSP_extent_t {
+ uint32_t start_block;
+ uint32_t block_count;
+} __attribute__ ((packed));
+
+static inline HFSP_extent_t *HFSP_get_extent (HFSP_extent_t *extp)
+{
+ extp->start_block = get_be32(&extp->start_block);
+ extp->block_count = get_be32(&extp->block_count);
+
+ return extp;
+}
+
+/* Information for a "Fork" in a file */
+typedef struct HFSP_fork_t HFSP_fork_t;
+struct HFSP_fork_t {
+ /* 0x00 */
+ uint64_t total_size;
+ uint32_t clump_size;
+ uint32_t total_blocks;
+ /* 0x10 */
+ HFSP_extent_t extents[8];
+ /* 0x50 */
+} __attribute__ ((packed));
+
+static inline HFSP_fork_t *HFSP_get_fork (HFSP_fork_t *forkp)
+{
+ int i;
+
+ forkp->total_size = get_be64(&forkp->total_size);
+ forkp->clump_size = get_be32(&forkp->clump_size);
+ forkp->total_blocks = get_be32(&forkp->total_blocks);
+ for (i = 0; i < 8; i++) {
+ HFSP_get_extent(&forkp->extents[i]);
+ }
+
+ return forkp;
+}
+
+/* HFS+ Volume Header */
+typedef struct HFSP_vh_t HFSP_vh_t;
+struct HFSP_vh_t {
+ /* 0x000 */
+ uint16_t signature;
+ uint16_t version;
+ uint32_t attributes;
+ uint32_t last_mount_vers;
+ uint32_t reserved;
+
+ /* 0x010 */
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ uint32_t checked_date;
+
+ /* 0x020 */
+ uint32_t file_count;
+ uint32_t folder_count;
+ uint32_t blocksize;
+ uint32_t total_blocks;
+
+ /* 0x030 */
+ uint32_t free_blocks;
+ uint32_t next_alloc;
+ uint32_t rsrc_clump_sz;
+ uint32_t data_clump_sz;
+
+ /* 0x040 */
+ HFS_cnid_t next_cnid;
+ uint32_t write_count;
+ uint64_t encodings_bmp;
+
+ /* 0x050 */
+ uint32_t finder_info[8];
+
+ /* 0x070 */
+ HFSP_fork_t alloc_file;
+ /* 0x0C0 */
+ HFSP_fork_t ext_file;
+ /* 0x110 */
+ HFSP_fork_t cat_file;
+ /* 0x160 */
+ HFSP_fork_t attr_file;
+ /* 0x1B0 */
+ HFSP_fork_t start_file;
+ /* 0x1F0 */
+ uint8_t pad[16];
+} __attribute__ ((packed));
+
+static HFSP_vh_t *HFSP_read_volhead (part_t *part, uint32_t bloc,
+ uint32_t offset, void *buffer, int size)
+{
+ HFSP_vh_t *vh;
+ int i;
+
+ if (part_seek(part, bloc, offset) == -1)
+ return NULL;
+ if (part_read(part, buffer, size) < 0)
+ return NULL;
+ vh = buffer;
+ vh->signature = get_be16(&vh->signature);
+ vh->version = get_be16(&vh->version);
+ vh->attributes = get_be32(&vh->attributes);
+ vh->last_mount_vers = get_be32(&vh->last_mount_vers);
+ vh->create_date = get_be32(&vh->create_date);
+ vh->modify_date = get_be32(&vh->modify_date);
+ vh->backup_date = get_be32(&vh->backup_date);
+ vh->checked_date = get_be32(&vh->checked_date);
+ vh->file_count = get_be32(&vh->file_count);
+ vh->folder_count = get_be32(&vh->folder_count);
+ vh->blocksize = get_be32(&vh->blocksize);
+ vh->total_blocks = get_be32(&vh->total_blocks);
+ vh->free_blocks = get_be32(&vh->free_blocks);
+ vh->next_alloc = get_be32(&vh->next_alloc);
+ vh->rsrc_clump_sz = get_be32(&vh->rsrc_clump_sz);
+ vh->data_clump_sz = get_be32(&vh->data_clump_sz);
+ HFS_get_cnid(&vh->next_cnid);
+ vh->write_count = get_be32(&vh->write_count);
+ vh->encodings_bmp = get_be32(&vh->encodings_bmp);
+ for (i = 0; i < 8; i++) {
+ vh->finder_info[i] = get_be32(&vh->finder_info[i]);
+ }
+ HFSP_get_fork(&vh->alloc_file);
+ HFSP_get_fork(&vh->ext_file);
+ HFSP_get_fork(&vh->cat_file);
+ HFSP_get_fork(&vh->attr_file);
+ HFSP_get_fork(&vh->start_file);
+
+ return vh;
+}
+
+/* HFS support */
+/* A single contiguous area of a file */
+typedef struct HFS_extent_t HFS_extent_t;
+struct HFS_extent_t {
+ uint16_t start_block;
+ uint16_t block_count;
+} __attribute__ ((packed));
+
+static inline HFS_extent_t *HFS_get_extent (HFS_extent_t *extp)
+{
+ extp->start_block = get_be16(&extp->start_block);
+ extp->block_count = get_be16(&extp->block_count);
+
+ return extp;
+}
+
+/* HFS Volume Header */
+typedef struct HFS_vh_t HFS_vh_t;
+struct HFS_vh_t {
+ /* 0x000 */
+ uint16_t signature;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint16_t attributes;
+ uint16_t root_file_count;
+ uint16_t bitmap_start;
+
+ /* 0x010 */
+ uint16_t alloc_ptr;
+ uint16_t alloc_blocs;
+ uint32_t alloc_size;
+
+ /* 0x018 */
+ uint32_t clump_size;
+ uint16_t alloc_start;
+ HFS_cnid_t next_cnid;
+ uint16_t free_blocs;
+
+ /* 0x024 */
+ uint8_t label[28];
+
+ /* 0x040 */
+ uint32_t backup_tmsp;
+ uint16_t backup_seq;
+ uint32_t write_count;
+
+ /* 0x04A */
+ uint32_t ext_clump_size;
+ /* 0x04E */
+ uint32_t cat_clump_size;
+
+ /* 0x052 */
+ uint16_t root_dir_cnt;
+ /* 0x054 */
+ uint32_t file_cnt;
+ uint32_t dir_cnt;
+ /* 0x05C */
+ uint32_t finder_info[8];
+
+ /* 0x07C */
+ uint16_t embed_sig;
+ HFS_extent_t embed_ext;
+
+ /* 0x082 */
+ uint32_t ext_size;
+ HFS_extent_t ext_rec[3];
+
+ /* 0x092 */
+ uint32_t cat_size;
+ HFS_extent_t cat_rec[3];
+
+ /* 0x0A2 */
+} __attribute__(( __packed__ ));
+
+static HFS_vh_t *HFS_read_volhead (part_t *part, uint32_t bloc,
+ uint32_t offset, void *buffer, int size)
+{
+ HFS_vh_t *vh;
+ int i;
+
+ if (part_seek(part, bloc, offset) == -1)
+ return NULL;
+ if (part_read(part, buffer, size) < 0)
+ return NULL;
+ vh = buffer;
+ vh->signature = get_be16(&vh->signature);
+ vh->create_date = get_be32(&vh->create_date);
+ vh->modify_date = get_be32(&vh->modify_date);
+ vh->attributes = get_be16(&vh->attributes);
+ vh->root_file_count = get_be16(&vh->root_file_count);
+ vh->bitmap_start = get_be16(&vh->bitmap_start);
+ vh->alloc_ptr = get_be16(&vh->alloc_ptr);
+ vh->alloc_blocs = get_be16(&vh->alloc_blocs);
+ vh->alloc_size = get_be32(&vh->alloc_size);
+ vh->clump_size = get_be32(&vh->clump_size);
+ vh->alloc_start = get_be16(&vh->alloc_start);
+ HFS_get_cnid(&vh->next_cnid);
+ vh->free_blocs = get_be16(&vh->free_blocs);
+ vh->backup_tmsp = get_be32(&vh->backup_tmsp);
+ vh->backup_seq = get_be16(&vh->backup_seq);
+ vh->write_count = get_be32(&vh->write_count);
+ vh->ext_clump_size = get_be32(&vh->ext_clump_size);
+ vh->cat_clump_size = get_be32(&vh->cat_clump_size);
+ vh->root_dir_cnt = get_be16(&vh->root_dir_cnt);
+ vh->file_cnt = get_be32(&vh->file_cnt);
+ vh->dir_cnt = get_be32(&vh->dir_cnt);
+ for (i = 0; i < 8; i++) {
+ vh->finder_info[i] = get_be32(&vh->finder_info[i]);
+ }
+ vh->embed_sig = get_be16(&vh->embed_sig);
+ HFS_get_extent(&vh->embed_ext);
+ vh->ext_size = get_be16(&vh->ext_size);
+ for (i = 0; i < 3; i++) {
+ HFS_get_extent(&vh->ext_rec[i]);
+ }
+ vh->cat_size = get_be16(&vh->cat_size);
+ for (i = 0; i < 3; i++) {
+ HFS_get_extent(&vh->cat_rec[i]);
+ }
+
+ return vh;
+}
+
+enum {
+ HFS_NODE_LEAF = 0xFF,
+ HFS_NODE_IDX = 0x00,
+ HFS_NODE_HEAD = 0x01,
+ HFS_NODE_MAP = 0x02,
+};
+
+/* HFS B-tree structures */
+typedef struct HFS_bnode_t HFS_bnode_t;
+struct HFS_bnode_t {
+ uint32_t next;
+ uint32_t prev;
+ uint8_t type;
+ uint8_t height;
+ uint16_t nrecs;
+ uint16_t pad;
+} __attribute__ ((packed));
+
+static HFS_bnode_t *HFS_read_Hnode (part_t *part, uint32_t bloc,
+ uint32_t offset, void *buffer, int nsize)
+{
+ HFS_bnode_t *Hnode;
+
+ if (part_seek(part, bloc, offset) == -1) {
+ HFS_DPRINTF("seek failed\n");
+ return NULL;
+ }
+ if (part_read(part, buffer, nsize) < 0) {
+ HFS_DPRINTF("read failed\n");
+ return NULL;
+ }
+ Hnode = (void *)buffer;
+ Hnode->next = get_be32(&Hnode->next);
+ Hnode->prev = get_be32(&Hnode->prev);
+ Hnode->nrecs = get_be16(&Hnode->nrecs);
+
+ return Hnode;
+}
+
+typedef struct HFS_headrec_t HFS_headrec_t;
+struct HFS_headrec_t {
+ /* 0x00 */
+ uint16_t depth;
+ uint32_t rootnode;
+ /* 0x06 */
+ uint32_t nbleaves;
+ uint32_t firstleaf;
+ /* 0x0E */
+ uint32_t lastleaf;
+ uint16_t nodesize;
+ /* 0x14 */
+ uint16_t maxkeylen;
+ uint32_t nbnodes;
+ /* 0x18 */
+ uint32_t freenodes;
+ uint16_t pad0;
+ /* 0x1E */
+ uint32_t clump_size;
+ uint8_t type;
+ uint8_t pad1;
+ /* 0x24 */
+ uint32_t attr;
+ /* 0x28 */
+ uint32_t pad2[16];
+ /* 0x68 */
+} __attribute__ ((packed));
+
+static HFS_headrec_t *HFS_get_headrec (void *pos)
+{
+ HFS_headrec_t *head = pos;
+
+ head->depth = get_be16(&head->depth);
+ head->rootnode = get_be32(&head->rootnode);
+ head->nbleaves = get_be32(&head->nbleaves);
+ head->firstleaf = get_be32(&head->firstleaf);
+ head->lastleaf = get_be32(&head->lastleaf);
+ head->maxkeylen = get_be16(&head->maxkeylen);
+ head->nbnodes = get_be32(&head->nbnodes);
+ head->freenodes = get_be32(&head->freenodes);
+ head->clump_size = get_be32(&head->clump_size);
+ head->attr = get_be32(&head->attr);
+
+ return head;
+}
+
+typedef struct HFS_catkey_t HFS_catkey_t;
+struct HFS_catkey_t {
+ uint8_t len;
+ uint8_t pad;
+ HFS_cnid_t pID;
+ uint8_t nlen;
+ unsigned char name[0x1F];
+} __attribute__ ((packed));
+
+typedef struct HFSP_catkey_t HFSP_catkey_t;
+struct HFSP_catkey_t {
+ uint16_t len;
+ HFS_cnid_t pID;
+ uint16_t nlen;
+ HFSP_unichr_t uniname[255];
+} __attribute__ ((packed));
+
+enum {
+ HFS_CAT_FOLDER = 0x0100,
+ HFS_CAT_FILE = 0x0200,
+ HFS_CAT_FOLDTH = 0x0300,
+ HFS_CAT_FILETH = 0x0400,
+ HFSP_CAT_FOLDER = 0x0001,
+ HFSP_CAT_FILE = 0x0002,
+ HFSP_CAT_FOLDTH = 0x0003,
+ HFSP_CAT_FILETH = 0x0004,
+};
+
+typedef struct HFS_win_t HFS_win_t;
+struct HFS_win_t {
+ uint16_t top;
+ uint16_t left;
+ uint16_t bot;
+ uint16_t right;
+} __attribute__ ((packed));
+
+typedef struct HFS_pos_t HFS_pos_t;
+struct HFS_pos_t {
+ uint16_t y;
+ uint16_t x;
+} __attribute__ ((packed));
+
+typedef struct HFS_fdir_info_t HFS_fdir_info_t;
+struct HFS_fdir_info_t {
+ HFS_win_t win;
+ uint16_t flags;
+ HFS_pos_t pos;
+ uint16_t pad;
+} __attribute__ ((packed));
+
+typedef struct HFS_file_info_t HFS_file_info_t;
+struct HFS_file_info_t {
+ uint32_t ftype;
+ uint32_t owner;
+ uint16_t flags;
+ HFS_pos_t pos;
+ uint16_t pad;
+} __attribute__ ((packed));
+
+typedef struct HFSP_BSD_info_t HFSP_BSD_info_t;
+struct HFSP_BSD_info_t {
+ uint32_t owner;
+ uint32_t group;
+ uint8_t aflags;
+ uint8_t oflags;
+ uint16_t mode;
+ union {
+ uint32_t inum;
+ uint32_t lcount;
+ uint32_t device;
+ } u;
+} __attribute__ ((packed));
+
+typedef struct HFS_fold_t HFS_fold_t;
+struct HFS_fold_t {
+ uint16_t type;
+ uint16_t flags;
+ uint16_t valence;
+ HFS_cnid_t ID;
+ uint32_t created;
+ uint32_t modifd;
+ uint32_t backupd;
+ HFS_fdir_info_t finder_dir;
+ uint8_t finder_pad[16];
+ uint32_t pad[4];
+} __attribute__ ((packed));
+
+typedef struct HFSP_fold_t HFSP_fold_t;
+struct HFSP_fold_t {
+ uint16_t type;
+ uint16_t flags;
+ uint32_t valence;
+ HFS_cnid_t ID;
+ uint32_t created;
+ uint32_t modifd;
+ uint32_t attrd;
+ uint32_t accessd;
+ uint32_t attrmd;
+ HFSP_BSD_info_t BSD_infos;
+ HFS_fdir_info_t finder_dir;
+ uint8_t finder_pad[16];
+ uint32_t encoding;
+ uint32_t pad;
+} __attribute__ ((packed));
+
+typedef struct HFS_file_t HFS_file_t;
+struct HFS_file_t {
+ /* 0x00 */
+ uint16_t type;
+ uint8_t flags;
+ uint8_t ftype;
+ /* 0x04 */
+ HFS_file_info_t finder_file;
+ /* 0x14 */
+ HFS_cnid_t ID;
+ /* 0x18 */
+ uint16_t dstart;
+ uint32_t dlsize;
+ uint32_t dpsize;
+ uint16_t rstart;
+ /* 0x24 */
+ uint32_t rlsize;
+ uint32_t rpsize;
+ /* 0x2C */
+ uint32_t created;
+ /* 0x30 */
+ uint32_t modifd;
+ uint32_t backupd;
+ /* 0x38 */
+ uint8_t finder_pad[16];
+ /* 0x48 */
+ uint16_t clump_size;
+ /* 0x4C */
+ HFS_extent_t extents[3];
+ /* 0x54 */
+} __attribute__ ((packed));
+
+typedef struct HFSP_file_t HFSP_file_t;
+struct HFSP_file_t {
+ /* 0x00 */
+ uint16_t type;
+ uint16_t flags;
+ uint32_t pad;
+ /* 0x08 */
+ HFS_cnid_t ID;
+ uint32_t created;
+ /* 0x10 */
+ uint32_t modifd;
+ uint32_t attrd;
+ uint32_t accessd;
+ uint32_t backupd;
+ /* 0x20 */
+ HFSP_BSD_info_t BSD_infos;
+ /* 0x30 */
+ HFS_file_info_t finder_file;
+ /* 0x40 */
+ uint8_t finder_pad[16];
+ /* 0x50 */
+ uint32_t encoding;
+ uint32_t pad1[3];
+ HFSP_fork_t data;
+ HFSP_fork_t ressources;
+} __attribute__ ((packed));
+
+typedef struct HFS_thread_t HFS_thread_t;
+struct HFS_thread_t {
+ uint16_t type;
+ uint32_t pad[2];
+ HFS_cnid_t pid;
+ uint8_t pad0;
+ unsigned char name[32];
+} __attribute__ ((packed));
+
+typedef struct HFSP_thread_t HFSP_thread_t;
+struct HFSP_thread_t {
+ uint16_t type;
+ uint16_t pad;
+ HFS_cnid_t pid;
+ uint16_t nlen;
+ HFSP_unichr_t uniname[255];
+} __attribute__ ((packed));
+
+/* in memory structures */
+typedef struct hfs_vol_t hfs_vol_t;
+typedef struct hfs_btree_t hfs_btree_t;
+typedef struct hfs_rec_t hfs_rec_t;
+
+/* Volume/file structures */
+typedef struct hfs_extent_t {
+ uint32_t start;
+ uint32_t count;
+} hfs_extent_t;
+
+typedef struct hfs_fork_t {
+ hfs_vol_t *volume;
+ uint32_t nb_blocs;
+ hfs_extent_t extents[8];
+ hfs_rec_t *catrec;
+ hfs_rec_t *extrec;
+} hfs_fork_t;
+
+struct hfs_vol_t {
+ part_t *part;
+ int type;
+ HFS_cnid_t boot_id;
+ uint32_t embed_offset;
+ uint32_t start_offset;
+ uint32_t bsize;
+ hfs_fork_t alloc_file;
+ hfs_fork_t cat_file;
+ hfs_fork_t ext_file;
+ hfs_fork_t *boot_file;
+ hfs_btree_t *cat_tree;
+ hfs_btree_t *ext_tree;
+};
+
+/* Btree structures */
+/* Btree node */
+typedef struct hfs_bnode_t {
+ hfs_btree_t *tree;
+ uint32_t prev;
+ uint32_t next;
+ int type;
+ uint32_t nrecs;
+ hfs_rec_t *recs;
+} hfs_bnode_t;
+
+/* Cached Btree node */
+typedef struct hfs_cbnode_t hfs_cbnode_t;
+struct hfs_cbnode_t {
+ uint32_t location;
+ hfs_cbnode_t *next;
+ hfs_bnode_t bnode;
+};
+
+/* Bnode records */
+enum {
+ RECORD_HEAD = 0,
+ RECORD_IDX,
+ RECORD_CAT,
+ RECORD_EXT,
+};
+
+/* Header record */
+typedef struct hfs_headrec_t {
+ uint32_t rootnode;
+ uint32_t firstleaf;
+ uint32_t lastleaf;
+ uint32_t nodesize;
+} hfs_headrec_t;
+
+/* Index record */
+typedef struct hfs_idxrec_t {
+ HFS_cnid_t pid;
+ HFS_cnid_t uid;
+ unsigned char name[0x20];
+} hfs_idxrec_t;
+
+/* File extent records */
+/* TODO */
+typedef struct hfs_extrec_t {
+ HFS_cnid_t ID;
+} hfs_extrec_t;
+
+/* Catalog records */
+typedef struct hfs_catrec_t {
+ HFS_cnid_t ID;
+ HFS_cnid_t pid;
+ int type;
+ unsigned char name[0x20];
+ unsigned char finfo[9];
+ hfs_fork_t fork;
+} hfs_catrec_t;
+
+/* Generic record */
+struct hfs_rec_t {
+ hfs_bnode_t *node;
+ int type;
+ int num;
+ union {
+ hfs_headrec_t headrec;
+ hfs_idxrec_t idxrec;
+ hfs_catrec_t catrec;
+ hfs_extrec_t extrec;
+ } u;
+};
+
+struct hfs_btree_t {
+ hfs_fork_t *file;
+ hfs_cbnode_t *cache;
+ hfs_rec_t *head_rec;
+ hfs_bnode_t *root_node;
+ hfs_rec_t *root_catrec;
+ hfs_rec_t *root_extrec;
+ uint32_t nodesize;
+ unsigned char *buf;
+ int type;
+ int (*compare)(int type, HFS_cnid_t cnid,
+ const void *more, hfs_rec_t *rec, int rectype);
+};
+
+/* Unicode to ISO-8859-15, stolen from Linux nls */
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
+ 0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0x00, 0xb9, 0xba, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0xbc, 0xbd, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0xa6, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0xbe, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb8, 0x00, /* 0x78-0x7f */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static int uni2char (uint16_t uni, unsigned char *out)
+{
+ unsigned char *uni2charset;
+ unsigned char cl = uni & 0x00ff;
+ unsigned char ch = (uni & 0xff00) >> 8;
+
+ uni2charset = page_uni2charset[ch];
+ if (uni2charset && uni2charset[cl])
+ *out = uni2charset[cl];
+ else
+ return -1;
+
+ return 0;
+}
+
+static void hfs_get_str (unsigned char *out, int len, uint16_t *hfs_str)
+{
+ int i;
+ char c;
+
+ for (i = 0; i < len; i++) {
+ if (uni2char(*hfs_str++, &c) < 0)
+ c = '?';
+ out[i] = c;
+ }
+ out[i] = '\0';
+}
+
+/* Locate a bloc in the partition given a file and an offset */
+static uint32_t hfs_get_bloc (hfs_fork_t *file, uint32_t bloc)
+{
+ hfs_vol_t *volume;
+ hfs_extent_t *extent;
+ uint32_t abloc, aoffset;
+ int i;
+
+ volume = file->volume;
+ abloc = bloc / volume->bsize;
+ aoffset = bloc - (abloc * volume->bsize);
+ extent = file->extents;
+#if 0
+ HFS_DPRINTF("Look for bloc %08x => %08x %08x (%08x)\n",
+ bloc, abloc, aoffset, volume->bsize);
+#endif
+ for (i = 0; i < 8; i++) {
+#if 0
+ HFS_DPRINTF("Check extent %d %08x %08x (%08x)\n",
+ i, extent->start, extent->count, abloc);
+#endif
+ if (extent->count == 0)
+ break;
+ if (abloc < extent->count) {
+ return volume->start_offset + /*volume->embed_offset +*/
+ ((extent->start + abloc) * volume->bsize) + aoffset;
+ }
+ abloc -= extent->count;
+ extent++;
+ }
+ HFS_ERROR("Block %d not found\n", bloc);
+
+ return -1;
+}
+
+/* Convert HFS/HFS plus extent/fork records to memory structure */
+static inline void hfs_get_extent (hfs_extent_t *dst, HFS_extent_t *src)
+{
+ dst->start = src->start_block;
+ dst->count = src->block_count;
+}
+
+static void hfs_get_fork (hfs_fork_t *dst, uint32_t blocs,
+ HFS_extent_t *extents)
+{
+ int i;
+
+ dst->nb_blocs = blocs;
+ for (i = 0; i < 3; i++) {
+ hfs_get_extent(&dst->extents[i], &extents[i]);
+ }
+ memset(&dst->extents[3], 0, 5 * sizeof(hfs_extent_t));
+}
+
+static inline void hfsp_get_extent (hfs_extent_t *dst, HFSP_extent_t *src)
+{
+ dst->start = src->start_block;
+ dst->count = src->block_count;
+}
+
+static void hfsp_get_fork (hfs_fork_t *dst, uint32_t blocs,
+ HFSP_extent_t *extents)
+{
+ int i;
+
+ dst->nb_blocs = blocs;
+ for (i = 0; i < 8; i++) {
+ hfsp_get_extent(&dst->extents[i], &extents[i]);
+ }
+}
+
+static void hfs_dump_fork (hfs_fork_t *fork)
+{
+ int i;
+
+ HFS_DPRINTF("Nb blocs: %d\n", fork->nb_blocs);
+ for (i = 0; i < 8; i++) {
+ if (fork->extents[i].count == 0)
+ break;
+ HFS_DPRINTF(" extent %d: start: %08x count: %08x\n",
+ i, fork->extents[i].start, fork->extents[i].count);
+ }
+}
+
+/* Btree nodes cache */
+static inline void *hfs_brec_get (HFS_bnode_t *node, uint32_t nodesize, int nb)
+{
+ uint16_t *off;
+
+ if (nb < 1 || nb > node->nrecs) {
+ HFS_ERROR("nb=%d nrec=%d\n", nb, node->nrecs);
+ return NULL;
+ }
+ off = (void *)((char *)node + nodesize);
+ off -= nb;
+ HFS_DPRINTF("%d => %02x node %p off %p %p %d\n",
+ nb, *off, node, off, (char *)node + nodesize, nodesize);
+
+ return (char *)node + *off;
+}
+
+static hfs_bnode_t *hfs_bnode_get (hfs_btree_t *tree, uint32_t location)
+{
+ unsigned char *buffer, tmpbuf[HFS_NODE_SIZE];
+ void *HFS_recp;
+ HFS_bnode_t *Hnode;
+ HFS_headrec_t *Hhead;
+ HFSP_catkey_t *HPkey = NULL;
+ HFS_catkey_t *Hkey = NULL;
+ HFSP_thread_t *HPthread;
+ HFS_thread_t *Hthread;
+ HFSP_fold_t *HPdir;
+ HFS_fold_t *Hdir;
+ HFSP_file_t *HPfile;
+ HFS_file_t *Hfile;
+ hfs_headrec_t *head;
+ hfs_cbnode_t **cur;
+ hfs_bnode_t *node;
+ hfs_rec_t *rec;
+ uint32_t bloc, offset, bsize, *upID, nsize;
+ uint16_t *ptype;
+ int i, j, is_hfs;
+
+#if 1
+ for (cur = &tree->cache; *cur != NULL; cur = &((*cur)->next)) {
+ if ((*cur)->location == location) {
+ HFS_DPRINTF("found node %08x in cache (%08x %08x)\n",
+ location, (*cur)->bnode.prev, (*cur)->bnode.next);
+ return &(*cur)->bnode;
+ }
+ }
+#endif
+ /* Not found in cache, get it from disk */
+ head = &tree->head_rec->u.headrec;
+ if (tree->nodesize != 0) {
+ nsize = tree->nodesize;
+ buffer = tree->buf;
+ } else {
+ nsize = HFS_NODE_SIZE;
+ buffer = tmpbuf;
+ }
+ bsize = part_blocsize(tree->file->volume->part);
+ bloc = location * nsize / 512;
+ HFS_DPRINTF("Get node from %08x %08x %p\n",
+ bloc, nsize, tree->file->volume->part);
+ bloc = hfs_get_bloc(tree->file, bloc);
+ if (bloc == (uint32_t)-1)
+ return NULL;
+ HFS_DPRINTF(" => %08x\n", bloc);
+#if 0
+ offset = bloc % bsize;
+ bloc /= bsize;
+#else
+ offset = 0;
+#endif
+ HFS_DPRINTF(" => %08x %08x (%d)\n", bloc, offset, bsize);
+ Hnode = HFS_read_Hnode(tree->file->volume->part,
+ bloc, offset, buffer, nsize);
+ if (Hnode == NULL) {
+ HFS_DPRINTF("No Hnode !\n");
+ return NULL;
+ }
+ *cur = malloc(sizeof(hfs_cbnode_t) + (Hnode->nrecs * sizeof(hfs_rec_t)));
+ if (*cur == NULL)
+ return NULL;
+ memset(*cur, 0, sizeof(hfs_cbnode_t) + (Hnode->nrecs * sizeof(hfs_rec_t)));
+ (*cur)->location = location;
+ node = &(*cur)->bnode;
+ node->tree = tree;
+ node->prev = Hnode->prev;
+ node->next = Hnode->next;
+ node->type = Hnode->type;
+ node->nrecs = Hnode->nrecs;
+ node->recs = (void *)(node + 1);
+ if (tree->nodesize == 0 && node->type != HFS_NODE_HEAD) {
+ HFS_ERROR("first node should be a header !\n");
+ return NULL;
+ }
+ if (node->type == HFS_NODE_HEAD) {
+ Hhead = HFS_get_headrec(Hnode + 1);
+ nsize = Hhead->nodesize;
+ if (nsize == 0)
+ nsize = HFS_NODE_SIZE;
+ HFS_DPRINTF("Set node size to %d\n", nsize);
+ tree->nodesize = nsize;
+ tree->buf = malloc(nsize);
+ if (tree->buf == NULL)
+ return NULL;
+ memset(tree->buf, 0, nsize);
+ buffer = tree->buf;
+ Hnode = HFS_read_Hnode(tree->file->volume->part,
+ bloc, offset, buffer, nsize);
+ if (Hnode == NULL)
+ return NULL;
+ }
+ HFS_DPRINTF("New node %08x prev: %08x next: %08x type: %d nrecs: %d\n",
+ location, node->prev, node->next, node->type, node->nrecs);
+ is_hfs = tree->file->volume->type == FS_TYPE_HFS;
+ for (i = 0; i < (int)node->nrecs; i++) {
+ rec = &node->recs[i];
+ rec->node = node;
+ rec->num = i + 1;
+ HFS_recp = hfs_brec_get(Hnode, nsize, i + 1);
+ if (HFS_recp == NULL) {
+ HFS_ERROR("can't get record %d\n", i + 1);
+ continue;
+ }
+ if (is_hfs) {
+ Hkey = HFS_recp;
+#if 0
+ upID = (void *)(((uint32_t)Hkey + 2 + Hkey->len));
+#else
+ upID = (void *)(((uint32_t)Hkey + 2 + Hkey->len) & ~1);
+#endif
+ } else {
+ HPkey = HFS_recp;
+ upID = (void *)(((uint32_t)HPkey + 2 + HPkey->len) & ~1);
+ }
+ switch (node->type) {
+ case HFS_NODE_LEAF:
+ HFS_DPRINTF("record %d: leaf %p %p %d\n", i + 1, upID, HFS_recp,
+ (char *)upID - (char *)HFS_recp);
+ rec->type = tree->type;
+ switch (rec->type) {
+ case RECORD_CAT:
+ ptype = (void *)upID;
+ if (is_hfs) {
+ memcpy(rec->u.catrec.name, Hkey->name, Hkey->nlen);
+ rec->u.catrec.name[Hkey->nlen] = '\0';
+ rec->u.catrec.pid = Hkey->pID;
+ } else {
+ hfs_get_str(rec->u.catrec.name,
+ HPkey->nlen, HPkey->uniname);
+ rec->u.catrec.pid = HPkey->pID;
+ }
+ rec->u.catrec.type = *ptype;
+ rec->u.catrec.fork.volume = tree->file->volume;
+ rec->u.catrec.fork.catrec = rec;
+ switch (*ptype) {
+ case HFS_CAT_FOLDER:
+ Hdir = (void *)ptype;
+ rec->u.catrec.ID = Hdir->ID;
+ HFS_DPRINTF("HFS Catalog folder ID: %08x name '%s' %08x\n",
+ rec->u.catrec.ID, rec->u.catrec.name,
+ rec->u.catrec.pid);
+ break;
+ case HFS_CAT_FILE:
+ Hfile = (void *)ptype;
+ rec->u.catrec.ID = Hfile->ID;
+ memcpy(rec->u.catrec.finfo, &Hfile->finder_file, 8);
+ rec->u.catrec.finfo[8] = '\0';
+ for (j = 0; j < 3; j++) {
+ hfs_get_extent(&rec->u.catrec.fork.extents[j],
+ &Hfile->extents[j]);
+#if 0
+ HFS_DPRINTF("Extent %04x %04x => %08x %08x\n",
+ Hfile->extents[j].start_block,
+ Hfile->extents[j].block_count,
+ rec->u.catrec.fork.extents[j].start,
+ rec->u.catrec.fork.extents[j].count);
+#endif
+ }
+ memset(&rec->u.catrec.fork.extents[3], 0,
+ 5 * sizeof(hfs_extent_t));
+ HFS_DPRINTF("HFS Catalog file ID: %08x name '%s' '%s' %08x\n",
+ rec->u.catrec.ID, rec->u.catrec.name,
+ rec->u.catrec.finfo, rec->u.catrec.pid);
+#if 0
+ HFS_DPRINTF("Extent %08x %08x\n",
+ rec->u.catrec.fork.extents[0].start,
+ rec->u.catrec.fork.extents[0].count);
+#endif
+ break;
+ case HFS_CAT_FOLDTH:
+ Hthread = (void *)ptype;
+ strcpy(rec->u.catrec.name, Hthread->name);
+ rec->u.catrec.ID = rec->u.catrec.pid;
+ rec->u.catrec.pid = Hthread->pid;
+ HFS_DPRINTF("HFS Catalog folder thread '%s' %08x %08x\n",
+ rec->u.catrec.name, rec->u.catrec.ID,
+ rec->u.catrec.pid);
+ continue;
+ case HFS_CAT_FILETH:
+ Hthread = (void *)ptype;
+ strcpy(rec->u.catrec.name, Hthread->name);
+ rec->u.catrec.ID = rec->u.catrec.pid;
+ rec->u.catrec.pid = Hthread->pid;
+ HFS_DPRINTF("HFS Catalog file thread '%s' %08x %08x\n",
+ rec->u.catrec.name, rec->u.catrec.ID,
+ rec->u.catrec.pid);
+ continue;
+ case HFSP_CAT_FOLDER:
+ HPdir = (void *)ptype;
+ rec->u.catrec.ID = HPdir->ID;
+ HFS_DPRINTF("HFSplus Catalog folder ID: %08x name '%s'\n",
+ rec->u.catrec.ID, rec->u.catrec.name);
+ break;
+ case HFSP_CAT_FILE:
+ HPfile = (void *)ptype;
+ rec->u.catrec.ID = HPfile->ID;
+ memcpy(rec->u.catrec.finfo, &HPfile->finder_file, 8);
+ rec->u.catrec.finfo[8] = '\0';
+ memcpy(&rec->u.catrec.fork, &HPfile->data,
+ sizeof(HFSP_fork_t));
+ HFS_DPRINTF("HFSPlus Catalog file ID: %08x name '%s' '%s'\n",
+ rec->u.catrec.ID, rec->u.catrec.name,
+ rec->u.catrec.finfo);
+ HFS_DPRINTF("Extent %08x %08x\n",
+ rec->u.catrec.fork.extents[0].start,
+ rec->u.catrec.fork.extents[0].count);
+ break;
+ case HFSP_CAT_FOLDTH:
+ HPthread = (void *)ptype;
+ rec->u.catrec.ID = rec->u.catrec.pid;
+ rec->u.catrec.pid = HPthread->pid;
+ hfs_get_str(rec->u.catrec.name,
+ HPthread->nlen, HPthread->uniname);
+ HFS_DPRINTF("HFSplus Catalog folder thread '%s'...\n",
+ rec->u.catrec.name);
+ break;
+ case HFSP_CAT_FILETH:
+ HPthread = (void *)ptype;
+ hfs_get_str(rec->u.catrec.name,
+ HPthread->nlen, HPthread->uniname);
+ rec->u.catrec.ID = rec->u.catrec.pid;
+ rec->u.catrec.pid = HPthread->pid;
+ HFS_DPRINTF("HFSplus Catalog file thread '%s'...\n",
+ rec->u.catrec.name);
+ break;
+ default:
+ printf("Unknown catalog entry %d %d '%s' %d\n", rec->type,
+ *ptype, rec->u.catrec.name, (char *)ptype - (char *)Hkey);
+ continue;
+ }
+ break;
+ case RECORD_EXT:
+ /* TODO */
+ HFS_DPRINTF("Extent file entry\n");
+ continue;
+ default:
+ HFS_ERROR("Unknown entry\n");
+ continue;
+ }
+ break;
+ case HFS_NODE_IDX:
+ rec->type = RECORD_IDX;
+ rec->u.idxrec.uid = *upID;
+ if (is_hfs) {
+ rec->u.idxrec.pid = Hkey->pID;
+ memcpy(rec->u.idxrec.name, Hkey->name, Hkey->nlen);
+ rec->u.idxrec.name[Hkey->nlen] = '\0';
+ HFS_DPRINTF("HFS IDX record %d parent: %08x up: %08x name '%s'\n",
+ i + 1, rec->u.idxrec.pid, rec->u.idxrec.uid,
+ rec->u.idxrec.name);
+ HFS_DPRINTF("uidp : %d %d\n", (char *)upID - (char *)Hkey,
+ (char *)(Hkey + 1) - (char *)Hkey);
+ } else {
+ rec->u.idxrec.pid = HPkey->pID;
+ hfs_get_str(rec->u.idxrec.name,
+ HPkey->nlen, HPkey->uniname);
+ HFS_DPRINTF("HFSplus IDX record %d parent: %08x up: %08x "
+ "name '%s'\n", i + 1, rec->u.idxrec.pid,
+ rec->u.idxrec.uid, rec->u.idxrec.name);
+ }
+ break;
+ case HFS_NODE_HEAD:
+ Hhead = HFS_get_headrec(HFS_recp);
+ rec->type = RECORD_HEAD;
+ rec->u.headrec.rootnode = Hhead->rootnode;
+ rec->u.headrec.firstleaf = Hhead->firstleaf;
+ rec->u.headrec.lastleaf = Hhead->lastleaf;
+ rec->u.headrec.nodesize = Hhead->nodesize;
+ HFS_DPRINTF("Header record %d root: %08x first: %08x last: %08x "
+ "size: %08x\n", i + 1, rec->u.headrec.rootnode,
+ rec->u.headrec.firstleaf, rec->u.headrec.lastleaf,
+ rec->u.headrec.nodesize);
+ node->nrecs = 1;
+ goto out;
+ case HFS_NODE_MAP:
+ /* TODO */
+ default:
+ continue;
+ }
+ }
+
+ out:
+ return node;
+}
+
+static inline hfs_rec_t *hfs_rec_get (hfs_bnode_t *node, int nb)
+{
+ if (nb < 1 || nb > (int)node->nrecs) {
+ HFS_ERROR("nb: %d min: %d max: %d\n", nb, 1, node->nrecs);
+ return NULL;
+ }
+
+ return &node->recs[nb - 1];
+}
+
+static inline hfs_bnode_t *hfs_bnode_prev (hfs_bnode_t *cur)
+{
+ if (cur->prev == 0x00000000)
+ return NULL;
+
+ return hfs_bnode_get(cur->tree, cur->prev);
+}
+
+static inline hfs_bnode_t *hfs_bnode_next (hfs_bnode_t *cur)
+{
+ if (cur->next == 0x00000000)
+ return NULL;
+
+ return hfs_bnode_get(cur->tree, cur->next);
+}
+
+unused static hfs_rec_t *hfs_rec_prev (hfs_rec_t *cur)
+{
+ hfs_bnode_t *curn;
+ int num;
+
+ num = cur->num;
+ curn = cur->node;
+ if (num == 1) {
+ curn = hfs_bnode_prev(curn);
+ if (curn == NULL)
+ return NULL;
+ num = curn->nrecs + 1;
+ }
+
+ return hfs_rec_get(curn, num - 1);
+}
+
+unused static hfs_rec_t *hfs_rec_next (hfs_rec_t *cur)
+{
+ hfs_bnode_t *curn;
+ int num;
+
+ num = cur->num;
+ curn = cur->node;
+ if (num == (int)curn->nrecs) {
+ curn = hfs_bnode_next(curn);
+ if (curn == NULL)
+ return NULL;
+ num = 1;
+ }
+
+ return hfs_rec_get(curn, num - 1);
+}
+
+static int hfs_cat_compare (int type, HFS_cnid_t cnid,
+ const void *more, hfs_rec_t *rec, int rectype);
+
+/* Simplified Btree recurse function from Linux */
+static hfs_rec_t *hfs_rec_find (hfs_btree_t *tree,
+ HFS_cnid_t cnid, const char *name, int rectype)
+{
+ hfs_bnode_t *curn;
+ hfs_rec_t *cur;
+ unsigned int i;
+ int ret;
+
+ /*
+ * This is an ugly scattering of #if, but it's wonderful for debugging
+ * hfs_rec_find(). If you set this to 1, then the loop will traverse
+ * and show all of the records in a node before descending the correct
+ * record.
+ */
+#define DEBUG_HFS_REC_FIND 0
+#if DEBUG_HFS_REC_FIND
+ hfs_rec_t *idx_cur;
+ unsigned int idx;
+ int idx_ret;
+#endif /* DEBUG_HFS_REC_FIND */
+
+ HFS_DPRINTF("look for ID: %08x '%s'\n", cnid, name);
+ cur = NULL;
+ ret = -1;
+ i = 0;
+ for (curn = tree->root_node; curn != NULL;) {
+#if DEBUG_HFS_REC_FIND
+ idx = 0;
+ idx_ret = 0;
+ idx_cur = NULL;
+#endif /* DEBUG_HFS_REC_FIND */
+ for (i = curn->nrecs; i != 0; i--) {
+ cur = hfs_rec_get(curn, i);
+ if (cur == NULL) {
+ HFS_ERROR("Cannot get record %d\n", i);
+ return NULL;
+ }
+ HFS_DPRINTF("Check record %d %d %p %p %p\n", i, cur->type, cur,
+ curn->tree->compare, &hfs_cat_compare);
+ ret = (*curn->tree->compare)(cur->type, cnid, name, cur, rectype);
+ HFS_DPRINTF("\t%u:%d\n", i, ret);
+ if (ret >= 0) {
+#if !DEBUG_HFS_REC_FIND
+ break;
+#else
+ if (!idx) {
+ idx = i;
+ idx_ret = ret;
+ idx_cur = cur;
+ }
+#endif /* DEBUG_HFS_REC_FIND */
+ }
+ }
+#if DEBUG_HFS_REC_FIND
+ if (idx) {
+ i = idx;
+ ret = idx_ret;
+ cur = idx_cur;
+ }
+#endif /* DEBUG_HFS_REC_FIND */
+ HFS_DPRINTF("ret=%d HFS_NODE=%02x RECORD=%02x\n",
+ ret, curn->type, cur->type);
+ if (i == 0 || /* exhausted all the records */
+ curn->type == HFS_NODE_LEAF) { /* Can't descend any lower */
+ break;
+ }
+ HFS_DPRINTF("Recurse to record: %d %08x => %08x\n",
+ i, cnid, cur->u.idxrec.uid);
+ curn = hfs_bnode_get(curn->tree, cur->u.idxrec.uid);
+ }
+ if (ret != 0 || curn == NULL) {
+ /* We won't find what we're looking for... */
+ HFS_DPRINTF("NOT FOUND\n");
+ return NULL;
+ }
+#if 0
+ if (ret != 0 && cur->u.catrec.ID != cnid) {
+ HFS_ERROR("%d %d\n", cur->u.catrec.ID, cnid);
+ return NULL;
+ }
+#endif
+ HFS_DPRINTF("found %p %p %d %p\n", cur, curn, i, hfs_rec_get(curn, i));
+
+ return cur;
+}
+
+static inline hfs_rec_t *hfs_get_dir (hfs_btree_t *tree, HFS_cnid_t cnid,
+ const unsigned char *name)
+{
+ return hfs_rec_find(tree, cnid, name, 1);
+}
+
+static hfs_rec_t *hfs_get_dirfile (hfs_rec_t *dir, HFS_cnid_t cnid,
+ const unsigned char *name,
+ const unsigned char *info)
+{
+ hfs_btree_t *tree;
+ hfs_bnode_t *cur;
+ hfs_rec_t *rec;
+ hfs_catrec_t *frec;
+ int idx;
+
+ cur = dir->node;
+ tree = cur->tree;
+ for (idx = dir->num + 1;; idx++) {
+ if (idx > (int)cur->nrecs) {
+ HFS_DPRINTF("Go to next node %08x\n", cur->next);
+ cur = hfs_bnode_next(cur);
+ if (cur == NULL) {
+ HFS_ERROR("Node %08x not found\n", cur->next);
+ break;
+ }
+ idx = 1;
+ }
+ rec = hfs_rec_get(cur, idx);
+ if (rec == NULL) {
+ HFS_ERROR("Cannot get record %d\n", idx);
+ return NULL;
+ }
+ HFS_DPRINTF("Check record %d '%s' '%s' '%s' '%s'\n",
+ idx, rec->u.catrec.name, rec->u.catrec.finfo, name, info);
+ if (rec->type == RECORD_IDX) {
+ continue;
+ }
+ frec = &rec->u.catrec;
+ if (frec->type != HFS_CAT_FILE && frec->type != HFS_CAT_FILETH &&
+ frec->type != HFSP_CAT_FILE && frec->type != HFSP_CAT_FILETH)
+ continue;
+ if (frec->pid != cnid) {
+ HFS_ERROR("Out of directory %08x %08x\n", cnid, frec->pid);
+ break;
+ }
+ if (info != NULL && memcmp(frec->finfo, info, strlen(info)) != 0)
+ continue;
+ /* Beware: HFS is case insensitive ! */
+ if (name != NULL && strcasecmp(frec->name, name) != 0)
+ continue;
+ return rec;
+ }
+
+ return NULL;
+}
+
+static hfs_btree_t *hfs_btree_open (hfs_fork_t *fork, int type,
+ int (*compare)(int type,
+ HFS_cnid_t cnid,
+ const void *more,
+ hfs_rec_t *rec,
+ int rectype))
+{
+ hfs_bnode_t *node;
+ hfs_rec_t *rec;
+ hfs_headrec_t *head;
+ hfs_btree_t *newt;
+ uint32_t bloc;
+
+ bloc = hfs_get_bloc(fork, 0);
+ if (bloc == (uint32_t)-1)
+ return NULL;
+ HFS_DPRINTF("Open btree: bloc=%08x\n", bloc);
+ /* Allocate tree */
+ newt = malloc(sizeof(hfs_btree_t));
+ if (newt == NULL)
+ return NULL;
+ memset(newt, 0, sizeof(hfs_btree_t));
+ newt->file = fork;
+ newt->cache = NULL;
+ newt->type = type;
+ newt->compare = compare;
+ /* Get tree header */
+ HFS_DPRINTF("Get first node\n");
+ node = hfs_bnode_get(newt, 0);
+ if (node == NULL) {
+ HFS_ERROR("Cannot get tree head\n");
+ return NULL;
+ }
+ HFS_DPRINTF("Get first record\n");
+ rec = hfs_rec_get(node, 1);
+ if (rec == NULL) {
+ HFS_ERROR("Cannot get first record\n");
+ return NULL;
+ }
+ if (rec->type != RECORD_HEAD) {
+ HFS_ERROR("Not an header record !\n");
+ return NULL;
+ }
+ head = &rec->u.headrec;
+ newt->head_rec = rec;
+ /* Get root node */
+ HFS_DPRINTF("Get root entry node: %08x\n", head->rootnode);
+ newt->root_node = hfs_bnode_get(newt, head->rootnode);
+ if (newt->root_node == NULL)
+ return NULL;
+ /* Get root directory record */
+ HFS_DPRINTF("Get root folder record\n");
+ newt->root_catrec = hfs_get_dir(newt, HFS_ROOT_FOLDER, "");
+ HFS_DPRINTF("Found root folder record: %p\n", newt->root_catrec);
+ if (newt->root_catrec == NULL)
+ return NULL;
+
+ return newt;
+}
+
+static int hfs_cat_compare (int type, HFS_cnid_t cnid,
+ const void *more, hfs_rec_t *rec, int rectype)
+{
+ hfs_idxrec_t *idxrec;
+ hfs_catrec_t *catrec;
+ const unsigned char *name;
+ HFS_cnid_t id;
+ int ret;
+
+ if (type == RECORD_IDX) {
+ idxrec = &rec->u.idxrec;
+ id = idxrec->pid;
+ name = idxrec->name;
+ catrec = NULL;
+ } else {
+ catrec = &rec->u.catrec;
+ name = catrec->name;
+ if (type != RECORD_IDX &&
+ (catrec->type == HFS_CAT_FOLDTH ||
+ catrec->type == HFS_CAT_FILETH ||
+ catrec->type == HFSP_CAT_FOLDTH ||
+ catrec->type == HFSP_CAT_FILETH)) {
+ HFS_DPRINTF("CHECK FOLDER %08x %08x!\n", catrec->ID, catrec->pid);
+ id = catrec->ID;
+ } else {
+ id = catrec->pid;
+ }
+ }
+ HFS_DPRINTF("Compare cnid (%08x '%s') vs (%08x '%s') %08x %d\n",
+ cnid, (char *)more, id, name, catrec->type, rectype);
+
+ /*
+ * Always diff Record_IDXs, but diff RECORDS_CATs iff they match the type
+ * being looked for: THREAD vs NON-THREAD (rectype).
+ */
+ ret = cnid - id;
+
+ if (ret == 0 && type != RECORD_IDX) {
+ /* out on a leaf - don't compare different types */
+ if (rectype &&
+ (catrec->type == HFS_CAT_FILE ||
+ catrec->type == HFS_CAT_FOLDER ||
+ catrec->type == HFSP_CAT_FILE ||
+ catrec->type == HFSP_CAT_FOLDER)) {
+ /* looking for thread and this is a file/folder - keep looking */
+ ret = -1;
+ } else if (!rectype &&
+ (catrec->type == HFS_CAT_FILETH ||
+ catrec->type == HFS_CAT_FOLDTH ||
+ catrec->type == HFSP_CAT_FILETH ||
+ catrec->type == HFSP_CAT_FOLDTH)) {
+ /* looking for file/folder and this is a thread - keep looking */
+ ret = -1;
+ }
+ }
+
+ if (ret == 0 &&
+ /* Apparently there is still a match - further constrain it by
+ * checking if the name matches. Name matchs should be
+ * skipped if we're looking for a thread and we've reached a
+ * leaf record (that case will match solely on the record
+ * type and the cnid which has already been done).
+ */
+ (type == RECORD_IDX ||
+ (!rectype &&
+ (catrec->type == HFS_CAT_FILE ||
+ catrec->type == HFS_CAT_FOLDER ||
+ catrec->type == HFSP_CAT_FILE ||
+ catrec->type == HFSP_CAT_FOLDER)))) {
+ /* HFS is case insensitive - HFSP *can* be case sensitive */
+ ret = strcasecmp(more, name);
+ }
+
+ HFS_DPRINTF("ret %d catrec %p catrec->type %08x\n",
+ ret, catrec, catrec ? catrec->type : 0);
+ return ret;
+}
+
+static hfs_btree_t *hfs_cat_open (hfs_vol_t *volume)
+{
+ HFS_DPRINTF("Open HFS catalog\n");
+ return hfs_btree_open(&volume->cat_file, RECORD_CAT, &hfs_cat_compare);
+}
+
+unused static int hfs_ext_compare (unused int type, unused HFS_cnid_t cnid,
+ unused const void *more,
+ unused hfs_rec_t *rec)
+{
+ /* TODO */
+ return -1;
+}
+
+static hfs_btree_t *hfs_ext_open (unused hfs_vol_t *volume)
+{
+ HFS_DPRINTF("Open HFS extents file\n");
+#if 0
+ return hfs_btree_open(&volume->ext_file, RECORD_EXT, &hfs_ext_compare);
+#else
+ return NULL;
+#endif
+}
+
+static void hfs_map_boot_file (part_t *part, hfs_vol_t *volume,
+ uint32_t *boot_start, uint32_t *boot_offset,
+ uint32_t *boot_size)
+{
+ uint32_t bloc, size;
+
+ /* Now, patch the partition to register the boot file
+ * XXX: we "know" that only one extent is used...
+ * this may not be true if booting from a hard drive...
+ */
+ volume->boot_file->volume = volume;
+ bloc = hfs_get_bloc(volume->boot_file, 0);
+ if (bloc == (uint32_t)(-1)) {
+ printf("Cannot get boot file start bloc\n");
+ return;
+ }
+ size = volume->boot_file->extents[0].count * volume->bsize;
+ // printf("Map boot file bloc 0 to %08x\n", bloc);
+ part_set_boot_file(part, bloc, 0, size);
+ *boot_start = bloc;
+ *boot_size = size;
+ *boot_offset = 0;
+}
+
+static inode_t *fs_hfs_get_inode (inode_t *parent, const unsigned char *name)
+{
+ inode_t *new;
+ hfs_fork_t *pfile, *file;
+ hfs_rec_t *catrec, *extrec;
+ uint32_t size;
+ int i;
+
+ pfile = parent->private;
+ HFS_DPRINTF("Get inode '%s' %p %p %p %08x\n", name, pfile, pfile->catrec,
+ pfile->catrec->node->tree, pfile->catrec->u.catrec.pid);
+ catrec = hfs_rec_find(pfile->catrec->node->tree,
+ pfile->catrec->u.catrec.ID, name, 0);
+#if 0
+ extrec = hfs_rec_find(pfile->extrec->node->tree,
+ pfile->extrec->u.extrec.pid, name, 0);
+#else
+ extrec = NULL;
+#endif
+ if (catrec == NULL /* || extrec == NULL */)
+ return NULL;
+ new = malloc(sizeof(inode_t));
+ if (new == NULL)
+ return NULL;
+ memset(new, 0, sizeof(inode_t));
+ new->flags = 0;
+ file = &catrec->u.catrec.fork;
+ new->private = file;
+ size = 0;
+ for (i = 0; i < 8; i++) {
+ if (file->extents[i].count == 0)
+ break;
+ size += file->extents[i].count;
+ }
+ size *= file->volume->bsize;
+ new->size.bloc = size;
+ new->size.offset = 0;
+ HFS_DPRINTF("File: '%s'\n", name);
+ hfs_dump_fork(new->private);
+
+ return new;
+}
+
+static void fs_hfs_put_inode (unused inode_t *inode)
+{
+}
+
+static uint32_t fs_hfs_map_bloc (inode_t *inode, uint32_t bloc)
+{
+ return hfs_get_bloc(inode->private, bloc);
+}
+
+static inode_t *fs_hfs_get_special_inode (fs_t *fs, int type)
+{
+ hfs_vol_t *volume;
+ inode_t *bfile, *bdir, *cur;
+ hfs_rec_t *drec, *rec;
+ hfs_fork_t *fork;
+ uint32_t boot_start, boot_size, boot_offset;
+ HFS_cnid_t id;
+
+ volume = fs->private;
+ switch (type) {
+ case FILE_ROOT:
+ if (fs->root == NULL) {
+ volume->cat_tree = hfs_cat_open(volume);
+ volume->ext_tree = hfs_ext_open(volume);
+ if (volume->cat_tree == NULL /*|| volume->ext_tree == NULL*/) {
+ HFS_ERROR("Can't open volume catalog/extent files\n");
+ return NULL;
+ }
+ cur = malloc(sizeof(inode_t));
+ if (cur == NULL)
+ return NULL;
+ memset(cur, 0, sizeof(inode_t));
+ cur->flags = INODE_TYPE_DIR;
+ cur->private = &volume->cat_tree->root_catrec->u.catrec.fork;
+ cur->parent = NULL;
+ } else {
+ cur = fs->root;
+ }
+ return cur;
+ case FILE_BOOT:
+ if (fs->bootfile != NULL)
+ return fs->bootfile;
+ break;
+ case FILE_BOOTDIR:
+ if (fs->bootdir != NULL)
+ return fs->bootdir;
+ if (volume->boot_file != NULL) {
+ bfile = malloc(sizeof(inode_t));
+ if (bfile == NULL)
+ return NULL;
+ memset(bfile, 0, sizeof(inode_t));
+ fs->bootfile = bfile;
+ rec = volume->boot_file->catrec;
+ bfile->name = strdup(rec->u.catrec.name);
+ if (bfile->name == NULL) {
+ free(bfile);
+ fs->bootfile = NULL;
+ return NULL;
+ }
+ bfile->private = volume->boot_file;
+ bfile->flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT;
+ fs->bootdir = fs->root;
+ hfs_map_boot_file(fs->part, volume,
+ &boot_start, &boot_offset, &boot_size);
+ }
+ break;
+ default:
+ return NULL;
+ }
+ HFS_DPRINTF("Look for boot file (%d)\n", volume->boot_id);
+ if (volume->boot_file == NULL ||
+ volume->boot_file->extents[0].count == 0) {
+ if (volume->boot_id != 0x00000000) {
+ /* Try to find regular MacOS bootfile */
+ drec = hfs_get_dir(volume->cat_tree, volume->boot_id, "");
+ if (drec == NULL) {
+ HFS_ERROR("Didn't find boot directory %d\n", volume->boot_id);
+ return NULL;
+ }
+ HFS_DPRINTF("Found boot directory '%s'\n", drec->u.catrec.name);
+ rec = hfs_get_dirfile(drec, volume->boot_id, NULL, "tbxi");
+ } else {
+ /* Try NetBSD boot */
+ drec = hfs_get_dir(volume->cat_tree, HFS_ROOT_FOLDER, "");
+ if (drec == NULL)
+ return NULL;
+ rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER, "ofwboot", NULL);
+ if (rec == NULL) {
+ rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER,
+ "ofwboot.xcf", NULL);
+ if (rec == NULL) {
+ rec = hfs_get_dirfile(drec, HFS_ROOT_FOLDER,
+ "ofwboot.elf", NULL);
+ }
+ }
+ if (rec != NULL) {
+ volume->boot_id = rec->u.catrec.pid;
+ drec = hfs_get_dir(volume->cat_tree, volume->boot_id, "");
+ }
+ }
+ if (rec == NULL) {
+ HFS_ERROR("Didn't find boot file\n");
+ return NULL;
+ }
+ volume->boot_file = &rec->u.catrec.fork;
+ hfs_map_boot_file(fs->part, volume,
+ &boot_start, &boot_offset, &boot_size);
+ HFS_DPRINTF("boot file mapped: %08x-%08x %08x\n",
+ boot_start, boot_offset, boot_size);
+#if 0
+ hfs_treat_boot_file(fs->part, volume,
+ &boot_start, &boot_offset, &boot_size);
+#endif
+ HFS_DPRINTF("Dump boot file\n");
+ hfs_dump_fork(volume->boot_file);
+ HFS_DPRINTF("boot file mapped: %08x-%08x %08x\n",
+ boot_start, boot_offset, boot_size);
+ } else {
+ drec = hfs_get_dir(volume->cat_tree, HFS_ROOT_FOLDER, "");
+ if (drec == NULL)
+ return NULL;
+ }
+ rec = volume->boot_file->catrec;
+ fork = volume->boot_file;
+ HFS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n",
+ rec, rec->u.catrec.name, drec, drec->u.catrec.name);
+ bfile = malloc(sizeof(inode_t));
+ if (bfile == NULL)
+ return NULL;
+ memset(bfile, 0, sizeof(inode_t));
+ fs->bootfile = bfile;
+ bfile->name = strdup(rec->u.catrec.name);
+ if (bfile->name == NULL) {
+ free(bfile);
+ return NULL;
+ }
+ bfile->private = fork;
+ bfile->flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT;
+ bfile->size.bloc = boot_size / part_blocsize(volume->part);
+ bfile->size.offset = boot_size % part_blocsize(volume->part);
+ HFS_DPRINTF("%s: look for parent ID: %08x\n", __func__, volume->boot_id);
+ bdir = NULL;
+ cur = NULL;
+ if (type == FILE_BOOT) {
+ cur = bfile;
+ }
+ for (id = volume->boot_id; id != HFS_ROOT_FOLDER;
+ id = drec->u.catrec.pid) {
+ drec = hfs_get_dir(volume->cat_tree, id, "");
+ if (drec == NULL)
+ return NULL;
+ bdir = malloc(sizeof(inode_t));
+ if (bdir == NULL)
+ return NULL;
+ memset(bdir, 0, sizeof(inode_t));
+ if (id == volume->boot_id) {
+ if (type == FILE_BOOTDIR)
+ cur = bdir;
+ fs->bootdir = bdir;
+ }
+ bdir->name = strdup(drec->u.catrec.name);
+ if (bdir->name == NULL) {
+ free(bdir);
+ return NULL;
+ }
+ bdir->private = &drec->u.catrec.fork;
+ bdir->flags = INODE_TYPE_DIR;
+ bfile->parent = bdir;
+ HFS_DPRINTF("%s: cache '%s' into '%s'\n",
+ __func__, bfile->name, bdir->name);
+ fs_cache_add_inode(bdir, bfile);
+ bfile = bdir;
+ }
+ bfile->parent = fs->root;
+ HFS_DPRINTF("%s: cache '%s' into root dir\n", __func__, bfile->name);
+ fs_cache_add_inode(fs->root, bfile);
+ if (bdir == NULL) {
+ bdir = fs->root;
+ fs->bootdir = bdir;
+ if (type == FILE_BOOTDIR)
+ cur = bdir;
+ }
+ cur->fs = fs;
+ HFS_DPRINTF("boot file: %p '%s' boot dir: %p '%s'\n",
+ fs->bootfile, fs->bootfile->name,
+ fs->bootdir, fs->bootdir->name);
+ HFS_DPRINTF("boot fork %p rec %p %p %08x\n",
+ bfile->private, rec, rec->u.catrec.fork.catrec,
+ rec->u.catrec.ID);
+ HFS_DPRINTF("boot dir fork %p rec %p %p %08x %08x\n",
+ bdir->private, drec, drec->u.catrec.fork.catrec,
+ drec->u.catrec.ID, volume->boot_id);
+ HFS_DPRINTF("FS cat tree: %p\n", volume->cat_tree);
+
+ return cur;
+}
+
+static fs_ops_t hfs_fs_ops = {
+ &fs_hfs_get_inode,
+ &fs_hfs_put_inode,
+ &fs_hfs_map_bloc,
+ &fs_hfs_get_special_inode,
+};
+
+int fs_hfs_probe (part_t *part, uint32_t *size,
+ fs_ops_t **fs_ops, unsigned char **name,
+ void **private)
+{
+ unsigned char buffer[512];
+ HFSP_vh_t *hfsp_vh;
+ HFS_vh_t *hfs_vh;
+ hfs_vol_t *volume;
+ uint32_t embed_offset = 0, boot_id;
+ int type;
+
+ hfs_vh = HFS_read_volhead(part, HFS_VOLHEAD_SECTOR, 0, buffer, 512);
+ hfsp_vh = NULL;
+ if (hfs_vh == NULL) {
+ DPRINTF("Can't read HFS volume header\n");
+ return -1;
+ }
+ type = -1;
+ if (hfs_vh->signature == HFS_VOLHEAD_SIG) {
+ /* HFS volume */
+ printf("HFS volume\n");
+ if (hfs_vh->embed_sig == HFSPLUS_VOLHEAD_SIG) {
+ embed_offset = hfs_vh->embed_ext.start_block *
+ hfs_vh->alloc_size / HFS_SECTOR_SIZE;
+ embed_offset += hfs_vh->alloc_start;
+ printf("HFSplus embedded volume offset=%08x\n", embed_offset);
+ hfsp_vh = HFSP_read_volhead(part,
+ HFS_VOLHEAD_SECTOR + embed_offset,
+ 0, buffer, 512);
+ goto handle_hfsp;
+ }
+ boot_id = hfs_vh->finder_info[0];
+ DPRINTF("HFS boot id : %d %04x\n", boot_id, boot_id);
+ volume = malloc(sizeof(hfs_vol_t));
+ if (volume == NULL)
+ return -1;
+ memset(volume, 0, sizeof(hfs_vol_t));
+ HFS_DPRINTF("sig: %x %x %x\n", hfs_vh->signature,
+ hfs_vh->embed_sig, HFSPLUS_VOLHEAD_SIG);
+ HFS_DPRINTF("cr: %08x mod: %08x attr: %04x count: %04x\n",
+ hfs_vh->create_date, hfs_vh->modify_date,
+ hfs_vh->attributes, hfs_vh->root_file_count);
+ HFS_DPRINTF("alloc ptr: %04x blocs: %04x size: %08x bmap %04x\n",
+ hfs_vh->alloc_ptr, hfs_vh->alloc_blocs, hfs_vh->alloc_size,
+ hfs_vh->bitmap_start);
+ volume->bsize = hfs_vh->alloc_size / HFS_SECTOR_SIZE;
+ volume->start_offset = hfs_vh->alloc_start;
+ /* Alloc file */
+ volume->alloc_file.volume = volume;
+ volume->alloc_file.nb_blocs = hfs_vh->alloc_size * volume->bsize;
+ volume->alloc_file.extents[0].start = 0;
+ volume->alloc_file.extents[0].count = hfs_vh->alloc_size;
+ /* Catalog file */
+ volume->cat_file.volume = volume;
+ hfs_get_fork(&volume->cat_file, hfs_vh->cat_size, hfs_vh->cat_rec);
+ /* Extents file */
+ volume->ext_file.volume = volume;
+ hfs_get_fork(&volume->ext_file, hfs_vh->ext_size, hfs_vh->ext_rec);
+ *size = hfs_vh->alloc_blocs * volume->bsize;
+ *name = strdup(hfs_vh->label);
+ if (*name == NULL)
+ return -1;
+ type = FS_TYPE_HFS;
+ } else {
+ hfsp_vh = HFSP_read_volhead(part, HFS_VOLHEAD_SECTOR, 0, buffer, 512);
+ handle_hfsp:
+ if (hfsp_vh == NULL) {
+ DPRINTF("Can't read HFS+ volume header\n");
+ return -1;
+ }
+ if (hfsp_vh->signature != HFSPLUS_VOLHEAD_SIG) {
+ DPRINTF("Bad HFS+ signature %02x %02x\n",
+ hfsp_vh->signature, HFSPLUS_VOLHEAD_SIG);
+ return -1;
+ }
+ /* HFS+ volume */
+ printf("HFSplus volume\n");
+ volume = malloc(sizeof(hfs_vol_t));
+ if (volume == NULL)
+ return -1;
+ memset(volume, 0, sizeof(hfs_vol_t));
+ volume->embed_offset = embed_offset;
+ volume->start_offset = embed_offset;
+ volume->bsize = hfsp_vh->blocksize / HFS_SECTOR_SIZE;
+ // volume->bsize = 2048;
+ /* Boot file */
+ HFS_DPRINTF("Boot file: %d %d\n",
+ hfsp_vh->start_file.total_blocks,
+ hfsp_vh->start_file.extents[0].block_count);
+ if (hfsp_vh->start_file.total_blocks != 0) {
+ volume->boot_file = malloc(sizeof(hfs_fork_t));
+ memset(volume->boot_file, 0, sizeof(hfs_fork_t));
+ volume->boot_file->volume = volume;
+ hfsp_get_fork(volume->boot_file,
+ hfsp_vh->start_file.total_blocks,
+ hfsp_vh->start_file.extents);
+ boot_id = 2;
+ } else {
+ boot_id = hfsp_vh->finder_info[0];
+ }
+ DPRINTF("HFS+ boot id : %d %04x %d\n", boot_id, boot_id,
+ hfsp_vh->start_file.total_blocks);
+ /* Catalog file */
+ volume->cat_file.volume = volume;
+ hfsp_get_fork(&volume->cat_file,
+ hfsp_vh->cat_file.total_blocks,
+ hfsp_vh->cat_file.extents);
+ /* Extents file */
+ volume->ext_file.volume = volume;
+ hfsp_get_fork(&volume->ext_file,
+ hfsp_vh->ext_file.total_blocks,
+ hfsp_vh->ext_file.extents);
+ *size = hfsp_vh->total_blocks * volume->bsize;
+ type = FS_TYPE_HFSP;
+ }
+ volume->boot_id = boot_id;
+ volume->type = type;
+ HFS_DPRINTF("%s volume: type: %d bsize: %d start_offset: %d\n",
+ type == FS_TYPE_HFS ? "HFS" : "HFSplus",
+ volume->type, volume->bsize, volume->start_offset);
+ HFS_DPRINTF("Catalog file:\n");
+ hfs_dump_fork(&volume->cat_file);
+ HFS_DPRINTF("Extents file:\n");
+ hfs_dump_fork(&volume->ext_file);
+ if (volume->boot_file != NULL) {
+ HFS_DPRINTF("Boot file:\n");
+ hfs_dump_fork(volume->boot_file);
+ }
+ *fs_ops = &hfs_fs_ops;
+ HFS_DPRINTF("Set part to %p\n", part);
+ volume->part = part;
+ *private = volume;
+
+ return type;
+}
diff --git a/src/libfs/isofs.c b/src/libfs/isofs.c
new file mode 100644
index 0000000..0e09094
--- /dev/null
+++ b/src/libfs/isofs.c
@@ -0,0 +1,32 @@
+/*
+ * <isofs.c>
+ *
+ * Open Hack'Ware BIOS ISO file system management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include "bios.h"
+#include "libfs.h"
+
+/* ISOFS filesystem */
+int fs_isofs_probe (unused part_t *part, unused uint32_t *size,
+ unused fs_ops_t **fs_ops, unused unsigned char **name,
+ unused void **private)
+{
+ return -1;
+}
diff --git a/src/libfs/libfs.h b/src/libfs/libfs.h
new file mode 100644
index 0000000..1c05bcb
--- /dev/null
+++ b/src/libfs/libfs.h
@@ -0,0 +1,129 @@
+/*
+ * <libfs.h>
+ *
+ * Open Hack'Ware BIOS: file system library definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined(__OHW_LIBFS_H__)
+#define __OHW_LIBFS_H__
+
+//#define DEBUG_FS 1
+#define FS_SPECIAL "<special>"
+
+static inline int is_special_file (const unsigned char *name)
+{
+ int splen = strlen(FS_SPECIAL);
+
+ return name[0] == '\0' && memcmp(name + 1, FS_SPECIAL, splen) == 0 &&
+ name[splen + 1] == '\0';
+}
+
+#if defined (DEBUG_FS)
+#define FS_DPRINTF(fmt, args...) \
+do { dprintf("%s: " fmt, __func__ , ##args); } while (0)
+#else
+#define FS_DPRINTF(fmt, args...) \
+do { } while (0)
+#endif
+#define FS_ERROR(fmt, args...) \
+do { printf("ERROR in %s: " fmt, __func__ , ##args); } while (0)
+
+typedef struct fs_ops_t {
+ inode_t *(*get_inode)(inode_t *parent, const unsigned char *name);
+ void (*put_inode)(inode_t *inode);
+ uint32_t (*map_bloc)(inode_t *inode, uint32_t bloc);
+ inode_t *(*get_special_inode)(fs_t *fs, int type);
+} fs_ops_t;
+
+#define MAXNAME_LEN 1024
+
+struct fs_t {
+ int type;
+ part_t *part;
+ inode_t *root;
+ fs_ops_t *fs_ops;
+ uint32_t size;
+ unsigned char *name;
+ inode_t *bootfile;
+ inode_t *bootdir;
+ void *private;
+};
+
+struct dir_t {
+ inode_t *inode;
+ dirent_t *cur;
+ int pos;
+};
+
+/* All internals use inodes */
+struct inode_t {
+ fs_t *fs;
+ /* parent inode */
+ inode_t *parent;
+ /* Next inode at the same level */
+ inode_t *next;
+ /* First child inode */
+ inode_t *child;
+ /* Private data */
+ int refcount;
+ uint32_t flags;
+ unsigned char *name;
+ int nb_blocs;
+ pos_t *blocs;
+ pos_t size;
+ void *private;
+ uint32_t vbloc;
+ uint32_t vpos;
+};
+
+/* Low-level helpers */
+enum {
+ FILE_UNKNOWN = -1,
+ FILE_ROOT = 0,
+ FILE_BOOT,
+ FILE_BOOTDIR,
+};
+
+void fs_cache_add_inode (inode_t *parent, inode_t *inode);
+
+int fs_raw_probe (part_t *part, uint32_t *size,
+ fs_ops_t **fs_ops, unsigned char **name,
+ void **private);
+int fs_ext2_probe (part_t *part, uint32_t *size,
+ fs_ops_t **fs_ops, unsigned char **name,
+ void **private);
+int fs_isofs_probe (part_t *part, uint32_t *size,
+ fs_ops_t **fs_ops, unsigned char **name,
+ void **private);
+int fs_hfs_probe (part_t *part, uint32_t *size,
+ fs_ops_t **fs_ops, unsigned char **name,
+ void **private);
+int fs_raw_set_bootfile (part_t *part,
+ uint32_t start_bloc, uint32_t start_offset,
+ uint32_t size_bloc, uint32_t size_offset);
+
+enum {
+ FS_TYPE_UNKNOWN = -1,
+ FS_TYPE_RAW = 0,
+ FS_TYPE_EXT2,
+ FS_TYPE_ISOFS,
+ FS_TYPE_HFS,
+ FS_TYPE_HFSP,
+};
+
+#endif /* !defined(__OHW_LIBFS_H__) */
diff --git a/src/libfs/raw.c b/src/libfs/raw.c
new file mode 100644
index 0000000..9ecd23a
--- /dev/null
+++ b/src/libfs/raw.c
@@ -0,0 +1,178 @@
+/*
+ * <raw.c>
+ *
+ * Open Hack'Ware BIOS raw file system management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "../libpart/libpart.h"
+#include "libfs.h"
+
+/* Raw filesystem (ie no filesystem) */
+static inode_t *fs_raw_get_inode (inode_t *parent, const unsigned char *name)
+{
+ inode_t *new;
+ fs_t *fs;
+ int flags;
+
+ if (parent != NULL) {
+ return NULL;
+ }
+ /* Open root inode */
+ flags = INODE_TYPE_DIR;
+ fs = NULL;
+ new = malloc(sizeof(inode_t));
+ memset(new, 0, sizeof(inode_t));
+ new->flags = flags;
+ new->name = strdup(name);
+
+ return new;
+}
+
+static void fs_raw_put_inode (inode_t *inode)
+{
+ free(inode);
+}
+
+static uint32_t fs_raw_map_bloc (unused inode_t *inode, uint32_t bloc)
+{
+ if (inode != NULL
+ /* XXX: can't figure out why I did this... */
+ /* && inode == inode->fs->bootfile*/
+ )
+ bloc += inode->blocs[0].bloc;
+
+ return bloc;
+}
+
+static inode_t *fs_raw_get_special_inode (fs_t *fs, int type)
+{
+ const unsigned char *name;
+ inode_t *new, *parent, **inp;
+ int flags;
+
+ new = NULL;
+ name = NULL;
+ parent = NULL;
+ inp = NULL;
+ flags = 0;
+ switch (type) {
+ case FILE_ROOT:
+ if (fs->root != NULL) {
+ new = fs->root;
+ } else {
+ flags = INODE_TYPE_DIR;
+ parent = NULL;
+ name = NULL;
+ inp = &fs->root;
+ }
+ break;
+ case FILE_BOOT:
+ if (fs->bootfile != NULL) {
+ dprintf("bootfile already exists\n");
+ new = fs->bootfile;
+ } else {
+ new = part_private_get(fs_part(fs));
+ if (fs->bootdir == NULL) {
+ dprintf("Get boot directory\n");
+ fs->bootdir = fs_raw_get_special_inode(fs, FILE_BOOTDIR);
+ }
+ parent = fs->bootdir;
+ if (new != NULL) {
+ dprintf("Fix bootfile\n");
+ new->parent = parent;
+ new->fs = fs;
+ } else {
+ dprintf("New bootfile\n");
+ flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT;
+ name = "ofwboot";
+ inp = &fs->bootfile;
+ }
+ }
+ break;
+ case FILE_BOOTDIR:
+ if (fs->bootdir != NULL) {
+ new = fs->bootdir;
+ } else {
+ flags = INODE_TYPE_DIR;
+ parent = fs->root;
+ name = "boot";
+ inp = &fs->bootdir;
+ }
+ break;
+ default:
+ return NULL;
+ }
+ if (new == NULL) {
+ new = malloc(sizeof(inode_t));
+ memset(new, 0, sizeof(inode_t));
+ new->flags = flags;
+ new->parent = parent;
+ if (name != NULL)
+ new->name = strdup(name);
+ new->fs = fs;
+ *inp = new;
+ }
+
+ return new;
+}
+
+static fs_ops_t fs_ops_raw = {
+ &fs_raw_get_inode,
+ &fs_raw_put_inode,
+ &fs_raw_map_bloc,
+ &fs_raw_get_special_inode,
+};
+
+int fs_raw_set_bootfile (part_t *part,
+ uint32_t start_bloc, uint32_t start_offset,
+ uint32_t size_bloc, uint32_t size_offset)
+{
+ inode_t *new;
+
+ new = malloc(sizeof(inode_t));
+ if (new == NULL)
+ return -1;
+ DPRINTF("%s: pos %d %d size %d %d\n", __func__, start_bloc, start_offset,
+ size_bloc, size_offset);
+ memset(new, 0, sizeof(inode_t));
+ new->flags = INODE_TYPE_FILE | INODE_FLAG_EXEC | INODE_FLAG_BOOT;
+ new->name = "ofwboot";
+ new->blocs[0].bloc = start_bloc;
+ new->blocs[0].offset = start_offset;
+ new->size.bloc = size_bloc;
+ new->size.offset = size_offset;
+ new->nb_blocs = size_bloc;
+ part_private_set(part, new);
+
+ return 0;
+}
+
+int fs_raw_probe (part_t *part, uint32_t *size,
+ fs_ops_t **fs_ops, unsigned char **name,
+ unused void **private)
+{
+ DPRINTF("%s: %p map_bloc %p\n", __func__, &fs_ops_raw, &fs_raw_map_bloc);
+ *fs_ops = &fs_ops_raw;
+ *name = "Raw FS";
+ *size = part_size(part);
+
+ return FS_TYPE_RAW;
+}
diff --git a/src/libpart/apple.c b/src/libpart/apple.c
new file mode 100644
index 0000000..b006c61
--- /dev/null
+++ b/src/libpart/apple.c
@@ -0,0 +1,305 @@
+/*
+ * <apple.c>
+ *
+ * Open Hack'Ware BIOS Apple partition type management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "libpart.h"
+
+/* Apple partitions handler */
+#define HFS_BLOCSIZE (512)
+
+typedef struct Mac_head_t Mac_head_t;
+struct Mac_head_t {
+ /* 0x000 */
+ uint8_t signature[2];
+ uint16_t bloc_size;
+ uint32_t bloc_count;
+ /* 0x008 */
+ uint16_t dev_type;
+ uint16_t dev_ID;
+ uint32_t data;
+ /* 0x010 */
+ uint16_t driver_cnt;
+ uint8_t pad[428];
+ /* 0x01BE */
+ uint8_t part_table[0x40];
+ /* 0x1FE */
+ uint8_t magic[2];
+ /* 0x0200 */
+} __attribute__ ((packed));
+
+typedef struct Mac_driver_entry_t Mac_driver_entry_t;
+struct Mac_driver_entry_t {
+ uint32_t start;
+ uint16_t size;
+ uint16_t type;
+} __attribute__ ((packed));
+
+typedef enum Mac_partflags_t Mac_partflags_t;
+enum Mac_partflags_t {
+ MACPART_SPEC2 = 0x0100,
+ MACPART_SPEC1 = 0x0080,
+ MACPART_PIC = 0x0040,
+ MACPART_WRITABLE = 0x0020,
+ MACPART_READABLE = 0x0010,
+ MACPART_BOOTABLE = 0x0008,
+ MACPART_INUSE = 0x0004,
+ MACPART_ALLOCATED = 0x0002,
+ MACPART_VALID = 0x0001,
+};
+
+#define MAC_BOOTABLE_PART (MACPART_VALID | MACPART_INUSE | MACPART_BOOTABLE)
+
+typedef struct Mac_partmap_t Mac_partmap_t;
+struct Mac_partmap_t {
+ /* 0x000 */
+ uint8_t signature[2];
+ uint8_t res0[2];
+ uint32_t map_cnt;
+ /* 0x008 */
+ uint32_t start_bloc;
+ uint32_t bloc_cnt;
+ /* 0x010 */
+ uint8_t name[32];
+ /* 0x030 */
+ uint8_t type[32];
+ /* 0x050 */
+ uint32_t data_start;
+ uint32_t data_cnt;
+ /* 0x058 */
+ uint32_t flags;
+ uint32_t boot_start;
+ /* 0x060 */
+ uint32_t boot_size;
+ uint32_t boot_load;
+ /* 0x068 */
+ uint32_t boot_load2;
+ uint32_t boot_entry;
+ /* 0x070 */
+ uint32_t boot_entry2;
+ uint32_t boot_csum;
+ /* 0x078 */
+ uint8_t CPU[16];
+ /* 0x088 */
+ uint8_t boot_args[0x80];
+ /* 0x108 */
+ uint8_t pad0[0xC8];
+ /* 0x1D4 */
+ uint16_t ntype;
+ uint8_t ff[2];
+ /* 0x1D8 */
+ uint8_t pad1[0x24];
+ /* 0x1FC */
+ uint8_t mark[4];
+ /* 0x200 */
+} __attribute__ ((packed));
+
+int fs_raw_set_bootfile (part_t *part,
+ uint32_t start_bloc, uint32_t start_offset,
+ uint32_t size_bloc, uint32_t size_offset);
+
+part_t *Apple_probe_partitions (bloc_device_t *bd)
+{
+ unsigned char tmp[33], *name;
+ Mac_head_t *head;
+ Mac_partmap_t *partmap;
+ part_t *part, *boot_part;
+ unsigned char *type;
+ uint8_t *buffer;
+ uint32_t pos, bloc, start, count;
+ uint32_t bloc_size, flags;
+ int map_count, i, n, len;
+
+ part = NULL;
+ boot_part = NULL;
+ n = 1;
+ buffer = malloc(HFS_BLOCSIZE);
+ /* Read first sector */
+ bd_seek(bd, 0, 0);
+ if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) {
+ ERROR("Unable to read boot sector from boot device. Aborting...\n");
+ goto error;
+ }
+ head = (Mac_head_t *)buffer;
+ if (head->signature[0] != 'E' || head->signature[1] != 'R') {
+ // MSG("\rNo Apple boot bloc signature...\n");
+ goto error;
+ }
+ MSG("\rFound Apple partition map...\n");
+ bloc = 0;
+ bloc_size = bd_seclen(bd);
+ map_count = 1;
+#if 0
+ if (head->magic[0] == 0x55 && head->magic[1] == 0xAA) {
+ /* PREP boot image ! Must parse it as MS-DOS boot bloc */
+ ERROR("%s PREP head magic\n", __func__);
+ goto error;
+ }
+#endif
+ /* Partition table starts in sector 1 */
+ for (i = 1; i < (map_count + 1); i++) {
+ bloc = (i * HFS_BLOCSIZE) / bloc_size;
+ pos = (i * HFS_BLOCSIZE) % bloc_size;
+ DPRINTF("Check part %d of %d (%d %d %d)\n",
+ i, map_count, bloc, pos, bloc_size);
+ bd_seek(bd, bloc, pos);
+ if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) {
+ ERROR("%s sector_read failed (%d)\n", __func__, i);
+ goto error;
+ }
+ partmap = (Mac_partmap_t *)buffer;
+ if (partmap->signature[0] != 'P' || partmap->signature[1] != 'M' ) {
+ ERROR("%s bad partition signature (%c %c)\n",
+ __func__, partmap->signature[0], partmap->signature[1]);
+ goto error;
+ }
+ /* We found at least one Apple partition map,
+ * so we won't have to try to parse with other partition mappings.
+ */
+ for (type = partmap->type; (type - partmap->type) < 32; type++) {
+ if (*type != '\0')
+ break;
+ }
+ if (partmap->name[0] == '\0') {
+ sprintf(tmp, "part%d", i);
+ name = tmp;
+ } else {
+ name = partmap->name;
+ }
+ /* Regular Apple partition */
+ part = malloc(sizeof(part_t));
+ if (part == NULL) {
+ ERROR("%s: can't allocate partition\n", __func__);
+ return NULL;
+ }
+ memset(part, 0, sizeof(part_t));
+ part->start = partmap->start_bloc;
+ part->size = partmap->bloc_cnt;
+ part_set_blocsize(bd, part, HFS_BLOCSIZE);
+ len = 32 - (type - partmap->type);
+ if (len == 0) {
+ /* Place holder. Skip it */
+ DPRINTF("%s placeholder part\t%d\n", __func__, i);
+ } else if (strncmp("Apple_Void", type, 32) == 0) {
+ /* Void partition. Skip it */
+ DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type);
+ } else if (strncmp("Apple_Free", type, 32) == 0) {
+ /* Free space. Skip it */
+ DPRINTF("%s Free part (%d)\n", __func__, i);
+ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
+ part_register(bd, part, name);
+ } else if (strncmp("Apple_partition_map", type, 32) == 0 ||
+ strncmp("Apple_Partition_Map", type, 32) == 0
+#if 0 // Is this really used or is it just a mistake ?
+ || strncmp("Apple_patition_map", type, 32) == 0
+#endif
+ ) {
+ DPRINTF("%s Partition map\t%d [%s]\n", __func__, i, type);
+ /* We are in the partition map descriptor */
+ if (i == 1) {
+ /* Get the real map blocs count */
+ map_count = partmap->map_cnt;
+ DPRINTF("%s: map_count: %d\n", __func__, map_count);
+ } else {
+ /* Don't about about secondary partition map
+ * Seems to be used, at least on CDROMs, to describe
+ * the same partition map with bloc_size = 2048
+ */
+ }
+ part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
+ part_register(bd, part, name);
+ } else if (strncmp("Apple_Driver", type, 32) == 0 ||
+ strncmp("Apple_Driver43", type, 32) == 0 ||
+ strncmp("Apple_Driver43_CD", type, 32) == 0 ||
+ strncmp("Apple_Driver_ATA", type, 32) == 0 ||
+ strncmp("Apple_Driver_ATAPI", type, 32) == 0 ||
+ strncmp("Apple_FWDriver", type, 32) == 0 ||
+ strncmp("Apple_Driver_IOKit", type, 32) == 0) {
+ /* Drivers. don't care for now */
+ DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type);
+ } else if (strncmp("Apple_Patches", type, 32) == 0) {
+ /* Patches: don't care for now */
+ DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type);
+ } else if (strncmp("Apple_HFS", type, 32) == 0 ||
+ strncmp("Apple_MFS", type, 32) == 0 ||
+ strncmp("Apple_UFS", type, 32) == 0 ||
+ strncmp("Apple_PRODOS", type, 32) == 0 ||
+ strncmp("Apple_UNIX_SVR2", type, 32) == 0 ||
+ strncmp("Linux", type, 32) == 0 ||
+ strncmp("NetBSD/macppc", type, 32) == 0 ||
+ strncmp("Apple_boot", type, 32) == 0 ||
+ strncmp("Apple_bootstrap", type, 32) == 0 ||
+ strncmp("Apple_Bootstrap", type, 32) == 0) {
+ DPRINTF("%s Fs part\t%d [%s]\n", __func__, i, type);
+ /* Filesystems / boot partitions */
+ flags = partmap->flags;
+ start = partmap->start_bloc * HFS_BLOCSIZE;
+ count = partmap->bloc_cnt * HFS_BLOCSIZE;
+ if (partmap->boot_size == 0 || partmap->boot_load == 0) {
+ printf("Not a bootable partition %d %d (%p %p)\n",
+ partmap->boot_size, partmap->boot_load,boot_part, part);
+ if (boot_part == NULL)
+ boot_part = part;
+ part->flags = PART_TYPE_APPLE | PART_FLAG_FS;
+ } else {
+ part->boot_start.bloc = partmap->boot_start;
+ part->boot_start.offset = 0;
+ part->boot_size.bloc = partmap->boot_size / HFS_BLOCSIZE;
+#if 0
+ printf("%0x %0x %0x\n", partmap->boot_size, HFS_BLOCSIZE,
+ part->boot_size.bloc);
+#endif
+ part->boot_size.offset = (partmap->boot_size) % HFS_BLOCSIZE;
+ part->boot_load = partmap->boot_load;
+ part->boot_entry = partmap->boot_entry;
+ fs_raw_set_bootfile(part, part->boot_start.bloc,
+ part->boot_start.offset,
+ part->boot_size.bloc,
+ part->boot_size.offset);
+ boot_part = part;
+ part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT;
+ }
+ printf("Partition: %d %s st %0x size %0x",
+ i, name, partmap->start_bloc, partmap->bloc_cnt);
+#ifndef DEBUG
+ printf("\n");
+#endif
+ DPRINTF(" - %0x %0x %p %p\n",
+ partmap->boot_start, partmap->boot_size, part, part->fs);
+ DPRINTF(" boot %0x %0x load %0x entry %0x\n",
+ part->boot_start.bloc, part->boot_size.bloc,
+ part->boot_load, part->boot_entry);
+ DPRINTF(" load %0x entry %0x %0x\n",
+ partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE);
+ part_register(bd, part, name);
+ } else {
+ memcpy(tmp, type, 32);
+ tmp[32] = '\0';
+ ERROR("Unknown partition type [%s]\n", tmp);
+ }
+ }
+ error:
+ free(buffer);
+
+ return boot_part;
+
+}
diff --git a/src/libpart/core.c b/src/libpart/core.c
new file mode 100644
index 0000000..030104d
--- /dev/null
+++ b/src/libpart/core.c
@@ -0,0 +1,289 @@
+/*
+ * <part.c>
+ *
+ * Open Hack'Ware BIOS partitions management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "libpart.h"
+
+/* Bootable partitions detection and management */
+part_t *part_open (bloc_device_t *bd,
+ uint32_t start, uint32_t size, uint32_t spb)
+{
+ part_t *part;
+
+ if (bd_seek(bd, (start + size) * spb, 0) < 0)
+ return NULL;
+ part = malloc(sizeof(part_t));
+ if (part == NULL)
+ return NULL;
+ part->bd = bd;
+ part->start = start;
+ part->size = size;
+ part->spb = spb;
+
+ return part;
+}
+
+int part_seek (part_t *part, uint32_t bloc, uint32_t pos)
+{
+ if (bloc > part->size) {
+ ERROR("bloc: %d part size: %d %p\n", bloc, part->size, part);
+ return -1;
+ }
+ bloc += part->start;
+ if (part->spb != 0) {
+ bloc *= part->spb;
+ pos = pos % part->bloc_size;
+ } else {
+ pos += (bloc % part->bps) * part->bloc_size;
+ bloc /= part->bps;
+ }
+
+ return bd_seek(part->bd, bloc, pos);
+}
+
+int part_read (part_t *part, void *buffer, int len)
+{
+ return bd_read(part->bd, buffer, len);
+}
+
+int part_write (part_t *part, const void *buffer, int len)
+{
+ return bd_write(part->bd, buffer, len);
+}
+
+void part_close (part_t *part)
+{
+ part->size = 0;
+}
+
+uint32_t part_blocsize (part_t *part)
+{
+ return part->bloc_size;
+}
+
+uint32_t part_flags (part_t *part)
+{
+ return part->flags;
+}
+
+uint32_t part_size (part_t *part)
+{
+ return part->size;
+}
+
+fs_t *part_fs (part_t *part)
+{
+ return part->fs;
+}
+
+void part_private_set (part_t *part, void *private)
+{
+ part->private = private;
+}
+
+void *part_private_get (part_t *part)
+{
+ return part->private;
+}
+
+void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize)
+{
+ uint32_t seclen;
+
+ part->bloc_size = blocsize;
+ seclen = bd_seclen(bd);
+ if (blocsize < seclen) {
+ part->spb = 0;
+ part->bps = bd_seclen(bd) / part->bloc_size;
+ DPRINTF("%d part blocs in one sector (%d %d)\n", part->bps,
+ part->bloc_size, bd_seclen(bd));
+ } else {
+ part->spb = part->bloc_size / bd_seclen(bd);
+ part->bps = 0;
+ DPRINTF("%d sectors in one part bloc (%d %d)\n", part->spb,
+ part->bloc_size, bd_seclen(bd));
+ }
+}
+
+int part_register (bloc_device_t *bd, part_t *partition,
+ const unsigned char *name)
+{
+ part_t **cur;
+
+ DPRINTF("Register partition '%s'\n", name);
+ partition->bd = bd;
+ partition->next = NULL;
+ partition->name = strdup(name);
+ for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next)
+ continue;
+ *cur = partition;
+
+ return 0;
+}
+
+static inline int set_boot_part (bloc_device_t *bd, int partnum)
+{
+ part_t *cur;
+
+ cur = part_get(bd, partnum);
+ if (cur == NULL)
+ return -1;
+ bd_set_boot_part(bd, cur);
+
+ return 0;
+}
+
+part_t *part_get (bloc_device_t *bd, int partnum)
+{
+ part_t **listp, *cur;
+ int i;
+
+ listp = _bd_parts(bd);
+ cur = *listp;
+ for (i = 0; i != partnum; i++) {
+ if (cur == NULL)
+ break;
+ cur = cur->next;
+ }
+
+ return cur;
+}
+
+part_t *part_get_raw (bloc_device_t *bd)
+{
+ part_t *part;
+ uint32_t seclen;
+
+ part = malloc(sizeof(part_t));
+ part->start = 0;
+ seclen = bd_seclen(bd);
+ part->size = bd_maxbloc(bd);
+ if (seclen > 512) {
+ part->size *= seclen / 512;
+ } else {
+ part->size *= 512 / seclen;
+ }
+ part->boot_start.bloc = 0;
+ part->boot_start.offset = 0;
+ part->boot_size.bloc = part->size;
+ part->boot_size.offset = 0;
+ part->boot_load = 0;
+ part->boot_entry = 0;
+ part_set_blocsize(bd, part, 512);
+ part->bd = bd;
+ part->flags = PART_TYPE_RAW | PART_FLAG_BOOT;
+ part_register(bd, part, "Raw");
+
+ return part;
+}
+
+part_t *part_probe (bloc_device_t *bd, int set_raw)
+{
+ part_t *part0, *boot_part, **cur;
+
+ /* Register the 0 partition: raw partition containing the whole disk */
+ part0 = part_get_raw(bd);
+ /* Try to find a valid boot partition */
+ boot_part = Apple_probe_partitions(bd);
+ if (boot_part == NULL) {
+ boot_part = isofs_probe_partitions(bd);
+ if (boot_part == NULL && arch == ARCH_PREP)
+ boot_part = PREP_find_partition(bd);
+ if (boot_part == NULL && set_raw != 0) {
+ boot_part = part0;
+ set_boot_part(bd, 0);
+ }
+ }
+ /* Probe filesystem on each found partition */
+ for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) {
+ const unsigned char *map, *type;
+ switch ((*cur)->flags & 0x0F) {
+ case PART_TYPE_PREP:
+ map = "PREP";
+ break;
+ case PART_TYPE_APPLE:
+ map = "Apple";
+ break;
+ case PART_TYPE_ISO9660:
+ map = "ISO9660";
+ break;
+ default:
+ map = "Raw";
+ break;
+ }
+ switch ((*cur)->flags & 0xF0) {
+ case PART_FLAG_DUMMY:
+ type = "dummy";
+ break;
+ case PART_FLAG_DRIVER:
+ type = "driver";
+ break;
+ case PART_FLAG_PATCH:
+ type = "patches";
+ break;
+ case PART_FLAG_FS:
+ type = "filesystem";
+ break;
+ default:
+ type = "unknown";
+ break;
+ }
+ DPRINTF("Probe filesystem on %s %s partition '%s' %s\n",
+ type, map, (*cur)->name,
+ ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "");
+ if (((*cur)->flags) & PART_FLAG_FS) {
+ if (((*cur)->flags) & PART_FLAG_BOOT)
+ (*cur)->fs = fs_probe(*cur, 1);
+ else
+ (*cur)->fs = fs_probe(*cur, 0);
+ } else {
+ (*cur)->fs = fs_probe(*cur, 2);
+ }
+ if (((*cur)->flags) & PART_FLAG_BOOT) {
+ bd_set_boot_part(bd, *cur);
+ fs_get_bootfile((*cur)->fs);
+ }
+ }
+ DPRINTF("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs,
+ part_fs(boot_part), part0);
+
+ return boot_part;
+}
+
+int part_set_boot_file (part_t *part, uint32_t start, uint32_t offset,
+ uint32_t size)
+{
+ part->boot_start.bloc = start;
+ part->boot_start.offset = offset;
+ part->boot_size.bloc = size;
+ part->boot_size.offset = 0;
+ part->boot_load = 0;
+ part->boot_entry = 0;
+
+ return 0;
+}
+
+unsigned int part_get_entry (part_t *part)
+{
+ return part->boot_entry;
+}
diff --git a/src/libpart/isofs.c b/src/libpart/isofs.c
new file mode 100644
index 0000000..466a2e7
--- /dev/null
+++ b/src/libpart/isofs.c
@@ -0,0 +1,257 @@
+/*
+ * <isofs.c>
+ *
+ * Open Hack'Ware BIOS ISOFS partition type management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "libpart.h"
+
+/* ISO FS partitions handlers */
+#define ISOFS_BLOCSIZE (2048)
+
+/* Generic ISO fs descriptor */
+typedef struct isofs_desc_t isofs_desc_t;
+struct isofs_desc_t {
+ uint8_t type;
+ uint8_t ID[5];
+ uint8_t version;
+ uint8_t data[2041];
+} __attribute__ ((packed));
+
+typedef struct iso_primary_desc_t iso_primary_desc_t;
+struct iso_primary_desc_t {
+ uint8_t type;
+ uint8_t ID[5];
+ uint8_t version;
+ uint8_t pad0;
+ uint8_t system_id[32];
+ uint8_t volume_id[32];
+ uint8_t pad1[8];
+ uint32_t volume_size;
+} __attribute__ ((packed));
+
+/* The only descriptor we're interrested in here
+ * is El-torito boot descriptor
+ */
+typedef struct isofs_bootdesc_t isofs_bootdesc_t;
+struct isofs_bootdesc_t {
+ uint8_t type;
+ uint8_t ID[5];
+ uint8_t version;
+ uint8_t sys_ID[32];
+ uint8_t pad[32];
+ uint32_t catalog;
+ uint8_t data[1973];
+} __attribute__ ((packed));
+
+#define ISO_BOOTABLE 0x88
+enum {
+ ISOBOOT_IX86 = 0,
+ ISOBOOT_PPC = 1,
+ ISOBOOT_MAC = 2,
+};
+
+enum {
+ ISOMEDIA_NOEMUL = 0,
+ ISOMEDIA_FL12 = 1,
+ ISOMEDIA_FL144 = 2,
+ ISOMEDIA_FL288 = 3,
+ ISOMEDIA_HD = 4,
+};
+
+typedef struct isofs_validdesc_t isofs_validdesc_t;
+struct isofs_validdesc_t {
+ uint8_t ID;
+ uint8_t arch;
+ uint8_t pad[2];
+ uint8_t name[24];
+ uint8_t csum[2];
+ uint16_t key;
+} __attribute__ ((packed));
+
+typedef struct isofs_bootcat_t isofs_bootcat_t;
+struct isofs_bootcat_t {
+ uint8_t bootable;
+ uint8_t media;
+ uint8_t segment[2];
+ uint8_t sys_type;
+ uint8_t pad;
+ uint16_t nsect;
+ uint32_t offset;
+ uint8_t data[20];
+} __attribute__ ((packed));
+
+part_t *isofs_probe_partitions (bloc_device_t *bd)
+{
+ unsigned char name[32];
+ void *buffer;
+ union {
+ isofs_desc_t desc;
+ isofs_bootdesc_t bootdesc;
+ iso_primary_desc_t primdesc;
+ } *desc;
+ isofs_validdesc_t *valid;
+ isofs_bootcat_t *bootcat;
+ part_t *part;
+ uint32_t boot_desc;
+ uint32_t nsect, bloc, offset, length;
+ int i, end_reached;
+
+ part = NULL;
+ buffer = malloc(ISOFS_BLOCSIZE);
+ end_reached = 0;
+ desc = buffer;
+ boot_desc = -1;
+ /* The descriptors start at offset 0x8000 */
+ for (bloc = 0x8000 / ISOFS_BLOCSIZE; end_reached == 0; bloc++) {
+ bd_seek(bd, bloc, 0);
+ if (bd_read(bd, buffer, ISOFS_BLOCSIZE) < 0) {
+ ERROR("%s bloc_read %d failed\n", __func__, bloc);
+ goto error;
+ }
+ if (strncmp("CD001", desc->desc.ID, 5) != 0) {
+ // MSG("\rNo ISO9660 signature\n");
+ goto error;
+ }
+ /* We found at least one valid descriptor */
+ switch (desc->desc.type) {
+ case 0x00:
+ /* El-torito descriptor, great ! */
+ DPRINTF("El-torito descriptor: %08x %d\n", desc->bootdesc.catalog,
+ (char *)&desc->bootdesc.catalog - (char *)desc);
+ boot_desc = get_le32(&desc->bootdesc.catalog);
+ break;
+ case 0x01:
+ /* ISOFS primary descriptor */
+ DPRINTF("ISOFS primary descriptor (%d %d)\n",
+ get_le32(&desc->primdesc.volume_size) * 2048,
+ get_le32(&desc->primdesc.volume_size));
+ break;
+ case 0x02:
+ /* ISOFS suplementary descriptor */
+ DPRINTF("ISOFS suplementary descriptor\n");
+ break;
+ case 0xFF:
+ /* End of descriptor list */
+ DPRINTF("End of descriptor list\n");
+ end_reached = 1;
+ break;
+ }
+ }
+ if (boot_desc != (uint32_t)(-1)) {
+ /* Find the validation descriptor */
+ bd_seek(bd, boot_desc, 0);
+ for (i = 0; i < (ISOFS_BLOCSIZE / 64); i++) {
+ DPRINTF("ISO catalog...\n");
+ bd_read(bd, buffer, 64);
+ valid = buffer;
+#if 1
+ if (valid->ID != 0x01 || get_le16(&valid->key) != 0xAA55) {
+ ERROR("ISO catalog with invalid ID/key: %x %x\n",
+ valid->ID, valid->key);
+ continue;
+ }
+#endif
+#if 0
+#if defined (__i386__)
+ if (valid->arch != ISOBOOT_IX86) {
+ ERROR("ISO catalog not for x86: %d\n", valid->arch);
+ continue;
+ }
+#elif defined (__powerpc__)
+ if (valid->arch != ISOBOOT_PPC && valid->arch != ISOBOOT_MAC) {
+ ERROR("ISO catalog not for PPC: %d\n", valid->arch);
+ continue;
+ }
+#else
+ ERROR("Unknown host architecture !\n");
+ continue;
+#endif
+#endif
+ bootcat = (void *)(valid + 1);
+ if (bootcat->bootable != ISO_BOOTABLE) {
+ ERROR("Non bootable ISO catalog\n");
+ continue;
+ }
+ nsect = get_le16(&bootcat->nsect);
+ switch (bootcat->media) {
+ case ISOMEDIA_NOEMUL:
+ length = nsect * ISOFS_BLOCSIZE;
+ dprintf("No emulation\n");
+ break;
+ case ISOMEDIA_FL12:
+ length = 1200 * 1024;
+ dprintf("1.2 MB floppy\n");
+ break;
+ case ISOMEDIA_FL144:
+ length = 1440 * 1024;
+ dprintf("1.44 MB floppy\n");
+ break;
+ case ISOMEDIA_FL288:
+ length = 2880 * 1024;
+ dprintf("2.88 MB floppy\n");
+ break;
+ case ISOMEDIA_HD:
+ length = nsect * ISOFS_BLOCSIZE;
+ dprintf("HD image\n");
+ break;
+ default:
+ ERROR("Unknown media type: %d\n", bootcat->media);
+ continue;
+ }
+ offset = get_le32(&bootcat->offset);
+ /* Register boot disc */
+ part = malloc(sizeof(part_t));
+ part->bd = bd;
+ part_set_blocsize(bd, part, ISOFS_BLOCSIZE);
+ part->start = offset;
+ part->size = (length + ISOFS_BLOCSIZE - 1) / ISOFS_BLOCSIZE;
+ part->boot_start.bloc = 0;
+ part->boot_start.offset = 0;
+ part->boot_size.bloc = length / ISOFS_BLOCSIZE;
+ part->boot_size.offset = length % ISOFS_BLOCSIZE;
+ part->boot_load = 0;
+ part->boot_entry = 0;
+ if (valid->name[0] == '\0') {
+ strcpy(name, "ISOFS");
+ } else {
+ memcpy(name, valid->name, sizeof(valid->name));
+ name[sizeof(valid->name)] = '\0';
+ }
+ printf("Partition '%s': %p st %0x size %0x %d\n",
+ name, part, offset, length, bootcat->media);
+ printf(" boot %0x %0x load %0x entry %0x\n",
+ part->boot_start.bloc, part->boot_size.bloc,
+ part->boot_load, part->boot_entry);
+ part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT;
+ part_register(bd, part, name);
+ fs_raw_set_bootfile(part, part->boot_start.bloc,
+ part->boot_start.offset,
+ part->boot_size.bloc,
+ part->boot_size.offset);
+ break;
+ }
+ }
+error:
+ free(buffer);
+
+ return part;
+}
diff --git a/src/libpart/libpart.h b/src/libpart/libpart.h
new file mode 100644
index 0000000..b8c38c9
--- /dev/null
+++ b/src/libpart/libpart.h
@@ -0,0 +1,66 @@
+/*
+ * <libpart.h>
+ *
+ * Open Hack'Ware BIOS partitions management definitions
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#if !defined (__OHW_LIBPART_H__)
+#define __OHW_LIBPART_H__
+
+/* LBA for IDE is 48 bits long.
+ * For now, I'll use 32 bits to store bloc nr
+ * and 32 bits to store offsets in blocs and will only handle LBA 28.
+ * So, I'll be affected with the well known 128 GB disk barrier bug...
+ */
+
+struct part_t {
+ bloc_device_t *bd;
+ uint32_t start; /* Partition first bloc */
+ uint32_t size; /* Partition size, in blocs */
+ uint32_t spb;
+ uint32_t bps;
+ uint32_t flags;
+
+ uint32_t bloc_size; /* Bloc size (may be != bd->seclen) */
+ /* XXX: broken: to be reworked */
+ pos_t boot_start; /* Boot program start bloc & offset */
+ pos_t boot_size; /* Boot program size */
+ uint32_t boot_load; /* Boot program address load */
+ uint32_t boot_entry; /* Boot program entry point */
+
+ unsigned char *name;
+ inode_t *boot_file;
+ fs_t *fs;
+
+ void *private;
+
+ part_t *next;
+ part_t *bnext;
+};
+
+int part_register (bloc_device_t *bd, part_t *partition,
+ const unsigned char *name);
+void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize);
+void part_private_set (part_t *part, void *private);
+void *part_private_get (part_t *part);
+
+part_t *PREP_find_partition (bloc_device_t *bd);
+part_t *Apple_probe_partitions (bloc_device_t *bd);
+part_t *isofs_probe_partitions (bloc_device_t *bd);
+
+#endif /* !defined (__OHW_LIBPART_H__) */
diff --git a/src/libpart/prep.c b/src/libpart/prep.c
new file mode 100644
index 0000000..b3bcdb9
--- /dev/null
+++ b/src/libpart/prep.c
@@ -0,0 +1,216 @@
+/*
+ * <prep.c>
+ *
+ * Open Hack'Ware PREP BIOS partition type management
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+#include "libpart.h"
+
+/* PREP image management */
+typedef struct MSDOS_part_t MSDOS_part_t;
+struct MSDOS_part_t {
+ uint8_t boot_ind;
+ uint8_t start_head;
+ uint8_t start_sect;
+ uint8_t start_cyl;
+ uint8_t sys_ind;
+ uint8_t end_head;
+ uint8_t end_sect;
+ uint8_t end_cyl;
+ uint32_t LBA_start;
+ uint32_t LBA_end;
+} __attribute__ ((packed));
+
+part_t *PREP_find_partition (bloc_device_t *bd)
+{
+ MSDOS_part_t *p;
+ part_t *part;
+ uint8_t *buffer;
+ uint32_t boot_offset, boot_size;
+ int i;
+
+ part = NULL;
+ buffer = malloc(0x200);
+ bd_seek(bd, 0, 0);
+ if (bd_read(bd, buffer, 0x200) < 0) {
+ ERROR("Unable to read boot sector from boot device. Aborting...\n");
+ goto error;
+ }
+ if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) {
+ ERROR("No MSDOS signature (%x %x %x %x)\n",
+ buffer[0x000], buffer[0x001], buffer[0x1FE], buffer[0x1FF]);
+ goto error;
+ }
+ for (i = 0; i < 4; i++) {
+ p = (void *)(&buffer[0x1BE + (0x10 * i)]);
+ DPRINTF("partition %d: %x is %sbootable - ", i, p->boot_ind,
+ (p->boot_ind & 0x80) ? "" : "not ");
+ DPRINTF("start %0x end %0x type %x\n",
+ get_le32(&p->LBA_start), get_le32(&p->LBA_end), p->sys_ind);
+#if 0
+ if (p->boot_ind != 0x80)
+ continue;
+#endif
+ switch (p->sys_ind) {
+ case 0x07: /* HPFS/NTFS */
+ goto register_nonboot;
+ case 0x08: /* AIX */
+ goto register_nonboot;
+ case 0x09: /* AIX bootable */
+ /* Not supported by now */
+ break;
+ case 0x0A: /* OS/2 boot manager */
+ /* Not supported by now */
+ break;
+ case 0x41: /* PREP boot */
+ part = malloc(sizeof(part_t));
+ memset(part, 0, sizeof(part_t));
+ part->bd = bd;
+ part_set_blocsize(bd, part, 0x200);
+ /* Convert start and size into LBA */
+ if ((p->start_head != 0 || p->start_cyl != 0 ||
+ p->start_sect != 0) && p->LBA_start == 0) {
+ DPRINTF("start: use CHS\n");
+ part->start = bd_CHS2sect(bd, p->start_cyl,
+ p->start_head,
+ p->start_sect);
+ } else {
+ DPRINTF("start: use LBA\n");
+ part->start = get_le32(&p->LBA_start);
+ }
+ if ((p->end_head != 0 || p->end_cyl != 0 ||
+ p->end_sect != 0) && p->LBA_end == 0) {
+ DPRINTF("end: use CHS\n");
+ part->size = bd_CHS2sect(bd, p->end_cyl,
+ p->end_head, p->end_sect);
+ } else {
+ DPRINTF("end: use LBA\n");
+ part->size = get_le32(&p->LBA_end);
+ }
+ /* XXX: seems that some (AIX !)
+ * code the size here instead of partition end
+ */
+ if (part->size > part->start)
+ part->size -= part->start;
+ DPRINTF("LBA: start %0x size: %0x\n", part->start, part->size);
+ /* Now, find and check boot record */
+ part_seek(part, 0, 0);
+ if (bd_read(bd, buffer, part->bloc_size) < 0) {
+ ERROR("%s sector_read failed (%d)\n", __func__, i);
+ freep(&part);
+ goto error;
+ }
+#if 0
+ if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) {
+ ERROR("No MSDOS signature on PREP boot record\n");
+ freep(&part);
+ goto error;
+ }
+#endif
+ boot_offset = get_le32(buffer);
+ boot_size = get_le32(buffer + 4);
+ if ((boot_offset & 3) || /*(boot_size & 3) ||*/
+ boot_offset == 0 || boot_size == 0) {
+ DPRINTF("Suspicious PREP boot parameters: %08x %08x %08x %08x\n",
+ part->start, part->start * 0x200, boot_offset, boot_size);
+#if 0
+ freep(&part);
+ goto error;
+#else
+ /* IBM boot blocs respect the norm better than others... */
+ part->start++;
+ part_seek(part, 0, 0);
+ if (bd_read(bd, buffer, part->bloc_size) < 0) {
+ ERROR("%s sector_read failed (%d)\n", __func__, i);
+ freep(&part);
+ goto error;
+ }
+ boot_offset = get_le32(buffer);
+ boot_size = get_le32(buffer + 4);
+#endif
+ }
+ DPRINTF("PREP boot parameters: %08x %08x %08x %08x\n",
+ part->start, part->start * 0x200, boot_offset, boot_size);
+ if (boot_size > (part->size * part->bloc_size)) {
+ ERROR("PREP boot image greater than boot partition: %0x %0x\n",
+ boot_size, part->size * part->bloc_size);
+#if 0
+ freep(&part);
+ goto error;
+#endif
+ }
+ part->boot_start.bloc = 0;
+ part->boot_start.offset = 0;
+ part->boot_size.bloc = boot_size / part->bloc_size;
+ part->boot_size.offset = boot_size % part->bloc_size;
+ part->boot_load = 0;
+ part->boot_entry = boot_offset - part->bloc_size;
+ part->flags = PART_TYPE_PREP | PART_FLAG_BOOT;
+ part_register(bd, part, "PREP boot");
+ fs_raw_set_bootfile(part, part->boot_start.bloc,
+ part->boot_start.offset,
+ part->boot_size.bloc,
+ part->boot_size.offset);
+ break;
+ case 0x63: /* GNU Hurd */
+ goto register_nonboot;
+ case 0x83: /* Linux */
+ goto register_nonboot;
+ case 86 ... 87: /* NFTS volume set */
+ /* Not supported by now */
+ break;
+ case 0x8E: /* Linux LVM */
+ /* Not supported by now */
+ break;
+ case 0x96: /* AIX seems to use this to identify ISO 9660 'partitions' */
+ break;
+ case 0xA5: /* FreeBSD */
+ goto register_nonboot;
+ case 0xA6: /* OpenBSD */
+ goto register_nonboot;
+ case 0xA7: /* NeXTSTEP */
+ goto register_nonboot;
+ case 0xA8: /* Darwin UFS */
+ goto register_nonboot;
+ case 0xA9: /* NetBSD */
+ goto register_nonboot;
+ case 0xAB: /* Darwin boot */
+ /* Not supported by now */
+ break;
+ case 0xBE: /* Solaris boot */
+ /* Not supported by now */
+ break;
+ case 0xEB: /* BeOS fs */
+ goto register_nonboot;
+ case 0xFD: /* Linux RAID */
+ /* Not supported by now */
+ break;
+ default:
+ break;
+ register_nonboot:
+ break;
+ }
+ }
+ error:
+ free(buffer);
+
+ return part;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..081f517
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,558 @@
+/*
+ * Open Hack'Ware BIOS main.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+/*
+ * Status:
+ * - boots Linux 2.4 from floppy and IDE
+ * - preliminary residual data support
+ * - can find PREP boot images and Apple boot blocs
+ *
+ * TODO:
+ * 1/ Cleanify boot partitions:
+ * allow more than one boot bloc + fix PREP load again
+ * 2/ add ATAPI driver
+ * 3/ add a prompt to let the user choose its boot device / PREP image
+ * 4/ add POST
+ * 5/ add VGA driver (SVGA/VESA ?)
+ * 6/ add a user accessible setup
+ * 7/ add netboot
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+
+#include "char.h"
+
+//#define DEBUG_MEMORY 1
+
+/* Version string */
+const unsigned char *BIOS_str =
+"PPC Open Hack'Ware BIOS for qemu version " BIOS_VERSION "\n";
+const unsigned char *copyright = "Copyright 2003-2005 Jocelyn Mayer\n";
+
+uint32_t isa_io_base = ISA_IO_BASE;
+
+/* Temporary hack: boots only from floppy */
+int boot_device = 'a';
+
+/* Some other PPC helper */
+/* Setup a memory mapping, using BAT0
+ * BATU:
+ * BEPI : bloc virtual address
+ * BL : area size bits (128 kB is 0, 256 1, 512 3, ...
+ * Vs/Vp
+ * BATL:
+ * BPRN : bloc real address align on 4MB boundary
+ * WIMG : cache access mode : not used
+ * PP : protection bits
+ */
+static void BAT_setup (int nr, uint32_t virtual, uint32_t physical,
+ uint32_t size, int Vs, int Vp, int PP)
+{
+ uint32_t sz_bits, tmp_sz, align, tmp;
+
+ sz_bits = 0;
+ align = 131072;
+ DPRINTF("Set BAT %d v=%0x p=%0x size=%0x\n", nr, virtual, physical, size);
+ if (size < 131072)
+ size = 131072;
+ for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) {
+ sz_bits = (sz_bits << 1) + 1;
+ align = align << 1;
+ }
+ tmp = virtual & ~(align - 1); /* Align virtual area start */
+ tmp |= sz_bits << 2; /* Fix BAT size */
+ tmp |= Vs << 1; /* Supervisor access */
+ tmp |= Vp; /* User access */
+ DPRINTF("Set BATU%d to %0x\n", nr, tmp);
+ switch (nr) {
+ case 0:
+ /* Setup IBAT0U */
+ MTSPR(528, tmp);
+ /* Setup DBAT0U */
+ MTSPR(536, tmp);
+ break;
+ case 1:
+ /* Setup DBAT1U */
+ MTSPR(538, tmp);
+ break;
+ case 2:
+ /* Setup DBAT2U */
+ MTSPR(540, tmp);
+ break;
+ }
+ tmp = physical & ~(align - 1); /* Align physical area start */
+ tmp |= 0; /* Don't care about WIMG */
+ tmp |= PP; /* Protection */
+ DPRINTF("Set BATL%d to %0x\n", nr, tmp);
+ switch (nr) {
+ case 0:
+ /* Setup IBAT0L */
+ MTSPR(529, tmp);
+ /* Setup DBAT0L */
+ MTSPR(537, tmp);
+ break;
+ case 1:
+ /* Setup DBAT1L */
+ MTSPR(539, tmp);
+ break;
+ case 2:
+ /* Setup DBAT2L */
+ MTSPR(541, tmp);
+ break;
+ }
+}
+
+typedef struct PPC_CPU_t {
+ uint32_t pvr;
+ uint32_t mask;
+ unsigned char *name;
+} PPC_CPU_t;
+
+static const PPC_CPU_t CPU_PPC[] = {
+ /* For now, know only G3 */
+ {
+ 0x00080000,
+ 0xFFFF0000,
+ "PowerPC,G3",
+ },
+ {
+ 0x00000000,
+ 0x00000000,
+ "PowerPC,generic",
+ },
+};
+
+static const unsigned char *CPU_get_name (uint32_t pvr)
+{
+ int i;
+
+ for (i = 0;; i++) {
+ if ((pvr & CPU_PPC[i].mask) == CPU_PPC[i].pvr)
+ return CPU_PPC[i].name;
+ }
+
+ return NULL;
+}
+
+#define TB_FREQ (10 * 1000 * 1000) // XXX: should calibrate
+void usleep (uint32_t usec)
+{
+#if 0 // Buggy: makes OpenDarwin crash (!)
+ uint32_t tb0[2], tb1[2], count[2];
+ uint32_t tpu;
+ int wrap = 0;
+
+ tpu = TB_FREQ / (1000 * 1000);
+ mul64(count, usec, tpu);
+ mftb(tb0);
+ add64(count, count, tb0);
+ if (count[0] < tb0[0])
+ wrap = 1;
+ while (1) {
+ mftb(tb1);
+ if (wrap == 1 && tb1[0] < tb0[0])
+ wrap = 0;
+ if (wrap == 0 &&
+ (tb1[0] > count[0] ||
+ (tb1[0] == count[0] && tb1[1] >= count[1])))
+ break;
+ tb0[0] = tb1[0];
+ }
+#else
+ uint32_t i, j;
+
+ for (i = 0; i < (usec >> 16) * 50; i++) {
+ for (j = 0; j < (usec & 0xFFFF) * 50; j++) {
+ continue;
+ }
+ }
+#endif
+}
+
+void sleep (int sec)
+{
+ int i;
+
+ for (i = 0; i < sec; i++)
+ usleep(1 * 1000 * 1000);
+}
+
+/* Stolen from Linux code */
+#define CRCPOLY_LE 0xedb88320
+
+uint32_t crc32 (uint32_t crc, const uint8_t *p, int len)
+{
+ int i;
+
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ }
+
+ return crc;
+}
+
+/* Fake write */
+int write (unused int fd, unused const char *buf, int len)
+{
+ return len;
+}
+
+/* BIOS library functions */
+/* Fake memory management (to be removed) */
+void *mem_align (unused int align)
+{
+ return malloc(0);
+}
+#if 1
+void free (unused void *p)
+{
+}
+#endif
+
+void freep (void *p)
+{
+ void **_p = p;
+
+ free(*_p);
+ *_p = NULL;
+}
+
+static inline int in_area (const void *buf,
+ const void *start, const void *end)
+{
+ return buf >= start && buf <= end;
+}
+
+#ifdef DEBUG_MEMORY
+static void *load_dest, *load_end;
+static int relax_check;
+#endif
+
+void set_loadinfo (unused void *load_base, unused uint32_t size)
+{
+#ifdef DEBUG_MEMORY
+ load_dest = load_base;
+ load_end = (char *)load_dest + size;
+#endif
+}
+
+void set_check (unused int do_it)
+{
+#ifdef DEBUG_MEMORY
+ relax_check = do_it == 0 ? 1 : 0;
+#endif
+}
+
+void check_location (unused const void *buf,
+ unused const char *func,
+ unused const char *name)
+{
+#ifdef DEBUG_MEMORY
+ if (relax_check != 0)
+ return;
+ if (!in_area(buf, &_data_start, &_data_end) &&
+ !in_area(buf, &_OF_vars_start, &_OF_vars_end) &&
+ !in_area(buf, &_sdata_start, &_sdata_end) &&
+ !in_area(buf, &_ro_start, &_ro_end) &&
+ !in_area(buf, &_RTAS_data_start, &_RTAS_data_end) &&
+ !in_area(buf, &_bss_start, &_bss_end) &&
+ !in_area(buf, &_ram_start, malloc_base) &&
+ /* Let's say 64 kB of stack is enough */
+ !in_area(buf, (void *)0x5ff0000, (void *)0x6000000) &&
+ !in_area(buf, load_dest, load_end) &&
+ /* IO area */
+ !in_area(buf, (void *)0x80000000, (void *)0x88000000)) {
+ printf("**************************************************************"
+ "**************\n");
+ printf("%s: %s: %p\n", func, name, buf);
+ printf(" data: %p %p\n", &_data_start, &_data_end);
+ printf(" OF_vars: %p %p\n", &_OF_vars_start, &_OF_vars_end);
+ printf(" sdata: %p %p\n", &_sdata_start, &_sdata_end);
+ printf(" rodata: %p %p\n", &_ro_start, &_ro_end);
+ printf(" RTAS_data: %p %p\n", &_RTAS_data_start, &_RTAS_data_end);
+ printf(" bss: %p %p\n", &_bss_start, &_bss_end);
+ printf(" mallocated: %p %p\n", &_ram_start, malloc_base);
+ printf(" stack : %p %p\n", (void *)0x5ff0000,
+ (void *)0x6000000);
+ printf(" load image: %p %p\n", load_dest, load_end);
+ printf("**************************************************************"
+ "**************\n");
+ bug();
+ }
+#endif
+}
+
+/* No overflow check here... */
+long strtol (const unsigned char *str, unsigned char **end, int base)
+{
+ long ret = 0, tmp, sign = 1;
+
+ check_location(str, __func__, "str");
+ if (base < 0 || base > 36)
+ return 0;
+ for (; *str == ' '; str++)
+ continue;
+ if (*str == '-') {
+ sign = -1;
+ str++;
+ }
+ for (;; str++) {
+ tmp = *str;
+ if (tmp < '0')
+ break;
+ if (base <= 10) {
+ if (tmp > '0' + base - 1)
+ break;
+ tmp -= '0';
+ } else {
+ if (tmp <= '9') {
+ tmp -= '0';
+ } else {
+ tmp &= ~0x20;
+ if (tmp < 'A' || tmp > 'A' + base - 11)
+ break;
+ tmp += 10 - 'A';
+ }
+ }
+ ret = (ret * base) + tmp;
+ }
+ if (sign == -1)
+ ret = -ret;
+ if (end != NULL)
+ *end = (unsigned char *)str;
+
+ return ret;
+}
+
+nvram_t *nvram;
+int arch;
+/* HACK... */
+int vga_width, vga_height, vga_depth;
+
+part_t *boot_part;
+
+/* XXX: to fix */
+void mm_init (uint32_t memsize);
+int page_descrs_init (void);
+
+int main (void)
+{
+ bloc_device_t *bd;
+ pci_host_t *pci_main;
+ void *res, *bootinfos;
+ void *boot_image, *cmdline, *ramdisk;
+ void *load_base, *load_entry, *last_alloc, *load_end;
+ uint32_t memsize, boot_image_size, cmdline_size, ramdisk_size;
+ uint32_t boot_base, boot_nb;
+ int boot_device;
+
+ /* Retrieve NVRAM configuration */
+ nvram_retry:
+ nvram = NVRAM_get_config(&memsize, &boot_device,
+ &boot_image, &boot_image_size,
+ &cmdline, &cmdline_size,
+ &ramdisk, &ramdisk_size);
+ if (nvram == NULL) {
+ /* Retry with another isa_io_base */
+ if (isa_io_base == 0x80000000) {
+ isa_io_base = 0xF2000000;
+ goto nvram_retry;
+ }
+ ERROR("Unable to load configuration from NVRAM. Aborting...\n");
+ return -1;
+ }
+#if 1
+ mm_init(memsize);
+#endif
+#if 1
+ page_descrs_init();
+#endif
+#ifdef USE_OPENFIRMWARE
+ OF_init();
+#endif
+ pci_main = pci_init();
+ if (pci_main == NULL)
+ ERROR("Unable to configure PCI\n");
+#ifdef USE_OPENFIRMWARE
+ /* XXX: this mess needs a serious cleanup... */
+ {
+ const unsigned char *cpu_name;
+ uint32_t pvr = mfpvr();
+
+ cpu_name = CPU_get_name(pvr);
+ OF_register_cpu(cpu_name, 0, pvr,
+ 200 * 1000 * 1000, 200 * 1000 * 1000,
+ 100 * 1000 * 1000, 10 * 1000 * 1000,
+ 0x0092);
+ }
+ OF_register_memory(memsize, 512 * 1024 /* TOFIX */);
+ /* Claim memory used by the BIOS */
+ OF_claim_virt(0x05800000, 0x00080000, NULL);
+ OF_register_bootargs(cmdline);
+#endif
+ if (isa_io_base == 0x80000000 || 1) {
+ pc_serial_register(0x3F8);
+#ifdef USE_OPENFIRMWARE
+ OF_register_bus("isa", isa_io_base, "ISA");
+ OF_register_serial("isa", "com1", 0x3F8, 4);
+ OF_register_stdio("com1", "com1");
+#endif
+ }
+#ifdef USE_OPENFIRMWARE
+ RTAS_init();
+#endif
+ /* Get a console */
+ console_open();
+ printf("%s", BIOS_str);
+ printf("Build " stringify(BUILD_DATE) " " stringify(BUILD_TIME) "\n");
+ printf("%s\n", copyright);
+ printf("Memory size: %d MB. \nBooting from device %c\n",
+ memsize >> 20, boot_device);
+ vga_puts(BIOS_str);
+ vga_puts("Build " stringify(BUILD_DATE) " " stringify(BUILD_TIME) "\n");
+ vga_puts(copyright);
+ vga_puts("\n");
+
+ /* QEMU is quite incoherent: d is cdrom, not second drive */
+ if (boot_device == 'd')
+ boot_device = 'e';
+ /* Open boot device */
+ boot_part = bd_probe(boot_device);
+ if (boot_device == 'm') {
+ bd = bd_get('m');
+ if (bd == NULL) {
+ ERROR("Unable to get memory bloc device\n");
+ return -1;
+ }
+ printf("boot device: %p image %p size %d\n",
+ bd, boot_image, boot_image_size);
+ bd_ioctl(bd, MEM_SET_ADDR, boot_image);
+ bd_ioctl(bd, MEM_SET_SIZE, &boot_image_size);
+ boot_part = part_probe(bd, 1);
+ bd_put(bd);
+ printf("boot device: %p\n", bd);
+ }
+ if (boot_part == NULL) {
+ ERROR("Found no boot partition!\n");
+ return -1;
+ }
+ ERROR("Found boot partition : %p %p\n", boot_part, part_fs(boot_part));
+ mem_align(0x00001000);
+ res = malloc(0x4000);
+ last_alloc = malloc(0);
+ boot_base = 0;
+ boot_nb = 0;
+ DPRINTF("Load base: %p - residual data: %p %p %p %p\n",
+ load_base, res, last_alloc, boot_part, part_fs(boot_part));
+ /* Load the whole boot image */
+ if (bootfile_load((void *)&load_base, (void *)&load_entry,
+ (void *)&load_end, boot_part, -1, NULL, 0) < 0) {
+ printf("Unable to load boot file\n");
+ return -1;
+ }
+#ifdef USE_OPENFIRMWARE
+ DPRINTF("Boot parameters: res: %p load_base: %p OF: %p entry: %p\n",
+ res, load_base, &OF_entry, load_entry);
+#else
+ DPRINTF("Boot parameters: res: %p load_base: %p OF: %p entry: %p\n",
+ res, load_base, NULL, load_entry);
+#endif
+ DPRINTF("Boot: %0x %0x %0x %0x\n", *(uint32_t *)load_entry,
+ *((uint32_t *)load_entry + 1),
+ *((uint32_t *)load_entry + 2),
+ *((uint32_t *)load_entry + 3));
+ /* Fill residual data structure */
+ residual_build(res, memsize, (uint32_t)load_base,
+ (uint32_t)boot_nb * part_blocsize(boot_part),
+ (uint32_t)last_alloc);
+ /* Fill bootinfos */
+ bootinfos = (void *)(((uint32_t)load_end + (1 << 20) - 1) & ~((1 << 20) - 1));
+ if (boot_image != NULL && cmdline == NULL) {
+ cmdline = bootinfos + 0x1000;
+ *(char *)cmdline = '\0';
+ }
+ set_check(0);
+ prepare_bootinfos(bootinfos, memsize, cmdline, ramdisk, ramdisk_size);
+ set_check(1);
+ if (part_flags(boot_part) & PART_PREP) {
+ vga_prep_init();
+ }
+ /* Format NVRAM */
+ NVRAM_format(nvram);
+ /* Setup MMU and boot the loaded image */
+ DPRINTF("\nSet up MMU context\n");
+ /* Map all memory with transparent mapping */
+ BAT_setup(0, 0x00000000, 0x00000000, memsize, 1, 0, 2);
+ /* Open IO ports */
+ BAT_setup(1, isa_io_base, isa_io_base, 0x00800000, 1, 1, 2);
+#if 0
+ /* Open the frame-buffer area */
+ BAT_setup(2, vga_fb_phys_addr, vga_fb_phys_addr, 0x00200000, 1, 1, 2);
+#else
+ if (pci_main != NULL) {
+ uint32_t mem_start, mem_size;
+ pci_get_mem_range(pci_main, &mem_start, &mem_size);
+ BAT_setup(2, mem_start, mem_start, mem_size, 1, 1, 2);
+ }
+#endif
+ /* Enable MMU */
+ MMU_on();
+ usleep(500);
+ dprintf("Boot: %08x %08x %08x %08x\n", *(uint32_t *)load_base,
+ *(uint32_t *)(load_base + 4), *(uint32_t *)(load_base + 8),
+ *(uint32_t *)(load_base + 12));
+ dprintf("Bootinfos at : %p\n", bootinfos);
+ printf("\nNow boot it... (%p)\n\n", malloc(0));
+ usleep(500);
+ {
+ register uint32_t r1 __asm__ ("r1");
+ printf("stack: %0x malloc_base: %p 0x05800000 0x06000000\n",
+ r1, malloc(0));
+ }
+
+ if (part_flags(boot_part) & PART_PREP) {
+ printf("PREP boot... %p %p\n", load_entry, load_base);
+ /* Hack for Linux to boot without OpenFirmware */
+ put_be32(load_base, 0xdeadc0de);
+ }
+ transfer_handler(res /* residual data */,
+ load_base /* load address */,
+#ifdef USE_OPENFIRMWARE
+ &OF_entry /* OF entry point */,
+#else
+ NULL,
+#endif
+ bootinfos /* bootinfos for Linux */,
+ cmdline /* command line for Linux */,
+ NULL /* unused for now */,
+ load_entry /* start address */,
+#if 0
+ mem_align(0x00100000) /* Stack base */
+#else
+ (void *)0x05800000
+#endif
+ );
+ /* Should never come here */
+
+ return 0;
+}
diff --git a/src/main.ld b/src/main.ld
new file mode 100644
index 0000000..9b6e8c4
--- /dev/null
+++ b/src/main.ld
@@ -0,0 +1,79 @@
+/*
+ * Open Hack'Ware BIOS main.
+ *
+ * Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+OUTPUT_ARCH(powerpc)
+
+MEMORY
+{
+ start (rwx) : ORIGIN = 0x05800000, LENGTH = 0x00000400
+ bios (rwx) : ORIGIN = 0x05800400, LENGTH = 0x0007FC00
+ ram (rw) : ORIGIN = 0x06000000, LENGTH = 0x00200000
+}
+
+SECTIONS
+{
+ .start : { *(.start) } > start
+ . = ALIGN(4) ;
+ .text : { *(.text) } > bios
+ . = ALIGN(4) ;
+ .OpenFirmware : { *(.OpenFirmware) } > bios
+ . = ALIGN(4) ;
+ _data_start = . ;
+ .data : { *(.data) } > bios
+ _data_end = . ;
+ . = ALIGN(4) ;
+ _OF_vars_start = . ;
+ .OpenFirmware_vars : { *(.OpenFirmware_vars) } > bios
+ _OF_vars_end = . ;
+ . = ALIGN(4) ;
+ _sdata_start = . ;
+ .sdata : { *(.sdata) } > bios
+ . = ALIGN(4) ;
+ .sdata2 : { *(.sdata2) } > bios
+ _sdata_end = . ;
+ . = ALIGN(4) ;
+ _ro_start = . ;
+ .rodata : { *(.rodata) } > bios
+ _ro_end = . ;
+ . = ALIGN(4) ;
+ _RTAS_start = .;
+ .RTAS : { *(.RTAS) } > bios
+ _RTAS_end = .;
+ . = ALIGN(4) ;
+ _RTAS_data_start = .;
+ .RTAS_vars : { *(.RTAS_vars) } > bios
+ . = ALIGN(4) ;
+ _RTAS_data_end = .;
+ _bss_start = . ;
+ .sbss : {
+ *(.sbss) *(.scommon)
+ } > bios
+ . = ALIGN(4) ;
+ .bss : { *(.bss) *(COMMON) } > bios
+ _bss_end = . ;
+ . = ALIGN(4) ;
+ _ram_start = . ;
+ .ram : {
+ *(.ram)
+ } > ram
+ /DISCARD/ : { *(.stab) }
+ /DISCARD/ : { *(.stabstr) }
+ /DISCARD/ : { *(.comment) }
+ /DISCARD/ : { *(.note) }
+}
diff --git a/src/mm.c b/src/mm.c
new file mode 100644
index 0000000..e7fa067
--- /dev/null
+++ b/src/mm.c
@@ -0,0 +1,145 @@
+/*
+ * Open Hack'Ware BIOS memory management.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include "bios.h"
+
+#if 0
+static uint8_t *page_bitmap;
+static uint32_t memory_size;
+
+static void mark_page_in_use (uint32_t page_nb)
+{
+ uint32_t offset, bit;
+
+ offset = page_nb >> 3;
+ bit = page_nb & 7;
+ page_bitmap[offset] |= 1 << bit;
+}
+
+static void mark_page_free (uint32_t page_nb)
+{
+ uint32_t offset, bit;
+
+ offset = page_nb >> 3;
+ bit = page_nb & 7;
+ page_bitmap[offset] &= ~(1 << bit);
+}
+
+static int is_page_in_use (uint32_t page_nb)
+{
+ uint32_t offset, bit;
+
+ offset = page_nb >> 3;
+ bit = page_nb & 7;
+
+ return (page_bitmap[offset] & (~(1 << bit))) != 0;
+}
+
+void mm_init (uint32_t memsize)
+{
+ uint32_t page_start, page_ram_start, page, ram_start;
+ uint32_t nb_pages, bitmap_size;
+
+ /* Init bitmap */
+ ram_start = (uint32_t)(&_ram_start);
+ ram_start = (ram_start + (1 << 12) - 1) & ~((1 << 12) - 1);
+ page_bitmap = (void *)ram_start;
+ nb_pages = (memsize + (1 << 12) - 1) >> 12;
+ bitmap_size = (nb_pages + 7) >> 3;
+ /* First mark all pages as free */
+ memset(page_bitmap, 0, bitmap_size);
+ /* Mark all pages used by the BIOS as used (code + data + bitmap) */
+ page_start = (uint32_t)(0x05800000) >> 12; /* TO FIX */
+ ram_start += bitmap_size;
+ ram_start = (ram_start + (1 << 12) - 1) & ~((1 << 12) - 1);
+ page_ram_start = ram_start >> 12;
+ for (page = page_start; page < page_ram_start; page++)
+ mark_page_in_use(page);
+ memory_size = memsize;
+}
+
+void *page_get (int nb_pages)
+{
+ uint32_t page_start, page_end, page;
+ int nb;
+
+ page_start = (uint32_t)(0x05800000) >> 12; /* TO FIX */
+ page_end = memory_size >> 12;
+ for (page = page_start; page < page_end; ) {
+ /* Skip all full "blocs" */
+ for (; page < page_end; page += 8) {
+ if (page_bitmap[page >> 3] != 0xFF)
+ break;
+ }
+ for (nb = 0; page < page_end; page++) {
+ if (!is_page_in_use(page)) {
+ nb++;
+ if (nb == nb_pages) {
+ /* Found ! */
+ for (; nb >= 0; nb--, page--)
+ mark_page_in_use(page);
+
+ return (void *)(page << 12);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void page_put (void *addr, int nb_pages)
+{
+ uint32_t page_start, page_end, page;
+
+ page_start = (uint32_t)addr >> 12;
+ page_end = page_start + nb_pages;
+ for (page = page_start; page < page_end; page++) {
+ if (!is_page_in_use(page))
+ printf("ERROR: page %u has already been freed !\n", page);
+ mark_page_free(page);
+ }
+}
+#else
+static uint8_t *page_alloc;
+
+void mm_init (unused uint32_t memsize)
+{
+ uint32_t ram_start;
+ ram_start = (uint32_t)(&_ram_start);
+ ram_start = (ram_start + (1 << 12) - 1) & ~((1 << 12) - 1);
+ page_alloc = (void *)ram_start;
+}
+
+void *page_get (unused int nb_pages)
+{
+ void *ret;
+
+ ret = page_alloc;
+ page_alloc += nb_pages << 12;
+ memset(ret, 0, nb_pages << 12);
+
+ return ret;
+}
+
+void page_put (unused void *addr, unused int nb_pages)
+{
+}
+#endif
diff --git a/src/nvram.c b/src/nvram.c
new file mode 100644
index 0000000..58d63df
--- /dev/null
+++ b/src/nvram.c
@@ -0,0 +1,450 @@
+/*
+ * <nvram.c>
+ *
+ * Open Hack'Ware BIOS NVRAM management routines.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+
+#define NVRAM_MAX_SIZE 0x2000
+#define NVRAM_IO_BASE 0x0074
+
+struct nvram_t {
+ uint16_t io_base;
+ uint16_t size;
+};
+
+/* NVRAM access */
+static void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
+{
+ NVRAM_write(nvram, addr, value);
+}
+
+static uint8_t NVRAM_get_byte (nvram_t *nvram, uint16_t addr)
+{
+ return NVRAM_read(nvram, addr);
+}
+
+static void NVRAM_set_word (nvram_t *nvram, uint16_t addr, uint16_t value)
+{
+ NVRAM_write(nvram, addr, value >> 8);
+ NVRAM_write(nvram, addr + 1, value);
+}
+
+static uint16_t NVRAM_get_word (nvram_t *nvram, uint16_t addr)
+{
+ uint16_t tmp;
+
+ tmp = NVRAM_read(nvram, addr) << 8;
+ tmp |= NVRAM_read(nvram, addr + 1);
+
+ return tmp;
+}
+
+static void NVRAM_set_lword (nvram_t *nvram, uint16_t addr, uint32_t value)
+{
+ NVRAM_write(nvram, addr, value >> 24);
+ NVRAM_write(nvram, addr + 1, value >> 16);
+ NVRAM_write(nvram, addr + 2, value >> 8);
+ NVRAM_write(nvram, addr + 3, value);
+}
+
+static uint32_t NVRAM_get_lword (nvram_t *nvram, uint16_t addr)
+{
+ uint32_t tmp;
+
+ tmp = NVRAM_read(nvram, addr) << 24;
+ tmp |= NVRAM_read(nvram, addr + 1) << 16;
+ tmp |= NVRAM_read(nvram, addr + 2) << 8;
+ tmp |= NVRAM_read(nvram, addr + 3);
+
+ return tmp;
+}
+
+static void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
+ const unsigned char *str, uint32_t max)
+{
+ uint32_t i;
+
+ for (i = 0; i < max && str[i] != '\0'; i++) {
+ NVRAM_write(nvram, addr + i, str[i]);
+ }
+ NVRAM_write(nvram, addr + i, '\0');
+}
+
+static int NVRAM_get_string (nvram_t *nvram, uint8_t *dst,
+ uint16_t addr, int max)
+{
+ int i;
+
+ memset(dst, 0, max);
+ for (i = 0; i < max; i++) {
+ dst[i] = NVRAM_get_byte(nvram, addr + i);
+ if (dst[i] == '\0')
+ break;
+ }
+
+ return i;
+}
+
+static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
+{
+ uint16_t tmp;
+ uint16_t pd, pd1, pd2;
+
+ tmp = prev >> 8;
+ pd = prev ^ value;
+ pd1 = pd & 0x000F;
+ pd2 = ((pd >> 4) & 0x000F) ^ pd1;
+ tmp ^= (pd1 << 3) | (pd1 << 8);
+ tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
+
+ return tmp;
+}
+
+static uint16_t NVRAM_compute_crc (nvram_t *nvram,
+ uint32_t start, uint32_t count)
+{
+ uint32_t i;
+ uint16_t crc = 0xFFFF;
+ int odd;
+
+ odd = count & 1;
+ count &= ~1;
+ for (i = 0; i != count; i++) {
+ crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
+ }
+ if (odd) {
+ crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
+ }
+
+ return crc;
+}
+
+/* Format NVRAM for PREP target */
+static int NVRAM_prep_format (nvram_t *nvram)
+{
+#define NVRAM_PREP_OSAREA_SIZE 512
+#define NVRAM_PREP_CONFSIZE 1024
+ uint16_t crc;
+
+ /* NVRAM header */
+ /* 0x00: NVRAM size in kB */
+ NVRAM_set_word(nvram, 0x00, nvram->size >> 10);
+ /* 0x02: NVRAM version */
+ NVRAM_set_byte(nvram, 0x02, 0x01);
+ /* 0x03: NVRAM revision */
+ NVRAM_set_byte(nvram, 0x03, 0x01);
+ /* 0x08: last OS */
+ NVRAM_set_byte(nvram, 0x08, 0x00); /* Unknown */
+ /* 0x09: endian */
+ NVRAM_set_byte(nvram, 0x09, 'B'); /* Big-endian */
+ /* 0x0A: OSArea usage */
+ NVRAM_set_byte(nvram, 0x0A, 0x00); /* Empty */
+ /* 0x0B: PM mode */
+ NVRAM_set_byte(nvram, 0x0B, 0x00); /* Normal */
+ /* Restart block description record */
+ /* 0x0C: restart block version */
+ NVRAM_set_word(nvram, 0x0C, 0x01);
+ /* 0x0E: restart block revision */
+ NVRAM_set_word(nvram, 0x0E, 0x01);
+ /* 0x20: restart address */
+ NVRAM_set_lword(nvram, 0x20, 0x00);
+ /* 0x24: save area address */
+ NVRAM_set_lword(nvram, 0x24, 0x00);
+ /* 0x28: save area length */
+ NVRAM_set_lword(nvram, 0x28, 0x00);
+ /* 0x1C: checksum of restart block */
+ crc = NVRAM_compute_crc(nvram, 0x0C, 32);
+ NVRAM_set_word(nvram, 0x1C, crc);
+
+ /* Security section */
+ /* Set all to zero */
+ /* 0xC4: pointer to global environment area */
+ NVRAM_set_lword(nvram, 0xC4, 0x0100);
+ /* 0xC8: size of global environment area */
+ NVRAM_set_lword(nvram, 0xC8, nvram->size - NVRAM_PREP_OSAREA_SIZE -
+ NVRAM_PREP_CONFSIZE - 0x0100);
+ /* 0xD4: pointer to configuration area */
+ NVRAM_set_lword(nvram, 0xD4, nvram->size - NVRAM_PREP_CONFSIZE);
+ /* 0xD8: size of configuration area */
+ NVRAM_set_lword(nvram, 0xD8, NVRAM_PREP_CONFSIZE);
+ /* 0xE8: pointer to OS specific area */
+ NVRAM_set_lword(nvram, 0xE8, nvram->size - NVRAM_PREP_CONFSIZE
+ - NVRAM_PREP_OSAREA_SIZE);
+ /* 0xD8: size of OS specific area */
+ NVRAM_set_lword(nvram, 0xEC, NVRAM_PREP_OSAREA_SIZE);
+
+ /* Configuration area */
+
+ /* 0x04: checksum 0 => OS area */
+ crc = NVRAM_compute_crc(nvram, 0x00, nvram->size - NVRAM_PREP_CONFSIZE -
+ NVRAM_PREP_OSAREA_SIZE);
+ NVRAM_set_word(nvram, 0x04, crc);
+ /* 0x06: checksum of config area */
+ crc = NVRAM_compute_crc(nvram, nvram->size - NVRAM_PREP_CONFSIZE,
+ NVRAM_PREP_CONFSIZE);
+ NVRAM_set_word(nvram, 0x06, crc);
+
+ return 0;
+}
+
+static uint8_t NVRAM_chrp_chksum (nvram_t *nvram, uint16_t pos)
+{
+ uint16_t sum, end;
+
+ end = pos + 0x10;
+ sum = NVRAM_get_byte(nvram, pos);
+ for (pos += 2; pos < end; pos++) {
+ sum += NVRAM_get_byte(nvram, pos);
+ }
+ while (sum > 0xFF) {
+ sum = (sum & 0xFF) + (sum >> 8);
+ }
+
+ return sum;
+}
+
+static int NVRAM_chrp_format (unused nvram_t *nvram)
+{
+ uint8_t chksum;
+
+ /* Mark NVRAM as free */
+ NVRAM_set_byte(nvram, 0x00, 0x5A);
+ NVRAM_set_byte(nvram, 0x01, 0x00);
+ NVRAM_set_word(nvram, 0x02, 0x2000);
+ NVRAM_set_string(nvram, 0x04, "wwwwwwwwwwww", 12);
+ chksum = NVRAM_chrp_chksum(nvram, 0x00);
+ NVRAM_set_byte(nvram, 0x01, chksum);
+
+ return 0;
+}
+
+#if 0
+static uint16_t NVRAM_mac99_chksum (nvram_t *nvram,
+ uint16_t start, uint16_t len)
+ int cnt;
+ u32 low, high;
+
+ buffer += CORE99_ADLER_START;
+ low = 1;
+ high = 0;
+ for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+ if ((cnt % 5000) == 0) {
+ high %= 65521UL;
+ high %= 65521UL;
+ }
+ low += buffer[cnt];
+ high += low;
+ }
+ low %= 65521UL;
+ high %= 65521UL;
+
+ return (high << 16) | low;
+{
+ uint16_t pos;
+ uint8_t tmp, sum;
+
+ sum = 0;
+ for (pos = start; pos < (start + len); pos++) {
+ tmp = sum + NVRAM_get_byte(nvram, pos);
+ if (tmp < sum)
+ tmp++;
+ sum = tmp;
+ }
+
+ return sum;
+}
+#endif
+
+static int NVRAM_mac99_format (nvram_t *nvram)
+{
+ uint8_t chksum;
+
+ /* Mark NVRAM as free */
+ NVRAM_set_byte(nvram, 0x00, 0x5A);
+ NVRAM_set_byte(nvram, 0x01, 0x00);
+ NVRAM_set_word(nvram, 0x02, 0x2000);
+ NVRAM_set_string(nvram, 0x04, "wwwwwwwwwwww", 12);
+ chksum = NVRAM_chrp_chksum(nvram, 0x00);
+ NVRAM_set_byte(nvram, 0x01, chksum);
+
+ return 0;
+}
+
+static int NVRAM_pop_format (unused nvram_t *nvram)
+{
+ /* TODO */
+ return -1;
+}
+
+/* Interface */
+uint8_t NVRAM_read (nvram_t *nvram, uint32_t addr)
+{
+ outb(nvram->io_base + 0x00, addr);
+ outb(nvram->io_base + 0x01, addr >> 8);
+
+ return inb(NVRAM_IO_BASE + 0x03);
+}
+
+void NVRAM_write (nvram_t *nvram, uint32_t addr, uint8_t value)
+{
+ outb(nvram->io_base + 0x00, addr);
+ outb(nvram->io_base + 0x01, addr >> 8);
+ outb(nvram->io_base + 0x03, value);
+}
+
+uint16_t NVRAM_get_size (nvram_t *nvram)
+{
+ return nvram->size;
+}
+
+int NVRAM_format (nvram_t *nvram)
+{
+ int ret;
+
+ {
+ uint16_t pos;
+
+ for (pos = 0; pos < nvram->size; pos += 4)
+ NVRAM_set_lword(nvram, pos, 0);
+ }
+ switch (arch) {
+ case ARCH_PREP:
+ ret = NVRAM_prep_format(nvram);
+ break;
+ case ARCH_CHRP:
+ ret = NVRAM_chrp_format(nvram);
+ break;
+ case ARCH_MAC99:
+ ret = NVRAM_mac99_format(nvram);
+ break;
+ case ARCH_POP:
+ ret = NVRAM_pop_format(nvram);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+/* HACK... */
+extern int vga_width, vga_height, vga_depth;
+
+static nvram_t global_nvram;
+
+nvram_t *NVRAM_get_config (uint32_t *RAM_size, int *boot_device,
+ void **boot_image, uint32_t *boot_size,
+ void **cmdline, uint32_t *cmdline_size,
+ void **ramdisk, uint32_t *ramdisk_size)
+{
+ unsigned char sign[16];
+ nvram_t *nvram;
+ uint32_t lword;
+ uint16_t NVRAM_size, crc;
+ uint8_t byte;
+
+#if 0
+ nvram = malloc(sizeof(nvram_t));
+ if (nvram == NULL)
+ return NULL;
+#else
+ nvram = &global_nvram;
+#endif
+ nvram->io_base = NVRAM_IO_BASE;
+ /* Pre-initialised NVRAM is not supported any more */
+ if (NVRAM_get_string(nvram, sign, 0x00, 0x10) <= 0 ||
+ strcmp(sign, "QEMU_BIOS") != 0) {
+ ERROR("Wrong NVRAM signature %s\n", sign);
+ return NULL;
+ }
+ /* Check structure version */
+ lword = NVRAM_get_lword(nvram, 0x10);
+ if (lword != 0x00000002) {
+ ERROR("Wrong NVRAM structure version: %0x\n", lword);
+ return NULL;
+ }
+ /* Check CRC */
+ crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
+ if (NVRAM_get_word(nvram, 0xFC) != crc) {
+ ERROR("Invalid NVRAM structure CRC: %0x <=> %0x\n", crc,
+ NVRAM_get_word(nvram, 0xFC));
+ return NULL;
+ }
+ NVRAM_size = NVRAM_get_word(nvram, 0x14);
+ if ((NVRAM_size & 0x100) != 0x00 || NVRAM_size < 0x400 ||
+ NVRAM_size > 0x2000) {
+ ERROR("Invalid NVRAM size: %d\n", NVRAM_size);
+ return NULL;
+ }
+ nvram->size = NVRAM_size;
+ if (NVRAM_get_string(nvram, sign, 0x20, 0x10) < 0) {
+ ERROR("Unable to get architecture from NVRAM\n");
+ return NULL;
+ }
+ if (strcmp(sign, "PREP") == 0) {
+ arch = ARCH_PREP;
+ } else if (strcmp(sign, "CHRP") == 0) {
+ arch = ARCH_CHRP;
+ } else if (strcmp(sign, "MAC99") == 0) {
+ arch = ARCH_MAC99;
+ } else if (strcmp(sign, "POP") == 0) {
+ arch = ARCH_POP;
+ } else {
+ ERROR("Unknown PPC architecture: '%s'\n", sign);
+ return NULL;
+ }
+ /* HACK */
+ if (arch == ARCH_CHRP)
+ arch = ARCH_MAC99;
+ lword = NVRAM_get_lword(nvram, 0x30);
+ *RAM_size = lword;
+ byte = NVRAM_get_byte(nvram, 0x34);
+ *boot_device = byte;
+ /* Preloaded boot image */
+ lword = NVRAM_get_lword(nvram, 0x38);
+ *boot_image = (void *)lword;
+ lword = NVRAM_get_lword(nvram, 0x3C);
+ *boot_size = lword;
+ /* Preloaded cmdline */
+ lword = NVRAM_get_lword(nvram, 0x40);
+ *cmdline = (void *)lword;
+ lword = NVRAM_get_lword(nvram, 0x44);
+ *cmdline_size = lword;
+ /* Preloaded RAM disk */
+ lword = NVRAM_get_lword(nvram, 0x48);
+ *ramdisk = (void *)lword;
+ lword = NVRAM_get_lword(nvram, 0x4C);
+ *ramdisk_size = lword;
+ /* Preloaded NVRAM image */
+ lword = NVRAM_get_lword(nvram, 0x50);
+ /* Display init geometry */
+ lword = NVRAM_get_word(nvram, 0x54);
+ vga_width = lword;
+ lword = NVRAM_get_word(nvram, 0x56);
+ vga_height = lword;
+ lword = NVRAM_get_word(nvram, 0x58);
+ vga_depth = lword;
+ /* TODO: write it into NVRAM */
+
+ return nvram;
+}
diff --git a/src/of.c b/src/of.c
new file mode 100644
index 0000000..c2db8ec
--- /dev/null
+++ b/src/of.c
@@ -0,0 +1,5235 @@
+/* Open firmware emulation.
+ *
+ * This is really simplistic. The first goal is to implement all stuff
+ * needed to boot Linux. Then, I'll try Darwin.
+ * Note that this emulation run in the host environment.
+ * There is no Forth interpreter, so standard bootloader cannot be launched.
+ * In the future, it will be nice to get a complete OpenFirmware implementation
+ * so that OSes can be launched exactly the way they are in the real world...
+ *
+ * Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+
+//#define DEBUG_OF 1
+
+#if defined (DEBUG_OF)
+#define OF_DPRINTF(fmt, args...) \
+do { dprintf("%s: " fmt, __func__ , ##args); } while (0)
+#else
+#define OF_DPRINTF(fmt, args...) \
+do { } while (0)
+#endif
+
+#define PROT_READ 1
+#define PROT_WRITE 2
+
+typedef struct OF_transl_t OF_transl_t;
+struct OF_transl_t {
+ uint32_t virt;
+ uint32_t size;
+ uint32_t phys;
+ uint32_t mode;
+};
+
+typedef struct OF_env_t OF_env_t;
+struct OF_env_t {
+ uint32_t *stackp; /* Stack pointer */
+ uint32_t *stackb; /* Stack base */
+ uint32_t *funcp; /* Function stack pointer */
+ uint32_t *funcb; /* Function stack base */
+};
+
+typedef struct OF_bustyp_t OF_bustyp_t;
+struct OF_bustyp_t {
+ const char *name;
+ int type;
+};
+
+typedef struct pci_address_t pci_address_t;
+struct pci_address_t {
+ uint32_t hi;
+ uint32_t mid;
+ uint32_t lo;
+};
+
+typedef struct pci_reg_prop_t pci_reg_prop_t;
+struct pci_reg_prop_t {
+ pci_address_t addr;
+ uint32_t size_hi;
+ uint32_t size_lo;
+};
+
+typedef struct pci_range_t pci_range_t;
+struct pci_range_t {
+ pci_address_t addr;
+ uint32_t phys;
+ uint32_t size_hi;
+ uint32_t size_lo;
+};
+
+/*****************************************************************************/
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_lds (uint8_t *dst, const void *address)
+{
+ const uint8_t *p;
+ uint8_t *_d = dst;
+
+ for (p = address; *p != '\0'; p++) {
+ *_d++ = *p;
+ }
+ *_d = '\0';
+ OF_DPRINTF("Loaded string %s\n", dst);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_sts (void *address, const uint8_t *src)
+{
+ const uint8_t *_s;
+ uint8_t *p = address;
+
+ OF_DPRINTF("Store string %s\n", src);
+ for (_s = src; *_s != '\0'; _s++) {
+ *p++ = *_s;
+ }
+ *p = '\0';
+}
+
+#define OF_DUMP_STRING(env, buffer) \
+do { \
+ unsigned char tmp[OF_NAMELEN_MAX]; \
+ OF_lds(tmp, buffer); \
+ OF_DPRINTF("[%s]\n", tmp); \
+} while (0)
+
+/*****************************************************************************/
+/* Forth like environmnent */
+#define OF_CHECK_NBARGS(env, nb) \
+do { \
+ int nb_args; \
+ nb_args = stackd_depth((env)); \
+ if (nb_args != (nb)) { \
+ printf("%s: Bad number of arguments (%d - %d)\n", \
+ __func__, nb_args, (nb)); \
+ bug(); \
+ popd_all((env), nb_args); \
+ pushd((env), -1); \
+ return; \
+ } \
+} while (0)
+
+#define OF_STACK_SIZE 0x1000
+#define OF_FSTACK_SIZE 0x100
+__attribute__ (( section (".OpenFirmware_vars") ))
+uint8_t OF_stack[OF_STACK_SIZE];
+__attribute__ (( section (".OpenFirmware_vars") ))
+uint8_t OF_fstack[OF_FSTACK_SIZE];
+
+typedef void (*OF_cb_t)(OF_env_t *OF_env);
+
+static inline void _push (uint32_t **stackp, uint32_t data)
+{
+ // OF_DPRINTF("%p 0x%0x\n", *stackp, data);
+ **stackp = data;
+ (*stackp)--;
+}
+
+static inline uint32_t _pop (uint32_t **stackp)
+{
+ (*stackp)++;
+ // OF_DPRINTF("%p 0x%0x\n", *stackp, **stackp);
+ return **stackp;
+}
+
+static inline void _pop_all (uint32_t **stackp, int nb)
+{
+ int i;
+
+ for (i = 0; i < nb; i++)
+ (*stackp)++;
+}
+
+static inline int _stack_depth (uint32_t *stackp, uint32_t *basep)
+{
+ return basep - stackp;
+}
+
+static inline void pushd (OF_env_t *OF_env, uint32_t data)
+{
+ _push(&OF_env->stackp, data);
+}
+
+static inline uint32_t popd (OF_env_t *OF_env)
+{
+ return _pop(&OF_env->stackp);
+}
+
+static inline void popd_all (OF_env_t *OF_env, int nb)
+{
+ _pop_all(&OF_env->stackp, nb);
+}
+
+static inline int stackd_depth (OF_env_t *OF_env)
+{
+ return _stack_depth(OF_env->stackp, OF_env->stackb);
+}
+
+static inline void pushf (OF_env_t *OF_env, OF_cb_t *func)
+{
+ _push(&OF_env->funcp, (uint32_t)func);
+}
+
+static inline OF_cb_t *popf (OF_env_t *OF_env)
+{
+ return (OF_cb_t *)_pop(&OF_env->funcp);
+}
+
+static inline void popf_all (OF_env_t *OF_env, int nb)
+{
+ _pop_all(&OF_env->funcp, nb);
+}
+
+static inline int stackf_depth (OF_env_t *OF_env)
+{
+ return _stack_depth(OF_env->funcp, OF_env->funcb);
+}
+
+static inline void OF_env_init (OF_env_t *OF_env)
+{
+ OF_env->stackb = (uint32_t *)(OF_stack + OF_STACK_SIZE - 4);
+ OF_env->stackp = OF_env->stackb;
+ OF_env->funcb = (uint32_t *)(OF_fstack + OF_FSTACK_SIZE - 4);
+ OF_env->funcp = OF_env->funcb;
+}
+
+/* Forth run-time */
+__attribute__ (( section (".OpenFirmware") ))
+static void C_to_Forth (OF_env_t *env, void *p, OF_cb_t *cb)
+{
+ OF_cb_t *_cb;
+ uint32_t *u, *rets;
+ uint32_t i, n_args, n_rets, tmp;
+
+ // OF_DPRINTF("enter\n");
+ /* Fill argument structure */
+ u = p;
+ n_args = *u++;
+ n_rets = *u++;
+ u += n_args;
+ rets = u;
+ // OF_DPRINTF("n_args=%d n_rets=%d\n", n_args, n_rets);
+ /* Load arguments */
+ for (i = 0; i < n_args; i++)
+ pushd(env, *(--u));
+ pushf(env, cb);
+ while (stackf_depth(env) != 0) {
+ // OF_DPRINTF("func stack: %p %p\n", env->funcb, env->funcp);
+ _cb = popf(env);
+ // OF_DPRINTF("Next func: %p %d\n", cb, stackf_depth(env));
+ (*_cb)(env);
+ }
+ // OF_DPRINTF("Back to C: n_args=%d n_rets=%d\n", n_args, n_rets);
+ /* Copy returned values */
+ for (i = 0; stackd_depth(env) != 0; i++) {
+ tmp = popd(env);
+ // OF_DPRINTF("Store 0x%0x (%d)\n", tmp, tmp);
+ *rets++ = tmp;
+ }
+ for (; i < n_rets; i++)
+ *rets++ = 0;
+ OF_CHECK_NBARGS(env, 0);
+ // OF_DPRINTF("done\n");
+}
+
+/*****************************************************************************/
+/* Memory pool (will be needed when it'll become native) */
+#if 0
+#define OF_INTBITS_LEN 128
+#define OF_INTPOOL_LEN (OF_INTBITS_LEN * 8)
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint32_t OF_int_pool[OF_INTPOOL_LEN];
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint8_t OF_int_bits[OF_INTBITS_LEN];
+
+__attribute__ (( section (".OpenFirmware") ))
+static uint32_t *OF_int_alloc (unused OF_env_t *env)
+{
+ uint8_t tmp;
+ int i, j;
+
+ for (i = 0; i < OF_INTBITS_LEN; i++) {
+ tmp = OF_int_bits[i];
+ if (tmp == 0xFF)
+ continue;
+ for (j = 0; j < 7; j++) {
+ if ((tmp & 1) == 0) {
+ OF_int_bits[i] |= 1 << j;
+ return &OF_int_pool[(i << 3) | j];
+ }
+ tmp = tmp >> 1;
+ }
+ }
+ printf("ALERT: unable to \"allocate\" new integer\n");
+
+ return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_int_free (unused OF_env_t *env,
+ uint32_t *area)
+{
+ int i, j;
+
+ i = area - OF_int_pool;
+ j = i & 7;
+ i = i >> 3;
+ OF_int_bits[i] &= ~(1 << j);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_free (unused OF_env_t *env, void *area)
+{
+ uint32_t *check;
+
+ /* Check if it's in our int pool */
+ check = area;
+ if (check >= OF_int_pool && check < (OF_int_pool + OF_INTPOOL_LEN)) {
+ OF_int_free(env, check);
+ return;
+ }
+#if 0
+ free(area);
+#endif
+}
+#endif
+
+/*****************************************************************************/
+/* Internal structures */
+/* Property value types */
+typedef struct OF_node_t OF_node_t;
+typedef struct OF_prop_t OF_prop_t;
+typedef struct OF_method_t OF_method_t;
+typedef struct OF_inst_t OF_inst_t;
+
+#define OF_ADDRESS_NONE ((uint32_t)(-1))
+
+/* Tree node */
+struct OF_node_t {
+ /* Parent node */
+ OF_node_t *parent;
+ /* Link to next node at the same level */
+ OF_node_t *next;
+ /* Link to children, if any */
+ OF_node_t *children, *child_last;
+ /* refcount */
+ int refcount;
+ /* The following ones belong to the package */
+ /* Package */
+ uint16_t pack_id;
+ /* links count */
+ uint16_t link_count;
+ uint16_t link_cur;
+ OF_node_t *link_ref;
+ /* Properties */
+ OF_prop_t *properties, *prop_last, *prop_name, *prop_address;
+ /* Methods */
+ OF_method_t *methods, *method_last;
+ /* private data */
+ void *private_data;
+ /* static data */
+ void *static_data;
+ /* instances */
+ OF_inst_t *instances, *inst_last;
+};
+
+/* Node property */
+struct OF_prop_t {
+ /* Link to next property */
+ OF_prop_t *next;
+ /* The node it belongs to */
+ OF_node_t *node;
+ /* property name */
+ const unsigned char *name;
+ /* property value len */
+ int vlen;
+ /* property value buffer */
+ char *value;
+ /* Property change callback */
+ void (*cb)(OF_env_t *OF_env, OF_prop_t *prop, const void *data, int len);
+};
+
+/* Node method */
+enum {
+ OF_METHOD_INTERNAL = 0,
+ OF_METHOD_EXPORTED,
+};
+
+struct OF_method_t {
+ /* Link to next method */
+ OF_method_t *next;
+ /* The package it belongs to */
+ OF_node_t *node;
+ /* method name */
+ unsigned char *name;
+ /* Method function pointer */
+ OF_cb_t func;
+};
+
+/* Package instance */
+struct OF_inst_t {
+ /* Link to next instance of the same package */
+ OF_inst_t *next;
+ /* Link to the parent instance */
+ OF_inst_t *parent;
+ /* The package it belongs to */
+ OF_node_t *node;
+ /* Instance identifier */
+ uint16_t inst_id;
+ /* Instance data */
+ void *data;
+};
+
+/* reg property */
+typedef struct OF_regprop_t OF_regprop_t;
+struct OF_regprop_t {
+ uint32_t address;
+ uint32_t size;
+};
+
+/* range property */
+typedef struct OF_range_t OF_range_t;
+struct OF_range_t {
+ uint32_t virt;
+ uint32_t size;
+ uint32_t phys;
+};
+
+/* Open firmware tree */
+#define OF_MAX_PACKAGE 256
+/* nodes and packages */
+__attribute__ (( section (".OpenFirmware_vars") ))
+static OF_node_t *OF_node_root;
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint16_t OF_pack_last_id = 0;
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint16_t inst_last_id = 0;
+/* To speed up lookup by id, we get a package table */
+__attribute__ (( section (".OpenFirmware_vars") ))
+static OF_node_t *OF_packages[OF_MAX_PACKAGE];
+__attribute__ (( section (".OpenFirmware_vars") ))
+static OF_node_t *OF_pack_active;
+
+static OF_prop_t *OF_prop_string_new (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name,
+ const unsigned char *string);
+static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name, uint32_t value);
+static OF_prop_t *OF_property_get (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name);
+static uint16_t OF_pack_handle (OF_env_t *env, OF_node_t *node);
+
+__attribute__ (( section (".OpenFirmware_vars") ))
+static uint8_t *RTAS_memory;
+
+/*****************************************************************************/
+/* Node management */
+/* Insert a new node */
+__attribute__ (( section (".OpenFirmware") ))
+static uint16_t OF_pack_new_id (unused OF_env_t *env, OF_node_t *node)
+{
+ uint16_t cur_id;
+
+ for (cur_id = OF_pack_last_id + 1; cur_id != OF_pack_last_id; cur_id++) {
+ if (cur_id == (uint16_t)(OF_MAX_PACKAGE))
+ cur_id = 1;
+ if (OF_packages[cur_id] == NULL) {
+ OF_packages[cur_id] = node;
+ OF_pack_last_id = cur_id;
+ return cur_id;
+ }
+ }
+
+ return (uint16_t)(-1);
+}
+
+static OF_node_t *OF_node_create (OF_env_t *env, OF_node_t *parent,
+ const unsigned char *name, uint32_t address)
+{
+ OF_node_t *new;
+
+ OF_DPRINTF("New node: %s\n", name);
+ new = malloc(sizeof(OF_node_t));
+ if (new == NULL) {
+ ERROR("%s can't alloc new node '%s'\n", __func__, name);
+ return NULL;
+ }
+ memset(new, 0, sizeof(OF_node_t));
+ new->parent = parent;
+ new->refcount = 1;
+ new->link_count = 1;
+ new->prop_name = OF_prop_string_new(env, new, "name", name);
+ if (new->prop_name == NULL) {
+ free(new);
+ ERROR("%s can't alloc new node '%s' name\n", __func__, name);
+ return NULL;
+ }
+ new->prop_address = OF_prop_int_new(env, new, "address", address);
+ if (new->prop_address == NULL) {
+ free(new->prop_name->value);
+ free(new->prop_name);
+ free(new);
+ ERROR("%s can't alloc new node '%s' address\n", __func__, name);
+ return NULL;
+ }
+ /* Link it in parent tree */
+ if (parent != NULL) {
+ /* SHOULD LOCK */
+ if (parent->children == NULL) {
+ parent->children = new;
+ } else {
+ parent->child_last->next = new;
+ }
+ parent->child_last = new;
+ } else {
+ /* This is a bug and should never happen, but for root node */
+ if (strcmp(name, "device-tree") != 0)
+ ERROR("WARNING: parent of '%s' is NULL!\n", name);
+ }
+ // OF_DPRINTF("New node: %s get id\n", name);
+
+ return new;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_node_new (OF_env_t *env, OF_node_t *parent,
+ const unsigned char *name, uint32_t address)
+{
+ OF_node_t *new;
+
+ new = OF_node_create(env, parent, name, address);
+ if (new == NULL)
+ return NULL;
+ new->pack_id = OF_pack_new_id(env, new);
+ // OF_DPRINTF("New node: %s id=0x%0x\n", name, new->pack_id);
+ OF_pack_active = new;
+
+ return new;
+}
+
+static inline OF_node_t *OF_node_parent (unused OF_env_t *env, OF_node_t *node)
+{
+ return node->parent;
+}
+
+/* Look for a node, given its name */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_node_get_child (OF_env_t *env, OF_node_t *parent,
+ const unsigned char *name,
+ uint32_t address)
+{
+ unsigned char tname[OF_NAMELEN_MAX];
+ OF_node_t *parse, *tmp;
+ OF_prop_t *prop_name, *prop_address;
+ uint32_t *addr_valp;
+ int len, i;
+
+ if (parent == OF_node_root) {
+ OF_DPRINTF("Look for node [%s]\n", name);
+ }
+ len = strlen(name);
+ memcpy(tname, name, len + 1);
+ for (i = len; i > 0; i--) {
+ if (tname[i - 1] == ',') {
+ tname[i - 1] = '\0';
+ len = i;
+ break;
+ }
+ }
+ for (parse = parent->children; parse != NULL; parse = parse->next) {
+ prop_name = parse->prop_name;
+ prop_address = parse->prop_address;
+ if (prop_address == NULL)
+ addr_valp = NULL;
+ else
+ addr_valp = (void *)prop_address->value;
+#if 0
+ OF_DPRINTF("node [%s] <=> [%s]\n", prop_name->value, tname);
+#endif
+ if (prop_name != NULL && strncmp(prop_name->value, tname, len) == 0 &&
+ (prop_name->value[len] == '\0') &&
+ (address == OF_ADDRESS_NONE || addr_valp == NULL ||
+ address == *addr_valp)) {
+ parse->refcount++;
+ return parse;
+ }
+#if 1
+ OF_DPRINTF("look in children [%s]\n", prop_name->value);
+#endif
+ tmp = OF_node_get_child(env, parse, tname, address);
+ if (tmp != NULL)
+ return tmp;
+#if 0
+ OF_DPRINTF("didn't find in children [%s]\n", prop_name->value);
+#endif
+ }
+ if (parent == OF_node_root) {
+ OF_DPRINTF("node [%s] not found\n", name);
+ }
+
+ return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_node_get (OF_env_t *env, const unsigned char *name)
+{
+ unsigned char tname[OF_NAMELEN_MAX];
+ unsigned char *addrp;
+ uint32_t address;
+
+ if (strcmp(name, "device_tree") == 0)
+ return OF_node_root;
+
+ strcpy(tname, name);
+ addrp = strchr(tname, '@');
+ if (addrp == NULL) {
+ address = OF_ADDRESS_NONE;
+ } else {
+ *addrp++ = '\0';
+ address = strtol(addrp, NULL, 16);
+ }
+
+ /* SHOULD LOCK */
+ return OF_node_get_child(env, OF_node_root, name, address);
+}
+
+/* Release a node */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_node_put (unused OF_env_t *env, OF_node_t *node)
+{
+ if (--node->refcount < 0)
+ node->refcount = 0;
+}
+
+/*****************************************************************************/
+/* Packages tree walk */
+__attribute__ (( section (".OpenFirmware") ))
+static uint16_t OF_pack_handle (unused OF_env_t *env, OF_node_t *node)
+{
+ if (node == NULL)
+ return 0;
+
+ return node->pack_id;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_find_by_name (OF_env_t *env, OF_node_t *base,
+ const unsigned char *name)
+{
+ unsigned char tmp[OF_NAMELEN_MAX], *addrp;
+ const unsigned char *sl, *st;
+ OF_node_t *parse;
+ OF_prop_t *prop_name, *prop_address;
+ uint32_t address, *addr_valp;
+ int len;
+
+ OF_DPRINTF("Path [%s] in '%s'\n", name, base->prop_name->value);
+ st = name;
+ if (*st == '/') {
+ st++;
+ }
+ if (*st == '\0') {
+ /* Should never happen */
+ OF_DPRINTF("Done\n");
+ return base;
+ }
+ sl = strchr(st, '/');
+ if (sl == NULL) {
+ len = strlen(st);
+ } else {
+ len = sl - st;
+ }
+ memcpy(tmp, st, len);
+ tmp[len] = '\0';
+ addrp = strchr(tmp, '@');
+ if (addrp == NULL) {
+ address = OF_ADDRESS_NONE;
+ } else {
+ len = addrp - tmp;
+ *addrp++ = '\0';
+ address = strtol(addrp, NULL, 16);
+ }
+ OF_DPRINTF("Look for [%s] '%s' %08x\n", tmp, sl, address);
+ for (parse = base->children; parse != NULL; parse = parse->next) {
+ prop_name = parse->prop_name;
+ prop_address = parse->prop_address;
+ if (prop_address == NULL)
+ addr_valp = NULL;
+ else
+ addr_valp = (void *)prop_address->value;
+#if 0
+ OF_DPRINTF("Check [%s]\n", prop_name->value);
+#endif
+ if (prop_name == NULL) {
+ printf("ERROR: missing address in node, parent: '%s'\n",
+ base->prop_name->value);
+ bug();
+ }
+ if (strncmp(prop_name->value, tmp, len) == 0 &&
+ prop_name->value[len] == '\0' &&
+ (address == OF_ADDRESS_NONE || addr_valp == NULL ||
+ address == *addr_valp)) {
+ OF_pack_active = parse;
+ if (sl == NULL) {
+ OF_DPRINTF("Done\n");
+ return parse;
+ }
+ OF_DPRINTF("Recurse: '%s'\n", sl + 1);
+ return OF_pack_find_by_name(env, parse, sl + 1);
+ }
+ }
+ OF_DPRINTF("Didn't found [%s]\n", tmp);
+
+ return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_find (unused OF_env_t *env, uint16_t phandle)
+{
+ if (phandle > OF_MAX_PACKAGE)
+ return NULL;
+ if (OF_packages[phandle] == NULL) {
+ OF_DPRINTF("No package %0x\n", phandle);
+ } else {
+ OF_DPRINTF("return package: %0x %p [%s]\n", phandle,
+ OF_packages[phandle],
+ OF_packages[phandle]->prop_name->value);
+ }
+
+ return OF_packages[phandle];
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_next (OF_env_t *env, uint16_t phandle)
+{
+ OF_node_t *node;
+
+ for (node = OF_pack_find(env, phandle); node != NULL; node = node->next) {
+ if (OF_pack_handle(env, node) != phandle)
+ break;
+ }
+#if 0
+ OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value);
+#endif
+
+ return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_child (OF_env_t *env, uint16_t phandle)
+{
+ OF_node_t *node;
+
+ node = OF_pack_find(env, phandle);
+ if (node == NULL) {
+ ERROR("%s didn't find pack %04x\n", __func__, phandle);
+ return NULL;
+ }
+ node = node->children;
+#if 0
+ OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value);
+#endif
+
+ return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_pack_parent (OF_env_t *env, uint16_t phandle)
+{
+ OF_node_t *node;
+
+ node = OF_pack_find(env, phandle);
+ if (node == NULL) {
+ ERROR("%s didn't find pack %04x\n", __func__, phandle);
+ return NULL;
+ }
+ node = OF_node_parent(env, node);
+#if 0
+ OF_DPRINTF("found node %p [%s]\n", node, node->prop_name->value);
+#endif
+
+ return node;
+}
+
+/*****************************************************************************/
+/* Package properties management */
+/* Insert a new property */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_new (unused OF_env_t *env, OF_node_t *node,
+ const unsigned char *name,
+ const void *data, int len)
+{
+ OF_prop_t *prop;
+
+#ifdef DEBUG_OF
+ {
+ OF_prop_t *_prop;
+ _prop = OF_property_get(env, node, name);
+ if (_prop != NULL) {
+ printf("Property '%s' already present !\n", name);
+ bug();
+ }
+ }
+#endif
+ /* Allocate a new property */
+ prop = malloc(sizeof(OF_prop_t));
+ if (prop == NULL) {
+ ERROR("%s cannot allocate property '%s'\n", __func__, name);
+ return NULL;
+ }
+ memset(prop, 0, sizeof(OF_prop_t));
+ prop->name = strdup(name);
+ if (prop->name == NULL) {
+ free(prop);
+ ERROR("%s cannot allocate property '%s' name\n", __func__, name);
+ return NULL;
+ }
+ /* Fill it */
+ if (data != NULL && len > 0) {
+ prop->value = malloc(len);
+ if (prop->value == NULL) {
+ free(prop);
+ ERROR("%s cannot allocate property '%s' value\n", __func__, name);
+ return NULL;
+ }
+ prop->vlen = len;
+ memcpy(prop->value, data, len);
+ }
+ OF_DPRINTF("New property [%s] '%s'\n\t%p %p %d %p\n", name, prop->name, prop->name, data, len, prop->value);
+ /* Link it */
+ /* SHOULD LOCK */
+ if (node->properties == NULL)
+ node->properties = prop;
+ else
+ node->prop_last->next = prop;
+ node->prop_last = prop;
+
+ return prop;
+}
+
+/* Find a property given its name */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_get (unused OF_env_t *env, OF_node_t *node,
+ const unsigned char *name)
+{
+ OF_prop_t *prop;
+
+#if 0
+ OF_DPRINTF("Look for property [%s] in 0x%0x '%s'\n", name,
+ node->pack_id, node->prop_name->value);
+#endif
+ if (node == NULL)
+ return NULL;
+ /* *SHOULD LOCK* */
+ for (prop = node->properties; prop != NULL; prop = prop->next) {
+#if 0
+ OF_DPRINTF("property [%s] <=> [%s]\n", prop->name, name);
+#endif
+ if (strcmp(prop->name, name) == 0) {
+ return prop;
+ }
+ }
+#if 0
+ OF_DPRINTF("property [%s] not found in 0x%08x '%s'\n", name,
+ node->pack_id, node->prop_name->value);
+#endif
+
+ return NULL;
+}
+
+/* Change a property */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_set (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name,
+ const void *data, int len)
+{
+ OF_prop_t *prop;
+ void *tmp;
+
+ if (node == NULL)
+ return NULL;
+ prop = OF_property_get(env, node, name);
+ if (prop != NULL) {
+ OF_DPRINTF("change property [%s]\n", name);
+ tmp = malloc(len);
+ if (tmp == NULL && len != 0) {
+ ERROR("%s cannot set property '%s'\n", __func__, name);
+ return NULL;
+ }
+ free(prop->value);
+ prop->value = tmp;
+ prop->vlen = len;
+ memcpy(prop->value, data, len);
+ if (prop->cb != NULL) {
+ (*prop->cb)(env, prop, data, len);
+ }
+ } else {
+ OF_DPRINTF("new property [%s]\n", name);
+ prop = OF_property_new(env, node, name, data, len);
+ }
+
+ return prop;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_property_len (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name)
+{
+ OF_prop_t *prop;
+
+ prop = OF_property_get(env, node, name);
+ if (prop == NULL)
+ return -1;
+
+ return prop->vlen;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static unsigned char *hex2buf (unsigned char *buf, uint32_t value, int fill)
+{
+ int pos, d;
+
+ buf[8] = '\0';
+ pos = 7;
+ if (value == 0) {
+ buf[pos--] = '0';
+ } else {
+ for (; value != 0; pos--) {
+ d = value & 0xF;
+ if (d > 9)
+ d += 'a' - '0' - 10;
+ buf[pos] = d + '0';
+ value = value >> 4;
+ }
+ }
+ if (fill != 0) {
+ for (; pos != -1; pos--) {
+ buf[pos] = '0';
+ }
+ }
+
+ return &buf[pos];
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_property_copy (OF_env_t *env, void *buffer, int maxlen,
+ OF_node_t *node, const unsigned char *name)
+{
+ unsigned char tmp[OF_PROPLEN_MAX];
+ OF_prop_t *prop;
+ int len;
+
+ prop = OF_property_get(env, node, name);
+ if (prop == NULL) {
+ ERROR("%s cannot get property '%s' for %s\n", __func__, name,
+ node->prop_name->value);
+ return -1;
+ }
+ len = prop->vlen > maxlen ? maxlen : prop->vlen;
+ if (prop->value != NULL) {
+ tmp[0] = '0';
+ tmp[1] = 'x';
+ hex2buf(tmp + 2, *((uint32_t *)prop->value), 1);
+ } else {
+ *tmp = '\0';
+ }
+ OF_DPRINTF("copy property [%s] len=%d to %p len=%d\n",
+ name, prop->vlen, buffer, maxlen);
+ if (strcmp(name, "name") == 0) {
+ OF_DPRINTF("=> '%s'\n", prop->value);
+ }
+ memcpy(buffer, prop->value, len);
+ // OF_DPRINTF("done\n");
+
+ return len;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_property_next (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name)
+{
+ OF_prop_t *prop, *next;
+
+ if (name == NULL || *name == '\0') {
+ next = node->properties;
+ } else {
+ prop = OF_property_get(env, node, name);
+ if (prop == NULL) {
+ OF_DPRINTF("Property [%s] not found\n", name);
+ next = NULL;
+ } else {
+ next = prop->next;
+ /* Skip address if not set */
+ if (next == node->prop_address &&
+ *((uint32_t *)next->value) == OF_ADDRESS_NONE)
+ next = next->next;
+ }
+ }
+#if 0
+ OF_DPRINTF("Found property %p\n", next);
+#endif
+
+ return next;
+}
+
+/* Simplified helpers */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_string_new (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name,
+ const unsigned char *string)
+{
+#ifdef DEBUG_OF
+ {
+ OF_prop_t *prop;
+ prop = OF_property_get(env, node, name);
+ if (prop != NULL) {
+ printf("Property '%s' already present !\n", name);
+ bug();
+ }
+ }
+#endif
+ return OF_property_new(env, node, name,
+ string, strlen(string) + 1);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name, uint32_t value)
+{
+#ifdef DEBUG_OF
+ {
+ OF_prop_t *prop;
+ prop = OF_property_get(env, node, name);
+ if (prop != NULL) {
+ printf("Property '%s' already present !\n", name);
+ bug();
+ }
+ }
+#endif
+ return OF_property_new(env, node, name, &value, sizeof(uint32_t));
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_string_set (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name,
+ const unsigned char *string)
+{
+ const unsigned char *tmp;
+
+ tmp = strdup(string);
+ if (tmp == NULL) {
+ ERROR("%s cannot duplicate property '%s'\n", __func__, name);
+ return NULL;
+ }
+
+ return OF_property_set(env, node, name, tmp, strlen(string) + 1);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_prop_t *OF_prop_int_set (OF_env_t *env, OF_node_t *node,
+ const unsigned char *name, uint32_t value)
+{
+ return OF_property_set(env, node, name, &value, sizeof(uint32_t));
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+unused
+static OF_prop_t *OF_set_compatibility (OF_env_t *env, OF_node_t *node,
+ const unsigned char *compat)
+{
+ return OF_prop_string_new(env, node, "compatible", compat);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static inline void OF_property_set_cb (unused OF_env_t *OF_env,
+ OF_prop_t *prop,
+ void (*cb)(OF_env_t *OF_env,
+ OF_prop_t *prop,
+ const void *data, int len))
+{
+ prop->cb = cb;
+}
+
+/*****************************************************************************/
+/* Packages methods management */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_method_t *OF_method_new (unused OF_env_t *env, OF_node_t *node,
+ const unsigned char *name, OF_cb_t cb)
+{
+ OF_method_t *new;
+
+ new = malloc(sizeof(OF_method_t));
+ if (new == NULL) {
+ ERROR("%s cannot allocate method '%s'\n", __func__, name);
+ return NULL;
+ }
+ memset(new, 0, sizeof(OF_method_t));
+ new->node = node;
+ new->name = strdup(name);
+ if (new->name == NULL) {
+ free(new);
+ ERROR("%s cannot allocate method '%s' name\n", __func__, name);
+ return NULL;
+ }
+ OF_DPRINTF("new method name %p %s\n", new, new->name);
+ new->func = cb;
+ /* Link it */
+ /* *SHOULD LOCK* */
+ if (node->method_last == NULL)
+ node->methods = new;
+ else
+ node->method_last->next = new;
+ node->method_last = new;
+
+ return new;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_method_t *OF_method_get (unused OF_env_t *env, OF_node_t *node,
+ const unsigned char *name)
+{
+ OF_method_t *parse;
+
+ if (node == NULL) {
+ OF_DPRINTF("No method in NULL package !\n");
+ return NULL;
+ }
+#if 0
+ OF_DPRINTF("Look for method %s in package %0x\n",
+ name, node->pack_id);
+#endif
+ for (parse = node->methods; parse != NULL; parse = parse->next) {
+#if 0
+ OF_DPRINTF("check %p %p\n", parse, parse->name);
+ OF_DPRINTF("name=%s\n", parse->name);
+#endif
+ if (strcmp(parse->name, name) == 0)
+ return parse;
+ }
+
+ return NULL;
+}
+
+/*****************************************************************************/
+/* Packages instances management */
+__attribute__ (( section (".OpenFirmware") ))
+static uint16_t OF_inst_new_id (unused OF_env_t *env, OF_node_t *node)
+{
+ OF_inst_t *tmp_inst;
+ uint16_t cur_id;
+
+#if 0
+ OF_DPRINTF("[%s] %d\n", node->prop_name->value,
+ inst_last_id);
+#endif
+ for (cur_id = inst_last_id + 1;
+ cur_id != inst_last_id; cur_id++) {
+ if (cur_id == (uint16_t)(OF_MAX_PACKAGE))
+ cur_id = 0;
+ for (tmp_inst = node->instances; tmp_inst != NULL;
+ tmp_inst = tmp_inst->next) {
+ if (tmp_inst->inst_id == cur_id)
+ continue;
+ }
+ inst_last_id = cur_id;
+#if 1
+ OF_DPRINTF("0x%0x\n", cur_id);
+#endif
+ return cur_id;
+ }
+ OF_DPRINTF("no ID found\n");
+
+ return (uint16_t)(-1);
+}
+
+/* Create a new package's instance */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_instance_new (OF_env_t *env, OF_node_t *node)
+{
+ OF_inst_t *new, *parent;
+ uint16_t new_id;
+
+ /* TODO: recurse to root... */
+ new = malloc(sizeof(OF_inst_t));
+ if (new == NULL) {
+ ERROR("%s cannot allocate instance of '%s'\n", __func__,
+ node->prop_name->value);
+ return NULL;
+ }
+ memset(new, 0, sizeof(OF_inst_t));
+ if (OF_node_parent(env, node) != NULL) {
+ parent = OF_instance_new(env, OF_node_parent(env, node));
+ if (parent == NULL) {
+ free(new);
+ ERROR("%s cannot allocate instance of '%s' parent\n", __func__,
+ node->prop_name->value);
+ return NULL;
+ }
+ new->parent = parent;
+ } else {
+ new->parent = NULL;
+ }
+ new_id = OF_inst_new_id(env, node);
+ if (new_id == (uint16_t)(-1)) {
+ free(new);
+ return NULL;
+ }
+ new->inst_id = new_id;
+ new->node = node;
+ /* Link it */
+ /* SHOULD LOCK */
+ if (node->inst_last == NULL)
+ node->instances = new;
+ else
+ node->inst_last->next = new;
+ node->inst_last = new;
+
+ return new;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static uint32_t OF_instance_get_id (unused OF_env_t *env, OF_inst_t *instance)
+{
+ OF_DPRINTF("p: %0x i: %0x\n", instance->node->pack_id, instance->inst_id);
+ return (instance->node->pack_id << 16) | instance->inst_id;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_inst_find (OF_env_t *env, uint32_t ihandle)
+{
+ OF_node_t *node;
+ OF_inst_t *parse;
+ uint16_t phandle = ihandle >> 16;
+
+ ihandle &= 0xFFFF;
+ OF_DPRINTF("p: %0x i: %0x\n", phandle, ihandle);
+ if (ihandle > OF_MAX_PACKAGE)
+ return NULL;
+ node = OF_pack_find(env, phandle);
+ if (node == NULL)
+ return NULL;
+ for (parse = node->instances; parse != NULL; parse = parse->next) {
+ if (parse->inst_id == ihandle)
+ return parse;
+ }
+
+ return NULL;
+}
+
+#if 0
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_inst_get_child (OF_env_t *env, OF_node_t *parent,
+ const uint32_t handle)
+{
+ OF_node_t *parse, *tmp;
+
+ for (parse = parent->children; parse != NULL; parse = parse->next) {
+ if (parse->pack_id == (handle >> 16)) {
+ return NULL;
+ }
+ tmp = OF_inst_get_child(env, parse, handle);
+ if (tmp != NULL)
+ return tmp;
+ }
+
+ return NULL;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static OF_inst_t *OF_inst_get (OF_env_t *env, const unsigned char *name)
+{
+ return _OF_node_get(env, &OF_node_root);
+
+}
+#endif
+
+#if 0
+__attribute__ (( section (".OpenFirmware") ))
+int get_node_name (OF_env_t *env, unsigned char *name,
+ int len, OF_node_t *node)
+{
+ int tmp, total;
+ int i;
+
+ /* Set up manufacturer name */
+ total = 0;
+ tmp = 0;
+#if 0
+ if (OF_node_parent(env, node) == NULL ||
+ node->manufct != OF_node_parent(env, node)->manufct) {
+ tmp = strlen(node->manufct);
+ if ((tmp + 2) > len)
+ return -1;
+ memcpy(name, node->manufct, tmp);
+ name += tmp;
+ } else if (len < 2) {
+ return -1;
+ }
+ *name++ = ',';
+ len -= tmp + 1;
+ total += tmp + 1;
+#endif
+ /* Set up device model */
+ tmp = strlen(node->name);
+ if ((tmp + 2) > len)
+ return -1;
+ memcpy(name, node->model, tmp);
+ name += tmp;
+ *name++ = '@';
+ len -= tmp + 1;
+ total += tmp + 1;
+ /* Set up unit address */
+ tmp = strlen(node->address);
+ if ((tmp + 2) > len)
+ return -1;
+ memcpy(name, node->address, tmp);
+ name += tmp;
+ *name++ = ':';
+ len -= tmp + 1;
+ total += tmp + 1;
+ for (i = 0; node->arguments[i] != NULL; i++) {
+ if (i != 0)
+ *name++ = ',';
+ tmp = strlen(node->arguments[i]);
+ if ((tmp + 2) > len)
+ return -1;
+ memcpy(name, node->arguments[i], tmp);
+ name += tmp;
+ len -= tmp + 1;
+ total += tmp + 1;
+ }
+ *name = '\0';
+
+ return total;
+}
+#endif
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_pack_get_path (OF_env_t *env, unsigned char *name,
+ int len, OF_node_t *node)
+{
+ OF_prop_t *prop_name, *prop_address;
+ uint32_t address;
+ int tmp, nlen;
+
+ /* Recurse until we reach the root node */
+ OF_DPRINTF("look for [%s]\n", node->prop_name->value);
+ if (OF_node_parent(env, node) == NULL) {
+ name[0] = '/';
+ tmp = 0;
+ nlen = 1;
+ } else {
+ tmp = OF_pack_get_path(env, name, len, OF_node_parent(env, node));
+ /* Add node name */
+ prop_name = node->prop_name;
+ prop_address = node->prop_address;
+#if 1
+ OF_DPRINTF("Found [%s]\n", prop_name->value);
+#endif
+ if ((len - tmp) < 2) {
+ OF_DPRINTF("Buffer too short (%d 2)\n", len - tmp);
+ return 0;
+ }
+ if (prop_name == NULL) {
+ printf("No name in node !\n");
+ bug();
+ }
+ nlen = strlen(prop_name->value);
+#if 1
+ OF_DPRINTF("got '%s' for '%s' parent (%d %d)\n",
+ name, prop_name->value, tmp, nlen);
+#endif
+ if (name[tmp - 1] != '/') {
+ name[tmp] = '/';
+ tmp++;
+ }
+ address = *((uint32_t *)prop_address->value);
+ if (address != OF_ADDRESS_NONE) {
+ if ((len - tmp - nlen) < 10) {
+ OF_DPRINTF("Buffer too short (%d %d)\n", len - tmp, nlen + 10);
+ return 0;
+ }
+ } else {
+ if ((len - tmp - nlen) < 1) {
+ OF_DPRINTF("Buffer too short (%d %d)\n", len - tmp, nlen + 1);
+ return 0;
+ }
+ }
+ memcpy(name + tmp, prop_name->value, nlen);
+ if (address != OF_ADDRESS_NONE) {
+ OF_DPRINTF("Add address 0x%08x\n", address);
+ sprintf(name + tmp + nlen, "@%x", address);
+ nlen += strlen(name + tmp + nlen);
+ } else {
+ OF_DPRINTF("No address....\n");
+ }
+ }
+ name[tmp + nlen] = '\0';
+ OF_DPRINTF("stored [%d]\n", tmp + nlen);
+ OF_DUMP_STRING(env, name);
+#if 1
+ OF_DPRINTF("name '%s' => '%s' %d\n",
+ node->properties->value, name, tmp + nlen);
+#endif
+
+ return tmp + nlen;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static int OF_inst_get_path (OF_env_t *env, unsigned char *name,
+ int len, OF_inst_t *inst)
+{
+ return OF_pack_get_path(env, name, len, inst->node);
+}
+
+/*****************************************************************************/
+/* Open firmware C interface */
+static void OF_serial_write (OF_env_t *OF_env);
+static void OF_serial_read (OF_env_t *OF_env);
+static void OF_mmu_translate (OF_env_t *OF_env);
+static void OF_mmu_map (OF_env_t *OF_env);
+static void RTAS_instantiate (OF_env_t *RTAS_env);
+
+static OF_env_t *OF_env_main;
+
+/* Init standard OF structures */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_init (void)
+{
+ const unsigned char compat_str[] =
+#if 0
+ "PowerMac3,1\0MacRISC\0Power Macintosh\0";
+ "PowerMac1,2\0MacRISC\0Power Macintosh\0";
+ "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0";
+ "AAPL,PowerMac3,0\0MacRISC\0Power Macintosh\0";
+ "AAPL,Gossamer\0MacRISC\0Power Macintosh\0";
+#else
+ "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0";
+#endif
+ OF_env_t *OF_env;
+ OF_node_t *als, *opt, *chs, *pks;
+ OF_inst_t *inst;
+ OF_range_t range;
+
+ OF_DPRINTF("start\n");
+ OF_env_main = malloc(sizeof(OF_env_t));
+ if (OF_env_main == NULL) {
+ ERROR("%s cannot allocate main OF env\n", __func__);
+ return -1;
+ }
+ // memset(OF_env_main, 0, sizeof(OF_env_t));
+ OF_env = OF_env_main;
+ // OF_env_init(OF_env);
+
+ OF_DPRINTF("start\n");
+ /* Set up standard IEEE 1275 nodes */
+ /* "/device-tree" */
+ OF_node_root = OF_node_new(OF_env, NULL, "device-tree", OF_ADDRESS_NONE);
+ if (OF_node_root == NULL) {
+ ERROR("Cannot create 'device-tree'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom");
+#if 0
+ OF_prop_string_new(OF_env, OF_node_root,
+ "model", "PPC Open Hack'Ware " BIOS_VERSION);
+#else
+ OF_prop_string_new(OF_env, OF_node_root,
+ "model", compat_str);
+#endif
+ OF_property_new(OF_env, OF_node_root, "compatible",
+ compat_str, sizeof(compat_str));
+#if 0
+ OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright);
+#else
+ OF_prop_string_new(OF_env, OF_node_root, "copyright",
+ "Copyright 1983-1999 Apple Computer, Inc. All Rights Reserved");
+#endif
+ OF_prop_string_new(OF_env, OF_node_root, "system-id", "42");
+ OF_prop_int_new(OF_env, OF_node_root, "#address-cells", 1);
+ OF_prop_int_new(OF_env, OF_node_root, "#size-cells", 1);
+ OF_prop_int_new(OF_env, OF_node_root, "clock-frequency", 0x05F03E4D);
+ /* "/aliases" node */
+ als = OF_node_new(OF_env, OF_node_root, "aliases", OF_ADDRESS_NONE);
+ if (als == NULL) {
+ ERROR("Cannot create 'aliases'\n");
+ return -1;
+ }
+ /* "/chosen" node */
+ chs = OF_node_new(OF_env, OF_node_root, "chosen", OF_ADDRESS_NONE);
+ if (chs == NULL) {
+ ERROR("Cannot create 'choosen'\n");
+ return -1;
+ }
+ /* "/packages" node */
+ pks = OF_node_new(OF_env, OF_node_root, "packages", OF_ADDRESS_NONE);
+ if (pks == NULL) {
+ ERROR("Cannot create 'packages'\n");
+ return -1;
+ }
+ /* "/cpus" node */
+ {
+ OF_node_t *cpus;
+ cpus = OF_node_new(OF_env, OF_node_root, "cpus", OF_ADDRESS_NONE);
+ if (cpus == NULL) {
+ ERROR("Cannot create 'cpus'\n");
+ return -1;
+ }
+ OF_prop_int_new(OF_env, cpus, "#address-cells", 1);
+ OF_prop_int_new(OF_env, cpus, "#size-cells", 0);
+ OF_node_put(OF_env, cpus);
+ }
+ /* "/memory@0" node */
+ {
+ OF_node_t *mem;
+ mem = OF_node_new(OF_env, OF_node_root, "memory", 0);
+ if (mem == NULL) {
+ ERROR("Cannot create 'memory'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, mem, "device_type", "memory");
+ OF_prop_int_new(OF_env, chs, "memory", OF_pack_handle(OF_env, mem));
+ OF_node_put(OF_env, mem);
+ }
+ /* "/openprom" node */
+ {
+ OF_node_t *opp;
+ opp = OF_node_new(OF_env, OF_node_root, "openprom", OF_ADDRESS_NONE);
+ if (opp == NULL) {
+ ERROR("Cannot create 'openprom'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, opp, "device_type", "BootROM");
+ OF_prop_string_new(OF_env, opp, "model", "OpenFirmware 3");
+ OF_prop_int_new(OF_env, opp, "boot-syntax", 0x0001);
+ OF_property_new(OF_env, opp, "relative-addressing", NULL, 0);
+ OF_property_new(OF_env, opp, "supports-bootinfo", NULL, 0);
+ OF_prop_string_new(OF_env, opp, "built-on", stringify(BUILD_DATE));
+ OF_prop_string_new(OF_env, als, "rom", "/openprom");
+ OF_node_put(OF_env, opp);
+ }
+ /* "/options" node */
+ opt = OF_node_new(OF_env, OF_node_root, "options", OF_ADDRESS_NONE);
+ if (opt == NULL) {
+ ERROR("Cannot create 'options'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, opt, "little-endian?", "false");
+ OF_prop_string_new(OF_env, opt, "real-mode?", "false");
+ // Will play with this...
+ OF_prop_string_new(OF_env, opt, "security-mode", "none");
+ /* "/rom@ff800000" node */
+ {
+ OF_regprop_t regs;
+ OF_node_t *rom, *brom;
+
+ rom = OF_node_new(OF_env, OF_node_root, "rom", 0xff800000);
+ if (rom == NULL) {
+ ERROR("Cannot create 'rom'\n");
+ return -1;
+ }
+ regs.address = 0xFF800000;
+ regs.size = 0x00000000;
+ OF_property_new(OF_env, rom, "reg", &regs, sizeof(OF_regprop_t));
+ range.virt = 0xFF800000;
+ range.phys = 0xFF800000;
+ range.size = 0x00800000;
+ OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t));
+ OF_prop_int_new(OF_env, rom, "#address-cells", 1);
+ /* "/rom/boot-rom@fff00000" node */
+ brom = OF_node_new(OF_env, OF_node_root, "boot-rom", 0xfff00000);
+ if (brom == NULL) {
+ ERROR("Cannot create 'boot-rom'\n");
+ return -1;
+ }
+ regs.address = 0xFFF00000;
+ regs.size = 0x00010000;
+ OF_property_new(OF_env, brom, "reg", &regs, sizeof(OF_regprop_t));
+ OF_prop_string_new(OF_env, brom, "write-characteristic", "flash");
+ OF_prop_string_new(OF_env, brom, "BootROM-build-date",
+ stringify(BUILD_DATE) " at " stringify(BUILD_TIME));
+ OF_prop_string_new(OF_env, brom, "BootROM-version", BIOS_VERSION);
+ OF_prop_string_new(OF_env, brom, "copyright", copyright);
+ OF_prop_string_new(OF_env, brom, "model", BIOS_str);
+ OF_prop_int_new(OF_env, brom, "result", 0);
+#if 0
+ {
+ /* Hack taken 'as-is' from PearPC */
+ unsigned char info[] = {
+ 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
+ 0x00, 0x01, 0x12, 0xf2, 0x19, 0x99, 0x08, 0x19,
+ 0x94, 0x4e, 0x73, 0x27, 0xff, 0xf0, 0x80, 0x00,
+ 0x00, 0x07, 0x80, 0x01, 0x00, 0x01, 0x12, 0xf2,
+ 0x19, 0x99, 0x08, 0x19, 0xd7, 0xf3, 0xfc, 0x17,
+ 0xff, 0xf8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02,
+ 0x00, 0x01, 0x12, 0xf2, 0x19, 0x99, 0x08, 0x19,
+ 0xbb, 0x10, 0xfc, 0x17,
+ };
+ OF_property_new(OF_env, brom, "info", info, sizeof(info));
+ }
+#endif
+ OF_node_put(OF_env, brom);
+ OF_node_put(OF_env, rom);
+ }
+ /* From here, hardcoded hacks to get a Mac-like machine */
+ /* "/nvram@fff04000" node */
+ {
+ OF_regprop_t regs;
+ OF_node_t *nvr;
+
+ nvr = OF_node_new(OF_env, OF_node_root, "nvram", 0xfff04000);
+ if (nvr == NULL) {
+ ERROR("Cannot create 'nvram'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, nvr, "device_type", "nvram");
+ /* XXX: use real NVRAM size instead */
+ OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000);
+ OF_prop_string_new(OF_env, nvr, "compatible", "nvram,flash");
+ regs.address = 0xFFF04000;
+ regs.size = 0x00004000; /* Strange, isn't it ? */
+ OF_property_new(OF_env, nvr, "reg", &regs, sizeof(regs));
+ OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr));
+ OF_node_put(OF_env, nvr);
+ }
+ /* "/pseudo-hid" : hid emulation as Apple does */
+ {
+ OF_node_t *hid;
+
+ hid = OF_node_new(OF_env, OF_node_root,
+ "pseudo-hid", OF_ADDRESS_NONE);
+ if (hid == NULL) {
+ ERROR("Cannot create 'pseudo-hid'\n");
+ return -1;
+ }
+
+ /* "keyboard" node */
+ {
+ OF_node_t *kbd;
+ kbd = OF_node_new(OF_env, hid, "keyboard", OF_ADDRESS_NONE);
+ if (kbd == NULL) {
+ ERROR("Cannot create 'keyboard'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, kbd, "device_type", "keyboard");
+ OF_node_put(OF_env, kbd);
+ }
+ /* "mouse" node */
+ {
+ OF_node_t *mouse;
+ mouse = OF_node_new(OF_env, hid, "mouse", OF_ADDRESS_NONE);
+ if (mouse == NULL) {
+ ERROR("Cannot create 'mouse'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, mouse, "device_type", "mouse");
+ OF_node_put(OF_env, mouse);
+ }
+ /* "eject-key" node */
+ {
+ OF_node_t *ejk;
+ ejk = OF_node_new(OF_env, hid, "eject-key", OF_ADDRESS_NONE);
+ if (ejk == NULL) {
+ ERROR("Cannot create 'eject-key'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, ejk, "device_type", "eject-key");
+ OF_node_put(OF_env, ejk);
+ }
+ OF_node_put(OF_env, hid);
+ }
+
+
+#if 1 /* This is mandatory for claim to work
+ * but I don't know where it should really be (in cpu ?)
+ */
+ {
+ OF_node_t *mmu;
+
+ /* "/mmu" node */
+ mmu = OF_node_new(OF_env, OF_node_root, "mmu", OF_ADDRESS_NONE);
+ if (mmu == NULL) {
+ ERROR("Cannot create 'mmu'\n");
+ return -1;
+ }
+ inst = OF_instance_new(OF_env, mmu);
+ if (inst == NULL) {
+ OF_node_put(OF_env, mmu);
+ ERROR("Cannot create 'mmu' instance\n");
+ return -1;
+ }
+ OF_prop_int_new(OF_env, chs, "mmu",
+ OF_instance_get_id(OF_env, inst));
+ OF_method_new(OF_env, mmu, "translate", &OF_mmu_translate);
+ OF_method_new(OF_env, mmu, "map", &OF_mmu_map);
+ OF_node_put(OF_env, mmu);
+ }
+#endif
+
+ /* "/options/boot-args" node */
+ {
+ const unsigned char *args = "-v rootdev cdrom";
+ /* Ask MacOS X to print debug messages */
+ // OF_prop_string_new(OF_env, chs, "machargs", args);
+ // OF_prop_string_new(OF_env, opt, "boot-command", args);
+ OF_prop_string_new(OF_env, opt, "boot-args", args);
+ }
+
+ /* Release nodes */
+ OF_node_put(OF_env, opt);
+ OF_node_put(OF_env, pks);
+ OF_node_put(OF_env, chs);
+ OF_node_put(OF_env, als);
+ OF_node_put(OF_env, OF_node_root);
+ OF_DPRINTF("done\n");
+
+ return 0;
+}
+
+/* Motherboard */
+#if 0 // For now, static values are used
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_mb (const unsigned char *model, const unsigned char **compats)
+{
+ OF_env_t *OF_env;
+ OF_node_t *root;
+ int i;
+
+ OF_env = OF_env_main;
+ OF_DPRINTF("start\n");
+ root = OF_node_get(OF_env, "device_tree");
+ if (root == NULL) {
+ ERROR("Cannot get 'device-tree'\n");
+ return -1;
+ }
+ OF_DPRINTF("add model\n");
+ OF_prop_string_new(OF_env, OF_node_root, "model", model);
+ for (i = 0; i < 1 && compats[i] != NULL; i++) {
+ OF_DPRINTF("add compats %s\n", compats[i]);
+ OF_set_compatibility(OF_env, OF_node_root, compats[i]);
+ }
+ /* we don't implement neither "l2-cache" nor "cache" nodes */
+ OF_node_put(OF_env, root);
+ OF_DPRINTF("done\n");
+
+ return 0;
+}
+#endif
+
+/* CPU */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_cpu (const unsigned char *name, int num, uint32_t pvr,
+ uint32_t min_freq, uint32_t max_freq, uint32_t bus_freq,
+ uint32_t tb_freq, uint32_t reset_io)
+{
+ unsigned char tmp[OF_NAMELEN_MAX];
+ OF_env_t *OF_env;
+ OF_node_t *cpus, *cpu, *l2c, *chs, *als;
+
+ OF_env = OF_env_main;
+ OF_DPRINTF("start\n");
+ cpus = OF_node_get(OF_env, "cpus");
+ if (cpus == NULL) {
+ ERROR("Cannot get 'cpus'\n");
+ return -1;
+ }
+ cpu = OF_node_new(OF_env, cpus, name, OF_ADDRESS_NONE);
+ if (cpu == NULL) {
+ OF_node_put(OF_env, cpus);
+ ERROR("Cannot create cpu '%s'\n", name);
+ return -1;
+ }
+ OF_prop_string_new(OF_env, cpu, "device_type", "cpu");
+ OF_prop_int_new(OF_env, cpu, "#address-cells", 0x00000001);
+ OF_prop_int_new(OF_env, cpu, "#size-cells", 0x00000000);
+ OF_prop_int_new(OF_env, cpu, "reg", num);
+ OF_prop_int_new(OF_env, cpu, "cpu-version", pvr);
+ OF_prop_int_new(OF_env, cpu, "clock-frequency", max_freq);
+ OF_prop_int_new(OF_env, cpu, "timebase-frequency", tb_freq);
+ OF_prop_int_new(OF_env, cpu, "bus-frequency", bus_freq);
+ OF_prop_int_new(OF_env, cpu, "min-clock-frequency", min_freq);
+ OF_prop_int_new(OF_env, cpu, "max-clock-frequency", max_freq);
+ OF_prop_int_new(OF_env, cpu, "tlb-size", 0x80);
+ OF_prop_int_new(OF_env, cpu, "tlb-sets", 0x40);
+ OF_prop_int_new(OF_env, cpu, "i-tlb-size", 0x40);
+ OF_prop_int_new(OF_env, cpu, "i-tlb-sets", 0x20);
+ OF_prop_int_new(OF_env, cpu, "i-cache-size", 0x8000);
+ OF_prop_int_new(OF_env, cpu, "i-cache-sets", 0x80);
+ OF_prop_int_new(OF_env, cpu, "i-cache-bloc-size", 0x20);
+ OF_prop_int_new(OF_env, cpu, "i-cache-line-size", 0x20);
+ OF_prop_int_new(OF_env, cpu, "d-tlb-size", 0x40);
+ OF_prop_int_new(OF_env, cpu, "d-tlb-sets", 0x20);
+ OF_prop_int_new(OF_env, cpu, "d-cache-size", 0x8000);
+ OF_prop_int_new(OF_env, cpu, "d-cache-sets", 0x80);
+ OF_prop_int_new(OF_env, cpu, "d-cache-bloc-size", 0x20);
+ OF_prop_int_new(OF_env, cpu, "d-cache-line-size", 0x20);
+ OF_prop_int_new(OF_env, cpu, "reservation-granule-size", 0x20);
+ OF_prop_int_new(OF_env, cpus, "soft-reset", reset_io);
+ OF_prop_string_new(OF_env, cpus, "graphics", "");
+ OF_prop_string_new(OF_env, cpus, "performance-monitor", "");
+ OF_prop_string_new(OF_env, cpus, "data-streams", "");
+ OF_prop_string_new(OF_env, cpu, "state", "running");
+ /* We don't implement:
+ * "dynamic-powerstep" & "reduced-clock-frequency"
+ * "l2cr-value"
+ */
+ /* Add L2 cache */
+ l2c = OF_node_new(OF_env, cpu, "l2cache", OF_ADDRESS_NONE);
+ if (l2c == NULL) {
+ ERROR("Cannot create 'l2cache'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, l2c, "device_type", "cache");
+ OF_prop_int_new(OF_env, l2c, "i-cache-size", 0x100000);
+ OF_prop_int_new(OF_env, l2c, "i-cache-sets", 0x2000);
+ OF_prop_int_new(OF_env, l2c, "i-cache-line-size", 0x40);
+ OF_prop_int_new(OF_env, l2c, "d-cache-size", 0x100000);
+ OF_prop_int_new(OF_env, l2c, "d-cache-sets", 0x2000);
+ OF_prop_int_new(OF_env, l2c, "d-cache-line-size", 0x40);
+ /* Register it in the cpu node */
+ OF_prop_int_new(OF_env, cpu, "l2-cache", OF_pack_handle(OF_env, l2c));
+ OF_node_put(OF_env, l2c);
+ /* Set it in "/chosen" and "/aliases" */
+ if (num == 0) {
+ OF_pack_get_path(OF_env, tmp, 512, cpu);
+ chs = OF_node_get(OF_env, "chosen");
+ if (chs == NULL) {
+ OF_node_put(OF_env, cpus);
+ ERROR("Cannot get 'chosen'\n");
+ return -1;
+ }
+ OF_prop_int_new(OF_env, chs, "cpu", OF_pack_handle(OF_env, cpu));
+ OF_node_put(OF_env, chs);
+ als = OF_node_get(OF_env, "aliases");
+ if (als == NULL) {
+ OF_node_put(OF_env, cpus);
+ ERROR("Cannot get 'aliases'\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, als, "cpu", tmp);
+ OF_node_put(OF_env, als);
+ }
+ OF_node_put(OF_env, cpu);
+ OF_node_put(OF_env, cpus);
+ OF_DPRINTF("done\n");
+
+ return 0;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_translations (int nb, OF_transl_t *translations)
+{
+ OF_env_t *OF_env;
+ OF_node_t *cpus, *cpu;
+ OF_transl_t *new;
+ int i;
+
+ OF_env = OF_env_main;
+ OF_DPRINTF("start\n");
+ cpus = OF_node_get(OF_env, "cpus");
+ if (cpus == NULL) {
+ OF_node_put(OF_env, cpus);
+ ERROR("Cannot get 'cpus'\n");
+ return -1;
+ }
+ cpu = cpus->children;
+ new = malloc(nb * sizeof(OF_transl_t));
+ if (new == NULL) {
+ ERROR("Cannot create new translation\n");
+ return -1;
+ }
+ for (i = 0; i < nb; i++) {
+ new->virt = translations[i].virt;
+ new->size = translations[i].size;
+ new->phys = translations[i].phys;
+ new->mode = translations[i].mode;
+ OF_DPRINTF("%d\n", i);
+ }
+ OF_property_new(OF_env, cpu, "translations",
+ new, nb * sizeof(OF_transl_t));
+ OF_node_put(OF_env, cpus);
+ OF_DPRINTF("done\n");
+
+ return 0;
+}
+
+/* Memory ranges */
+typedef struct OF_mem_t OF_mem_t;
+struct OF_mem_t {
+ uint32_t start;
+ uint32_t size;
+};
+
+#define OF_MAX_MEMRANGES 16
+/* First entry is the whole known memory space */
+static OF_mem_t OF_mem_ranges[OF_MAX_MEMRANGES + 1];
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_memory (uint32_t memsize, unused uint32_t bios_size)
+{
+ OF_env_t *OF_env;
+ OF_node_t *mem;
+ OF_regprop_t regs[4];
+ int i;
+
+ OF_env = OF_env_main;
+ OF_DPRINTF("find node\n");
+ mem = OF_node_get(OF_env, "memory");
+ if (mem == NULL) {
+ ERROR("Cannot get 'memory'\n");
+ return -1;
+ }
+ OF_DPRINTF("Memory package: %04x\n", OF_pack_handle(OF_env, mem));
+ regs[0].address = 0x00000000;
+ regs[0].size = memsize;
+ regs[1].address = 0x00000000;
+ regs[1].size = 0x00000000;
+ regs[2].address = 0x00000000;
+ regs[2].size = 0x00000000;
+ regs[3].address = 0x00000000;
+ regs[3].size = 0x00000000;
+ OF_property_new(OF_env, mem, "reg", regs, 4 * sizeof(OF_regprop_t));
+#if 0
+#if 1
+ regs[0].address = 0x00000000;
+ regs[0].size = 0x05800000;
+ regs[1].address = 0x06000000;
+ regs[1].size = memsize - 0x06000000;
+ regs[2].address = 0x00000000;
+ regs[2].size = 0x00000000;
+ OF_property_new(OF_env, mem, "available",
+ regs, 3 * sizeof(OF_regprop_t));
+#else
+ regs[0].address = 0x06000000;
+ regs[0].size = memsize - 0x06000000;
+ regs[1].address = 0x00000000;
+ regs[1].size = 0x00000000;
+ OF_property_new(OF_env, mem, "available",
+ regs, 2 * sizeof(OF_regprop_t));
+#endif
+#endif
+ OF_node_put(OF_env, mem);
+#if 0
+ {
+ OF_node_t *mmu;
+ mmu = OF_node_get(OF_env, "mmu");
+ if (mmu == NULL) {
+ ERROR("Cannot get 'mmu'\n");
+ return -1;
+ }
+ regs[0].address = 0x00000000;
+ regs[0].size = memsize;
+ OF_property_new(OF_env, mmu, "reg", regs, sizeof(OF_regprop_t));
+ regs[0].address = 0x00000000;
+ regs[0].size = 0x05800000;
+ regs[1].address = 0x06000000;
+ regs[1].size = memsize - 0x06000000;
+ regs[2].address = 0x00000000;
+ regs[2].size = 0x00000000;
+ OF_property_new(OF_env, mmu, "available",
+ regs, 3 * sizeof(OF_regprop_t));
+ OF_node_put(OF_env, mmu);
+ }
+#endif
+ /* Also update the claim areas */
+ OF_mem_ranges[0].start = 0x00000000;
+ OF_mem_ranges[0].size = memsize;
+ OF_mem_ranges[1].start = 0x58000000;
+ OF_mem_ranges[1].size = 0x08000000;
+ for (i = 2; i < OF_MAX_MEMRANGES + 1; i++) {
+ OF_mem_ranges[i].start = -1;
+ OF_mem_ranges[i].size = -1;
+ }
+ OF_DPRINTF("done\n");
+
+ return 0;
+}
+
+/* Linux kernel command line */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_bootargs (const unsigned char *bootargs)
+{
+ OF_env_t *OF_env;
+ OF_node_t *chs;
+
+ OF_env = OF_env_main;
+ if (bootargs == NULL)
+ bootargs = "";
+ chs = OF_node_get(OF_env, "chosen");
+ if (chs == NULL) {
+ ERROR("Cannot get 'chosen'\n");
+ return -1;
+ }
+ OF_prop_string_set(OF_env, chs, "bootargs", bootargs);
+ // OF_prop_string_set(OF_env, OF_node_root, "bootargs", "");
+ OF_node_put(OF_env, chs);
+
+ return 0;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void *OF_pci_device_new (OF_env_t *OF_env, OF_node_t *parent,
+ pci_dev_t *dev, uint32_t address,
+ uint16_t rev, uint32_t ccode,
+ uint16_t min_grant, uint16_t max_latency)
+{
+ OF_node_t *node;
+
+ dprintf("register '%s' '%s' '%s' '%s' 0x%08x in '%s' 0x%08x\n",
+ dev->name, dev->type, dev->compat, dev->model, address,
+ parent->prop_name->value, *(uint32_t *)parent->prop_address->value);
+ node = OF_node_new(OF_env, parent, dev->name, address);
+ if (node == NULL)
+ return NULL;
+ OF_prop_int_new(OF_env, node, "vendor-id", dev->vendor);
+ OF_prop_int_new(OF_env, node, "device-id", dev->product);
+ OF_prop_int_new(OF_env, node, "revision-id", rev);
+ OF_prop_int_new(OF_env, node, "class-code", ccode);
+ OF_prop_int_new(OF_env, node, "min-grant", min_grant);
+ OF_prop_int_new(OF_env, node, "max-latency", max_latency);
+ if (dev->type != NULL)
+ OF_prop_string_new(OF_env, node, "device_type", dev->type);
+ if (dev->compat != NULL)
+ OF_prop_string_new(OF_env, node, "compatible", dev->compat);
+ if (dev->model != NULL)
+ OF_prop_string_new(OF_env, node, "model", dev->model);
+ if (dev->acells != 0)
+ OF_prop_int_new(OF_env, node, "#address-cells", dev->acells);
+ if (dev->scells != 0)
+ OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->acells);
+ if (dev->icells != 0)
+ OF_prop_int_new(OF_env, node, "#size-cells", dev->acells);
+ dprintf("Done %p %p\n", parent, node);
+
+ return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+void *OF_register_pci_host (pci_dev_t *dev, uint16_t rev, uint32_t ccode,
+ uint32_t cfg_base, uint32_t cfg_len,
+ uint32_t mem_base, uint32_t mem_len,
+ uint32_t io_base, uint32_t io_len,
+ uint32_t rbase, uint32_t rlen,
+ uint16_t min_grant, uint16_t max_latency)
+{
+ OF_env_t *OF_env;
+ pci_range_t ranges[3];
+ OF_regprop_t regs[1];
+ OF_node_t *pci_host;
+ int nranges;
+
+ OF_env = OF_env_main;
+ dprintf("register PCI host '%s' '%s' '%s' '%s'\n",
+ dev->name, dev->type, dev->compat, dev->model);
+ pci_host = OF_pci_device_new(OF_env, OF_node_root, dev, cfg_base,
+ rev, ccode, min_grant, max_latency);
+ if (pci_host == NULL) {
+ ERROR("Cannot create pci host\n");
+ return NULL;
+ }
+ regs[0].address = cfg_base;
+ regs[0].size = cfg_len;
+ OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t));
+ nranges = 0;
+ if (rbase != 0x00000000) {
+ ranges[nranges].addr.hi = 0x02000000;
+ ranges[nranges].addr.mid = 0x00000000;
+ ranges[nranges].addr.lo = rbase;
+ ranges[nranges].phys = rbase;
+ ranges[nranges].size_hi = 0x00000000;
+ ranges[nranges].size_lo = rlen;
+ nranges++;
+ }
+ if (io_base != 0x00000000) {
+ ranges[nranges].addr.hi = 0x01000000;
+ ranges[nranges].addr.mid = 0x00000000;
+ ranges[nranges].addr.lo = 0x00000000;
+ ranges[nranges].phys = io_base;
+ ranges[nranges].size_hi = 0x00000000;
+ ranges[nranges].size_lo = io_len;
+ nranges++;
+ }
+ if (mem_base != 0x00000000) {
+ ranges[nranges].addr.hi = 0x02000000;
+ ranges[nranges].addr.mid = 0x00000000;
+ ranges[nranges].addr.lo = mem_base;
+ ranges[nranges].phys = mem_base;
+ ranges[nranges].size_hi = 0x00000000;
+ ranges[nranges].size_lo = mem_len;
+ nranges++;
+ }
+ OF_property_new(OF_env, pci_host, "ranges", ranges,
+ nranges * sizeof(pci_range_t));
+
+ return pci_host;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+void *OF_register_pci_bridge (void *parent, pci_dev_t *dev,
+ uint32_t cfg_base, uint32_t cfg_len,
+ uint8_t devfn, uint8_t rev, uint32_t ccode,
+ uint16_t min_grant, uint16_t max_latency)
+{
+ OF_env_t *OF_env;
+ OF_regprop_t regs[1];
+ OF_node_t *pci_bridge;
+
+ OF_env = OF_env_main;
+ OF_DPRINTF("register '%s' %08x '%s' '%s' '%s'\n",
+ dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+ dprintf("register PCI bridge '%s' %08x '%s' '%s' '%s'\n",
+ dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+ pci_bridge = OF_pci_device_new(OF_env, parent, dev, devfn >> 3,
+ rev, ccode, min_grant, max_latency);
+ if (pci_bridge == NULL) {
+ ERROR("Cannot create pci bridge\n");
+ return NULL;
+ }
+ regs[0].address = cfg_base;
+ regs[0].size = cfg_len;
+ OF_property_new(OF_env, pci_bridge, "reg", regs, sizeof(OF_regprop_t));
+
+ return pci_bridge;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+void *OF_register_pci_device (void *parent, pci_dev_t *dev,
+ uint8_t devfn, uint8_t rev, uint32_t ccode,
+ uint16_t min_grant, uint16_t max_latency)
+{
+ OF_env_t *OF_env;
+ OF_node_t *pci_dev;
+
+ OF_env = OF_env_main;
+ OF_DPRINTF("register '%s' %08x '%s' '%s' '%s'\n",
+ dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+ dprintf("register pci device '%s' %08x '%s' '%s' '%s'\n",
+ dev->name, devfn >> 3, dev->type, dev->compat, dev->model);
+ pci_dev = OF_pci_device_new(OF_env, parent, dev, devfn >> 3,
+ rev, ccode, min_grant, max_latency);
+
+ return pci_dev;
+}
+
+void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses)
+{
+ OF_env_t *OF_env;
+ OF_regprop_t regs[1];
+
+ OF_env = OF_env_main;
+ regs[0].address = first_bus;
+ regs[0].size = nb_busses;
+ OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t));
+}
+
+void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn,
+ uint32_t *regions, uint32_t *sizes)
+{
+ OF_env_t *OF_env;
+ pci_reg_prop_t pregs[6], rregs[6];
+ uint32_t mask;
+ int i, j, k;
+
+ OF_env = OF_env_main;
+ if (regions[0] != 0x00000000)
+ OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F);
+ for (i = 0, j = 0, k = 0; i < 6; i++) {
+ if (regions[i] != 0x00000000 && sizes[i] != 0x00000000) {
+ /* Generate "reg" property
+ */
+ if (regions[i] & 1) {
+ /* IO space */
+ rregs[j].addr.hi = 0x01000000;
+ mask = 0x00000001;
+ } else if (regions[i] & 4) {
+ /* 64 bits address space */
+ rregs[j].addr.hi = 0x83000000;
+ mask = 0x0000000F;
+#if 0
+ } else if ((regions[i] & 0xF) == 0x00) { /* ? */
+ /* Configuration space */
+ rregs[j].addr.hi = 0x00000000;
+ mask = 0x0000000F;
+#endif
+ } else {
+ /* 32 bits address space */
+ rregs[j].addr.hi = 0x82000000;
+ mask = 0x0000000F;
+ }
+ /* Set bus number */
+ rregs[j].addr.hi |= bus << 16;
+ /* Set device/function */
+ rregs[j].addr.hi |= devfn << 8;
+ /* Set register */
+#if 1
+ rregs[j].addr.hi |= 0x10 + (i * sizeof(uint32_t)); /* ? */
+#endif
+ /* Set address */
+ rregs[j].addr.mid = 0x00000000;
+ rregs[j].addr.lo = regions[i] & ~mask;
+ /* Set size */
+ rregs[j].size_hi = 0x00000000;
+ rregs[j].size_lo = sizes[i];
+#if 0
+ if ((rregs[j].addr.hi & 0x03000000) != 0x00000000)
+#endif
+ {
+ /* No assigned address for configuration space */
+ pregs[k].addr.hi = rregs[j].addr.hi; /* ? */
+ pregs[k].addr.mid = rregs[j].addr.mid;
+ pregs[k].addr.lo = rregs[j].addr.lo; /* ? */
+ pregs[k].size_hi = rregs[j].size_hi;
+ pregs[k].size_lo = rregs[j].size_lo;
+ k++;
+ }
+ j++;
+ }
+ }
+ if (j > 0) {
+ OF_property_new(OF_env, dev, "reg",
+ rregs, j * sizeof(pci_reg_prop_t));
+ } else {
+ OF_property_new(OF_env, dev, "reg", NULL, 0);
+ }
+ if (k > 0) {
+ OF_property_new(OF_env, dev, "assigned-addresses",
+ pregs, k * sizeof(pci_reg_prop_t));
+ } else {
+ OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0);
+ }
+#if 0
+ {
+ OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name;
+
+ if (j > 0) {
+ dprintf("PCI device '%s' %d %d %d reg properties:\n",
+ prop_name->value, bus, devfn >> 3, devfn & 7);
+ for (i = 0; i < j; i++) {
+ dprintf(" addr: %08x %08x %08x size: %08x %08x\n",
+ rregs[i].addr.hi, rregs[i].addr.mid, rregs[i].addr.lo,
+ rregs[i].size_hi, rregs[i].size_lo);
+ }
+ } else {
+ dprintf("PCI device '%s' %d %d %d has no reg properties:\n",
+ prop_name->value, bus, devfn >> 3, devfn & 7);
+ }
+ if (k > 0) {
+ dprintf("PCI device '%s' %d %d %d "
+ "assigned addresses properties:\n",
+ prop_name->value, bus, devfn >> 3, devfn & 7);
+ for (i = 0; i < j; i++) {
+ dprintf(" addr: %08x %08x %08x size: %08x %08x\n",
+ pregs[i].addr.hi, pregs[i].addr.mid, pregs[i].addr.lo,
+ pregs[i].size_hi, pregs[i].size_lo);
+ }
+ } else {
+ dprintf("PCI device '%s' %d %d %d has no "
+ "assigned addresses properties:\n",
+ prop_name->value, bus, devfn >> 3, devfn & 7);
+ }
+ }
+#endif
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_bus (const unsigned char *name, uint32_t address,
+ const unsigned char *type)
+{
+ unsigned char buffer[OF_NAMELEN_MAX];
+ OF_env_t *OF_env;
+ OF_node_t *bus, *als;
+
+ OF_env = OF_env_main;
+ als = OF_node_get(OF_env, "aliases");
+ if (als == NULL) {
+ ERROR("Cannot get 'aliases'\n");
+ return -1;
+ }
+ bus = OF_node_new(OF_env, OF_node_root, name, address);
+ if (bus == NULL) {
+ OF_node_put(OF_env, als);
+ ERROR("Cannot create bus '%s'\n", name);
+ return -1;
+ }
+ OF_prop_string_set(OF_env, bus, "type", type);
+ sprintf(buffer, "/%s", name);
+ OF_prop_string_set(OF_env, als, name, buffer);
+ /* For ISA, should add DMA ranges */
+ OF_node_put(OF_env, bus);
+ OF_node_put(OF_env, als);
+
+ return 0;
+}
+
+// We will need to register stdin & stdout via the serial port
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_serial (const unsigned char *bus, const unsigned char *name,
+ uint32_t io_base, unused int irq)
+{
+ unsigned char tmp[OF_NAMELEN_MAX];
+ OF_env_t *OF_env;
+ OF_node_t *busn, *srl, *als;
+
+ OF_env = OF_env_main;
+ als = OF_node_get(OF_env, "aliases");
+ if (als == NULL) {
+ ERROR("Cannot get 'aliases'\n");
+ return -1;
+ }
+ busn = OF_node_get(OF_env, bus);
+ srl = OF_node_new(OF_env, busn, name, io_base);
+ if (srl == NULL) {
+ OF_node_put(OF_env, als);
+ ERROR("Cannot create serial '%s'\n", name);
+ return -1;
+ }
+ OF_prop_string_set(OF_env, srl, "device_type", "serial");
+ OF_prop_string_set(OF_env, srl, "compatible", "pnpPNP,501");
+ switch (io_base) {
+ case 0x3F8:
+ OF_pack_get_path(OF_env, tmp, 512, srl);
+ OF_prop_string_new(OF_env, als, "com1", tmp);
+ break;
+ case 0x2F8:
+ OF_pack_get_path(OF_env, tmp, 512, srl);
+ OF_prop_string_new(OF_env, als, "com2", tmp);
+ break;
+ default:
+ break;
+ }
+ /* register read/write methods and create an instance of the package */
+ OF_method_new(OF_env, srl, "write", &OF_serial_write);
+ OF_method_new(OF_env, srl, "read", &OF_serial_read);
+ OF_node_put(OF_env, srl);
+ OF_node_put(OF_env, busn);
+ OF_node_put(OF_env, als);
+
+ return 0;
+}
+
+/* We will also need /isa/rtc */
+
+__attribute__ (( section (".OpenFirmware") ))
+int OF_register_stdio (const unsigned char *dev_in,
+ const unsigned char *dev_out)
+{
+ OF_env_t *OF_env;
+ OF_node_t *chs, *ndev_in, *ndev_out, *kbd;
+ OF_inst_t *in_inst, *out_inst;
+
+ OF_env = OF_env_main;
+ chs = OF_node_get(OF_env, "chosen");
+ if (chs == NULL) {
+ ERROR("Cannot get 'chosen'\n");
+ return -1;
+ }
+ ndev_in = OF_node_get(OF_env, dev_in);
+ ndev_out = OF_node_get(OF_env, dev_out);
+ in_inst = OF_instance_new(OF_env, ndev_in);
+ if (in_inst == NULL) {
+ OF_node_put(OF_env, ndev_out);
+ OF_node_put(OF_env, ndev_in);
+ OF_node_put(OF_env, chs);
+ ERROR("Cannot create in_inst\n");
+ return -1;
+ }
+ out_inst = OF_instance_new(OF_env, ndev_out);
+ if (out_inst == NULL) {
+ OF_node_put(OF_env, ndev_out);
+ OF_node_put(OF_env, ndev_in);
+ OF_node_put(OF_env, chs);
+ ERROR("Cannot create out_inst\n");
+ return -1;
+ }
+ OF_prop_int_set(OF_env, chs, "stdin",
+ OF_instance_get_id(OF_env, in_inst));
+ OF_prop_int_set(OF_env, chs, "stdout",
+ OF_instance_get_id(OF_env, out_inst));
+ kbd = OF_node_new(OF_env, ndev_in, "keyboard", OF_ADDRESS_NONE);
+ if (kbd == NULL) {
+ OF_node_put(OF_env, ndev_out);
+ OF_node_put(OF_env, ndev_in);
+ OF_node_put(OF_env, chs);
+ ERROR("Cannot create 'keyboard' for stdio\n");
+ return -1;
+ }
+ OF_prop_string_new(OF_env, kbd, "device_type", "keyboard");
+ OF_node_put(OF_env, kbd);
+ OF_DPRINTF("stdin h: 0x%0x out : 0x%0x\n",
+ OF_instance_get_id(OF_env, in_inst),
+ OF_instance_get_id(OF_env, out_inst));
+ OF_node_put(OF_env, ndev_out);
+ OF_node_put(OF_env, ndev_in);
+ OF_node_put(OF_env, chs);
+
+ return 0;
+}
+
+void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size,
+ void *private_data)
+{
+ unsigned char tmp[OF_NAMELEN_MAX];
+ OF_env_t *OF_env;
+ pci_reg_prop_t pregs[2];
+ OF_node_t *mio, *chs, *als;
+ uint16_t pic_phandle;
+
+ OF_DPRINTF("mac-io: %p\n", dev);
+ OF_env = OF_env_main;
+ chs = OF_node_get(OF_env, "chosen");
+ if (chs == NULL) {
+ ERROR("Cannot get 'chosen'\n");
+ return;
+ }
+ als = OF_node_get(OF_env, "aliases");
+ if (als == NULL) {
+ OF_node_put(OF_env, als);
+ ERROR("Cannot get 'aliases'\n");
+ return;
+ }
+ /* Mac-IO is mandatory for OSX to boot */
+ mio = dev;
+ mio->private_data = private_data;
+ pregs[0].addr.hi = 0x00000000;
+ pregs[0].addr.mid = 0x82013810;
+ pregs[0].addr.lo = 0x00000000;
+ pregs[0].size_hi = base_address;
+ pregs[0].size_lo = size;
+ OF_property_new(OF_env, mio, "ranges",
+ &pregs, sizeof(pci_reg_prop_t));
+#if 0
+ pregs[0].addr.hi = 0x82013810;
+ pregs[0].addr.mid = 0x00000000;
+ pregs[0].addr.lo = 0x80800000;
+ pregs[0].size_hi = 0x00000000;
+ pregs[0].size_lo = 0x00080000;
+ OF_property_new(OF_env, mio, "assigned-addresses",
+ &pregs, sizeof(pci_reg_prop_t));
+#endif
+ /* OpenPIC */
+ {
+ OF_regprop_t regs[4];
+ OF_node_t *mpic;
+ mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000);
+ if (mpic == NULL) {
+ ERROR("Cannot create 'mpic'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, mpic, "device_type", "open-pic");
+ OF_prop_string_new(OF_env, mpic, "compatible", "chrp,open-pic");
+ OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0);
+ OF_property_new(OF_env, mpic, "built-in", NULL, 0);
+ OF_prop_int_new(OF_env, mpic, "clock-frequency", 0x003F7A00);
+ OF_prop_int_new(OF_env, mpic, "#address-cells", 0);
+ OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 2);
+ memset(regs, 0, 4 * sizeof(OF_regprop_t));
+ regs[0].address = 0x00040000;
+ regs[0].size = 0x00040000;
+ OF_property_new(OF_env, mpic, "reg",
+ &regs, 1 * sizeof(OF_regprop_t));
+ pic_phandle = OF_pack_handle(OF_env, mpic);
+ OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle);
+ OF_node_put(OF_env, mpic);
+ }
+#if 1
+ /* escc is usefull to get MacOS X debug messages */
+ {
+ OF_regprop_t regs[8];
+ uint32_t irqs[6];
+ OF_node_t *scc, *chann;
+ scc = OF_node_new(OF_env, mio, "escc", 0x13000);
+ if (scc == NULL) {
+ ERROR("Cannot create 'escc'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, scc, "device_type", "escc");
+ OF_prop_string_new(OF_env, scc, "compatible", "chrp,es0");
+ OF_property_new(OF_env, scc, "built-in", NULL, 0);
+ OF_prop_int_new(OF_env, scc, "#address-cells", 1);
+ memset(regs, 0, 8 * sizeof(OF_regprop_t));
+ regs[0].address = 0x00013000;
+ regs[0].size = 0x00001000;
+ regs[1].address = 0x00008400;
+ regs[1].size = 0x00000100;
+ regs[2].address = 0x00008500;
+ regs[2].size = 0x00000100;
+ regs[3].address = 0x00008600;
+ regs[3].size = 0x00000100;
+ regs[4].address = 0x00008700;
+ regs[4].size = 0x00000100;
+ OF_property_new(OF_env, scc, "reg",
+ regs, 5 * sizeof(OF_regprop_t));
+ OF_property_new(OF_env, scc, "ranges", NULL, 0);
+ /* Set up two channels */
+ chann = OF_node_new(OF_env, scc, "ch-a", 0x13020);
+ if (chann == NULL) {
+ ERROR("Cannot create 'ch-a'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, chann, "device_type", "serial");
+ OF_prop_string_new(OF_env, chann, "compatible", "chrp,es2");
+ OF_property_new(OF_env, chann, "built-in", NULL, 0);
+ OF_prop_int_new(OF_env, chann, "slot-names", 0);
+ OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+ memset(regs, 0, 8 * sizeof(OF_regprop_t));
+ regs[0].address = 0x00013020;
+ regs[0].size = 0x00000001;
+ regs[1].address = 0x00013030;
+ regs[1].size = 0x00000001;
+ regs[2].address = 0x00013050;
+ regs[2].size = 0x00000001;
+ regs[3].address = 0x00008400;
+ regs[3].size = 0x00000100;
+ regs[4].address = 0x00008500;
+ regs[4].size = 0x00000100;
+ OF_property_new(OF_env, chann, "reg",
+ regs, 5 * sizeof(OF_regprop_t));
+ /* XXX: tofix: those are regprops */
+ irqs[0] = 0x16;
+ irqs[1] = 0x01;
+ irqs[2] = 0x05;
+ irqs[3] = 0x00;
+ irqs[4] = 0x06;
+ irqs[5] = 0x00;
+ OF_property_new(OF_env, chann, "interrupts",
+ irqs, 6 * sizeof(uint32_t));
+ OF_node_put(OF_env, chann);
+ chann = OF_node_new(OF_env, scc, "ch-b", 0x13000);
+ if (chann == NULL) {
+ ERROR("Cannot create 'ch-b'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, chann, "device_type", "serial");
+ OF_prop_string_new(OF_env, chann, "compatible", "chrp,es3");
+ OF_property_new(OF_env, chann, "built-in", NULL, 0);
+ OF_prop_int_new(OF_env, chann, "slot-names", 0);
+ OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+ memset(regs, 0, 8 * sizeof(OF_regprop_t));
+ regs[0].address = 0x00013000;
+ regs[0].size = 0x00000001;
+ regs[1].address = 0x00013010;
+ regs[1].size = 0x00000001;
+ regs[2].address = 0x00013040;
+ regs[2].size = 0x00000001;
+ regs[3].address = 0x00008600;
+ regs[3].size = 0x00000100;
+ regs[4].address = 0x00008700;
+ regs[4].size = 0x00000100;
+ OF_property_new(OF_env, chann, "reg",
+ regs, 5 * sizeof(OF_regprop_t));
+ /* XXX: tofix: those are regprops */
+ irqs[0] = 0x17;
+ irqs[1] = 0x01;
+ irqs[2] = 0x07;
+ irqs[3] = 0x00;
+ irqs[4] = 0x08;
+ irqs[5] = 0x00;
+ OF_property_new(OF_env, chann, "interrupts",
+ irqs, 6 * sizeof(uint32_t));
+ OF_node_put(OF_env, chann);
+ OF_node_put(OF_env, scc);
+ /* MacOS likes escc-legacy */
+ scc = OF_node_new(OF_env, mio, "escc-legacy", 0x12000);
+ if (scc == NULL) {
+ ERROR("Cannot create 'escc-legacy'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, scc, "device_type", "escc-legacy");
+ OF_prop_string_new(OF_env, scc, "compatible", "chrp,es1");
+ OF_property_new(OF_env, scc, "built-in", NULL, 0);
+ OF_prop_int_new(OF_env, scc, "#address-cells", 1);
+ memset(regs, 0, 8 * sizeof(OF_regprop_t));
+ regs[0].address = 0x00012000;
+ regs[0].size = 0x00001000;
+ regs[1].address = 0x00008400;
+ regs[1].size = 0x00000100;
+ regs[2].address = 0x00008500;
+ regs[2].size = 0x00000100;
+ regs[3].address = 0x00008600;
+ regs[3].size = 0x00000100;
+ regs[4].address = 0x00008700;
+ regs[4].size = 0x00000100;
+ OF_property_new(OF_env, scc, "reg",
+ regs, 8 * sizeof(OF_regprop_t));
+ OF_property_new(OF_env, scc, "ranges", NULL, 0);
+ /* Set up two channels */
+ chann = OF_node_new(OF_env, scc, "ch-a", 0x12004);
+ if (chann == NULL) {
+ ERROR("Cannot create 'ch-a'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, chann, "device_type", "serial");
+ OF_prop_string_new(OF_env, chann, "compatible", "chrp,es4");
+ OF_property_new(OF_env, chann, "built-in", NULL, 0);
+ OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+ memset(regs, 0, 8 * sizeof(OF_regprop_t));
+ regs[0].address = 0x00012004;
+ regs[0].size = 0x00000001;
+ regs[1].address = 0x00012006;
+ regs[1].size = 0x00000001;
+ regs[2].address = 0x0001200A;
+ regs[2].size = 0x00000001;
+ regs[3].address = 0x00008400;
+ regs[3].size = 0x00000100;
+ regs[4].address = 0x00008500;
+ regs[4].size = 0x00000100;
+ OF_property_new(OF_env, chann, "reg",
+ regs, 8 * sizeof(OF_regprop_t));
+ /* XXX: tofix: those are regprops */
+ irqs[0] = 0x16;
+ irqs[1] = 0x01;
+ irqs[2] = 0x05;
+ irqs[3] = 0x00;
+ irqs[4] = 0x06;
+ irqs[5] = 0x00;
+ OF_property_new(OF_env, chann, "interrupts",
+ irqs, 6 * sizeof(uint32_t));
+ OF_node_put(OF_env, chann);
+ chann = OF_node_new(OF_env, scc, "ch-b", 0x12000);
+ if (chann == NULL) {
+ ERROR("Cannot create 'ch-b'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, chann, "device_type", "serial");
+ OF_prop_string_new(OF_env, chann, "compatible", "chrp,es5");
+ OF_property_new(OF_env, chann, "built-in", NULL, 0);
+ OF_prop_int_new(OF_env, chann, "interrupt-parent", pic_phandle);
+ memset(regs, 0, 8 * sizeof(OF_regprop_t));
+ regs[0].address = 0x00012000;
+ regs[0].size = 0x00000001;
+ regs[1].address = 0x00012002;
+ regs[1].size = 0x00000001;
+ regs[2].address = 0x00012008;
+ regs[2].size = 0x00000001;
+ regs[3].address = 0x00008600;
+ regs[3].size = 0x00000100;
+ regs[4].address = 0x00008700;
+ regs[4].size = 0x00000100;
+ OF_property_new(OF_env, chann, "reg",
+ regs, 8 * sizeof(OF_regprop_t));
+ /* XXX: tofix: those are regprops */
+ irqs[0] = 0x17;
+ irqs[1] = 0x01;
+ irqs[2] = 0x07;
+ irqs[3] = 0x00;
+ irqs[4] = 0x08;
+ irqs[5] = 0x00;
+ OF_property_new(OF_env, chann, "interrupts",
+ irqs, 6 * sizeof(uint32_t));
+ OF_node_put(OF_env, chann);
+ OF_node_put(OF_env, scc);
+ }
+#endif
+ /* IDE controller */
+ {
+ OF_node_t *ata;
+ OF_regprop_t regs[2];
+ ata = OF_node_new(OF_env, mio, "ata-4", 0x1f000);
+ if (ata == NULL) {
+ ERROR("Cannot create 'ata-4'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, ata, "device_type", "ata");
+#if 1
+ OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata");
+ OF_prop_string_new(OF_env, ata, "model", "ata-4");
+#else
+ OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
+ OF_prop_string_new(OF_env, ata, "model", "ata-4");
+#endif
+ OF_prop_int_new(OF_env, ata, "#address-cells", 1);
+ OF_prop_int_new(OF_env, ata, "#size-cells", 0);
+ regs[0].address = 0x0001F000;
+ regs[0].size = 0x00001000;
+#if 0 // HACK: Don't set up DMA registers
+ regs[1].address = 0x00008A00;
+ regs[1].size = 0x00001000;
+ OF_property_new(OF_env, ata, "reg",
+ regs, 2 * sizeof(OF_regprop_t));
+#else
+ OF_property_new(OF_env, ata, "reg",
+ regs, sizeof(OF_regprop_t));
+#endif
+ OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
+ regs[0].address = 0x00000013;
+ regs[0].size = 0x00000001;
+ regs[1].address = 0x0000000B;
+ regs[1].size = 0x00000000;
+ OF_property_new(OF_env, ata, "interrupts",
+ regs, 2 * sizeof(OF_regprop_t));
+ ide_pci_pmac_register(base_address + 0x1f000, 0x00000000, ata);
+
+ }
+ {
+ OF_node_t *ata;
+ OF_regprop_t regs[2];
+ ata = OF_node_new(OF_env, mio, "ata-4", 0x20000);
+ if (ata == NULL) {
+ ERROR("Cannot create 'ata-4'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, ata, "device_type", "ata");
+#if 1
+ OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata");
+ OF_prop_string_new(OF_env, ata, "model", "ata-4");
+#else
+ OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
+ OF_prop_string_new(OF_env, ata, "model", "ata-4");
+#endif
+ OF_prop_int_new(OF_env, ata, "#address-cells", 1);
+ OF_prop_int_new(OF_env, ata, "#size-cells", 0);
+ regs[0].address = 0x00020000;
+ regs[0].size = 0x00001000;
+#if 0 // HACK: Don't set up DMA registers
+ regs[1].address = 0x00008A00;
+ regs[1].size = 0x00001000;
+ OF_property_new(OF_env, ata, "reg",
+ regs, 2 * sizeof(OF_regprop_t));
+#else
+ OF_property_new(OF_env, ata, "reg",
+ regs, sizeof(OF_regprop_t));
+#endif
+ OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
+ regs[0].address = 0x00000014;
+ regs[0].size = 0x00000001;
+ regs[1].address = 0x0000000B;
+ regs[1].size = 0x00000000;
+ OF_property_new(OF_env, ata, "interrupts",
+ regs, 2 * sizeof(OF_regprop_t));
+ ide_pci_pmac_register(0x00000000, base_address + 0x20000, ata);
+
+ }
+ /* Timer */
+ {
+ OF_node_t *tmr;
+ OF_regprop_t regs[1];
+ tmr = OF_node_new(OF_env, mio, "timer", 0x15000);
+ if (tmr == NULL) {
+ ERROR("Cannot create 'timer'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, tmr, "device_type", "timer");
+ OF_prop_string_new(OF_env, tmr, "compatible", "keylargo-timer");
+ OF_prop_int_new(OF_env, tmr, "clock-frequency", 0x01194000);
+ regs[0].address = 0x00015000;
+ regs[0].size = 0x00001000;
+ OF_property_new(OF_env, tmr, "reg", regs, sizeof(OF_regprop_t));
+ OF_prop_int_new(OF_env, tmr, "interrupt-parent", pic_phandle);
+ regs[0].address = 0x00000020;
+ regs[0].size = 0x00000001;
+ OF_property_new(OF_env, tmr, "interrupts",
+ regs, sizeof(OF_regprop_t));
+ OF_node_put(OF_env, tmr);
+ }
+ /* VIA-PMU */
+ {
+ /* Controls adb, RTC and power-mgt (forget it !) */
+ OF_node_t *via, *adb, *rtc;
+ OF_regprop_t regs[1];
+#if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD !
+ // (but needed has Qemu doesn't emulate via-pmu).
+ via = OF_node_new(OF_env, mio, "via-pmu", 0x16000);
+ if (via == NULL) {
+ ERROR("Cannot create 'via-pmu'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, via, "device_type", "via-pmu");
+ OF_prop_string_new(OF_env, via, "compatible", "pmu");
+#else
+ via = OF_node_new(OF_env, mio, "via-cuda", 0x16000);
+ if (via == NULL) {
+ ERROR("Cannot create 'via-cuda'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, via, "device_type", "via-cuda");
+ OF_prop_string_new(OF_env, via, "compatible", "cuda");
+#endif
+ regs[0].address = 0x00016000;
+ regs[0].size = 0x00002000;
+ OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t));
+ OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle);
+ regs[0].address = 0x00000019;
+ regs[0].size = 0x00000001;
+ OF_property_new(OF_env, via, "interrupts",
+ regs, sizeof(OF_regprop_t));
+#if 0
+ OF_prop_int_new(OF_env, via, "pmu-version", 0x00D0740C);
+#endif
+#if 1
+ /* ADB pseudo-device */
+ adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE);
+ if (adb == NULL) {
+ ERROR("Cannot create 'adb'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, adb, "device_type", "adb");
+#if 0
+ OF_prop_string_new(OF_env, adb, "compatible", "pmu-99");
+#else
+ OF_prop_string_new(OF_env, adb, "compatible", "adb");
+#endif
+ OF_prop_int_new(OF_env, adb, "#address-cells", 1);
+ OF_prop_int_new(OF_env, adb, "#size-cells", 0);
+ OF_pack_get_path(OF_env, tmp, 512, adb);
+ OF_prop_string_new(OF_env, als, "adb", tmp);
+ /* XXX: add "keyboard@2" and "mouse@3" */
+ OF_node_put(OF_env, adb);
+#endif
+
+ rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE);
+ if (rtc == NULL) {
+ ERROR("Cannot create 'rtc'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, rtc, "device_type", "rtc");
+#if 0
+ OF_prop_string_new(OF_env, rtc, "compatible", "rtc,via-pmu");
+#else
+ OF_prop_string_new(OF_env, rtc, "compatible", "rtc");
+#endif
+ OF_node_put(OF_env, rtc);
+ OF_node_put(OF_env, via);
+ }
+ out:
+ // OF_node_put(OF_env, mio);
+ OF_node_put(OF_env, chs);
+ OF_node_put(OF_env, als);
+}
+
+/*****************************************************************************/
+/* Fake package */
+static void OF_method_fake (OF_env_t *OF_env)
+{
+ uint32_t ihandle;
+
+ ihandle = popd(OF_env);
+ OF_DPRINTF("ih: %0x %d\n", ihandle, stackd_depth(OF_env));
+ pushd(OF_env, ihandle);
+}
+
+static void OF_mmu_translate (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ uint32_t address, more;
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 4);
+ /* As we get a 1:1 mapping, do nothing */
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ address = popd(OF_env);
+ more = popd(OF_env);
+ OF_DPRINTF("Translate address %0x %0x %0x\n", ihandle, address, more);
+ // BAT_setup(3, more, address, 0x10000000, 1, 1, 2);
+ pushd(OF_env, address);
+ pushd(OF_env, 0x00000000);
+ pushd(OF_env, 0x00000000);
+ pushd(OF_env, 0);
+}
+
+static void OF_mmu_map (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ uint32_t address, virt, size;
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 6);
+ /* As we get a 1:1 mapping, do nothing */
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ address = popd(OF_env);
+ virt = popd(OF_env);
+ size = popd(OF_env);
+ popd(OF_env);
+ OF_DPRINTF("Translate address %0x %0x %0x %0x\n", ihandle, address,
+ virt, size);
+ pushd(OF_env, 0);
+}
+
+/* Serial device package */
+static void OF_serial_write (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ OF_inst_t *inst;
+ OF_node_t *node;
+ uint32_t ihandle;
+ unsigned char *str;
+ int len;
+
+ OF_CHECK_NBARGS(OF_env, 4);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ str = (void *)popd(OF_env);
+ len = popd(OF_env);
+ inst = OF_inst_find(OF_env, ihandle);
+ if (inst == NULL) {
+ pushd(OF_env, -1);
+ ERROR("Cannot get serial instance\n");
+ return;
+ }
+ node = inst->node;
+ // OF_DPRINTF("args: %p str: %p\n", args, str);
+ /* XXX: should use directly the serial port
+ * and have another console package.
+ */
+ console_write(str, len);
+ pushd(OF_env, 0);
+}
+
+static void OF_serial_read (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ char *dest;
+ uint32_t len;
+ uint32_t ihandle;
+ uint16_t phandle;
+ int ret, count;
+
+ OF_CHECK_NBARGS(OF_env, 4);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ phandle = (ihandle >> 16) & 0xFFFF;
+ dest = (void *)popd(OF_env);
+ len = popd(OF_env);
+ ret = -1; /* Don't know why gcc thinks it might be uninitialized... */
+ for (count = 0; count < 1000; count++) {
+ ret = console_read(dest, len);
+ /* Stop if we read something or got an error */
+ if (ret != 0)
+ break;
+ /* Random sleep. Seems allright for serial port */
+ usleep(10000);
+ }
+ if (ret <= 0) {
+ pushd(OF_env, 0);
+ } else {
+ OF_DPRINTF("send '%s'\n", dest);
+ pushd(OF_env, ret);
+ }
+}
+
+typedef struct blockdev_inst_t {
+ int type;
+ union {
+ bloc_device_t *bd;
+ part_t *part;
+ inode_t *file;
+ } u;
+} blockdev_inst_t;
+
+static int OF_split_args (unsigned char *args, unsigned char **argv,
+ int max_args)
+{
+ unsigned char *pos, *end;
+ int i;
+
+ pos = args;
+ end = pos;
+ for (i = 0; i < max_args && *pos != '\0' && end != NULL; i++) {
+ end = strchr(pos, ',');
+ if (end != NULL)
+ *end = '\0';
+ argv[i] = pos;
+ pos = end + 1;
+ }
+
+ return i;
+}
+
+static void OF_convert_path (unsigned char **path)
+{
+ unsigned char *pos;
+
+ OF_DPRINTF("%s: '%s'\n", __func__, *path);
+ for (pos = *path; *pos != '\0'; pos++) {
+ if (*pos == '\\')
+ *pos = '/';
+ }
+ OF_DPRINTF("%s: '%s'\n", __func__, *path);
+ pos = *path;
+#if 1
+ if (pos[0] == '/' && pos[1] == '/') {
+ pos += 2;
+ *path = pos;
+ }
+#else
+ for (; *pos == '/'; pos++)
+ continue;
+ *path = pos;
+#endif
+ OF_DPRINTF("%s: '%s'\n", __func__, *path);
+}
+
+/* Block devices package */
+static void OF_blockdev_open (OF_env_t *OF_env)
+{
+ unsigned char tmp[OF_NAMELEN_MAX];
+ unsigned char *args, *argv[4];
+ OF_inst_t *dsk_inst;
+ OF_node_t *dsk;
+ bloc_device_t *bd;
+ blockdev_inst_t *bdinst;
+ uint32_t ihandle;
+ uint16_t phandle;
+ int nargs, partnum;
+
+ OF_CHECK_NBARGS(OF_env, 2);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ phandle = (ihandle >> 16) & 0xFFFF;
+ dsk_inst = OF_inst_find(OF_env, ihandle);
+ if (dsk_inst == NULL) {
+ ERROR("Disk not found (ih: %0x)\n", ihandle);
+ pushd(OF_env, -1);
+ return;
+ }
+ dsk = dsk_inst->node;
+ bd = dsk->private_data;
+ bdinst = malloc(sizeof(blockdev_inst_t));
+ if (bdinst == NULL) {
+ ihandle = -1;
+ ERROR("Cannot alloc blockdev instance\n");
+ goto out;
+ }
+ memset(bdinst, 0, sizeof(blockdev_inst_t));
+ OF_DPRINTF("called with args '%s'\n", args);
+ nargs = OF_split_args(args, argv, 4);
+ partnum = -1;
+ if (nargs > 0) {
+ partnum = strtol(argv[0], NULL, 10);
+ if (partnum > 0) {
+ OF_DPRINTF("Open partition... %d %d\n", partnum, nargs);
+ bdinst->type = 1;
+ bdinst->u.part = part_get(bd, partnum);
+ if (bdinst->u.part == NULL) {
+ OF_DPRINTF("Partition %d not found\n", partnum);
+ free(bdinst);
+ pushd(OF_env, -1);
+ return;
+ }
+ if (nargs > 1) {
+ /* TODO: open file */
+ bdinst->type = 2;
+ OF_DPRINTF("Open file... %d %d '%s'\n",
+ partnum, nargs, argv[1]);
+ OF_convert_path(&argv[1]);
+ if (*argv[1] != '/') {
+ sprintf(tmp, "%s/%s",
+ fs_get_boot_dirname(part_fs(bdinst->u.part)),
+ argv[1]);
+ bdinst->u.file = fs_open(part_fs(bdinst->u.part), tmp);
+ } else {
+ bdinst->u.file = fs_open(part_fs(bdinst->u.part), argv[1]);
+ }
+ if (bdinst->u.file == NULL) {
+#if 0
+ bug();
+#endif
+ pushd(OF_env, 0x00000000);
+ ERROR("File not found '%s'\n", argv[1]);
+ return;
+ }
+ }
+ }
+ }
+ if (nargs == 0 || partnum == 0) {
+ OF_DPRINTF("Open disk... %d %d\n", nargs, partnum);
+ bdinst->type = 0;
+ bdinst->u.bd = bd;
+ }
+ /* TODO: find partition &/| file */
+ dsk_inst->data = bdinst;
+ OF_node_put(OF_env, dsk);
+ out:
+ pushd(OF_env, ihandle);
+}
+
+static void OF_blockdev_seek (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ OF_inst_t *dsk_inst;
+ blockdev_inst_t *bdinst;
+ uint32_t posh, posl, bloc, pos, blocsize, tmp;
+ uint32_t ihandle;
+ uint16_t phandle;
+ int sh;
+
+ OF_CHECK_NBARGS(OF_env, 4);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ phandle = (ihandle >> 16) & 0xFFFF;
+ posh = popd(OF_env);
+ posl = popd(OF_env);
+ dsk_inst = OF_inst_find(OF_env, ihandle);
+ if (dsk_inst == NULL) {
+ ERROR("Disk not found (ih: %0x)\n", ihandle);
+ pushd(OF_env, -1);
+ return;
+ }
+ bdinst = dsk_inst->data;
+ switch (bdinst->type) {
+ case 0:
+ blocsize = bd_seclen(bdinst->u.bd);
+ for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2)
+ sh++;
+ bloc = ((posh << (32 - sh)) | (posl / blocsize));
+ pos = posl % blocsize;
+ OF_DPRINTF("disk: bsize %08x %08x %08x => %08x %08x\n", blocsize,
+ posh, posl, bloc, pos);
+ pushd(OF_env, bd_seek(bdinst->u.bd, bloc, pos));
+ break;
+ case 1:
+ blocsize = part_blocsize(bdinst->u.part);
+ for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2)
+ sh++;
+ bloc = ((posh << (32 - sh)) | (posl / blocsize));
+ pos = posl % blocsize;
+ OF_DPRINTF("part: bsize %08x %08x %08x => %08x %08x\n", blocsize,
+ posh, posl, bloc, pos);
+ pushd(OF_env, part_seek(bdinst->u.part, bloc, pos));
+ break;
+ case 2:
+ blocsize = part_blocsize(fs_inode_get_part(bdinst->u.file));
+ for (tmp = blocsize, sh = 0; tmp != 1; tmp = tmp / 2)
+ sh++;
+ bloc = ((posh << (32 - sh)) | (posl / blocsize));
+ pos = posl % blocsize;
+ OF_DPRINTF("file: bsize %08x %08x %08x => %08x %08x\n", blocsize,
+ posh, posl, bloc, pos);
+ pushd(OF_env, fs_seek(bdinst->u.file, bloc, pos));
+ break;
+ }
+}
+
+static void OF_blockdev_read (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ OF_inst_t *dsk_inst;
+ blockdev_inst_t *bdinst;
+ void *dest;
+ uint32_t len;
+ uint32_t ihandle;
+ uint16_t phandle;
+
+ OF_CHECK_NBARGS(OF_env, 4);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ phandle = (ihandle >> 16) & 0xFFFF;
+ dest = (void *)popd(OF_env);
+ len = popd(OF_env);
+ dsk_inst = OF_inst_find(OF_env, ihandle);
+ if (dsk_inst == NULL) {
+ ERROR("Disk not found (ih: %0x)\n", ihandle);
+ pushd(OF_env, -1);
+ return;
+ }
+ bdinst = dsk_inst->data;
+ set_check(0);
+ OF_DPRINTF("dest: %p len: %d %d\n", dest, len, bdinst->type);
+ switch (bdinst->type) {
+ case 0:
+ OF_DPRINTF("read disk\n");
+ pushd(OF_env, bd_read(bdinst->u.bd, dest, len));
+ break;
+ case 1:
+ OF_DPRINTF("read partition\n");
+ pushd(OF_env, part_read(bdinst->u.part, dest, len));
+ break;
+ case 2:
+ OF_DPRINTF("read file\n");
+ pushd(OF_env, fs_read(bdinst->u.file, dest, len));
+ break;
+ }
+ OF_DPRINTF("%08x %08x %08x %08x\n",
+ ((uint32_t *)dest)[0], ((uint32_t *)dest)[1],
+ ((uint32_t *)dest)[2], ((uint32_t *)dest)[3]);
+ OF_DPRINTF("%08x %08x %08x %08x\n",
+ ((uint32_t *)dest)[4], ((uint32_t *)dest)[5],
+ ((uint32_t *)dest)[6], ((uint32_t *)dest)[7]);
+
+ set_check(1);
+}
+
+static void OF_blockdev_get_blocsize (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ OF_inst_t *dsk_inst;
+ blockdev_inst_t *bdinst;
+ uint32_t ihandle;
+ uint16_t phandle;
+ uint32_t blocsize;
+
+ OF_CHECK_NBARGS(OF_env, 2);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ phandle = (ihandle >> 16) & 0xFFFF;
+ dsk_inst = OF_inst_find(OF_env, ihandle);
+ if (dsk_inst == NULL) {
+ ERROR("Disk not found (ih: %0x)\n", ihandle);
+ pushd(OF_env, -1);
+ return;
+ }
+ bdinst = dsk_inst->data;
+#if 0
+ switch (bdinst->type) {
+ case 0:
+ blocsize = bd_seclen(bdinst->u.bd);
+ break;
+ case 1:
+ blocsize = part_blocsize(bdinst->u.part);
+ break;
+ case 2:
+ blocsize = 512;
+ break;
+ }
+#else
+ blocsize = 512;
+#endif
+ pushd(OF_env, blocsize);
+ pushd(OF_env, 0);
+}
+
+static void OF_blockdev_dma_alloc (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ void *address;
+ uint32_t ihandle;
+ uint32_t size;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ size = popd(OF_env);
+ OF_DPRINTF("size: %08x\n", size);
+ mem_align(size);
+ address = malloc(size);
+ if (address != NULL)
+ memset(address, 0, size);
+ pushd(OF_env, (uint32_t)address);
+ pushd(OF_env, 0);
+}
+
+static void OF_blockdev_dma_free (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ void *address;
+ uint32_t ihandle;
+ uint32_t size;
+
+ OF_CHECK_NBARGS(OF_env, 4);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ size = popd(OF_env);
+ address = (void *)popd(OF_env);
+ OF_DPRINTF("address: %p size: %08x\n", address, size);
+ free(address);
+ pushd(OF_env, 0);
+}
+
+void *OF_blockdev_register (void *parent, void *private,
+ const unsigned char *type,
+ const unsigned char *name, int devnum,
+ const char *alias)
+{
+ unsigned char tmp[OF_NAMELEN_MAX], path[OF_NAMELEN_MAX], *pos;
+ OF_env_t *OF_env;
+ OF_node_t *dsk, *als;
+ int i;
+
+ OF_env = OF_env_main;
+ dsk = OF_node_new(OF_env, parent, name, devnum);
+ if (dsk == NULL) {
+ ERROR("Cannot create blockdev '%s'\n", name);
+ return NULL;
+ }
+ OF_prop_string_new(OF_env, dsk, "device_type", "block");
+ OF_prop_string_new(OF_env, dsk, "category", type);
+ OF_prop_int_new(OF_env, dsk, "device_id", devnum);
+ OF_prop_int_new(OF_env, dsk, "reg", 0);
+ OF_method_new(OF_env, dsk, "open", &OF_blockdev_open);
+ OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek);
+ OF_method_new(OF_env, dsk, "read", &OF_blockdev_read);
+ OF_method_new(OF_env, dsk, "block-size",
+ &OF_blockdev_get_blocsize);
+ OF_method_new(OF_env, dsk, "dma-alloc", &OF_blockdev_dma_alloc);
+ OF_method_new(OF_env, dsk, "dma-free", &OF_blockdev_dma_free);
+ if (strcmp(type, "cdrom") == 0)
+ OF_method_new(OF_env, dsk, "eject", &OF_method_fake);
+ OF_method_new(OF_env, dsk, "close", &OF_method_fake);
+ dsk->private_data = private;
+ /* Set up aliases */
+ OF_pack_get_path(OF_env, path, OF_NAMELEN_MAX, dsk);
+ if (alias != NULL) {
+ als = OF_node_get(OF_env, "aliases");
+ if (als == NULL) {
+ ERROR("Cannot get 'aliases'\n");
+ return NULL;
+ }
+ strcpy(tmp, alias);
+ if (OF_property_copy(OF_env, NULL, 0, als, tmp) >= 0) {
+ pos = tmp + strlen(alias);
+ for (i = 0; ; i++) {
+ sprintf(pos, "%d", i);
+ if (OF_property_copy(OF_env, NULL, 0, als, tmp) < 0)
+ break;
+ }
+ }
+ OF_DPRINTF("Set alias to %s\n", tmp);
+ OF_prop_string_new(OF_env, dsk, "alias", tmp);
+ OF_prop_string_new(OF_env, als, tmp, path);
+ OF_node_put(OF_env, als);
+ }
+
+ return dsk;
+}
+
+void OF_blockdev_set_boot_device (void *disk, int partnum,
+ const unsigned char *file)
+{
+ unsigned char tmp[OF_NAMELEN_MAX], *pos;
+ OF_env_t *OF_env;
+ OF_node_t *dsk = disk, *opts, *chs;
+
+ OF_env = OF_env_main;
+
+ if (OF_property_copy(OF_env, tmp, OF_NAMELEN_MAX, dsk, "alias") < 0)
+ OF_pack_get_path(OF_env, tmp, OF_NAMELEN_MAX, dsk);
+ sprintf(tmp + strlen(tmp), ":%d", partnum);
+ /* OpenDarwin 6.02 seems to need this one */
+ opts = OF_node_get(OF_env, "options");
+ if (opts == NULL) {
+ ERROR("Cannot get 'options'\n");
+ return;
+ }
+ OF_prop_string_set(OF_env, OF_node_root, "boot-device", tmp);
+ OF_prop_string_set(OF_env, opts, "boot-device", tmp);
+ OF_DPRINTF("Set boot device to: '%s'\n", tmp);
+ OF_node_put(OF_env, opts);
+ /* Set the real boot path */
+ pos = tmp + strlen(tmp);
+ sprintf(pos, ",%s", file);
+ /* Convert all '/' into '\' in the boot file name */
+ for (; *pos != '\0'; pos++) {
+ if (*pos == '/')
+ *pos = '\\';
+ }
+ chs = OF_node_get(OF_env, "chosen");
+ if (chs == NULL) {
+ ERROR("Cannot get 'chosen'\n");
+ return;
+ }
+ OF_prop_string_set(OF_env, chs, "bootpath", tmp);
+ OF_DPRINTF("Set boot path to: '%s'\n", tmp);
+ OF_node_put(OF_env, chs);
+}
+
+/* Display package */
+static void OF_vga_draw_rectangle (OF_env_t *OF_env)
+{
+ const void *buf;
+ const unsigned char *args;
+ uint32_t posx, posy, width, height;
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 7);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ height = popd(OF_env);
+ width = popd(OF_env);
+ posy = popd(OF_env);
+ posx = popd(OF_env);
+ buf = (const void *)popd(OF_env);
+ OF_DPRINTF("x=%d y=%d h=%d ", posx, posy, width);
+ OF_DPRINTF("w=%d buf=%p\n", height, buf);
+ set_check(0);
+ vga_draw_buf(buf, width * vga_fb_bpp, posx, posy, width, height);
+ set_check(1);
+ pushd(OF_env, 0);
+}
+
+static void OF_vga_fill_rectangle (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ uint32_t color, posx, posy, width, height;
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 7);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ height = popd(OF_env);
+ width = popd(OF_env);
+ posy = popd(OF_env);
+ posx = popd(OF_env);
+ color = popd(OF_env);
+ OF_DPRINTF("x=%d y=%d\n", posx, posy);
+ OF_DPRINTF("h=%d w=%d c=%0x\n", width, height, color);
+ vga_fill_rect(posx, posy, width, height, color);
+ pushd(OF_env, 0);
+}
+
+static void OF_vga_set_width (OF_env_t *OF_env, OF_prop_t *prop,
+ const void *data, int len)
+{
+ uint32_t width, height, depth;
+
+ if (len == sizeof(uint32_t)) {
+ width = *(uint32_t *)data;
+ OF_property_copy(OF_env, &height, 4, prop->node, "height");
+ OF_property_copy(OF_env, &depth, 4, prop->node, "depth");
+ vga_set_mode(width, height, depth);
+ }
+}
+
+static void OF_vga_set_height (OF_env_t *OF_env, OF_prop_t *prop,
+ const void *data, int len)
+{
+ uint32_t width, height, depth;
+
+ if (len == sizeof(uint32_t)) {
+ OF_property_copy(OF_env, &width, 4, prop->node, "width");
+ height = *(uint32_t *)data;
+ OF_property_copy(OF_env, &depth, 4, prop->node, "depth");
+ vga_set_mode(width, height, depth);
+ }
+}
+
+static void OF_vga_set_depth (OF_env_t *OF_env, OF_prop_t *prop,
+ const void *data, int len)
+{
+ uint32_t width, height, depth;
+
+ if (len == sizeof(uint32_t)) {
+ OF_property_copy(OF_env, &width, 4, prop->node, "width");
+ OF_property_copy(OF_env, &height, 4, prop->node, "height");
+ depth = *(uint32_t *)data;
+ vga_set_mode(width, height, depth);
+ }
+}
+
+void OF_vga_register (const unsigned char *name, unused uint32_t address,
+ int width, int height, int depth)
+{
+ OF_env_t *OF_env;
+ unsigned char tmp[OF_NAMELEN_MAX];
+ OF_node_t *disp, *chs, *als;
+ OF_prop_t *prop;
+
+ OF_DPRINTF("Set frame buffer %08x %dx%dx%d\n",
+ address, width, height, depth);
+ OF_env = OF_env_main;
+ disp = OF_node_get(OF_env, name);
+ if (disp == NULL) {
+ ERROR("Cannot get display '%s'\n", name);
+ return;
+ }
+ prop = OF_prop_int_new(OF_env, disp, "width", width);
+ if (prop == NULL) {
+ OF_node_put(OF_env, disp);
+ ERROR("Cannot create display width property\n");
+ return;
+ }
+ OF_property_set_cb(OF_env, prop, &OF_vga_set_width);
+ prop = OF_prop_int_new(OF_env, disp, "height", height);
+ if (prop == NULL) {
+ OF_node_put(OF_env, disp);
+ ERROR("Cannot create display height property\n");
+ return;
+ }
+ OF_property_set_cb(OF_env, prop, &OF_vga_set_height);
+ switch (depth) {
+ case 8:
+ break;
+ case 15:
+ depth = 16;
+ break;
+ case 32:
+ break;
+ default:
+ /* OF spec this is mandatory, but we have no support for it */
+ printf("%d bits VGA isn't implemented\n", depth);
+ bug();
+ /* Never come here */
+ break;
+ }
+ prop = OF_prop_int_new(OF_env, disp, "depth", depth);
+ if (prop == NULL) {
+ ERROR("Cannot create display depth\n");
+ goto out;
+ }
+ OF_property_set_cb(OF_env, prop, &OF_vga_set_depth);
+ OF_prop_int_new(OF_env, disp, "linebytes", vga_fb_linesize);
+ OF_method_new(OF_env, disp, "draw-rectangle", &OF_vga_draw_rectangle);
+ OF_method_new(OF_env, disp, "fill-rectangle", &OF_vga_fill_rectangle);
+ OF_method_new(OF_env, disp, "color!", &OF_method_fake);
+ chs = OF_node_get(OF_env, "chosen");
+ if (chs == NULL) {
+ ERROR("Cannot get 'chosen'\n");
+ goto out;
+ }
+ OF_prop_int_new(OF_env, chs, "display", OF_pack_handle(OF_env, disp));
+ OF_node_put(OF_env, chs);
+ OF_pack_get_path(OF_env, tmp, 512, disp);
+ printf("Set display '%s' path to '%s'\n", name, tmp);
+ als = OF_node_get(OF_env, "aliases");
+ if (als == NULL) {
+ ERROR("Cannot get 'aliases'\n");
+ goto out;
+ }
+ OF_prop_string_new(OF_env, als, "screen", tmp);
+ OF_prop_string_new(OF_env, als, "display", tmp);
+ OF_node_put(OF_env, als);
+ /* XXX: may also need read-rectangle */
+ out:
+ OF_node_put(OF_env, disp);
+}
+
+/* Pseudo packages to make BootX happy */
+/* sl_words package */
+static void slw_set_output_level (OF_env_t *OF_env)
+{
+ OF_node_t *slw;
+ const unsigned char *args;
+ int level;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ level = popd(OF_env);
+ slw = OF_node_get(OF_env, "sl_words");
+ if (slw == NULL) {
+ pushd(OF_env, -1);
+ } else {
+ OF_DPRINTF("Set output level to: %d\n", level);
+ OF_prop_int_set(OF_env, slw, "outputLevel", level);
+ OF_node_put(OF_env, slw);
+ pushd(OF_env, 0);
+ }
+}
+
+#ifdef DEBUG_BIOS
+#define EMIT_BUFFER_LEN 256
+static unsigned char emit_buffer[EMIT_BUFFER_LEN];
+static int emit_pos = 0;
+#endif
+
+static void slw_emit (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ int c;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ c = popd(OF_env);
+ // OF_DPRINTF("Emit char %d\n", c);
+#ifdef DEBUG_BIOS
+ if (emit_pos < EMIT_BUFFER_LEN - 1) {
+ emit_buffer[emit_pos++] = c;
+ // outb(0xFF00, c);
+ outb(0x0F00, c);
+ } else {
+ emit_buffer[emit_pos] = '\0';
+ }
+#else
+ outb(0x0F00, c);
+#endif
+ pushd(OF_env, 0);
+}
+
+static void slw_cr (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+
+ OF_CHECK_NBARGS(OF_env, 2);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ // OF_DPRINTF("Emit CR char\n");
+ // outb(0xFF01, '\n');
+ outb(0x0F01, '\n');
+#ifdef DEBUG_BIOS
+ emit_buffer[emit_pos] = '\0';
+ if (strcmp(emit_buffer, "Call Kernel!") == 0) {
+ /* Set qemu in debug mode:
+ * log in_asm,op,int,ioport,cpu
+ */
+ uint16_t loglevel = 0x02 | 0x10 | 0x80;
+ // outw(0xFF02, loglevel);
+ outb(0x0F02, loglevel);
+ }
+ emit_pos = 0;
+#endif
+ pushd(OF_env, 0);
+}
+
+static void slw_init_keymap (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ OF_node_t *node;
+ OF_prop_t *prop;
+ uint32_t phandle, ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ ihandle = popd(OF_env);
+ args = (void *)popd(OF_env);
+ phandle = ihandle >> 16;
+ ihandle &= 0xFFFF;
+ OF_DPRINTF("\n");
+ node = OF_pack_find(OF_env, phandle);
+ if (node == NULL) {
+ ERROR("Cant' init slw keymap\n");
+ pushd(OF_env, -1);
+ } else {
+ prop = OF_property_get(OF_env, node, "keyMap");
+ if (prop == NULL) {
+ pushd(OF_env, -1);
+ } else {
+ pushd(OF_env, (uint32_t)prop->value);
+ pushd(OF_env, 0);
+ }
+ }
+}
+
+static void slw_update_keymap (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+
+ OF_CHECK_NBARGS(OF_env, 2);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ OF_DPRINTF("\n");
+ pushd(OF_env, 0);
+}
+
+static void slw_spin (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ /* XXX: cur_spin should be in sl_words package */
+ static int cur_spin = 0;
+ int c;
+
+ OF_CHECK_NBARGS(OF_env, 2);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ if (cur_spin > 15) {
+ c = RGB(0x30, 0x30, 0x50);
+ } else {
+ c = RGB(0x11, 0x11, 0x11);
+ }
+ c = vga_get_color(c);
+ vga_fill_rect((cur_spin % 15) * 5 + 280, 420, 4, 3, c);
+ cur_spin = (cur_spin + 1) & 31;
+ OF_DPRINTF("\n");
+ pushd(OF_env, -1);
+}
+
+static void slw_spin_init (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+
+ OF_CHECK_NBARGS(OF_env, 8);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ popd(OF_env);
+ popd(OF_env);
+ popd(OF_env);
+ popd(OF_env);
+ popd(OF_env);
+ popd(OF_env);
+ pushd(OF_env, -1);
+}
+
+static void slw_pwd (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ OF_DPRINTF("\n");
+ pushd(OF_env, -1);
+}
+
+static void slw_sum (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ popd(OF_env);
+ args = (void *)popd(OF_env);
+ OF_DPRINTF("\n");
+ pushd(OF_env, -1);
+}
+
+/*****************************************************************************/
+/* Client program interface */
+/* Client interface services */
+static void OF_test (OF_env_t *OF_env);
+
+/* Device tree services */
+/* Get next package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_peer (OF_env_t *OF_env)
+{
+ OF_node_t *node;
+ uint32_t phandle;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ phandle = popd(OF_env);
+ OF_DPRINTF("phandle 0x%0x\n", phandle);
+ if (phandle == 0)
+ node = OF_node_root;
+ else
+ node = OF_pack_next(OF_env, phandle);
+ if (node == NULL)
+ pushd(OF_env, 0);
+ else
+ pushd(OF_env, OF_pack_handle(OF_env, node));
+}
+
+/* Get first child package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_child (OF_env_t *OF_env)
+{
+ OF_node_t *node;
+ uint32_t phandle;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ phandle = popd(OF_env);
+ OF_DPRINTF("phandle 0x%0x\n", phandle);
+ node = OF_pack_child(OF_env, phandle);
+ if (node == NULL)
+ pushd(OF_env, 0);
+ else
+ pushd(OF_env, OF_pack_handle(OF_env, node));
+}
+
+/* Get parent package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_parent (OF_env_t *OF_env)
+{
+ OF_node_t *node;
+ uint32_t phandle;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ phandle = popd(OF_env);
+ OF_DPRINTF("phandle 0x%0x\n", phandle);
+ node = OF_pack_parent(OF_env, phandle);
+ if (node == NULL)
+ pushd(OF_env, 0);
+ else
+ pushd(OF_env, OF_pack_handle(OF_env, node));
+}
+
+/* Get package related to an instance */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_instance_to_package (OF_env_t *OF_env)
+{
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ ihandle = popd(OF_env);
+ OF_DPRINTF("ihandle 0x%0x\n", ihandle);
+ pushd(OF_env, (ihandle >> 16) & 0xFFFF);
+}
+
+/* Get property len */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_getproplen (OF_env_t *OF_env)
+{
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ OF_node_t *node;
+ uint32_t phandle;
+
+ OF_CHECK_NBARGS(OF_env, 2);
+ phandle = popd(OF_env);
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+ node = OF_pack_find(OF_env, phandle);
+ if (node == NULL)
+ pushd(OF_env, -1);
+ else
+ pushd(OF_env, OF_property_len(OF_env, node, name));
+}
+
+/* Get property */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_getprop (OF_env_t *OF_env)
+{
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ OF_node_t *node;
+ void *buffer;
+ uint32_t phandle;
+ int len, nb_args;
+
+ // OF_CHECK_NBARGS(OF_env, 4);
+ nb_args = stackd_depth(OF_env);
+ phandle = popd(OF_env);
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ buffer = (void *)popd(OF_env);
+ if (nb_args == 3) {
+ /* This hack is needed to boot MacOS X panther (10.3) */
+ len = 1024;
+ } else {
+ len = popd(OF_env);
+ }
+ OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+ OF_DPRINTF("buffer %p len %d\n", buffer, len);
+ node = OF_pack_find(OF_env, phandle);
+ if (node == NULL) {
+ len = -1;
+ } else {
+ len = OF_property_copy(OF_env, buffer, len, node, name);
+ if (len != -1) {
+ OF_DPRINTF("Copied %d bytes\n", len);
+ }
+ }
+ pushd(OF_env, len);
+}
+
+/* Check existence of next property */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_nextprop (OF_env_t *OF_env)
+{
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ OF_node_t *node;
+ OF_prop_t *next;
+ unsigned char *next_name;
+ uint32_t phandle;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ phandle = popd(OF_env);
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+ next_name = (unsigned char *)popd(OF_env);
+ node = OF_pack_find(OF_env, phandle);
+ if (node == NULL) {
+ pushd(OF_env, -1);
+ } else {
+ next = OF_property_next(OF_env, node, name);
+ if (next == NULL || next->name == NULL) {
+ OF_DPRINTF("No next property found [%s]\n", name);
+ pushd(OF_env, 0);
+ } else {
+ OF_DPRINTF("Return property name [%s]\n", next->name);
+ OF_sts(next_name, (void *)(next->name));
+ OF_DUMP_STRING(OF_env, next_name);
+ pushd(OF_env, strlen(next->name) + 1);
+ }
+ }
+}
+
+/* Set a property */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_setprop (OF_env_t *OF_env)
+{
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ unsigned char *value, *buffer;
+ OF_node_t *node;
+ OF_prop_t *prop;
+ uint32_t phandle;
+ int len;
+ int i;
+
+ OF_CHECK_NBARGS(OF_env, 4);
+ phandle = popd(OF_env);
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ OF_DPRINTF("phandle 0x%0x prop [%s]\n", phandle, name);
+ buffer = (unsigned char *)popd(OF_env);
+ len = popd(OF_env);
+ node = OF_pack_find(OF_env, phandle);
+ if (node == NULL) {
+ pushd(OF_env, -1);
+ ERROR("Cannot get pack %04x\n", phandle);
+ return;
+ }
+ value = malloc(len);
+ if (value == NULL && len != 0) {
+ pushd(OF_env, -1);
+ ERROR("%s: Cannot alloc property '%s' (%d)\n", __func__, name, len);
+ return;
+ }
+ for (i = 0; i < len; i++)
+ value[i] = buffer[i];
+ prop = OF_property_set(OF_env, node, name, value, len);
+ if (prop == NULL)
+ len = -1;
+ pushd(OF_env, len);
+}
+
+/* "canon" */
+
+/* Find a device given its path */
+__attribute__ (( section (".OpenFirmware") ))
+static OF_node_t *OF_get_alias (OF_env_t *OF_env, const unsigned char *name)
+{
+ unsigned char tmp[OF_NAMELEN_MAX], *pos, *st;
+ const unsigned char *alias, *npos;
+ OF_node_t *als, *node;
+ OF_prop_t *prop;
+
+ node = NULL;
+ strcpy(tmp, name);
+ for (st = tmp; *st == '/'; st++)
+ continue;
+ pos = strchr(st, '/');
+ if (pos == NULL) {
+ pos = strchr(st, ':');
+ }
+ if (pos != NULL) {
+ *pos = '\0';
+ npos = name + (pos - tmp);
+ } else {
+ npos = "";
+ }
+ OF_DPRINTF("Look for alias for '%s' => '%s' '%s'\n", name, tmp, npos);
+ als = OF_pack_find_by_name(OF_env, OF_node_root, "/aliases");
+ if (als == NULL) {
+ ERROR("Cannot get 'aliases'\n");
+ return NULL;
+ }
+ prop = OF_property_get(OF_env, als, tmp);
+ if (prop == NULL) {
+ OF_DPRINTF("No %s alias !\n", tmp);
+ goto out;
+ }
+ alias = prop->value;
+ OF_DPRINTF("Found alias '%s' '%s'\n", alias, npos);
+ sprintf(tmp, "%s%s", alias, npos);
+ node = OF_pack_find_by_name(OF_env, OF_node_root, tmp);
+ if (node == NULL) {
+ printf("%s alias is a broken link !\n", name);
+ goto out;
+ }
+ OF_node_put(OF_env, node);
+ out:
+ OF_node_put(OF_env, als);
+
+ return node;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_finddevice (OF_env_t *OF_env)
+{
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ OF_node_t *node;
+ int ret;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ OF_DPRINTF("name %p [%s]\n", namep, name);
+ /* Search first in "/aliases" */
+ node = OF_get_alias(OF_env, name);
+ if (node == NULL) {
+ node = OF_pack_find_by_name(OF_env, OF_node_root, name);
+ }
+ if (node == NULL)
+ ret = -1;
+ else
+ ret = OF_pack_handle(OF_env, node);
+ OF_DPRINTF("ret 0x%0x\n", ret);
+ pushd(OF_env, ret);
+}
+
+/* "instance-to-path */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_instance_to_path (OF_env_t *OF_env)
+{
+ void *buffer;
+ OF_inst_t *inst;
+ uint32_t ihandle;
+ int len;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ OF_DPRINTF("\n");
+ ihandle = popd(OF_env);
+ buffer = (void *)popd(OF_env);
+ len = popd(OF_env);
+ OF_DPRINTF("ihandle: 0x%0x len=%d\n", ihandle, len);
+ inst = OF_inst_find(OF_env, ihandle);
+ if (inst == NULL)
+ len = -1;
+ else
+ len = OF_inst_get_path(OF_env, buffer, len, inst) + 1;
+ OF_DUMP_STRING(OF_env, buffer);
+ pushd(OF_env, len);
+}
+
+/* "package-to-path" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_package_to_path (OF_env_t *OF_env)
+{
+ void *buffer;
+ OF_node_t *node;
+ uint32_t phandle;
+ int len;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ OF_DPRINTF("\n");
+ phandle = popd(OF_env);
+ buffer = (void *)popd(OF_env);
+ len = popd(OF_env);
+ node = OF_pack_find(OF_env, phandle);
+ if (node == NULL)
+ len = -1;
+ else
+ len = OF_pack_get_path(OF_env, buffer, len, node) + 1;
+ OF_DUMP_STRING(OF_env, buffer);
+ pushd(OF_env, len);
+}
+
+/* Call a package's method */
+__attribute__ (( section (".OpenFirmware") ))
+static void _OF_callmethod (OF_env_t *OF_env, const unsigned char *name,
+ uint32_t ihandle, const unsigned char *argp)
+{
+ OF_node_t *node;
+ OF_inst_t *inst;
+ OF_method_t *method;
+ OF_cb_t cb;
+
+ inst = OF_inst_find(OF_env, ihandle);
+ OF_DPRINTF("Attempt to call method [%s] of package instance 0x%0x\n",
+ name, ihandle);
+ if (inst == NULL) {
+ OF_DPRINTF("No instance %0x\n", ihandle);
+ pushd(OF_env, -1);
+ return;
+ }
+ node = inst->node;
+ method = OF_method_get(OF_env, node, name);
+ if (method != NULL) {
+ cb = method->func;
+ } else {
+ if (strcmp(name, "open") == 0) {
+ cb = &OF_method_fake;
+ } else {
+ printf("Method '%s' not found in '%s'\n",
+ name, node->prop_name->value);
+ pushd(OF_env, -1);
+ bug();
+ return;
+ }
+ }
+#if 0
+ OF_DPRINTF("Push instance method %p (%p)...\n", &method->func,
+ &slw_emit);
+#endif
+ pushf(OF_env, &cb);
+ if (argp != NULL)
+ pushd(OF_env, (uint32_t)argp);
+ else
+ pushd(OF_env, 0x00000000);
+ pushd(OF_env, ihandle);
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static unsigned char *OF_get_args (unused OF_env_t *env, unsigned char *name)
+{
+ unsigned char *sd;
+
+ sd = strchr(name, ':');
+ if (sd == NULL)
+ return NULL;
+ *sd = '\0';
+
+ return sd + 1;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_callmethod (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ uint32_t ihandle;
+
+ OF_DPRINTF("\n\n\n#### CALL METHOD ####\n\n");
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ args = OF_get_args(OF_env, name);
+ ihandle = popd(OF_env);
+ _OF_callmethod(OF_env, name, ihandle, args);
+}
+
+/* Device IO services */
+/* Create a new instance of a device's package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_open (OF_env_t *OF_env)
+{
+ const unsigned char *args;
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ OF_node_t *node;
+ OF_inst_t *inst;
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ OF_DPRINTF("package [%s]\n", name);
+ args = OF_get_args(OF_env, name);
+ node = OF_get_alias(OF_env, name);
+ if (node == NULL) {
+ node = OF_pack_find_by_name(OF_env, OF_node_root, name);
+ }
+ if (node == NULL) {
+ OF_DPRINTF("package not found !\n");
+ pushd(OF_env, -1);
+ return;
+ }
+ inst = OF_instance_new(OF_env, node);
+ if (inst == NULL) {
+ pushd(OF_env, -1);
+ ERROR("Cannot create package instance\n");
+ return;
+ }
+ ihandle = OF_instance_get_id(OF_env, inst);
+ /* If an "open" method exists in the package, call it */
+ OF_DPRINTF("package [%s] => %0x\n", name, ihandle);
+ OF_node_put(OF_env, node);
+ _OF_callmethod(OF_env, "open", ihandle, args);
+}
+
+/* De-instanciate a package */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_close (OF_env_t *OF_env)
+{
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ ihandle = popd(OF_env);
+ /* If an "close" method exists in the package, call it */
+ _OF_callmethod(OF_env, "close", ihandle, NULL);
+ /* XXX: Should free the instance */
+}
+
+/* "read" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_read (OF_env_t *OF_env)
+{
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ ihandle = popd(OF_env);
+ OF_DPRINTF("ih: %0x\n", ihandle);
+ /* If a "read" method exists in the package, call it */
+ _OF_callmethod(OF_env, "read", ihandle, NULL);
+}
+
+/* Try call the "read" method of a device's package */
+/* "write" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_write (OF_env_t *OF_env)
+{
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ ihandle = popd(OF_env);
+ // OF_DPRINTF("ih: %0x\n", ihandle);
+ /* If a "write" method exists in the package, call it */
+ _OF_callmethod(OF_env, "write", ihandle, NULL);
+}
+
+/* "seek" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_seek (OF_env_t *OF_env)
+{
+ uint32_t ihandle;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ ihandle = popd(OF_env);
+ OF_DPRINTF("ih: %0x\n", ihandle);
+ /* If a "seek" method exists in the package, call it */
+ _OF_callmethod(OF_env, "seek", ihandle, NULL);
+}
+
+/* Memory services */
+/* Claim some memory space */
+__attribute__ (( section (".OpenFirmware") ))
+uint32_t OF_claim_virt (uint32_t virt, uint32_t size, int *range)
+{
+ int i, keep = -1;
+
+ OF_DPRINTF("Claim %d bytes at 0x%0x\n", size, virt);
+ /* First check that the requested memory stands in the physical memory */
+ if (OF_mem_ranges[0].start > virt ||
+ (OF_mem_ranges[0].start + OF_mem_ranges[0].size) < (virt + size)) {
+ ERROR("not in memory: start 0x%0x virt 0x%0x end 0x%0x 0x%0x\n",
+ OF_mem_ranges[0].start, virt,
+ OF_mem_ranges[0].start + OF_mem_ranges[0].size,
+ virt + size);
+ return (uint32_t)(-1);
+ }
+ /* Now check that it doesn't overlap with already claimed areas */
+ for (i = 1; i < OF_MAX_MEMRANGES + 1; i++) {
+ if (OF_mem_ranges[i].start == (uint32_t)(-1) ||
+ OF_mem_ranges[i].size == (uint32_t)(-1)) {
+ if (keep == -1)
+ keep = i;
+ continue;
+ }
+ if (OF_mem_ranges[i].start == virt &&
+ (OF_mem_ranges[i].start + OF_mem_ranges[i].size) == (virt + size)) {
+ return virt;
+ }
+ if (!((OF_mem_ranges[i].start >= (virt + size) ||
+ (OF_mem_ranges[i].start + OF_mem_ranges[i].size) <= virt))) {
+ ERROR("overlap: start 0x%0x virt 0x%0x end 0x%0x 0x%0x\n",
+ OF_mem_ranges[i].start, virt,
+ OF_mem_ranges[i].start + OF_mem_ranges[i].size,
+ virt + size);
+ /* Aie... */
+ return (uint32_t)(-1);
+ }
+ }
+ OF_DPRINTF("return range: %d\n", keep);
+ if (keep == -1) {
+ /* no more rooms */
+ ERROR("No more rooms\n");
+ return (uint32_t)(-1);
+ } else {
+ ERROR("Give range: start 0x%0x 0x%0x\n", virt, size);
+ }
+ if (range != NULL)
+ *range = keep;
+
+ return virt;
+}
+
+/* We always try to get the upper address we can */
+__attribute__ (( section (".OpenFirmware") ))
+static uint32_t OF_claim_size (uint32_t size, int align, int *range)
+{
+ uint32_t addr, max = (uint32_t)(-1);
+ int i;
+
+ OF_DPRINTF("Try map %d bytes at 0x00000000\n", size);
+ if (OF_claim_virt(0, size, range) != (uint32_t)(-1))
+ max = 0;
+ for (i = 1; i < OF_MAX_MEMRANGES + 1; i++) {
+ if (OF_mem_ranges[i].start == (uint32_t)(-1) ||
+ OF_mem_ranges[i].size == (uint32_t)(-1))
+ continue;
+ addr = (OF_mem_ranges[i].start + OF_mem_ranges[i].size + align - 1) &
+ ~(align - 1);
+ OF_DPRINTF("Try map %d bytes at 0x%0x\n", size, addr);
+ if ((addr + 1) > (max + 1)) {
+ if (OF_claim_virt(addr, size, range) != (uint32_t)(-1))
+ max = addr;
+ }
+ }
+
+ return max;
+}
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_claim (OF_env_t *OF_env)
+{
+ uint32_t virt, size, addr;
+ int align;
+ int i, range;
+
+ OF_CHECK_NBARGS(OF_env, 3);
+ virt = popd(OF_env);
+ size = popd(OF_env);
+ align = popd(OF_env);
+ DPRINTF("virt 0x%0x size 0x%0x align %d\n", virt, size, align);
+ if (align == 0) {
+ addr = OF_claim_virt(virt, size, &range);
+ } else {
+ for (i = 1; i < align; i = i << 1)
+ continue;
+ align = i;
+ size = (size + align - 1) & ~(align - 1);
+ addr = OF_claim_size(size, align, &range);
+ }
+ if (addr == (uint32_t)-1) {
+ ERROR("No range match !\n");
+ pushd(OF_env, -1);
+ }
+ if (range != -1) {
+ OF_mem_ranges[range].start = addr;
+ OF_mem_ranges[range].size = size;
+ }
+ OF_DPRINTF("Give address 0x%0x\n", addr);
+ pushd(OF_env, addr);
+}
+
+/* release some previously claimed memory */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_release (OF_env_t *OF_env)
+{
+ uint32_t virt, size;
+ int i;
+
+ OF_CHECK_NBARGS(OF_env, 2);
+ virt = popd(OF_env);
+ size = popd(OF_env);
+ OF_DPRINTF("virt 0x%0x size 0x%0x\n", virt, size);
+ for (i = 0; i < OF_MAX_MEMRANGES; i++) {
+ if (OF_mem_ranges[i].start == virt && OF_mem_ranges[i].size == size) {
+ OF_mem_ranges[i].start = (uint32_t)(-1);
+ OF_mem_ranges[i].size = (uint32_t)(-1);
+ break;
+ }
+ }
+}
+
+/* Control transfer services */
+/* "boot" */
+
+/* Enter Open-Firmware interpreter */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_enter (OF_env_t *OF_env)
+{
+ int n_args;
+
+ n_args = stackd_depth(OF_env);
+ /* means that the bootloader has ended.
+ * So qemu will...
+ */
+ OF_DPRINTF("%d \n", n_args);
+ // printf("Bootloader has quitted...\n");
+ // abort();
+}
+
+/* Exit client program */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_exit (OF_env_t *OF_env)
+{
+ int n_args;
+
+ n_args = stackd_depth(OF_env);
+ /* means that the bootloader has ended.
+ * So qemu will...
+ */
+ OF_DPRINTF("%d \n", n_args);
+ // printf("Bootloader has quitted...\n");
+ // abort();
+}
+
+/* "chain" */
+
+/* User interface services */
+/* "interpret" */
+
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_interpret (OF_env_t *OF_env)
+{
+ const unsigned char *FString;
+ void *buf;
+ OF_inst_t *inst;
+ OF_node_t *pks, *slw, *chs, *disp;
+ uint32_t ihandle, crc;
+
+ OF_DPRINTF("\n");
+ // OF_CHECK_NBARGS(OF_env, 1);
+ FString = (const void *)popd(OF_env);
+ crc = crc32(0, FString, strlen(FString));
+ OF_DPRINTF("\n\nOF INTERPRETER CALL:\n [%s]\n crc=%0x\n", FString, crc);
+ /* Do some hacks to make BootX happy */
+ switch (crc) {
+ case 0x225b6748: /* MacOS X 10.2 and OpenDarwin 1.41 */
+ case 0xb1cd4d25: /* OpenDarwin 6.02 */
+ /* Create "sl_words" package */
+ popd(OF_env);
+ /* Find "/packages" */
+ pks = OF_pack_find_by_name(OF_env, OF_node_root, "/packages");
+ if (pks == NULL) {
+ OF_node_put(OF_env, pks);
+ pushd(OF_env, -1);
+ ERROR("Cannot get '/packages'\n");
+ break;
+ }
+ slw = OF_node_new(OF_env, pks, "sl_words", OF_ADDRESS_NONE);
+ if (slw == NULL) {
+ OF_node_put(OF_env, pks);
+ pushd(OF_env, -1);
+ ERROR("Cannot create 'sl_words'\n");
+ break;
+ }
+ /* Create methods */
+ OF_method_new(OF_env, slw, "slw_set_output_level",
+ &slw_set_output_level);
+ OF_method_new(OF_env, slw, "slw_emit", &slw_emit);
+ OF_method_new(OF_env, slw, "slw_cr", &slw_cr);
+ OF_method_new(OF_env, slw, "slw_init_keymap", &slw_init_keymap);
+ OF_method_new(OF_env, slw, "slw_update_keymap", &slw_update_keymap);
+ OF_method_new(OF_env, slw, "slw_spin", &slw_spin);
+ OF_method_new(OF_env, slw, "slw_spin_init", &slw_spin_init);
+ OF_method_new(OF_env, slw, "slw_pwd", &slw_pwd);
+ OF_method_new(OF_env, slw, "slw_sum", &slw_sum);
+ /* Init properties */
+ OF_prop_int_new(OF_env, slw, "outputLevel", 0);
+ OF_prop_int_new(OF_env, slw, "keyboardIH", 0);
+ {
+#if 0
+ OF_node_t *kbd;
+ kbd = OF_pack_find_by_name(OF_env, OF_node_root, "/keyboard");
+ if (kbd == NULL) {
+ OF_node_put(OF_env, pks);
+ pushd(OF_env, -1);
+ ERROR("Cannot get '/keyboard'\n");
+ break;
+ }
+ buf = malloc(0x20);
+ if (buf == NULL) {
+ OF_node_put(OF_env, pks);
+ pushd(OF_env, -1);
+ ERROR("Cannot allocate keyboard buff\n");
+ break;
+ }
+#else
+ buf = malloc(0x20);
+ if (buf == NULL) {
+ OF_node_put(OF_env, pks);
+ pushd(OF_env, -1);
+ ERROR("Cannot allocate keyboard buff\n");
+ break;
+ }
+ memset(buf, 0, 0x20);
+ OF_property_new(OF_env, slw, "keyMap", buf, 0x20);
+#endif
+ }
+ OF_prop_int_new(OF_env, slw, "screenIH", 0);
+ OF_prop_int_new(OF_env, slw, "cursorAddr", 0);
+ OF_prop_int_new(OF_env, slw, "cursorX", 0);
+ OF_prop_int_new(OF_env, slw, "cursorY", 0);
+ OF_prop_int_new(OF_env, slw, "cursorW", 0);
+ OF_prop_int_new(OF_env, slw, "cursorH", 0);
+ OF_prop_int_new(OF_env, slw, "cursorFrames", 0);
+ OF_prop_int_new(OF_env, slw, "cursorPixelSize", 0);
+ OF_prop_int_new(OF_env, slw, "cursorStage", 0);
+ OF_prop_int_new(OF_env, slw, "cursorTime", 0);
+ OF_prop_int_new(OF_env, slw, "cursorDelay", 0);
+ /* Instanciate sl_words */
+ inst = OF_instance_new(OF_env, slw);
+ if (inst == NULL) {
+ OF_node_put(OF_env, pks);
+ pushd(OF_env, -1);
+ ERROR("Cannot create sl_words instance\n");
+ break;
+ }
+ ihandle = OF_instance_get_id(OF_env, inst);
+ /* Release packages */
+ OF_node_put(OF_env, slw);
+ OF_node_put(OF_env, pks);
+ OF_DPRINTF("sl_words instance: %0x\n", ihandle);
+ /* Set return value */
+ if (crc == 0xb1cd4d25) /* Hack for OpenDarwin 6.02 */
+ pushd(OF_env, ihandle);
+ pushd(OF_env, ihandle);
+ pushd(OF_env, 0);
+ break;
+ case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */
+ /* Create "memory-map" pseudo device */
+ popd(OF_env);
+ /* Find "/packages" */
+ chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen");
+ if (chs == NULL) {
+ pushd(OF_env, -1);
+ ERROR("Cannot get '/chosen'\n");
+ break;
+ }
+ {
+#if 1
+ OF_node_t *map;
+ uint32_t phandle;
+ map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE);
+ if (map == NULL) {
+ pushd(OF_env, -1);
+ ERROR("Cannot create 'memory-map'\n");
+ break;
+ }
+ phandle = OF_pack_handle(OF_env, map);
+ OF_node_put(OF_env, map);
+ OF_node_put(OF_env, chs);
+ pushd(OF_env, phandle);
+ }
+#else
+ pushd(OF_env, 0);
+#endif
+ pushd(OF_env, 0);
+ break;
+ case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */
+ /* Return screen ihandle */
+ disp = OF_get_alias(OF_env, "screen");
+ if (disp == NULL) {
+ pushd(OF_env, 0);
+ pushd(OF_env, -1);
+ ERROR("Cannot get 'screen' alias\n");
+ break;
+ }
+ inst = OF_instance_new(OF_env, disp);
+ if (inst == NULL) {
+ OF_node_put(OF_env, disp);
+ pushd(OF_env, 0);
+ pushd(OF_env, -1);
+ ERROR("Cannot create 'screen' instance\n");
+ break;
+ }
+ ihandle = OF_instance_get_id(OF_env, inst);
+ OF_node_put(OF_env, disp);
+ OF_DPRINTF("Return screen ihandle: %0x\n", ihandle);
+ pushd(OF_env, ihandle);
+ pushd(OF_env, 0);
+ break;
+ case 0xF3A9841F: /* MacOS X 10.2 */
+ case 0x76fbdf18: /* OpenDarwin 6.02 */
+ /* Set current display as active package */
+ disp = OF_get_alias (OF_env, "screen");
+ if (disp == NULL) {
+ pushd(OF_env, 0);
+ pushd(OF_env, -1);
+ }
+ OF_node_put(OF_env, disp);
+ break;
+ case 0x1c3bc93f: /* MacOS X 10.3 */
+ /* get-package-property if 0 0 then */
+ OF_getprop(OF_env);
+ {
+ uint32_t len;
+ len = popd(OF_env);
+ if (len == (uint32_t)-1)
+ len = 0;
+ pushd(OF_env, len);
+ }
+ break;
+ case 0x218d5ccb: /* yaboot */
+ case 0x27b32255:
+ case 0x05d332ef:
+ case 0xc7b5d3b5:
+ /* skip it */
+ break;
+ case 0xf541a878:
+ case 0x6a9b2be6:
+ /* Yaboot: set background color to black */
+ break;
+ case 0x846077fb:
+ case 0x299c2c5d: /* gentoo */
+ /* Yaboot: set foreground color to grey */
+ break;
+ case 0x4ad41f2d:
+ /* Yaboot: wait 10 ms: sure ! */
+ break;
+ default:
+ /* ERROR */
+ printf("Script:\n%s\n", FString);
+ printf("Call %0x NOT IMPLEMENTED !\n", crc);
+ bug();
+ break;
+ }
+ OF_DPRINTF("\n\nOF INTERPRETER CALL DONE\n\n");
+}
+
+/* "set-callback" */
+/* "set-symbol-lookup" */
+
+/* Time services */
+/* "milliseconds" */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_milliseconds (OF_env_t *OF_env)
+{
+#if 0
+ struct timeval tv;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(OF_env, 0);
+ gettimeofday(&tv, NULL);
+ pushd(OF_env, (tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#else
+ static uint32_t ms = 0;
+
+ OF_CHECK_NBARGS(OF_env, 0);
+ pushd(OF_env, ms);
+ usleep(10000); /* XXX: TOFIX: Random sleep */
+ ms += 10;
+#endif
+}
+
+/* Undocumented in IEEE 1275 */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_quiesce (OF_env_t *OF_env)
+{
+ OF_CHECK_NBARGS(OF_env, 0);
+ /* Should free all OF resources */
+#if defined (DEBUG_BIOS)
+ {
+ uint16_t loglevel = 0x02 | 0x10 | 0x80;
+ // outw(0xFF02, loglevel);
+ outb(0x0F02, loglevel);
+ }
+#endif
+}
+
+typedef struct OF_service_t OF_service_t;
+struct OF_service_t {
+ const unsigned char *name;
+ OF_cb_t cb;
+};
+
+static OF_service_t services[] = {
+ { "test", &OF_test, },
+ { "peer", &OF_peer, },
+ { "child", &OF_child, },
+ { "parent", &OF_parent, },
+ { "instance-to-package", &OF_instance_to_package, },
+ { "getproplen", &OF_getproplen, },
+ { "getprop", &OF_getprop, },
+ { "nextprop", &OF_nextprop, },
+ { "setprop", &OF_setprop, },
+ { "finddevice", &OF_finddevice, },
+ { "instance-to-path", &OF_instance_to_path, },
+ { "package-to-path", &OF_package_to_path, },
+ { "call-method", &OF_callmethod, },
+ { "open", &OF_open, },
+ { "open-package", &OF_open, },
+ { "close", &OF_close, },
+ { "read", &OF_read, },
+ { "write", &OF_write, },
+ { "seek", &OF_seek, },
+ { "claim", &OF_claim, },
+ { "release", &OF_release, },
+ { "enter", &OF_enter, },
+ { "exit", &OF_exit, },
+ { "interpret", &OF_interpret, },
+ { "milliseconds", &OF_milliseconds, },
+ { "quiesce", &OF_quiesce, },
+};
+
+/* Probe if a named service exists */
+__attribute__ (( section (".OpenFirmware") ))
+static void OF_test (OF_env_t *OF_env)
+{
+ unsigned char name[OF_NAMELEN_MAX], *namep;
+ uint32_t i;
+ int ret = -1;
+
+ OF_CHECK_NBARGS(OF_env, 1);
+ namep = (unsigned char *)popd(OF_env);
+ OF_lds(name, namep);
+ OF_DPRINTF("service [%s]\n", name);
+ for (i = 0; i < (sizeof(services) / sizeof(OF_service_t)); i++) {
+ if (strcmp(services[i].name, name) == 0) {
+ ret = 0;
+ break;
+ }
+ }
+ pushd(OF_env, ret);
+}
+
+/* Main entry point for PPC clients */
+__attribute__ (( section (".OpenFirmware") ))
+int OF_client_entry (void *p)
+{
+ unsigned char buffer[OF_NAMELEN_MAX];
+ OF_env_t OF_env;
+ OF_cb_t cb;
+ unsigned char *namep;
+ uint32_t i;
+
+ /* set our environment */
+ MMU_off();
+ OF_DPRINTF("Called with arg: %p\n", p);
+ /* Load function name string */
+ namep = (unsigned char *)(*(uint32_t *)p);
+ OF_lds(buffer, namep);
+ /* Find callback */
+ cb = NULL;
+ OF_DPRINTF("Look for service [%s]\n", buffer);
+ for (i = 0; i < (sizeof(services) / sizeof(OF_service_t)); i++) {
+ if (strcmp(services[i].name, buffer) == 0) {
+ cb = services[i].cb;
+ break;
+ }
+ }
+ if (cb == NULL) {
+ OF_DPRINTF("service [%s] not implemented\n", buffer);
+ // bug();
+ return -1;
+ }
+#if 0
+ OF_DPRINTF("Service [%s] found\n", buffer);
+#endif
+ /* Set up stack *NON REENTRANT* */
+ OF_env_init(&OF_env);
+ /* Launch Forth glue */
+ C_to_Forth(&OF_env, (uint32_t *)p + 1, &cb);
+ OF_DPRINTF("done\n");
+ MMU_on();
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Run-time abstraction services */
+/* RTAS RAM is organised this way:
+ * RTAS_memory is given by the OS when instanciating RTAS.
+ * it's an 32 kB area divided in 2 zones:
+ * Up is a stack, used to call RTAS services
+ * Down is the variables area.
+ */
+
+__attribute__ (( section (".RTAS_vars") ))
+static OF_cb_t *RTAS_callbacks[32];
+#if 0
+__attribute__ (( section (".RTAS_vars") ))
+static uint8_t *RTAS_base;
+#endif
+
+/* RTAS is called in real mode (ie no MMU), privileged with all exceptions
+ * disabled. It has to preserve all registers except R3 to R12.
+ * The OS should ensure it's not re-entered.
+ */
+__attribute__ (( section (".RTAS") ))
+int RTAS_entry (void *p)
+{
+ OF_env_t RTAS_env;
+ uint32_t token;
+
+ OF_DPRINTF("Called with arg: %p\n", p);
+ /* set our environment */
+ token = *(uint32_t *)p;
+ /* Set up stack */
+ RTAS_env.stackb = (uint32_t *)(RTAS_memory + 0x8000 - 4);
+ RTAS_env.stackp = RTAS_env.stackb;
+ RTAS_env.funcb = (uint32_t *)(RTAS_memory + 0x8000 - OF_STACK_SIZE - 4);
+ RTAS_env.funcp = RTAS_env.funcb;
+ /* Call Forth glue */
+ C_to_Forth(&RTAS_env, (uint32_t *)p + 1, RTAS_callbacks[token & 0x3F]);
+ OF_DPRINTF("done\n");
+
+ return 0;
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_restart_rtas (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 0);
+ /* No implementation: return error */
+ pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_nvram_fetch (OF_env_t *RTAS_env)
+{
+ uint8_t *buffer;
+ int offset, length;
+ int i;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 3);
+ offset = popd(RTAS_env);
+ buffer = (uint8_t *)popd(RTAS_env);
+ length = popd(RTAS_env);
+ for (i = 0; i < length; i++) {
+ if ((i + offset) >= NVRAM_get_size(nvram)) {
+ pushd(RTAS_env, -3);
+ return;
+ }
+ *buffer++ = NVRAM_read(nvram, i + offset);
+ }
+ pushd(RTAS_env, length);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_nvram_store (OF_env_t *RTAS_env)
+{
+ uint8_t *buffer;
+ int offset, length;
+ int i;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 3);
+ offset = popd(RTAS_env);
+ buffer = (uint8_t *)popd(RTAS_env);
+ length = popd(RTAS_env);
+ for (i = 0; i < length; i++) {
+ if ((i + offset) >= NVRAM_get_size(nvram)) {
+ pushd(RTAS_env, -3);
+ return;
+ }
+ NVRAM_write(nvram, i + offset, *buffer++);
+ }
+ pushd(RTAS_env, length);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_get_time_of_day (OF_env_t *RTAS_env)
+{
+#if 0
+ struct tm tm;
+ time_t t;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 0);
+ t = get_time();
+ localtime_r(&t, &tm);
+ pushd(RTAS_env, 0); /* nanoseconds */
+ pushd(RTAS_env, tm.tm_sec);
+ pushd(RTAS_env, tm.tm_min);
+ pushd(RTAS_env, tm.tm_hour);
+ pushd(RTAS_env, tm.tm_mday);
+ pushd(RTAS_env, tm.tm_mon);
+ pushd(RTAS_env, tm.tm_year);
+ pushd(RTAS_env, 0); /* status */
+#else
+ pushd(RTAS_env, 0);
+ pushd(RTAS_env, 0);
+ pushd(RTAS_env, 0);
+ pushd(RTAS_env, 0);
+ pushd(RTAS_env, 0);
+ pushd(RTAS_env, 0);
+ pushd(RTAS_env, 0);
+ pushd(RTAS_env, 0);
+#endif
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_time_of_day (OF_env_t *RTAS_env)
+{
+#if 0
+ struct tm tm;
+ time_t t;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 7);
+ tm.tm_year = popd(RTAS_env);
+ tm.tm_mon = popd(RTAS_env);
+ tm.tm_mday = popd(RTAS_env);
+ tm.tm_hour = popd(RTAS_env);
+ tm.tm_min = popd(RTAS_env);
+ tm.tm_sec = popd(RTAS_env);
+ popd(RTAS_env); /* nanoseconds */
+ t = mktime(&tm);
+ set_time_offset(t);
+#endif
+ pushd(RTAS_env, 0); /* status */
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_time_for_power_on (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 7);
+ /* Do nothing */
+ pushd(RTAS_env, 0); /* status */
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_event_scan (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 4);
+ /* Pretend there are no new events */
+ pushd(RTAS_env, 1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_check_exception (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 6);
+ /* Pretend we found no exceptions */
+ pushd(RTAS_env, 1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_read_pci_config (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 2);
+ /* Hardware error */
+ pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_write_pci_config (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 3);
+ /* Hardware error */
+ pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_display_character (OF_env_t *RTAS_env)
+{
+ int c;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 1);
+ c = popd(RTAS_env);
+#if 0
+ printf("%c", c);
+#else
+ outb(0x0F00, c);
+#endif
+ pushd(RTAS_env, 0);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_indicator (OF_env_t *RTAS_env)
+{
+ const unsigned char *name;
+ int indic, state;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 3);
+ indic = popd(RTAS_env);
+ state = popd(RTAS_env);
+ switch (indic) {
+ case 1:
+ name = "tone frequency";
+ break;
+ case 2:
+ name = "tone volume";
+ break;
+ case 3:
+ name = "system power state";
+ break;
+ case 4:
+ name = "warning light";
+ break;
+ case 5:
+ name = "disk activity light";
+ break;
+ case 6:
+ name = "hexadecimal display unit";
+ break;
+ case 7:
+ name = "batery warning time";
+ break;
+ case 8:
+ name = "condition cycle request";
+ break;
+ case 9000 ... 9999:
+ name = "vendor specific";
+ break;
+ default:
+ pushd(RTAS_env, -3);
+ return;
+ }
+ OF_DPRINTF("Set indicator %d [%s] to %d\n", indic, name, state);
+ pushd(RTAS_env, 0);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_get_sensor_state (OF_env_t *RTAS_env)
+{
+ const unsigned char *name;
+ int type, index;
+ int state;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 2);
+ type = popd(RTAS_env);
+ index = popd(RTAS_env);
+ switch (index) {
+ case 1:
+ name = "key switch";
+ state = 1; /* Normal */
+ break;
+ case 2:
+ name = "enclosure switch";
+ state = 0; /* Closed */
+ break;
+ case 3:
+ name = "thermal sensor";
+ state = 40; /* in degrees Celsius (not too hot !) */
+ break;
+ case 4:
+ name = "lid status";
+ state = 1; /* Open */
+ break;
+ case 5:
+ name = "power source";
+ state = 0; /* AC */
+ break;
+ case 6:
+ name = "battery voltage";
+ state = 6; /* Let's have a moderated answer :-) */
+ break;
+ case 7:
+ name = "battery capacity remaining";
+ state = 3; /* High */
+ break;
+ case 8:
+ name = "battery capacity percentage";
+ state = 1000; /* 100 % */
+ break;
+ case 9:
+ name = "EPOW sensor";
+ state = 5; /* ? */
+ break;
+ case 10:
+ name = "battery condition cycle state";
+ state = 0; /* none */
+ break;
+ case 11:
+ name = "battery charge state";
+ state = 2; /* No current flow */
+ break;
+ case 9000 ... 9999:
+ name = "vendor specific";
+ state = 0;
+ break;
+ default:
+ pushd(RTAS_env, -3);
+ return;
+ }
+ OF_DPRINTF("Pretend sensor %d [%s] is in state %d\n", index, name, state);
+ pushd(RTAS_env, state);
+ pushd(RTAS_env, 0);
+}
+
+#if 0 // No power management */
+__attribute__ (( section (".RTAS") ))
+static void RTAS_set_power_level (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_get_power_level (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_assume_power_management (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_relinquish_power_management (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+#endif
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_power_off (OF_env_t *RTAS_env)
+{
+ printf("RTAS was asked to switch off\n");
+ OF_CHECK_NBARGS(RTAS_env, 2);
+ // abort();
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_suspend (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 3);
+ /* Pretend we don't succeed */
+ pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_hibernate (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 3);
+ /* Pretend we don't succeed */
+ pushd(RTAS_env, -1);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_system_reboot (OF_env_t *RTAS_env)
+{
+ printf("RTAS was asked to reboot\n");
+ OF_CHECK_NBARGS(RTAS_env, 0);
+ // abort();
+}
+
+#if 0 // No power management nor SMP */
+__attribute__ (( section (".RTAS") ))
+static void RTAS_cache_control (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_freeze_time_base (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_thaw_time_base (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_stop_self (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_start_cpu (OF_env_t *RTAS_env)
+{
+ OF_DPRINTF("\n");
+}
+#endif
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_instantiate (OF_env_t *RTAS_env)
+{
+ const unsigned char *args;
+ uint32_t ihandle;
+ uint32_t base_address;
+
+ OF_DPRINTF("\n");
+ OF_CHECK_NBARGS(RTAS_env, 3);
+ ihandle = popd(RTAS_env);
+ args = (void *)popd(RTAS_env);
+ base_address = popd(RTAS_env);
+ memmove((void *)base_address, (void *)(&_RTAS_start),
+ (char *)(&_RTAS_data_end) - (char *)(&_RTAS_start));
+ OF_DPRINTF("base_address=0x%0x\n", base_address);
+ pushd(RTAS_env, base_address);
+ pushd(RTAS_env, 0);
+}
+
+__attribute__ (( section (".RTAS") ))
+static void RTAS_new_cb (OF_env_t *env, OF_node_t *rtas,
+ const unsigned char *name,
+ OF_cb_t cb, uint32_t *token_next)
+{
+ OF_prop_int_new(env, rtas, name, 0xabcd0000 | *token_next);
+ RTAS_callbacks[*token_next] = &cb;
+ (*token_next)++;
+}
+
+__attribute__ (( section (".RTAS") ))
+void RTAS_init (void)
+{
+ OF_env_t *RTAS_env;
+ OF_node_t *rtas, *chs;
+ OF_prop_t *stdout;
+ uint32_t token_next = 0, size;
+
+ RTAS_env = OF_env_main;
+ rtas = OF_node_new(RTAS_env, OF_node_root, "rtas", OF_ADDRESS_NONE);
+ if (rtas == NULL) {
+ ERROR("RTAS not found\n");
+ return;
+ }
+ size = ((char *)(&_RTAS_data_end) - (char *)(&_RTAS_start) + 0x0000FFFF) &
+ ~0x0000FFFF;
+ OF_DPRINTF("RTAS size: %d bytes (%d)\n", size,
+ (char *)(&_RTAS_data_end) - (char *)(&_RTAS_start));
+ OF_prop_int_new(RTAS_env, rtas, "rtas-size", size);
+ OF_prop_int_new(RTAS_env, rtas, "rtas-version", 1);
+ OF_prop_int_new(RTAS_env, rtas, "rtas-event-scan-rate", 0);
+ OF_prop_int_new(RTAS_env, rtas, "rtas-error-log-max", 0);
+ chs = OF_node_get(RTAS_env, "chosen");
+ if (chs == NULL) {
+ ERROR("choosen not found\n");
+ return;
+ }
+ stdout = OF_property_get(RTAS_env, chs, "stdout");
+ if (stdout == NULL) {
+ OF_node_put(RTAS_env, chs);
+ ERROR("stdout not found\n");
+ return;
+ }
+ OF_prop_int_new(RTAS_env, rtas, "rtas-display-device",
+ *(uint32_t *)stdout->value);
+ /* RTAS tokens */
+ RTAS_new_cb(RTAS_env, rtas, "restart_rtas",
+ &RTAS_restart_rtas, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "nvram_fetch",
+ &RTAS_nvram_fetch, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "nvram_store",
+ &RTAS_nvram_store, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "get-time-of_day",
+ &RTAS_get_time_of_day, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "set-time-of-day",
+ &RTAS_set_time_of_day, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "set-time-for-power-on",
+ &RTAS_set_time_for_power_on, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "event-scan", &RTAS_event_scan, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "check-exception",
+ &RTAS_check_exception, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "read-pci-config",
+ &RTAS_read_pci_config, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "write-pci-config",
+ &RTAS_write_pci_config, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "display-character",
+ &RTAS_display_character, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "set-indicator",
+ &RTAS_set_indicator, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "get-sensor-state",
+ &RTAS_get_sensor_state, &token_next);
+#if 0 // No power management */
+ RTAS_new_cb(RTAS_env, rtas, "set-power-level",
+ &RTAS_set_power_level, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "get-power-level",
+ &RTAS_get_power_level, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "assume-power-management",
+ &RTAS_assume_power_management, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "relinquish-power-management",
+ &RTAS_relinquish_power_management, &token_next);
+#endif
+ RTAS_new_cb(RTAS_env, rtas, "power-off", &RTAS_power_off, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "suspend", &RTAS_suspend, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "hibernate", &RTAS_hibernate, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "system-reboot",
+ &RTAS_system_reboot, &token_next);
+#if 0 // No power management nor SMP */
+ RTAS_new_cb(RTAS_env, rtas, "cache-control",
+ &RTAS_cache_control, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "freeze_time_base",
+ &RTAS_freeze_time_base, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "thaw_time_base",
+ &RTAS_thaw_time_base, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "stop-self", &RTAS_stop_self, &token_next);
+ RTAS_new_cb(RTAS_env, rtas, "start-cpu", &RTAS_start_cpu, &token_next);
+#endif
+ /* missing
+ * "update-flash"
+ * "update-flash-and-reboot"
+ * "query-cpu-stopped-state" for SMP
+ */
+ OF_method_new(RTAS_env, rtas, "instantiate-rtas", &RTAS_instantiate);
+ OF_node_put(RTAS_env, rtas);
+ OF_node_new(RTAS_env, OF_node_root, "nomore", OF_ADDRESS_NONE);
+ DPRINTF("RTAS done\n");
+}
+
+/*****************************************************************************/
+/* That's all for now... */
+/*****************************************************************************/
diff --git a/src/pci.c b/src/pci.c
new file mode 100644
index 0000000..10e6eb3
--- /dev/null
+++ b/src/pci.c
@@ -0,0 +1,2250 @@
+/* PCI BIOS.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bios.h"
+
+//#define DEBUG_PCI 1
+
+#if defined (DEBUG_PCI)
+#define PCI_DPRINTF(fmt, args...) \
+do { dprintf("PCI %s: " fmt, __func__ , ##args); } while (0)
+#else
+#define PCI_DPRINTF(fmt, args...) \
+do { } while (0)
+#endif
+
+/* On PMAC, there are four kind of PCI bridges:
+ * - uninorth, for all recent machines (all Core99 and more).
+ * - chaos : buggy bandit like
+ * - grackle, for powerbook 1998 & some powermac G3
+ * - bandit : some early PCI powermacs.
+ * For now, only uninorth will be supported, as other ones are deprecated.
+ */
+
+enum {
+ /* Fake devices */
+ PCI_FAKE_HOST = 0x00000001,
+ PCI_FAKE_BRIDGE = 0x00000002,
+ /* Device found during PCI probe */
+ PCI_HOST_BRIDGE = 0x00000003,
+ PCI_DEV_BRIDGE = 0x00000004,
+ PCI_DEVICE = 0x00000005,
+};
+
+enum {
+ BRIDGE_TYPE_UNINORTH = 0x0001,
+};
+
+/* PCI devices database */
+typedef struct pci_class_t pci_class_t;
+typedef struct pci_subclass_t pci_subclass_t;
+typedef struct pci_iface_t pci_iface_t;
+
+struct pci_iface_t {
+ uint8_t iface;
+ const unsigned char *name;
+ const unsigned char *type;
+ const pci_dev_t *devices;
+ int (*config_cb)(pci_device_t *device);
+ const void *private;
+};
+
+struct pci_subclass_t {
+ uint8_t subclass;
+ const unsigned char *name;
+ const unsigned char *type;
+ const pci_dev_t *devices;
+ const pci_iface_t *iface;
+ int (*config_cb)(pci_device_t *device);
+ const void *private;
+};
+
+struct pci_class_t {
+ const unsigned char *name;
+ const unsigned char *type;
+ const pci_subclass_t *subc;
+};
+
+/* PCI devices tree */
+struct pci_common_t {
+ int type;
+ const pci_dev_t *device;
+ const pci_u_t *parent;
+ void *OF_private;
+};
+
+struct pci_device_t {
+ pci_common_t common;
+ uint8_t bus;
+ uint8_t devfn;
+ uint16_t rev;
+ uint32_t class_code;
+ uint16_t min_grant;
+ uint16_t max_latency;
+ uint8_t irq_line;
+ uint32_t regions[6];
+ uint32_t sizes[6];
+ pci_device_t *next;
+};
+
+struct pci_host_t {
+ pci_device_t dev;
+ pci_bridge_t *bridge;
+ pci_host_t *next;
+};
+
+struct pci_bridge_t {
+ pci_device_t dev;
+ uint32_t cfg_base;
+ uint32_t cfg_len;
+ uint32_t io_base;
+ uint32_t io_len;
+ uint32_t io_cur;
+ uint32_t mem_base;
+ uint32_t mem_len;
+ uint32_t mem_cur;
+ uint32_t rbase;
+ uint32_t rlen;
+ uint32_t cfg_addr;
+ uint32_t cfg_data;
+ uint32_t flags;
+ const pci_ops_t *ops;
+ pci_device_t *devices;
+ pci_bridge_t *next;
+};
+
+union pci_u_t {
+ pci_common_t common;
+ pci_host_t host;
+ pci_device_t device;
+ pci_bridge_t bridge;
+};
+
+/* Low level access helpers */
+struct pci_ops_t {
+ uint8_t (*config_readb)(pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn, uint8_t offset);
+ void (*config_writeb)(pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint8_t val);
+ uint16_t (*config_readw)(pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn, uint8_t offset);
+ void (*config_writew)(pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint16_t val);
+ uint32_t (*config_readl)(pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn, uint8_t offset);
+ void (*config_writel)(pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint32_t val);
+};
+
+/* IRQ numbers assigned to PCI IRQs */
+static uint8_t prep_pci_irqs[4] = { 9, 11, 9, 11 };
+static uint8_t pmac_pci_irqs[4] = { 8, 9, 10, 11 };
+
+/* PREP PCI host */
+static inline uint32_t PREP_cfg_addr (pci_bridge_t *bridge, unused uint8_t bus,
+ uint8_t devfn, uint8_t offset)
+{
+#if 0
+ printf("Translate %0x %0x %d %x %x => %0x",
+ bridge->cfg_addr, bridge->cfg_data, bus, devfn, offset,
+ bridge->cfg_addr |
+ (1 << (devfn >> 3)) | ((devfn & 7) << 8) | offset);
+#endif
+ return bridge->cfg_addr |
+ (1 << (devfn >> 3)) | ((devfn & 7) << 8) | offset;
+}
+
+static uint8_t PREP_config_readb (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ uint32_t addr;
+
+ if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21)
+ return 0xFF;
+ addr = PREP_cfg_addr(bridge, bus, devfn, offset);
+
+ return *((uint8_t *)addr);
+}
+
+static void PREP_config_writeb (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint8_t val)
+{
+ uint32_t addr;
+
+ if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21)
+ return;
+ addr = PREP_cfg_addr(bridge, bus, devfn, offset);
+ *((uint8_t *)addr) = val;
+}
+
+static uint16_t PREP_config_readw (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ uint32_t addr;
+
+ if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21)
+ return 0xFFFF;
+ addr = PREP_cfg_addr(bridge, bus, devfn, offset);
+
+ return ldswap16((uint16_t *)addr);
+}
+
+static void PREP_config_writew (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint16_t val)
+{
+ uint32_t addr;
+
+ if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21)
+ return;
+ addr = PREP_cfg_addr(bridge, bus, devfn, offset);
+ stswap16((uint16_t *)addr, val);
+}
+
+static uint32_t PREP_config_readl (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ uint32_t addr;
+
+ if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21)
+ return 0xFFFFFFFF;
+ addr = PREP_cfg_addr(bridge, bus, devfn, offset);
+
+ return ldswap32((uint32_t *)addr);
+}
+
+static void PREP_config_writel (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint32_t val)
+{
+ uint32_t addr;
+
+ if (bus != 0 || (devfn >> 3) < 11 || (devfn >> 3) > 21)
+ return;
+ addr = PREP_cfg_addr(bridge, bus, devfn, offset);
+ stswap32((uint32_t *)addr, val);
+}
+
+static pci_ops_t PREP_pci_ops = {
+ &PREP_config_readb, &PREP_config_writeb,
+ &PREP_config_readw, &PREP_config_writew,
+ &PREP_config_readl, &PREP_config_writel,
+};
+
+/* Uninorth PCI host */
+static uint32_t macrisc_cfg_address (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ uint32_t addr;
+ int i;
+
+ /* Kind of magic... */
+ if (bridge->cfg_base == 0xF2000000) {
+ if (bus != 0) {
+#if 0
+ printf("Skip bus: %d dev: %x offset: %x\n", bus, devfn, offset);
+#endif
+ return -1;
+ }
+ addr = (1 << (devfn >> 3));
+ } else {
+ addr = (bus << 16) | ((devfn & 0xF8) << 8) | 0x01;
+ }
+ addr |= ((devfn & 0x07) << 8) | (offset & 0xFC);
+ /* Avoid looping forever */
+#if 0
+ printf("Translate %0x %0x %d %x %x => %0x",
+ bridge->cfg_addr, bridge->cfg_data, bus, devfn, offset, addr);
+#endif
+ for (i = 0; i < 100; i++) {
+ stswap32((uint32_t *)bridge->cfg_addr, addr);
+ eieio();
+ if (ldswap32((uint32_t *)bridge->cfg_addr) == addr)
+ break;
+ }
+ if (i == 100) {
+#if 1
+ printf("Translate %0x %0x %d %x %x => %0x",
+ bridge->cfg_addr, bridge->cfg_data, bus, devfn, offset, addr);
+ printf("\nTimeout accessing PCI bridge cfg address\n");
+#endif
+ return -1;
+ }
+ if (bridge->flags & BRIDGE_TYPE_UNINORTH)
+ offset &= 0x07;
+ else
+ offset &= 0x03;
+#if 0
+ printf(" %0x\n", bridge->cfg_data + offset);
+#endif
+
+ return bridge->cfg_data + offset;
+}
+
+static uint8_t uninorth_config_readb (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ uint32_t addr;
+
+ if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11)
+ return 0xFF;
+ addr = macrisc_cfg_address(bridge, bus, devfn, offset);
+ if (addr == (uint32_t)(-1))
+ return 0xFF;
+
+ return *((uint8_t *)addr);
+}
+
+static void uninorth_config_writeb (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint8_t val)
+{
+ uint32_t addr;
+
+ if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11)
+ return;
+ addr = macrisc_cfg_address(bridge, bus, devfn, offset);
+ if (addr != (uint32_t)(-1))
+ *((uint8_t *)addr) = val;
+}
+
+static uint16_t uninorth_config_readw (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ uint32_t addr;
+
+ if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11)
+ return 0xFFFF;
+ addr = macrisc_cfg_address(bridge, bus, devfn, offset);
+ if (addr == (uint32_t)(-1))
+ return 0xFFFF;
+
+ return ldswap16((uint16_t *)addr);
+}
+
+static void uninorth_config_writew (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint16_t val)
+{
+ uint32_t addr;
+
+ if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11)
+ return;
+ addr = macrisc_cfg_address(bridge, bus, devfn, offset);
+ if (addr != (uint32_t)(-1))
+ stswap16((uint16_t *)addr, val);
+}
+
+static uint32_t uninorth_config_readl (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ uint32_t addr;
+
+ if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11)
+ return 0xFFFFFFFF;
+ addr = macrisc_cfg_address(bridge, bus, devfn, offset);
+ if (addr == (uint32_t)(-1)) {
+ // printf("bad address -1\n");
+ return 0xFFFFFFFF;
+ }
+ // printf("%s: addr=%0x\n", __func__, addr);
+
+ return ldswap32((uint32_t *)addr);
+}
+
+static void uninorth_config_writel (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint32_t val)
+{
+ uint32_t addr;
+
+ if (bridge->cfg_base == 0xF2000000 && (devfn >> 3) < 11)
+ return;
+ addr = macrisc_cfg_address(bridge, bus, devfn, offset);
+ if (addr != (uint32_t)(-1))
+ stswap32((uint32_t *)addr, val);
+}
+
+static pci_ops_t uninorth_pci_ops = {
+ &uninorth_config_readb, &uninorth_config_writeb,
+ &uninorth_config_readw, &uninorth_config_writew,
+ &uninorth_config_readl, &uninorth_config_writel,
+};
+
+static inline uint8_t pci_config_readb (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ return (*bridge->ops->config_readb)(bridge, bus, devfn, offset);
+}
+
+static inline void pci_config_writeb (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint8_t val)
+{
+ (*bridge->ops->config_writeb)(bridge, bus, devfn, offset, val);
+}
+
+static inline uint16_t pci_config_readw (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ return (*bridge->ops->config_readw)(bridge, bus, devfn, offset);
+}
+
+static inline void pci_config_writew (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint16_t val)
+{
+ (*bridge->ops->config_writew)(bridge, bus, devfn, offset, val);
+}
+
+static inline uint32_t pci_config_readl (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset)
+{
+ return (*bridge->ops->config_readl)(bridge, bus, devfn, offset);
+}
+
+
+static inline void pci_config_writel (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ uint8_t offset, uint32_t val)
+{
+ (*bridge->ops->config_writel)(bridge, bus, devfn, offset, val);
+}
+
+unused static void *get_parent_OF_private (pci_device_t *device)
+{
+ const pci_u_t *u;
+
+ for (u = (pci_u_t *)device; u != NULL; u = u->common.parent) {
+ if (u->common.OF_private != NULL)
+ return u->common.OF_private;
+ }
+
+ return NULL;
+}
+
+/* PCI devices database */
+static pci_subclass_t undef_subclass[] = {
+ {
+ 0x00, "misc undefined", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_dev_t ide_devices[] = {
+ {
+ 0x8086, 0x0100,
+ NULL, "Qemu IDE", "Qemu IDE", "ide",
+ 0, 0, 0,
+ NULL, NULL,
+ },
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
+static int ide_config_cb (pci_device_t *device)
+{
+ printf("Register IDE controller\n");
+ switch (arch) {
+ case ARCH_MAC99:
+ ide_pci_pmac_register(device->regions[0] & ~0x0000000F,
+ device->regions[1] & ~0x0000000F,
+ device->common.OF_private);
+ break;
+ default:
+ ide_pci_pc_register(device->regions[0] & ~0x0000000F,
+ device->regions[1] & ~0x0000000F,
+ device->regions[2] & ~0x0000000F,
+ device->regions[3] & ~0x0000000F,
+ device->common.OF_private);
+ break;
+ }
+
+ return 0;
+}
+
+static int ata_config_cb (pci_device_t *device)
+{
+ printf("Register ATA controller\n");
+ switch (arch) {
+ case ARCH_MAC99:
+ ide_pci_pmac_register(device->regions[0] & ~0x0000000F,
+ device->regions[1] & ~0x0000000F,
+ device->common.OF_private);
+ break;
+ default:
+ ide_pci_pc_register(device->regions[0] & ~0x0000000F,
+ device->regions[1] & ~0x0000000F,
+ device->regions[2] & ~0x0000000F,
+ device->regions[3] & ~0x0000000F,
+ device->common.OF_private);
+ break;
+ }
+
+ return 0;
+}
+
+static pci_subclass_t mass_subclass[] = {
+ {
+ 0x00, "SCSI bus controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "IDE controller", "ide", ide_devices, NULL,
+ &ide_config_cb, NULL,
+ },
+ {
+ 0x02, "Floppy disk controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x03, "IPI bus controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x04, "RAID controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x05, "ATA controller", "ata", NULL, NULL,
+ &ata_config_cb, NULL,
+ },
+ {
+ 0x80, "misc mass-storage controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_dev_t eth_devices[] = {
+ { 0x10EC, 0x8029,
+ NULL, "NE2000", "NE2000 PCI", NULL,
+ 0, 0, 0,
+ NULL, "ethernet",
+ },
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t net_subclass[] = {
+ {
+ 0x00, "ethernet controller", NULL, eth_devices, NULL,
+ NULL, "ethernet",
+ },
+ {
+ 0x01, "token ring controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "FDDI controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x03, "ATM controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x04, "ISDN controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x05, "WordFip controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x06, "PICMG 2.14 controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc network controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_dev_t vga_devices[] = {
+ {
+ 0x1002, 0x5046,
+ NULL, "ATY", "ATY Rage128", "VGA",
+ 0, 0, 0,
+ NULL, NULL,
+ },
+ {
+ 0x1234, 0x1111,
+ NULL, "Qemu VGA", "Qemu VGA", "VGA",
+ 0, 0, 0,
+ NULL, NULL,
+ },
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
+/* VGA configuration */
+/* HACK... */
+extern int vga_width, vga_height, vga_depth;
+int vga_console_register (void);
+static int vga_config_cb (pci_device_t *device)
+{
+ /* Found a VGA device. Let's configure it ! */
+ printf("Set VGA to %0x\n", device->regions[0] & ~0x0000000F);
+ if (device->regions[0] != 0x00000000) {
+ vga_set_mode(vga_width, vga_height, vga_depth);
+ vga_set_address(device->regions[0] & ~0x0000000F);
+ /* VGA 640x480x16 */
+ OF_vga_register(device->common.device->name,
+ device->regions[0] & ~0x0000000F,
+ vga_width, vga_height, vga_depth);
+ }
+ vga_console_register();
+
+ return 0;
+}
+
+static struct pci_iface_t vga_iface[] = {
+ {
+ 0x00, "VGA controller", NULL,
+ vga_devices, &vga_config_cb, NULL,
+ },
+ {
+ 0x01, "8514 compatible controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_subclass_t displ_subclass[] = {
+ {
+ 0x00, "display controller", NULL, NULL, vga_iface,
+ NULL, NULL,
+ },
+ {
+ 0x01, "XGA display controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "3D display controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc display controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t media_subclass[] = {
+ {
+ 0x00, "video device", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "audio device", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "computer telephony device", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc multimedia device", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t mem_subclass[] = {
+ {
+ 0x00, "RAM controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "flash controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_dev_t uninorth_agp_fake_bridge = {
+ 0xFFFF, 0xFFFF,
+ "uni-north-agp", "uni-north-agp", NULL, "uni-north-agp",
+ -1, -1, -1,
+ NULL, &uninorth_pci_ops,
+};
+
+static pci_dev_t uninorth_fake_bridge = {
+ 0xFFFF, 0xFFFF,
+ "uni-north", "uni-north", NULL, "uni-north",
+ -1, -1, -1,
+ NULL, &uninorth_pci_ops,
+};
+
+static pci_dev_t PREP_fake_bridge = {
+ 0xFFFF, 0xFFFF,
+ "pci", "pci", NULL, "pci",
+ -1, -1, -1,
+ NULL, &PREP_pci_ops,
+};
+
+static pci_dev_t hbrg_devices[] = {
+ {
+ 0x106B, 0x0020, NULL,
+ "pci", "AAPL,UniNorth", "uni-north",
+ 3, 2, 1,
+ NULL, &uninorth_agp_fake_bridge,
+ },
+ {
+ 0x106B, 0x001F,
+ NULL, "pci", "AAPL,UniNorth", "uni-north",
+ 3, 2, 1,
+ NULL, &uninorth_fake_bridge,
+ },
+ {
+ 0x106B, 0x001E, NULL,
+ "pci", "AAPL,UniNorth", "uni-north",
+ 3, 2, 1,
+ NULL, &uninorth_fake_bridge,
+ },
+ {
+ 0x1011, 0x0026, NULL,
+ "pci-bridge", NULL, NULL,
+ 3, 2, 1,
+ NULL, &PREP_pci_ops,
+ },
+ {
+ 0x1057, 0x4801, NULL,
+ "pci-bridge", "PREP Host PCI Bridge - Motorola Raven", NULL,
+ 3, 2, 1,
+ NULL, &PREP_pci_ops,
+ },
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
+static pci_dev_t PCIbrg_devices[] = {
+ {
+ 0x1011, 0x0026, NULL,
+ "pci-bridge", NULL, NULL,
+ 3, 2, 1,
+ NULL, &PREP_pci_ops,
+ },
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t bridg_subclass[] = {
+ {
+ 0x00, "PCI host bridge", NULL, hbrg_devices, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "ISA bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "EISA bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x03, "MCA bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x04, "PCI-to-PCI bridge", NULL, PCIbrg_devices, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x05, "PCMCIA bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x06, "NUBUS bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x07, "cardbus bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x08, "raceway bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x09, "semi-transparent PCI-to-PCI bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x0A, "infiniband-to-PCI bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc PCI bridge", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_iface_t serial_iface[] = {
+ {
+ 0x00, "XT serial controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "16450 serial controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x02, "16550 serial controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x03, "16650 serial controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x04, "16750 serial controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x05, "16850 serial controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x06, "16950 serial controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_iface_t par_iface[] = {
+ {
+ 0x00, "parallel port", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "bi-directional parallel port", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x02, "ECP 1.x parallel port", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x03, "IEEE 1284 controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFE, "IEEE 1284 device", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_iface_t modem_iface[] = {
+ {
+ 0x00, "generic modem", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "Hayes 16450 modem", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x02, "Hayes 16550 modem", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x03, "Hayes 16650 modem", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x04, "Hayes 16750 modem", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_subclass_t comm_subclass[] = {
+ {
+ 0x00, "serial controller", NULL, NULL, serial_iface,
+ NULL, NULL,
+ },
+ {
+ 0x01, "parallel port", NULL, NULL, par_iface,
+ NULL, NULL,
+ },
+ {
+ 0x02, "multiport serial controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x03, "modem", NULL, NULL, modem_iface,
+ NULL, NULL,
+ },
+ {
+ 0x04, "GPIB controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x05, "smart card", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc communication device", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_iface_t pic_iface[] = {
+ {
+ 0x00, "8259 PIC", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "ISA PIC", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x02, "EISA PIC", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x10, "I/O APIC", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x20, "I/O APIC", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_iface_t dma_iface[] = {
+ {
+ 0x00, "8237 DMA controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "ISA DMA controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x02, "EISA DMA controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_iface_t tmr_iface[] = {
+ {
+ 0x00, "8254 system timer", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "ISA system timer", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x02, "EISA system timer", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_iface_t rtc_iface[] = {
+ {
+ 0x00, "generic RTC controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "ISA RTC controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static const pci_dev_t sys_devices[] = {
+ /* IBM MPIC controller */
+ {
+ 0x1014, 0x0002,
+ "open-pic", "MPIC", NULL, "chrp,open-pic",
+ 0, 0, 2,
+ NULL, NULL,
+ },
+ /* IBM MPIC2 controller */
+ {
+ 0x1014, 0xFFFF,
+ "open-pic", "MPIC2", NULL, "chrp,open-pic",
+ 0, 0, 2,
+ NULL, NULL,
+ },
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t sys_subclass[] = {
+ {
+ 0x00, "PIC", NULL, NULL, pic_iface,
+ NULL, NULL,
+ },
+ {
+ 0x01, "DMA controller", NULL, NULL, dma_iface,
+ NULL, NULL,
+ },
+ {
+ 0x02, "system timer", NULL, NULL, tmr_iface,
+ NULL, NULL,
+ },
+ {
+ 0x03, "RTC controller", NULL, NULL, rtc_iface,
+ NULL, NULL,
+ },
+ {
+ 0x04, "PCI hotplug controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc system peripheral", NULL, sys_devices, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t inp_subclass[] = {
+ {
+ 0x00, "keyboard controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "digitizer", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "mouse controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x03, "scanner controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x04, "gameport controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc input device", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t dock_subclass[] = {
+ {
+ 0x00, "generic docking station", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc docking station", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t cpu_subclass[] = {
+ {
+ 0x00, "i386 processor", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "i486 processor", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "pentium processor", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x10, "alpha processor", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x20, "PowerPC processor", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x30, "MIPS processor", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x40, "co-processor", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_iface_t usb_iface[] = {
+ {
+ 0x00, "UHCI USB controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x10, "OHCI USB controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x20, "EHCI USB controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x80, "misc USB controller", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFE, "USB device", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_iface_t ipmi_iface[] = {
+ {
+ 0x00, "IPMI SMIC interface", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x01, "IPMI keyboard interface", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0x02, "IPMI block transfer interface", NULL,
+ NULL, NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL,
+ NULL, NULL, NULL,
+ },
+};
+
+static pci_subclass_t ser_subclass[] = {
+ {
+ 0x00, "Firewire bus controller", "ieee1394", NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "ACCESS bus controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "SSA controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x03, "USB controller", "usb", NULL, usb_iface,
+ NULL, NULL,
+ },
+ {
+ 0x04, "fibre channel controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x05, "SMBus controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x06, "InfiniBand controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x07, "IPMI interface", NULL, NULL, ipmi_iface,
+ NULL, NULL,
+ },
+ {
+ 0x08, "SERCOS controller", NULL, NULL, ipmi_iface,
+ NULL, NULL,
+ },
+ {
+ 0x09, "CANbus controller", NULL, NULL, ipmi_iface,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t wrl_subclass[] = {
+ {
+ 0x00, "IRDA controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "consumer IR controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x10, "RF controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x11, "bluetooth controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x12, "broadband controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc wireless controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t sat_subclass[] = {
+ {
+ 0x01, "satellite TV controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x02, "satellite audio controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x03, "satellite voice controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x04, "satellite data controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t crypt_subclass[] = {
+ {
+ 0x00, "cryptographic network controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x10, "cryptographic entertainment controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc cryptographic controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static pci_subclass_t spc_subclass[] = {
+ {
+ 0x00, "DPIO module", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x01, "performances counters", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x10, "communication synchronisation", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x20, "management card", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0x80, "misc signal processing controller", NULL, NULL, NULL,
+ NULL, NULL,
+ },
+ {
+ 0xFF, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ },
+};
+
+static const pci_class_t pci_classes[] = {
+ /* 0x00 */
+ { "undefined", NULL, undef_subclass, },
+ /* 0x01 */
+ { "mass-storage controller", NULL, mass_subclass, },
+ /* 0x02 */
+ { "network controller", "network", net_subclass, },
+ /* 0x03 */
+ { "display controller", "display", displ_subclass, },
+ /* 0x04 */
+ { "multimedia device", NULL, media_subclass, },
+ /* 0x05 */
+ { "memory controller", "memory-controller", mem_subclass, },
+ /* 0x06 */
+ { "PCI bridge", "pci", bridg_subclass, },
+ /* 0x07 */
+ { "communication device", NULL, comm_subclass,},
+ /* 0x08 */
+ { "system peripheral", NULL, sys_subclass, },
+ /* 0x09 */
+ { "input device", NULL, inp_subclass, },
+ /* 0x0A */
+ { "docking station", NULL, dock_subclass, },
+ /* 0x0B */
+ { "processor", NULL, cpu_subclass, },
+ /* 0x0C */
+ { "serial bus controller", NULL, ser_subclass, },
+ /* 0x0D */
+ { "wireless controller", NULL, wrl_subclass, },
+ /* 0x0E */
+ { "intelligent I/O controller", NULL, NULL, },
+ /* 0x0F */
+ { "satellite communication controller", NULL, sat_subclass, },
+ /* 0x10 */
+ { "cryptographic controller", NULL, crypt_subclass, },
+ /* 0x11 */
+ { "signal processing controller", NULL, spc_subclass, },
+};
+
+static int macio_config_cb (pci_device_t *device)
+{
+ void *private_data;
+
+ private_data = cuda_init(device->regions[0] + 0x16000);
+ OF_finalize_pci_macio(device->common.OF_private,
+ device->regions[0] & ~0x0000000F, device->sizes[0],
+ private_data);
+
+ return 0;
+}
+
+static const pci_dev_t misc_pci[] = {
+ /* Apple Mac-io controller */
+ {
+ 0x106B, 0x0022,
+ "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo",
+ 1, 1, 2,
+ &macio_config_cb, NULL,
+ },
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
+static pci_dev_t *pci_find_device (uint8_t class, uint8_t subclass,
+ uint8_t iface, uint16_t vendor,
+ uint16_t product)
+{
+ int (*config_cb)(pci_device_t *device);
+ const pci_class_t *pclass;
+ const pci_subclass_t *psubclass;
+ const pci_iface_t *piface;
+ const pci_dev_t *dev;
+ const void *private;
+ pci_dev_t *new;
+ const unsigned char *name, *type;
+
+ name = "unknown";
+ type = "unknown";
+ config_cb = NULL;
+ private = NULL;
+#if 0
+ printf("check PCI device : %x %x (%x %x %x)\n",
+ vendor, product, class, subclass, iface);
+#endif
+ if (class == 0x00 && subclass == 0x01) {
+ /* Special hack for old style VGA devices */
+ class = 0x03;
+ subclass = 0x00;
+ } else if (class == 0xFF) {
+ /* Special case for misc devices */
+ dev = misc_pci;
+ goto find_device;
+ }
+ if (class > (sizeof(pci_classes) / sizeof(pci_class_t))) {
+ name = "invalid PCI device";
+ type = "invalid";
+ goto bad_device;
+ }
+ pclass = &pci_classes[class];
+ name = pclass->name;
+ type = pclass->type;
+ for (psubclass = pclass->subc; ; psubclass++) {
+ if (psubclass->subclass == 0xFF)
+ goto bad_device;
+ if (psubclass->subclass == subclass) {
+ if (psubclass->name != NULL)
+ name = psubclass->name;
+ if (psubclass->type != NULL)
+ type = psubclass->type;
+ if (psubclass->config_cb != NULL) {
+ config_cb = psubclass->config_cb;
+ }
+ if (psubclass->private != NULL)
+ private = psubclass->private;
+ if (psubclass->iface != NULL)
+ break;
+ dev = psubclass->devices;
+ goto find_device;
+ }
+ }
+ for (piface = psubclass->iface; ; piface++) {
+ if (piface->iface == 0xFF) {
+ dev = psubclass->devices;
+ break;
+ }
+ if (piface->iface == iface) {
+ if (piface->name != NULL)
+ name = piface->name;
+ if (piface->type != NULL)
+ type = piface->type;
+ if (piface->config_cb != NULL) {
+ config_cb = piface->config_cb;
+ }
+ if (piface->private != NULL)
+ private = piface->private;
+ dev = piface->devices;
+ break;
+ }
+ }
+ find_device:
+ for (;; dev++) {
+ if (dev->vendor == 0xFFFF && dev->product == 0xFFFF) {
+ goto bad_device;
+ }
+ if (dev->vendor == vendor && dev->product == product) {
+ if (dev->name != NULL)
+ name = dev->name;
+ if (dev->type != NULL)
+ type = dev->type;
+ if (dev->config_cb != NULL) {
+ config_cb = dev->config_cb;
+ }
+ if (dev->private != NULL)
+ private = dev->private;
+ new = malloc(sizeof(pci_dev_t));
+ if (new == NULL)
+ return NULL;
+ new->vendor = vendor;
+ new->product = product;
+ new->type = type;
+ new->name = name;
+ new->model = dev->model;
+ new->compat = dev->compat;
+ new->acells = dev->acells;
+ new->scells = dev->scells;
+ new->icells = dev->icells;
+ new->config_cb = config_cb;
+ new->private = private;
+
+ return new;
+ }
+ }
+ bad_device:
+ printf("Cannot manage '%s' PCI device type '%s':\n %x %x (%x %x %x)\n",
+ name, type, vendor, product, class, subclass, iface);
+
+ return NULL;
+}
+
+/* PCI devices discovery helpers */
+static inline void pci_fill_common (pci_common_t *comm, pci_u_t *parent,
+ int type, pci_dev_t *device)
+{
+ comm->type = type;
+ comm->device = device;
+ comm->parent = parent;
+}
+
+static inline void pci_fill_device (pci_device_t *device, pci_u_t *parent,
+ int type, uint8_t bus, uint8_t devfn,
+ pci_dev_t *dev, uint32_t class_code)
+{
+ pci_fill_common(&device->common, parent, type, dev);
+ device->bus = bus;
+ device->devfn = devfn;
+ device->class_code = class_code;
+ device->rev = class_code;
+}
+
+static inline void pci_update_device (pci_bridge_t *bridge,
+ pci_device_t *device,
+ uint8_t min_grant, uint8_t max_latency,
+ int irq_line)
+{
+ uint32_t cmd;
+ int i;
+
+ device->min_grant = min_grant;
+ device->max_latency = max_latency;
+ device->irq_line = irq_line;
+ if (irq_line != -1) {
+ pci_config_writeb(bridge, device->bus, device->devfn,
+ 0x3c, device->irq_line);
+ printf("MAP PCI device %d:%d to IRQ %d\n",
+ device->bus, device->devfn, irq_line);
+ }
+ for (i = 0; i < 6; i++) {
+ if ((device->regions[i] & ~0xF) != 0x00000000 &&
+ (device->regions[i] & ~0xF) != 0xFFFFFFF0) {
+ printf("Map PCI device %d:%d %d to %0x %0x (%s)\n",
+ device->bus, device->devfn, i,
+ device->regions[i], device->sizes[i],
+ device->regions[i] & 0x00000001 ? "I/O" : "memory");
+ cmd = pci_config_readl(bridge, device->bus, device->devfn, 0x04);
+ if (device->regions[i] & 0x00000001)
+ cmd |= 0x00000001;
+ else
+ cmd |= 0x00000002;
+ pci_config_writel(bridge, device->bus, device->devfn, 0x04, cmd);
+ pci_config_writel(bridge, device->bus, device->devfn,
+ 0x10 + (i * sizeof(uint32_t)),
+ device->regions[i]);
+ }
+ }
+}
+
+static pci_host_t *pci_add_host (pci_host_t **hostp, pci_dev_t *device,
+ uint32_t class_code)
+{
+ pci_host_t *new, **lnk;
+
+ new = malloc(sizeof(pci_host_t));
+ if (new == NULL)
+ return NULL;
+ pci_fill_common(&new->dev.common, NULL, PCI_HOST_BRIDGE, device);
+ new->dev.class_code = class_code;
+ new->dev.rev = class_code;
+ for (lnk = hostp; *lnk != NULL; lnk = &((*lnk)->next))
+ continue;
+ *lnk = new;
+
+ return new;
+}
+
+static pci_bridge_t *pci_add_bridge (pci_host_t *host,
+ uint8_t bus, uint8_t devfn,
+ pci_dev_t *dev, uint32_t class_code,
+ uint32_t cfg_base, uint32_t cfg_len,
+ uint32_t cfg_addr, uint32_t cfg_data,
+ uint32_t mem_base, uint32_t mem_len,
+ uint32_t io_base, uint32_t io_len,
+ uint32_t rbase, uint32_t rlen,
+ uint32_t flags, const pci_ops_t *ops)
+{
+ pci_u_t *u;
+ pci_bridge_t *new, **lnk;
+
+ new = malloc(sizeof(pci_bridge_t));
+ if (new == NULL)
+ return NULL;
+ u = (pci_u_t *)host;
+ pci_fill_device(&new->dev, u, PCI_DEV_BRIDGE, bus, devfn, dev, class_code);
+ new->cfg_base = cfg_base;
+ new->cfg_len = cfg_len;
+ new->mem_base = mem_base;
+ new->mem_len = mem_len;
+ new->io_base = io_base;
+ new->io_len = io_len;
+ new->mem_cur = mem_base;
+ if (io_base != 0x00000000)
+ new->io_cur = io_base + 0x1000;
+ else
+ new->io_cur = 0x00000000;
+ new->cfg_addr = cfg_addr;
+ new->cfg_data = cfg_data;
+ new->rbase = rbase;
+ new->rlen = rlen;
+ new->flags = flags;
+ new->ops = ops;
+ for (lnk = &host->bridge; *lnk != NULL; lnk = &((*lnk)->next))
+ continue;
+ *lnk = new;
+
+ return new;
+}
+
+static pci_device_t *pci_add_device (pci_bridge_t *bridge,
+ uint8_t bus, uint8_t devfn,
+ pci_dev_t *dev, uint32_t class_code)
+{
+ pci_u_t *u;
+ pci_device_t *new, **lnk;
+
+ new = malloc(sizeof(pci_device_t));
+ if (new == NULL)
+ return NULL;
+ u = (pci_u_t *)bridge;
+ pci_fill_device(new, u, PCI_DEV_BRIDGE, bus, devfn, dev, class_code);
+ for (lnk = &bridge->devices; *lnk != NULL; lnk = &((*lnk)->next))
+ continue;
+ *lnk = new;
+
+ return new;
+}
+
+static pci_u_t *pci_check_device (pci_host_t **hostp, pci_host_t **phost,
+ uint8_t bus, uint8_t devfn,
+ uint16_t checkv, uint16_t checkp,
+ uint8_t cclass, uint8_t csubclass,
+ uint8_t ciface, int check_bridges)
+{
+ pci_u_t *ret;
+ pci_host_t *host, *newh;
+ pci_bridge_t *bridge, *newb;
+ pci_device_t *newd;
+ pci_dev_t *dev;
+ uint32_t *io_base, *mem_base, *base;
+ uint32_t ccode, addr, omask, amask, size, smask, reloc, min_align;
+ uint16_t vendor, product;
+ uint8_t class, subclass, iface, rev, min_grant, max_latency;
+ int i, max_areas, irq_line, irq_pin;
+
+ ret = NULL;
+ newd = NULL;
+ host = *hostp;
+ irq_line = -1;
+ bridge = host->bridge;
+ vendor = pci_config_readw(bridge, bus, devfn, 0x00);
+ product = pci_config_readw(bridge, bus, devfn, 0x02);
+ if (vendor == 0xFFFF && product == 0xFFFF) {
+ /* No device: do nothing */
+ goto out;
+ }
+ ccode = pci_config_readl(bridge, bus, devfn, 0x08);
+ class = ccode >> 24;
+ subclass = ccode >> 16;
+ iface = ccode >> 8;
+ rev = ccode;
+ if (checkv != 0xFFFF && vendor != checkv) {
+#if 0
+ printf("Mismatching vendor for dev %x %x: %x %x\n",
+ bus, devfn, checkv, vendor);
+#endif
+ goto out;
+ }
+ if (checkp != 0xFFFF && product != checkp) {
+#if 0
+ printf("Mismatching product for dev %x %x: %x %x\n",
+ bus, devfn, checkp, product);
+#endif
+ goto out;
+ }
+ if (cclass != 0xFF && class != cclass) {
+#if 0
+ printf("Mismatching class for dev %x %x: %x %x\n",
+ bus, devfn, cclass, class);
+#endif
+ goto out;
+ }
+ if (csubclass != 0xFF && subclass != csubclass) {
+#if 0
+ printf("Mismatching subclass for dev %x %x: %x %x\n",
+ bus, devfn, csubclass, subclass);
+#endif
+ goto out;
+ }
+ if (ciface != 0xFF && iface != ciface) {
+#if 0
+ printf("Mismatching iface for dev %x %x: %x %x\n",
+ bus, devfn, ciface, iface);
+#endif
+ goto out;
+ }
+ dev = pci_find_device(class, subclass, iface, vendor, product);
+ if (dev == NULL) {
+ goto out;
+ }
+ min_grant = pci_config_readb(bridge, bus, devfn, 0x3C);
+ max_latency = pci_config_readb(bridge, bus, devfn, 0x3D);
+ /* Special cases for bridges */
+ if (class == 0x06) {
+ if (check_bridges < 1)
+ goto out;
+ if (subclass == 0x00) {
+ if (check_bridges < 2)
+ goto out;
+ /* host bridge case */
+ printf("Found new host bridge '%s' '%s' '%s'...\n",
+ dev->type, dev->model, dev->compat);
+ newh = pci_add_host(phost, dev, ccode);
+ if (newh == NULL) {
+ printf("Can't allocate new host bridge...\n");
+ goto out;
+ }
+ ret = (pci_u_t *)newh;
+#if 0
+ if ((*hostp)->bridge->dev.common.type != PCI_FAKE_BRIDGE) {
+ printf("Keep PCI bridge\n");
+ /* If we already found a PCI bridge, keep it */
+ newh->bridge = (*phost)->bridge;
+ goto out;
+ }
+ printf("Add fake PCI bridge\n");
+ /* Add fake PCI bridge */
+ newh->bridge = NULL;
+ dev = dev->private;
+ newb = pci_add_bridge(host, bus, devfn, dev, ccode,
+ bridge->cfg_base, bridge->cfg_len,
+ bridge->cfg_addr, bridge->cfg_data,
+ bridge->mem_base, bridge->mem_len,
+ bridge->io_base, bridge->io_len,
+ bridge->rbase, bridge->rlen,
+ bridge->flags, dev->private);
+ if (newb == NULL) {
+ printf("Can't allocate new PCI bridge\n");
+ goto out;
+ }
+ newb->dev.common.type = PCI_FAKE_BRIDGE;
+ newb->devices = bridge->devices;
+#else
+ newh->bridge = (*hostp)->bridge;
+ newb = newh->bridge;
+#endif
+ newd = &bridge->dev;
+ host = newh;
+ host->dev.common.OF_private =
+ OF_register_pci_host(dev, rev, ccode,
+ bridge->cfg_base, bridge->cfg_len,
+ bridge->mem_base, bridge->mem_len,
+ bridge->io_base, bridge->io_len,
+ bridge->rbase, bridge->rlen,
+ min_grant, max_latency);
+ goto update_device;
+ } else if (subclass == 0x04) {
+ /* PCI-to-PCI bridge case */
+ printf("Found new PCI bridge '%s' '%s' '%s' '%s' %p...\n",
+ dev->name, dev->type, dev->model, dev->compat,
+ dev->private);
+ newb = pci_add_bridge(host, bus + 1, devfn, dev, ccode,
+ bridge->cfg_base, bridge->cfg_len,
+ bridge->cfg_addr, bridge->cfg_data,
+ bridge->mem_base, bridge->mem_len,
+ bridge->io_base, bridge->io_len,
+ bridge->rbase, bridge->rlen,
+ 0, dev->private);
+ if (newb == NULL) {
+ printf("Can't allocate new PCI bridge...\n");
+ goto out;
+ }
+ ret = (pci_u_t *)newb;
+#if 0
+ printf("Config addr: 0x%0x data: 0x%0x cfg_base: 0x%08x "
+ "base: 0x%0x\n",
+ newb->cfg_addr, newb->cfg_data, newb->cfg_base, newb->base);
+ printf("newb: %p hb: %p b: %p next: %p\n", newb,
+ host->bridge, bridge, host->bridge->next);
+#endif
+ if (bridge->dev.common.type == PCI_FAKE_BRIDGE) {
+ /* Free fake bridge if it's still present
+ * Note: it should always be first...
+ */
+ printf("Free fake bridge\n");
+ newb->devices = host->bridge->devices;
+ host->bridge = bridge->next;
+ }
+ bridge = host->bridge;
+ newd = &bridge->dev;
+#if 0
+ printf("newb: %p hb: %p b: %p next: %p dev: %p\n", newb,
+ host->bridge, bridge, host->bridge->next, newd);
+#endif
+ max_areas = 2;
+ bridge->dev.common.OF_private =
+ OF_register_pci_bridge(host->dev.common.OF_private,
+ dev, devfn, rev, ccode,
+ bridge->cfg_base, bridge->cfg_len,
+ min_grant, max_latency);
+ goto configure_device;
+ }
+ printf("Bridges type %x aren't managed for now\n", subclass);
+ free(dev);
+ goto out;
+ }
+ /* Main case */
+ printf("Found PCI device %x:%x %d-%d %d %d\n",
+ vendor, product, bus, devfn, class, subclass);
+ printf("=> '%s' '%s' '%s' '%s' (%p)\n",
+ dev->name, dev->type, dev->model, dev->compat, dev->config_cb);
+ newd = pci_add_device(bridge, bus, devfn, dev, ccode);
+ if (newd == NULL) {
+ printf("Cannot allocate new PCI device: %x %x (%x %x %x) '%s' '%s'\n",
+ vendor, product, class, subclass, iface, dev->type, dev->name);
+ goto out;
+ }
+ ret = (pci_u_t *)newd;
+ max_areas = 6;
+ /* register PCI device in OF tree */
+ if (bridge->dev.common.type == PCI_FAKE_BRIDGE) {
+ newd->common.OF_private =
+ OF_register_pci_device(host->dev.common.OF_private, dev, devfn,
+ rev, ccode, min_grant, max_latency);
+ } else {
+ newd->common.OF_private =
+ OF_register_pci_device(bridge->dev.common.OF_private, dev, devfn,
+ rev, ccode, min_grant, max_latency);
+ }
+ configure_device:
+#if 0
+ printf("Config addr: 0x%08x data: 0x%08x cfg_base: 0x%08x base: 0x%08x\n",
+ bridge->cfg_addr, bridge->cfg_data, bridge->cfg_base, bridge->base);
+ printf("ops: %p uni-ops: %p\n", bridge->ops, &uninorth_pci_ops);
+#endif
+ io_base = &bridge->io_cur;
+ mem_base = &bridge->mem_cur;
+ omask = 0x00000000;
+ for (i = 0; i < max_areas; i++) {
+ newd->regions[i] = 0x00000000;
+ newd->sizes[i] = 0x00000000;
+ if ((omask & 0x0000000F) == 0x4) {
+ /* Handle 64 bits memory mapping */
+ continue;
+ }
+ addr = 0x10 + (i * sizeof(uint32_t));
+ /* Get region size
+ * Note: we assume it's always a power of 2
+ */
+ pci_config_writel(bridge, bus, devfn, addr, 0xFFFFFFFF);
+ smask = pci_config_readl(bridge, bus, devfn, addr);
+ if (smask == 0x00000000 || smask == 0xFFFFFFFF)
+ continue;
+ if (smask & 0x00000001) {
+ /* I/O space */
+ base = io_base;
+ /* Align to a minimum of 256 bytes (arbitrary) */
+ min_align = 1 << 8;
+ amask = 0x00000001;
+ } else {
+ /* Memory space */
+ base = mem_base;
+ /* Align to a minimum of 64 kB (arbitrary) */
+ min_align = 1 << 16;
+ amask = 0x0000000F;
+ }
+ omask = smask & amask;
+ smask &= ~amask;
+ size = (~smask) + 1;
+ reloc = *base;
+#if 0
+ printf("Relocate %s area %d of size %0x to 0x%0x (0x%0x 0x%0x %0x)\n",
+ omask & 0x00000001 ? "I/O" : "memory", i,
+ size, reloc, reloc + size, smask);
+#endif
+ if (size < min_align) {
+ size = min_align;
+ }
+ /* Align reloc to size */
+ reloc = (reloc + size - 1) & ~(size - 1);
+ (*base) = reloc + size;
+ if (omask & 0x00000001) {
+ /* I/O resources are offsets */
+ reloc -= bridge->io_base;
+ }
+ /* Set region address */
+ newd->regions[i] = reloc | omask;
+ newd->sizes[i] = size;
+ }
+ /* Realign io-base to 4 kB */
+ bridge->io_base = (bridge->io_base + (1 << 12) - 1) & ~((1 << 12) - 1);
+ /* Realign mem-base to 1 MB */
+ bridge->mem_base = (bridge->mem_base + (1 << 20) - 1) & ~((1 << 20) - 1);
+
+ irq_pin = pci_config_readb(bridge, bus, devfn, 0x3d);
+ if (irq_pin > 0) {
+ /* assign the IRQ */
+ irq_pin = ((devfn >> 3) + irq_pin - 1) & 3;
+ if (arch == ARCH_PREP) {
+ int elcr_port, val;
+ irq_line = prep_pci_irqs[irq_pin];
+ /* set the IRQ to level-sensitive */
+ elcr_port = 0x4d0 + (irq_line >> 8);
+ val = inb(elcr_port);
+ val |= 1 << (irq_line & 7);
+ outb(elcr_port, val);
+ } else {
+ irq_line = pmac_pci_irqs[irq_pin];
+ }
+ }
+ update_device:
+ pci_update_device(bridge, newd, min_grant, max_latency, irq_line);
+ OF_finalize_pci_device(newd->common.OF_private, bus, devfn,
+ newd->regions, newd->sizes);
+ /* Call special inits if needed */
+ if (dev->config_cb != NULL)
+ (*dev->config_cb)(newd);
+
+ out:
+ return ret;
+}
+
+static int pci_check_host (pci_host_t **hostp,
+ uint32_t cfg_base, uint32_t cfg_len,
+ uint32_t mem_base, uint32_t mem_len,
+ uint32_t io_base, uint32_t io_len,
+ uint32_t rbase, uint32_t rlen,
+ uint16_t checkv, uint16_t checkp)
+{
+ pci_host_t *fake_host, *host, **phost;
+ pci_bridge_t *fake_bridge;
+ pci_dev_t *dev;
+ int bus, devfn;
+ int ret;
+
+ fake_host = NULL;
+ ret = -1;
+ switch (arch) {
+ case ARCH_PREP:
+ dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp);
+ if (dev == NULL)
+ return -1;
+ fake_host = pci_add_host(hostp, dev,
+ (0x06 << 24) | (0x00 << 16) | (0xFF << 8));
+ if (fake_host == NULL)
+ return -1;
+ fake_host->dev.common.type = PCI_FAKE_HOST;
+ dev = &PREP_fake_bridge;
+ if (dev == NULL)
+ goto free_fake_host;
+ fake_bridge = pci_add_bridge(fake_host, 0, 11, dev,
+ (0x06 << 24) | (0x00 << 16) | (0xFF << 8),
+ cfg_base, cfg_len,
+ cfg_base + 0x00800000,
+ cfg_base + 0x00C00000,
+ mem_base, mem_len,
+ io_base, io_len,
+ rbase, rlen,
+ 0,
+ &PREP_pci_ops);
+ if (fake_bridge == NULL)
+ goto free_fake_host;
+ fake_bridge->dev.common.type = PCI_FAKE_BRIDGE;
+ break;
+ case ARCH_CHRP:
+ /* TODO */
+ break;
+ case ARCH_MAC99:
+ dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp);
+ if (dev == NULL)
+ return -1;
+ fake_host = pci_add_host(hostp, dev,
+ (0x06 << 24) | (0x00 << 16) | (0xFF << 8));
+ if (fake_host == NULL)
+ return -1;
+ fake_host->dev.common.type = PCI_FAKE_HOST;
+ dev = &uninorth_fake_bridge;
+ if (dev == NULL)
+ goto free_fake_host;
+ fake_bridge = pci_add_bridge(fake_host, 0, 11, dev,
+ (0x06 << 24) | (0x00 << 16) | (0xFF << 8),
+ cfg_base, cfg_len,
+ cfg_base + 0x00800000,
+ cfg_base + 0x00C00000,
+ mem_base, mem_len,
+ io_base, io_len,
+ rbase, rlen,
+ BRIDGE_TYPE_UNINORTH,
+ &uninorth_pci_ops);
+ if (fake_bridge == NULL)
+ goto free_fake_host;
+ fake_bridge->dev.common.type = PCI_FAKE_BRIDGE;
+ fake_bridge->flags |= BRIDGE_TYPE_UNINORTH;
+ break;
+ case ARCH_POP:
+ /* TODO */
+ break;
+ }
+ host = NULL;
+ phost = &host;
+ for (bus = 0; bus < 256; bus++) {
+ for (devfn = 0; devfn < 256; devfn++) {
+ /* Find host bridge */
+ pci_check_device(hostp, phost, bus, devfn,
+ checkv, checkp, 0x06, 0x00, 0xFF, 2);
+ if (host != NULL) {
+ *hostp = host;
+ OF_finalize_pci_host(host->dev.common.OF_private, bus, 1);
+ ret = 0;
+ goto done;
+ }
+ }
+ }
+ done:
+ free(fake_host->bridge);
+ free_fake_host:
+ free(fake_host);
+
+ return ret;
+}
+
+static int pci_check_devices (pci_host_t *host)
+{
+ int bus, devfn;
+
+ /* Find all PCI bridges */
+ printf("Check PCI bridges\n");
+ for (bus = 0; bus < 256; bus++) {
+ for (devfn = 0; devfn < 256; devfn++) {
+ pci_check_device(&host, &host, bus, devfn, 0xFFFF, 0xFFFF,
+ 0x06, 0xFF, 0xFF, 1);
+ }
+ }
+ /* Now, find all other devices */
+ /* XXX: should recurse thru all host and bridges ! */
+ printf("Check PCI devices\n");
+ for (bus = 0; bus < 256; bus++) {
+ for (devfn = 0; devfn < 256; devfn++) {
+ pci_check_device(&host, &host, bus, devfn, 0xFFFF, 0xFFFF,
+ 0xFF, 0xFF, 0xFF, 0);
+ }
+ }
+
+ return 0;
+}
+
+pci_host_t *pci_init (void)
+{
+ pci_host_t *pci_main = NULL, *curh;
+ uint32_t rbase, rlen, cfg_base, cfg_len;
+ uint32_t mem_base, mem_len, io_base, io_len;
+ uint8_t busnum;
+
+ printf("Probing PCI devices\n");
+ /* We need to discover PCI bridges and devices */
+ switch (arch) {
+ case ARCH_PREP:
+ /* supposed to have 1 host bridge:
+ * - the Motorola Raven PCI bridge
+ */
+ cfg_base = 0x80000000;
+ cfg_len = 0x00100000;
+ mem_base = 0xF0000000;
+ mem_len = 0x10000000;
+ io_base = 0x80000000;
+ io_len = 0x00010000;
+#if 0
+ rbase = 0x80C00000; /* ? */
+#else
+ rbase = 0x00000000;
+#endif
+ rlen = 0x00400000; /* ? */
+ if (pci_check_host(&pci_main, cfg_base, cfg_len,
+ mem_base, mem_len, io_base, io_len, rbase, rlen,
+ 0x1057, 0x4801) == 0) {
+ isa_io_base = io_base;
+ busnum++;
+ }
+ for (curh = pci_main; curh->next != NULL; curh = curh->next)
+ continue;
+ pci_check_devices(curh);
+ break;
+ case ARCH_CHRP:
+ /* TODO */
+ break;
+ case ARCH_MAC99:
+ /* We are supposed to have 3 host bridges:
+ * - the uninorth AGP bridge at 0xF0000000
+ * - the uninorth PCI expansion bridge at 0xF2000000
+ * - the uninorth PCI internal bridge at 0xF4000000
+ */
+ cfg_base = 0xF0000000;
+ cfg_len = 0x02000000;
+ mem_base = 0x90000000;
+ mem_len = 0x10000000;
+ io_base = 0xF0000000;
+ io_len = 0x00800000;
+ rbase = 0xF1000000;
+ rlen = 0x01000000;
+#if 0
+ if (pci_check_host(&pci_main, cfg_base, cfg_len,
+ mem_base, mem_len, io_base, io_len, rbase, rlen,
+ 0x106b, 0x0020) == 0) {
+ busnum++;
+ }
+ for (curh = pci_main; curh->next != NULL; curh = curh->next)
+ continue;
+ pci_check_devices(curh);
+#endif
+
+ cfg_base = 0xF2000000;
+ cfg_len = 0x02000000;
+ mem_base = 0x80000000;
+ mem_len = 0x10000000;
+ io_base = 0xF2000000;
+ io_len = 0x00800000;
+#if 0 // Hack
+ rbase = 0xF3000000;
+ rlen = 0x01000000;
+#else
+ rbase = 0x00000000;
+ rlen = 0x01000000;
+#endif
+ if (pci_check_host(&pci_main, cfg_base, cfg_len,
+ mem_base, mem_len, io_base, io_len, rbase, rlen,
+ 0x106b, 0x001F) == 0) {
+ isa_io_base = io_base;
+ busnum++;
+ }
+ for (curh = pci_main; curh->next != NULL; curh = curh->next)
+ continue;
+ pci_check_devices(curh);
+
+#if 0
+ cfg_base = 0xF4000000;
+ cfg_len = 0x02000000;
+ mem_base = 0xA0000000;
+ mem_len = 0x10000000;
+ io_base = 0xF4000000;
+ io_len = 0x00800000;
+ rbase = 0xF5000000;
+ rlen = 0x01000000;
+ if (pci_check_host(&pci_main, cfg_base, cfg_len,
+ mem_base, mem_len, io_base, io_len, rbase, rlen,
+ 0x106b, 0x001F) == 0) {
+ busnum++;
+ }
+ for (curh = pci_main; curh->next != NULL; curh = curh->next)
+ continue;
+ pci_check_devices(curh);
+#endif
+ break;
+ case ARCH_POP:
+ /* TODO */
+ break;
+ }
+ printf("PCI probe done (%p)\n", pci_main);
+
+ return pci_main;
+}
+
+void pci_get_mem_range (pci_host_t *host, uint32_t *start, uint32_t *len)
+{
+ *start = host->bridge->mem_base;
+ *len = host->bridge->mem_len;
+}
diff --git a/src/start.S b/src/start.S
new file mode 100644
index 0000000..471e56f
--- /dev/null
+++ b/src/start.S
@@ -0,0 +1,379 @@
+/*
+ * <start.S>
+ *
+ * BIOS start code for Open Hack'Ware.
+ *
+ * Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#define ASSEMBLY_CODE
+#include "bios.h"
+
+.section .start, "ax"
+.align 2
+
+.globl _start
+_start:
+ /* Save our stack pointer */
+ lis r11, saved_params@h ;
+ ori r11, r11, saved_params@l ;
+ stw r1, 0(r11) ;
+ /* Fill space from _bss_start to _ram_start with zeroes */
+ lis r11, _bss_start@h ;
+ ori r11, r11, _bss_start@l ;
+ lis r12, _ram_start@h ;
+ ori r12, r12, _ram_start@l ;
+ subf r12, r11, r12 ;
+ srawi r12, r12, 2 ;
+ cmpi 0, r12, 0 ;
+ beq _bss_done ;
+ mtctr r12 ;
+ subi r11, r11, 4 ;
+ li r12, 0 ;
+_bss_loop:
+ stwu r12, 4(r11) ;
+ bdnz _bss_loop ;
+_bss_done:
+ /* Now, we have a real C environment: call main */
+ bl main ;
+ /* If we return, stop */
+.globl bug
+bug:
+ li r0, 0x80 ;
+ mtlr r0 ;
+ blr ;
+_return_loop:
+ b _return_loop ;
+
+.section .data
+.align 2
+saved_params:
+ .long 0x00000000 /* OF stack */
+ .long 0x00000000 /* client stack */
+ .long 0x00000000 /* client link */
+
+.section .text
+.align 2
+
+.globl transfer_handler
+transfer_handler:
+ /* Build a new stack room and launch loaded image
+ * void transfer_handler (void *residual, void *load_addr,
+ * void *OF_entry, void *bootinfos,
+ * void *cmdline, void *unused,
+ * void *nip, void *stack_base);
+ */
+ mfmsr r0 ;
+ mtspr SRR1, r0 ;
+ mtspr SRR0, r9 ;
+ li r0, 0 ;
+ mr r1, r10 ;
+ stw r1, -16(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ /* Skip frame pointer */
+ stwu r0, -8(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ rfi ;
+ /* Should never return, but who knows... */
+ bl bug ;
+
+.globl OF_entry
+OF_entry:
+ /* Save the stack pointer and get our own one */
+ lis r11, saved_params@h ;
+ ori r11, r11, saved_params@l ;
+ mflr r12 ;
+ stw r12, 8(r11) ;
+ stw r1, 4(r11) ;
+ lwz r1, 0(r11) ;
+ bl OF_client_entry ;
+ lis r11, saved_params@h ;
+ ori r11, r11, saved_params@l ;
+ lwz r12, 8(r11) ;
+ mtlr r12 ;
+ lwz r1, 4(r11) ;
+ blr ;
+
+ /* PPC helpers */
+.globl mfmsr
+mfmsr:
+ /* uint32_t mfmsr (void); */
+ mfmsr r3 ;
+ blr ;
+.globl mtmsr
+mtmsr:
+ /* void mtmsr (uint32_t msr); */
+ lis r0, _mtmsr_rfi@h ;
+ ori r0, r0, _mtmsr_rfi@l ;
+ mtspr 26, r0 ;
+ mtspr 27, r3 ;
+ rfi ;
+_mtmsr_rfi:
+ blr ;
+.globl MMU_on
+MMU_on:
+ /* void MMU_on (void); */
+ stwu r1, -16(r1) ;
+ mflr r0 ;
+ stw r0, 20(r1) ;
+ mfmsr r3 ;
+ ori r3, r3, 0x30 ;
+ bl mtmsr ;
+ lwz r0, 20(r1) ;
+ mtlr r0 ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl MMU_off
+MMU_off:
+ /* void MMU_off (void); */
+ stwu r1, -16(r1) ;
+ mflr r0 ;
+ stw r0, 20(r1) ;
+ mfmsr r3 ;
+ andi. r3, r3, 0xFFCF ;
+ bl mtmsr ;
+ lwz r0, 20(r1) ;
+ mtlr r0 ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl mfpvr
+mfpvr:
+ /* uint32_t mfpvr (void); */
+ mfpvr r3 ;
+ blr ;
+
+.globl mftb
+mftb:
+ /* void mftb (uint32_t *tb); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ stw r12, 8(r1) ;
+ /* No need to save lr */
+_tb_loop:
+ mftbu r11 ;
+ mftb r12 ;
+ mftbu r0 ;
+ cmpw r0, r11 ;
+ bne _tb_loop ;
+ stw r11, 0(r3) ;
+ stw r12, 4(r3) ;
+ lwz r12, 8(r1) ;
+ lwz r11, 12(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+ /* IO helpers */
+.globl inb
+inb:
+ /* uint32_t inb (uint16_t port); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ lis r11, isa_io_base@h ;
+ ori r11, r11, isa_io_base@l ;
+ lwz r11, 0(r11) ;
+ add r3, r3, r11 ;
+ lbz r3, 0(r3) ;
+ eieio ;
+ lwz r11, 12(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl outb
+outb:
+ /* void outb (uint16_t port, uint32_t val); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ lis r11, isa_io_base@h ;
+ ori r11, r11, isa_io_base@l ;
+ lwz r11, 0(r11) ;
+ add r3, r3, r11 ;
+ eieio ;
+ stb r4, 0(r3) ;
+ lwz r11, 12(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl inw
+inw:
+ /* uint32_t inw (uint16_t port); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ lis r11, isa_io_base@h ;
+ ori r11, r11, isa_io_base@l ;
+ lwz r11, 0(r11) ;
+ add r3, r3, r11 ;
+ lhbrx r3, 0, r3 ;
+ eieio ;
+ lwz r11, 12(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl outw
+outw:
+ /* void outw (uint16_t port, uint32_t val); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ lis r11, isa_io_base@h ;
+ ori r11, r11, isa_io_base@l ;
+ lwz r11, 0(r11) ;
+ add r3, r3, r11 ;
+ eieio ;
+ sthbrx r4, 0, r3 ;
+ lwz r11, 12(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl inl
+inl:
+ /* uint32_t inl (uint16_t port); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ lis r11, isa_io_base@h ;
+ ori r11, r11, isa_io_base@l ;
+ lwz r11, 0(r11) ;
+ add r3, r3, r11 ;
+ lwbrx r3, 0, r3 ;
+ eieio ;
+ lwz r11, 12(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl outl
+outl:
+ /* void outl (uint16_t port, uint32_t val); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ lis r11, isa_io_base@h ;
+ ori r11, r11, isa_io_base@l ;
+ lwz r11, 0(r11) ;
+ add r3, r3, r11 ;
+ eieio ;
+ stwbrx r4, 0, r3 ;
+ lwz r11, 12(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl eieio
+eieio:
+ eieio ;
+ blr ;
+
+ /* Misc helpers */
+.globl ldswap16
+ldswap16:
+ /* uint16_t ldswap16 (uint16_t *addr); */
+ lhbrx r3, 0, r3 ;
+ blr ;
+
+.globl stswap16
+stswap16:
+ /* void stswap16 (void *addr, uint16_t val); */
+ sthbrx r4, 0, r3 ;
+ blr ;
+
+.globl ldswap32
+ldswap32:
+ /* uint32_t ldswap32 (uint32_t *addr); */
+ lwbrx r3, 0, r3 ;
+ blr ;
+
+.globl stswap32
+stswap32:
+ /* void stswap32 (void *addr, uint32_t val); */
+ stwbrx r4, 0, r3 ;
+ blr ;
+
+.globl mul64
+mul64:
+ /* void mul64 (uint32_t *ret, uint32_t a, uint32_t b); */
+ mulhwu r0, r4, r5 ;
+ stw r0, 0(r3) ;
+ mullw r0, r4, r5 ;
+ stw r0, 4(r3) ;
+ blr ;
+
+.globl add64
+add64:
+ /* void add64 (uint32_t *ret, uint32_t *a, uint32_t *b); */
+ stwu r1, -16(r1) ;
+ stw r11, 12(r1) ;
+ stw r12, 8(r1) ;
+ lwz r11, 4(r4) ;
+ lwz r12, 4(r5) ;
+ addc r0, r11, r12 ;
+ stw r0, 4(r3) ;
+ lwz r11, 0(r4) ;
+ lwz r12, 0(r5) ;
+ adde r0, r11, r12 ;
+ stw r0, 0(r3) ;
+ lwz r12, 8(r1) ;
+ lwz r11, 4(r1) ;
+ addi r1, r1, 16 ;
+ blr ;
+
+.globl setjmp
+setjmp:
+ /* int setjmp (jmp_buf env); */
+ /* save gprs */
+ stmw r0, 0(r3) ;
+ /* save lr, ctr, xer and ccr */
+ mflr r0 ;
+ stw r0, 0x80(r3) ;
+ mfctr r0 ;
+ stw r0, 0x84(r3) ;
+ mfxer r0 ;
+ stw r0, 0x88(r3) ;
+ mfcr r0 ;
+ stw r0, 0x8C(r3) ;
+ /* return 0 */
+ li r3, 0 ;
+ blr ;
+
+.globl longjmp
+longjmp:
+ /* void longjmp (jmp_buf env, int val); */
+ /* Let's pretend env is our stack */
+ mr r1, r3 ;
+ /* Be sure we won't return 0 */
+ cmpi 0, r4, 0 ;
+ bne _longjmp_cont ;
+ addi r4, r4, 1 ;
+_longjmp_cont:
+ /* Store return value in jmp_buf */
+ stw r4, 0x0C(r1) ;
+ /* restore lr, ctr, xer and ccr */
+ lwz r0, 0x80(r1) ;
+ mtlr r0 ;
+ lwz r0, 0x84(r1) ;
+ mtctr r0 ;
+ lwz r0, 0x88(r1) ;
+ mtxer r0 ;
+ lwz r0, 0x8C(r1) ;
+ mtcr r0 ;
+ /* Restore r2 to r31 */
+ lmw r2, 0x08(r1) ;
+ /* Restore r0 (could forget it...) */
+ lwz r0, 0x00(r1) ;
+ /* Restore stack */
+ lwz r1, 0x04(r1) ;
+ /* Return */
+ blr ;
diff --git a/src/vectors.S b/src/vectors.S
new file mode 100644
index 0000000..691d568
--- /dev/null
+++ b/src/vectors.S
@@ -0,0 +1,466 @@
+/*
+ * <vectors.S>
+ *
+ * Second stage boot-loader and exception vectors for Open Hack'Ware.
+ *
+ * Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#define ASSEMBLY_CODE
+#include "bios.h"
+
+.section .text
+.align 2
+
+.globl _start
+_start:
+ /* Entry point */
+ li r0, 0 ;
+_turn_off_mmu:
+ /* Be sure MMU is off and we are in 32 bits mode (for PPC64) */
+ lis r11, _hw_init@h ;
+ ori r11, r11, _hw_init@l ;
+ mtspr 26, r11 ;
+ mtspr 27, r0 ;
+ rfi ;
+_hw_init:
+ /* May need more hw init here */
+_load_bios:
+ /* Load the full BIOS into RAM */
+ lis r12, bios_base@h ;
+ ori r12, r12, bios_base@l ;
+ lmw r29, 0(r12) ;
+ /* Set up the C stack */
+ addis r1, r29, 0x0040 ;
+ clrrwi r1, r1, 19 ;
+ stw r1, -16(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ /* Skip frame pointer */
+ stwu r0, -8(r1) ;
+ stwu r0, -4(r1) ;
+ stwu r0, -4(r1) ;
+ /* Start copying */
+ mtctr r30 ;
+ subi r12, r3, 4 ;
+ subi r13, r29, 4 ;
+_bios_copy_loop:
+ lwzu r14, 4(r12) ;
+ stwu r14, 4(r13) ;
+ bdnz _bios_copy_loop ;
+ /* Synchronize the whole execution context */
+ /* Also enable FPU */
+ ori r0, r0, (1 << 13) ;
+ mtspr 26, r29 ;
+ mtspr 27, r0 ;
+ rfi ;
+ /* If we ever return, stop */
+ bl bug ;
+
+.org 0x0080
+.section .text
+.align 2
+bug:
+ /* Dump the exception and its context */
+ mflr r3 ;
+ mfspr r4, SRR0 ;
+ mfspr r5, SRR1 ;
+ mfspr r6, DAR ;
+ mfspr r7, DSISR ;
+ /* Turn MMU off */
+ lis r0, _bug_no_mmu@h ;
+ ori r0, r0, _bug_no_mmu@l ;
+ mtspr 26, r0 ;
+ li r0, 0 ;
+ mtspr 27, r0 ;
+ rfi ;
+_bug_no_mmu:
+ bl dump_exception ;
+_forever:
+ /* Loop forever */
+ b _forever ;
+
+skip_exception:
+ /* Skip external interrupts and decrementer exception */
+ /* BEWARE: be sure not to modify any register */
+ stw r11, save_area@l(0) ;
+ mfspr r11, 27 ;
+ clrlwi r11, r11, 16 ;
+ mtspr 27, r11 ;
+ lwz r11, save_area@l(0) ;
+ rfi ;
+
+#define EXCP_BUG(entry) \
+.org 0x##entry ; \
+.section .text ; \
+.align 2 ; \
+excp_##entry: ; \
+ bl bug
+
+#define EXCP_SKIP(entry) \
+.org 0x##entry ; \
+.section .text ; \
+.align 2 ; \
+excp_##entry##: ; \
+ b skip_exception
+
+ /* Exception vectors */
+ /* Reset exception */
+ EXCP_BUG(0100) ;
+
+ /* Machine check exception */
+ EXCP_BUG(0200) ;
+
+ /* DSI exception */
+ EXCP_BUG(0300) ;
+
+ /* ISI exception */
+ EXCP_BUG(0400) ;
+
+ /* External interrupt: skip it */
+ EXCP_SKIP(0500) ;
+
+ /* Alignment exception */
+ EXCP_BUG(0600) ;
+
+ /* Program exception */
+ EXCP_BUG(0700) ;
+
+ /* No floating point exception */
+ EXCP_BUG(0800) ;
+
+ /* Decrementer exception: skip it */
+ EXCP_SKIP(0900) ;
+
+ /* Reserved A exception */
+ EXCP_BUG(0A00) ;
+
+ /* Reserved B exception */
+ EXCP_BUG(0B00) ;
+
+ /* System call exception */
+ EXCP_BUG(0C00) ;
+
+ /* Trace exception */
+ EXCP_BUG(0D00) ;
+
+ /* Floating point assist exception */
+ EXCP_BUG(0E00) ;
+
+ /* Performance monitor exception */
+ EXCP_BUG(0F00) ;
+
+ /* Instruction TLB miss exception */
+ EXCP_BUG(1000) ;
+
+ /* Data TLB miss for store exception */
+ EXCP_BUG(1100) ;
+
+ /* Data TLB miss for load exception */
+ EXCP_BUG(1200) ;
+
+ /* Instruction address breakpoint exception */
+ EXCP_BUG(1300) ;
+
+ /* System management interrupt exception */
+ EXCP_BUG(1400) ;
+
+ /* Thermal management exception */
+ EXCP_BUG(1500) ;
+
+ /* Unknown exceptions */
+ EXCP_BUG(1600) ;
+
+ EXCP_BUG(1700) ;
+
+ EXCP_BUG(1800) ;
+
+ EXCP_BUG(1900) ;
+
+ EXCP_BUG(1A00) ;
+
+ EXCP_BUG(1B00) ;
+
+ EXCP_BUG(1C00) ;
+
+ EXCP_BUG(1D00) ;
+
+ EXCP_BUG(1E00) ;
+
+ EXCP_BUG(1F00) ;
+ /* End of exception vectors list */
+
+.org 0x2000
+.section .text
+.align 2
+helpers_start:
+
+outb:
+ /* void outb (uint32_t port, uint32_t data);
+ * Writes a single character on an IO port.
+ * Used for serial console.
+ */
+ stb r4, 0(r3) ;
+ eieio ;
+ blr ;
+
+outstr:
+ /* void outstr (uint32_t port, const unsigned char *str);
+ * Writes a string on an IO port.
+ */
+ mflr r20 ;
+ subi r11, r4, 1 ;
+
+_outstr_next:
+ lbzu r4, 1(r11) ;
+ cmpi 0, r4, 0 ;
+ beq _outstr_done ;
+ bl outb ;
+ b _outstr_next ;
+_outstr_done:
+ mtlr r20 ;
+ blr ;
+
+outdigit:
+ /* void outdigit (uint32_t port, uint32_t digit);
+ * Dumps a single digit on serial port.
+ */
+ mflr r20 ;
+ addi r4, r4, '0' ;
+ bl outb ;
+ mtlr r20 ;
+ blr ;
+
+outhex:
+ /* void outhex (uint32_t port, uint32_t value);
+ * Dumps a 32 bits hex number on serial port
+ */
+ mflr r21
+ li r11, 8 ;
+ mtctr r11 ;
+ mr r11, r4 ;
+_outhex_next:
+ rlwinm r11, r11, 4, 0, 31 ;
+ clrlwi r4, r11, 28 ;
+ cmpi 0, r4, 9 ;
+ bgt _outhex_xdigit ;
+ bl outdigit ;
+ bdnz _outhex_next ;
+ b _outhex_done ;
+_outhex_xdigit:
+ addi r4, r4, 'a' - 10 ;
+ bl outb ;
+ bdnz _outhex_next ;
+_outhex_done:
+ mtlr r21 ;
+ blr ;
+
+ /* void dump_exception (uint32_t lr, uint32_t srr0, uint32_t srr1,
+ * uint32_t dar, uint32_t dsisr);
+ * Dump a message when catching an exception
+ */
+dump_exception:
+ /* Save call parameters */
+ mflr r19 ;
+ mr r22, r3 ;
+ mr r23, r4 ;
+ mr r24, r5 ;
+ mr r25, r6 ;
+ mr r26, r7 ;
+ lis r11, registers_area@h ;
+ ori r11, r11, registers_area@l ;
+ lmw r27, 0(r11) ;
+ /* Now, serial IO port is in r27,
+ * message table start is in r28,
+ * first exception message offset is in r29,
+ * and last known exception number is in r30
+ */
+ /* Print error prompt message */
+ mr r3, r27 ;
+ lwzu r4, 4(r28) ;
+ bl outstr ;
+ /* Find message corresponding to the caught exception */
+ srwi r12, r22, 8 ;
+ cmp 0, r12, r30 ;
+ ble _dump_excp_msg ;
+ subi r12, r30, 1 ;
+_dump_excp_msg:
+ rlwinm r12, r12, 2, 0, 31 ;
+ /* Dump execption message */
+ mr r3, r27 ;
+ lwzx r4, r12, r29 ;
+ bl outstr ;
+ /* Complete exception message */
+ mr r3, r27 ;
+ lwzu r4, 4(r28) ;
+ bl outstr ;
+ /* Dump nip */
+ mr r3, r27 ;
+ lwzu r4, 4(r28) ;
+ bl outstr ;
+ mr r3, r27 ;
+ mr r4, r23 ;
+ bl outhex ;
+ /* dump msr */
+ mr r3, r27 ;
+ lwzu r4, 4(r28) ;
+ bl outstr ;
+ mr r3, r27 ;
+ mr r4, r24 ;
+ bl outhex ;
+ /* dump dar */
+ mr r3, r27 ;
+ lwzu r4, 4(r28) ;
+ bl outstr ;
+ mr r3, r27 ;
+ mr r4, r25 ;
+ bl outhex ;
+ /* dump dsisr */
+ mr r3, r27 ;
+ lwzu r4, 4(r28) ;
+ bl outstr ;
+ mr r3, r27 ;
+ mr r4, r26 ;
+ bl outhex ;
+ /* All done, dump last message and return */
+ mr r3, r27 ;
+ lwzu r4, 4(r28) ;
+ bl outstr ;
+ mtlr r19 ;
+ blr ;
+
+.section .rodata
+.align 2
+_BUG_message_0:
+ .string "ERROR: BUG caught...\n"
+_BUG_message_1:
+ .string " exception"
+_BUG_message_2:
+ .string "\nnip=0x"
+_BUG_message_3:
+ .string " msr=0x"
+_BUG_message_4:
+ .string " dar=0x"
+_BUG_message_5:
+ .string " dsisr=0x"
+_BUG_message_6:
+ .string "\nStopping execution\n"
+
+_excp_message_0x00:
+ .string "BIOS execution"
+_excp_message_0x01:
+ .string "Reset"
+_excp_message_0x02:
+ .string "Machine check"
+_excp_message_0x03:
+ .string "Data memory access"
+_excp_message_0x04:
+ .string "Instruction fetch"
+_excp_message_0x05:
+ .string "External"
+_excp_message_0x06:
+ .string "Alignment"
+_excp_message_0x07:
+ .string "Program"
+_excp_message_0x08:
+ .string "No floating point"
+_excp_message_0x09:
+ .string "Decrementer"
+_excp_message_0x0a:
+ .string "Reserved A"
+_excp_message_0x0b:
+ .string "Reserved B"
+_excp_message_0x0c:
+ .string "System call"
+_excp_message_0x0d:
+ .string "Trace"
+_excp_message_0x0e:
+ .string "Floating point assist"
+_excp_message_0x0f:
+ .string "Performance monitor"
+_excp_message_0x10:
+ .string "Instruction TLB miss"
+_excp_message_0x11:
+ .string "Data TLB miss for store"
+_excp_message_0x12:
+ .string "Data TLB miss for load"
+_excp_message_0x13:
+ .string "Instruction address breakpoint"
+_excp_message_0x14:
+ .string "System management"
+_excp_message_0x15:
+ .string "Thermal management"
+_excp_message_0x16:
+ .string "Unknown"
+_messages_table:
+ .long _BUG_message_0
+ .long _BUG_message_1
+ .long _BUG_message_2
+ .long _BUG_message_3
+ .long _BUG_message_4
+ .long _BUG_message_5
+ .long _BUG_message_6
+_excp_messages_table:
+ .long _excp_message_0x00
+ .long _excp_message_0x01
+ .long _excp_message_0x02
+ .long _excp_message_0x03
+ .long _excp_message_0x04
+ .long _excp_message_0x05
+ .long _excp_message_0x06
+ .long _excp_message_0x07
+ .long _excp_message_0x08
+ .long _excp_message_0x09
+ .long _excp_message_0x0a
+ .long _excp_message_0x0b
+ .long _excp_message_0x0c
+ .long _excp_message_0x0d
+ .long _excp_message_0x0e
+ .long _excp_message_0x0f
+ .long _excp_message_0x10
+ .long _excp_message_0x11
+ .long _excp_message_0x12
+ .long _excp_message_0x13
+ .long _excp_message_0x14
+ .long _excp_message_0x15
+ .long _excp_message_0x16
+_last_excp_message:
+
+bios_base:
+ .long BIOS_BASE
+bios_size:
+ .long BIOS_SIZE / 4
+_dummy_0:
+ .long 0x00000000
+
+registers_area: /* To be loaded in register when an exception is caught */
+_serial_IO: /* r27 */
+ .long 0x800003F8
+_messages_start: /* r28 */
+ .long _messages_table - 4
+_excp_messages: /* r29 */
+ .long _excp_messages_table
+_max_excp: /* r30 */
+ .long (_last_excp_message - _excp_messages_table) / 4
+_dummy_1: /* r31: dummy */
+ .long 0x00000000
+
+.section .data
+.align 2
+save_area: /* Area for r11 save when an exception is skipped */
+ .long 0x00000000
diff --git a/src/vectors.ld b/src/vectors.ld
new file mode 100644
index 0000000..f003109
--- /dev/null
+++ b/src/vectors.ld
@@ -0,0 +1,45 @@
+/*
+ * <vectors.ld>
+ *
+ * Second stage boot-loader and exception vectors for Open Hack'Ware
+ * linker script
+ *
+ * Copyright (C) 2004-2005 Jocelyn Mayer (l_indien@magic.fr)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+OUTPUT_ARCH(powerpc)
+
+MEMORY
+{
+ text (rx) : ORIGIN = 0x00000000, LENGTH = 0x3000
+ rodata (r) : ORIGIN = 0x00003000, LENGTH = 0x0C00
+ data (rw) : ORIGIN = 0x00003C00, LENGTH = 0x0200
+}
+
+SECTIONS
+{
+ .text : { *(.text) } > text
+ .rodata : { *(.rodata) } > rodata
+ .data : { *(.data) } > data
+ /DISCARD/ : { *(.bss) }
+ /DISCARD/ : { *(.sbss) }
+ /DISCARD/ : { *(.sdata) }
+ /DISCARD/ : { *(.sdata2) }
+ /DISCARD/ : { *(.stab) }
+ /DISCARD/ : { *(.stabstr) }
+ /DISCARD/ : { *(.comment) }
+ /DISCARD/ : { *(.note) }
+}
diff --git a/src/vga.c b/src/vga.c
new file mode 100644
index 0000000..d671bea
--- /dev/null
+++ b/src/vga.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include "bios.h"
+
+/* VGA init. We use the Bochs VESA VBE extensions */
+#define VBE_DISPI_INDEX_ID 0x0
+#define VBE_DISPI_INDEX_XRES 0x1
+#define VBE_DISPI_INDEX_YRES 0x2
+#define VBE_DISPI_INDEX_BPP 0x3
+#define VBE_DISPI_INDEX_ENABLE 0x4
+#define VBE_DISPI_INDEX_BANK 0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
+#define VBE_DISPI_INDEX_X_OFFSET 0x8
+#define VBE_DISPI_INDEX_Y_OFFSET 0x9
+#define VBE_DISPI_INDEX_NB 0xa
+
+#define VBE_DISPI_ID0 0xB0C0
+#define VBE_DISPI_ID1 0xB0C1
+#define VBE_DISPI_ID2 0xB0C2
+
+#define VBE_DISPI_DISABLED 0x00
+#define VBE_DISPI_ENABLED 0x01
+#define VBE_DISPI_LFB_ENABLED 0x40
+#define VBE_DISPI_NOCLEARMEM 0x80
+
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
+
+static void vga_text_init(void);
+
+unsigned long vga_fb_phys_addr;
+int vga_fb_width;
+int vga_fb_height;
+int vga_fb_linesize;
+int vga_fb_bpp;
+int vga_fb_depth;
+uint8_t rgb_to_index[256];
+
+static void vbe_outw(int index, int val)
+{
+ outw(0x1ce, index);
+ outw(0x1d0, val);
+}
+
+/* init VGA in standard state for PREP boot */
+void vga_prep_init(void)
+{
+ outb(0x3c0, 0x00); /* set blanking */
+ vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
+}
+
+/* build standard RGB palette */
+void vga_build_rgb_palette(void)
+{
+ static const uint8_t pal_value[6] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
+ int i, r, g, b;
+
+ i = 0;
+ for(r = 0; r < 6; r++) {
+ for(g = 0; g < 6; g++) {
+ for(b = 0; b < 6; b++) {
+ vga_set_palette(i, RGB(pal_value[r], pal_value[g],
+ pal_value[b]));
+ i++;
+ }
+ }
+ }
+ for(i = 0; i < 256; i++) {
+ rgb_to_index[i] = ((i * 5) + 128) / 255;
+ }
+}
+
+void vga_set_address (uint32_t address)
+{
+ vga_fb_phys_addr = address;
+}
+
+/* depth = 8, 15, 16 or 32 */
+void vga_set_mode(int width, int height, int depth)
+{
+ vbe_outw(VBE_DISPI_INDEX_XRES, width);
+ vbe_outw(VBE_DISPI_INDEX_YRES, height);
+ vbe_outw(VBE_DISPI_INDEX_BPP, depth);
+ vbe_outw(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED);
+ outb(0x3c0, 0x20); /* disable blanking */
+
+ if (vga_fb_phys_addr == 0x00000000)
+ vga_fb_phys_addr = VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+ vga_fb_width = width;
+ vga_fb_height = height;
+ vga_fb_depth = depth;
+ vga_fb_bpp = (depth + 7) >> 3;
+ vga_fb_linesize = width * vga_fb_bpp;
+
+ if (depth == 8)
+ vga_build_rgb_palette();
+ vga_text_init();
+}
+
+/* for depth = 8 mode, set a hardware palette entry */
+void vga_set_palette(int i, unsigned int rgba)
+{
+ unsigned int r, g, b;
+
+ r = (rgba >> 16) & 0xff;
+ g = (rgba >> 8) & 0xff;
+ b = (rgba) & 0xff;
+ outb(0x3c8, i);
+ outb(0x3c9, r >> 2);
+ outb(0x3c9, g >> 2);
+ outb(0x3c9, b >> 2);
+}
+
+/* convert a RGBA color to a color index usable in graphic primitives */
+unsigned int vga_get_color(unsigned int rgba)
+{
+ unsigned int r, g, b, color;
+
+ switch(vga_fb_depth) {
+ case 8:
+ r = (rgba >> 16) & 0xff;
+ g = (rgba >> 8) & 0xff;
+ b = (rgba) & 0xff;
+ color = (rgb_to_index[r] * 6 * 6) +
+ (rgb_to_index[g] * 6) +
+ (rgb_to_index[b]);
+ break;
+ case 15:
+ r = (rgba >> 16) & 0xff;
+ g = (rgba >> 8) & 0xff;
+ b = (rgba) & 0xff;
+ color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+ break;
+ case 16:
+ r = (rgba >> 16) & 0xff;
+ g = (rgba >> 8) & 0xff;
+ b = (rgba) & 0xff;
+ color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+ break;
+ case 32:
+ default:
+ color = rgba;
+ break;
+ }
+ return color;
+}
+
+void vga_draw_buf (const void *buf, int buf_linesize,
+ int posx, int posy, int width, int height)
+{
+ const uint8_t *s;
+ uint8_t *d;
+ int y, wb;
+
+ s = buf;
+ d = (uint8_t *)vga_fb_phys_addr +
+ vga_fb_linesize * posy + vga_fb_bpp * posx;
+ wb = width * vga_fb_bpp;
+ for (y = 0; y < height; y++) {
+ memcpy(d, s, wb);
+ s += buf_linesize;
+ d += vga_fb_linesize;
+ }
+}
+
+void vga_fill_rect (int posx, int posy, int width, int height, uint32_t color)
+{
+ uint8_t *d, *d1;
+ int x, y;
+
+ d1 = (uint8_t *)vga_fb_phys_addr +
+ vga_fb_linesize * posy + vga_fb_bpp * posx;
+ for (y = 0; y < height; y++) {
+ d = d1;
+ switch(vga_fb_bpp) {
+ case 1:
+ for (x = 0; x < width; x++) {
+ *((uint8_t *)d) = color;
+ d++;
+ }
+ break;
+ case 2:
+ for (x = 0; x < width; x++) {
+ *((uint16_t *)d) = color;
+ d += 2;
+ }
+ break;
+ case 4:
+ for (x = 0; x < width; x++) {
+ *((uint32_t *)d) = color;
+ d += 4;
+ }
+ break;
+ }
+ d1 += vga_fb_linesize;
+ }
+}
+
+/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
+void vga_bitblt(int xs, int ys, int xd, int yd, int w, int h)
+{
+ const uint8_t *s;
+ uint8_t *d;
+ int wb, y;
+
+ wb = w * vga_fb_bpp;
+ if (yd <= ys) {
+ s = (uint8_t *)vga_fb_phys_addr +
+ vga_fb_linesize * ys + vga_fb_bpp * xs;
+ d = (uint8_t *)vga_fb_phys_addr +
+ vga_fb_linesize * yd + vga_fb_bpp * xd;
+ for (y = 0; y < h; y++) {
+ memmove(d, s, wb);
+ d += vga_fb_linesize;
+ s += vga_fb_linesize;
+ }
+ } else {
+ s = (uint8_t *)vga_fb_phys_addr +
+ vga_fb_linesize * (ys + h - 1) + vga_fb_bpp * xs;
+ d = (uint8_t *)vga_fb_phys_addr +
+ vga_fb_linesize * (yd + h - 1) + vga_fb_bpp * xd;
+ for (y = 0; y < h; y++) {
+ memmove(d, s, wb);
+ d -= vga_fb_linesize;
+ s -= vga_fb_linesize;
+ }
+ }
+}
+
+/***********************************************************/
+/* basic char display */
+
+#define FONT_HEIGHT 16
+#define FONT_WIDTH 8
+
+#include "vgafont.h"
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+/* XXX: endianness */
+#if 0
+#define PAT(x) cbswap_32(x)
+#else
+#define PAT(x) x
+#endif
+
+static const uint32_t dmask16[16] = {
+ PAT(0x00000000),
+ PAT(0x000000ff),
+ PAT(0x0000ff00),
+ PAT(0x0000ffff),
+ PAT(0x00ff0000),
+ PAT(0x00ff00ff),
+ PAT(0x00ffff00),
+ PAT(0x00ffffff),
+ PAT(0xff000000),
+ PAT(0xff0000ff),
+ PAT(0xff00ff00),
+ PAT(0xff00ffff),
+ PAT(0xffff0000),
+ PAT(0xffff00ff),
+ PAT(0xffffff00),
+ PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+ PAT(0x00000000),
+ PAT(0x0000ffff),
+ PAT(0xffff0000),
+ PAT(0xffffffff),
+};
+
+int text_width, text_height, text_fgcol, text_bgcol, text_x, text_y;
+
+static void vga_text_init(void)
+{
+ text_width = vga_fb_width / FONT_WIDTH;
+ text_height = vga_fb_height / FONT_HEIGHT;
+ text_x = 0;
+ text_y = 0;
+ vga_text_set_fgcol(RGB(0xff, 0xff, 0xff));
+ vga_text_set_bgcol(RGB(0x00, 0x00, 0x00));
+}
+
+static inline unsigned int col_expand(unsigned int col)
+{
+ switch(vga_fb_bpp) {
+ case 1:
+ col |= col << 8;
+ col |= col << 16;
+ break;
+ case 2:
+ col |= col << 16;
+ break;
+ default:
+ text_fgcol = 0xffffff;
+ break;
+ }
+
+ return col;
+}
+
+void vga_text_set_fgcol(unsigned int rgba)
+{
+ text_fgcol = col_expand(vga_get_color(rgba));
+}
+
+void vga_text_set_bgcol(unsigned int rgba)
+{
+ text_bgcol = col_expand(vga_get_color(rgba));
+}
+
+void vga_putcharxy(int x, int y, int ch,
+ unsigned int fgcol, unsigned int bgcol)
+{
+ uint8_t *d;
+ const uint8_t *font_ptr;
+ unsigned int font_data, linesize, xorcol;
+ int i;
+
+ d = (uint8_t *)vga_fb_phys_addr +
+ vga_fb_linesize * y * FONT_HEIGHT + vga_fb_bpp * x * FONT_WIDTH;
+ linesize = vga_fb_linesize;
+ font_ptr = vgafont16 + FONT_HEIGHT * ch;
+ xorcol = bgcol ^ fgcol;
+ switch(vga_fb_depth) {
+ case 8:
+ for(i = 0; i < FONT_HEIGHT; i++) {
+ font_data = *font_ptr++;
+ ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+ d += linesize;
+ }
+ break;
+ case 16:
+ case 15:
+ for(i = 0; i < FONT_HEIGHT; i++) {
+ font_data = *font_ptr++;
+ ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+ d += linesize;
+ }
+ break;
+ case 32:
+ for(i = 0; i < FONT_HEIGHT; i++) {
+ font_data = *font_ptr++;
+ ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+ ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+ d += linesize;
+ }
+ break;
+ }
+}
+
+static void vga_put_lf(void)
+{
+ text_x = 0;
+ text_y++;
+ if (text_y >= text_height) {
+ text_y = text_height - 1;
+ vga_bitblt(0, FONT_HEIGHT, 0, 0,
+ text_width * FONT_WIDTH,
+ (text_height - 1) * FONT_HEIGHT);
+ vga_fill_rect(0, (text_height - 1) * FONT_HEIGHT,
+ text_width * FONT_WIDTH, FONT_HEIGHT, text_bgcol);
+ }
+}
+
+void vga_putchar(int ch)
+{
+ if (ch == '\r') {
+ text_x = 0;
+ } else if (ch == '\n') {
+ vga_put_lf();
+ } else if (ch == '\b') {
+ if (text_x == 0) {
+ if (text_y != 0) {
+ text_x = text_width;
+ text_y--;
+ goto eat_char;
+ }
+ } else {
+ eat_char:
+ vga_putcharxy(--text_x, text_y, ' ', text_fgcol, text_bgcol);
+ }
+ } else {
+ vga_putcharxy(text_x, text_y, ch, text_fgcol, text_bgcol);
+ text_x++;
+ if (text_x >= text_width)
+ vga_put_lf();
+ }
+}
+
+void vga_puts(const char *s)
+{
+ while (*s) {
+ vga_putchar(*(uint8_t *)s);
+ s++;
+ }
+}
diff --git a/src/vgafont.h b/src/vgafont.h
new file mode 100644
index 0000000..b571e65
--- /dev/null
+++ b/src/vgafont.h
@@ -0,0 +1,4627 @@
+/*
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License V2
+ * as published by the Free Software Foundation
+ *
+ * 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
+ */
+static uint8_t vgafont16[256 * 16] = {
+
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 1 0x01 '^A' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x81, /* 10000001 */
+ 0xa5, /* 10100101 */
+ 0x81, /* 10000001 */
+ 0x81, /* 10000001 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0x81, /* 10000001 */
+ 0x81, /* 10000001 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 2 0x02 '^B' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xdb, /* 11011011 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 3 0x03 '^C' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 4 0x04 '^D' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 5 0x05 '^E' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0xe7, /* 11100111 */
+ 0xe7, /* 11100111 */
+ 0xe7, /* 11100111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 6 0x06 '^F' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 7 0x07 '^G' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 8 0x08 '^H' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xe7, /* 11100111 */
+ 0xc3, /* 11000011 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 9 0x09 '^I' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x42, /* 01000010 */
+ 0x42, /* 01000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 10 0x0a '^J' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0x99, /* 10011001 */
+ 0xbd, /* 10111101 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0xc3, /* 11000011 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 11 0x0b '^K' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1e, /* 00011110 */
+ 0x0e, /* 00001110 */
+ 0x1a, /* 00011010 */
+ 0x32, /* 00110010 */
+ 0x78, /* 01111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 12 0x0c '^L' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 13 0x0d '^M' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x33, /* 00110011 */
+ 0x3f, /* 00111111 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x70, /* 01110000 */
+ 0xf0, /* 11110000 */
+ 0xe0, /* 11100000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 14 0x0e '^N' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x67, /* 01100111 */
+ 0xe7, /* 11100111 */
+ 0xe6, /* 11100110 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 15 0x0f '^O' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xdb, /* 11011011 */
+ 0x3c, /* 00111100 */
+ 0xe7, /* 11100111 */
+ 0x3c, /* 00111100 */
+ 0xdb, /* 11011011 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 16 0x10 '^P' */
+ 0x00, /* 00000000 */
+ 0x80, /* 10000000 */
+ 0xc0, /* 11000000 */
+ 0xe0, /* 11100000 */
+ 0xf0, /* 11110000 */
+ 0xf8, /* 11111000 */
+ 0xfe, /* 11111110 */
+ 0xf8, /* 11111000 */
+ 0xf0, /* 11110000 */
+ 0xe0, /* 11100000 */
+ 0xc0, /* 11000000 */
+ 0x80, /* 10000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 17 0x11 '^Q' */
+ 0x00, /* 00000000 */
+ 0x02, /* 00000010 */
+ 0x06, /* 00000110 */
+ 0x0e, /* 00001110 */
+ 0x1e, /* 00011110 */
+ 0x3e, /* 00111110 */
+ 0xfe, /* 11111110 */
+ 0x3e, /* 00111110 */
+ 0x1e, /* 00011110 */
+ 0x0e, /* 00001110 */
+ 0x06, /* 00000110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 18 0x12 '^R' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 19 0x13 '^S' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 20 0x14 '^T' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7f, /* 01111111 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7b, /* 01111011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 21 0x15 '^U' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x0c, /* 00001100 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 22 0x16 '^V' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 23 0x17 '^W' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 24 0x18 '^X' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 25 0x19 '^Y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 26 0x1a '^Z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0xfe, /* 11111110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 27 0x1b '^[' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xfe, /* 11111110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 28 0x1c '^\' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 29 0x1d '^]' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x28, /* 00101000 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x28, /* 00101000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 30 0x1e '^^' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 31 0x1f '^_' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 32 0x20 ' ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 33 0x21 '!' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 34 0x22 '"' */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x24, /* 00100100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 35 0x23 '#' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 36 0x24 '$' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x86, /* 10000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 37 0x25 '%' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc2, /* 11000010 */
+ 0xc6, /* 11000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc6, /* 11000110 */
+ 0x86, /* 10000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 38 0x26 '&' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 39 0x27 ''' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 40 0x28 '(' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 41 0x29 ')' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 42 0x2a '*' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0xff, /* 11111111 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 43 0x2b '+' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 44 0x2c ',' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 45 0x2d '-' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 46 0x2e '.' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 47 0x2f '/' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x02, /* 00000010 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0x80, /* 10000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 48 0x30 '0' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 49 0x31 '1' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x38, /* 00111000 */
+ 0x78, /* 01111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 50 0x32 '2' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 51 0x33 '3' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x3c, /* 00111100 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 52 0x34 '4' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x1c, /* 00011100 */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xfe, /* 11111110 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x1e, /* 00011110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 53 0x35 '5' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfc, /* 11111100 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 54 0x36 '6' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfc, /* 11111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 55 0x37 '7' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 56 0x38 '8' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 57 0x39 '9' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 58 0x3a ':' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 59 0x3b ';' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 60 0x3c '<' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 61 0x3d '=' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 62 0x3e '>' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 63 0x3f '?' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 64 0x40 '@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xde, /* 11011110 */
+ 0xde, /* 11011110 */
+ 0xde, /* 11011110 */
+ 0xdc, /* 11011100 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 65 0x41 'A' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 66 0x42 'B' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xfc, /* 11111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 67 0x43 'C' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc2, /* 11000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 68 0x44 'D' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 69 0x45 'E' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x66, /* 01100110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x60, /* 01100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 70 0x46 'F' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x66, /* 01100110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 71 0x47 'G' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xde, /* 11011110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x66, /* 01100110 */
+ 0x3a, /* 00111010 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 72 0x48 'H' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 73 0x49 'I' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 74 0x4a 'J' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1e, /* 00011110 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 75 0x4b 'K' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe6, /* 11100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x78, /* 01111000 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 76 0x4c 'L' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf0, /* 11110000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 77 0x4d 'M' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xee, /* 11101110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 78 0x4e 'N' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xe6, /* 11100110 */
+ 0xf6, /* 11110110 */
+ 0xfe, /* 11111110 */
+ 0xde, /* 11011110 */
+ 0xce, /* 11001110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 79 0x4f 'O' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 80 0x50 'P' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 81 0x51 'Q' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xde, /* 11011110 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0x0e, /* 00001110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 82 0x52 'R' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 83 0x53 'S' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x38, /* 00111000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 84 0x54 'T' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x5a, /* 01011010 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 85 0x55 'U' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 86 0x56 'V' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 87 0x57 'W' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xfe, /* 11111110 */
+ 0xee, /* 11101110 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 88 0x58 'X' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 89 0x59 'Y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 90 0x5a 'Z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x86, /* 10000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc2, /* 11000010 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 91 0x5b '[' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 92 0x5c '\' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x80, /* 10000000 */
+ 0xc0, /* 11000000 */
+ 0xe0, /* 11100000 */
+ 0x70, /* 01110000 */
+ 0x38, /* 00111000 */
+ 0x1c, /* 00011100 */
+ 0x0e, /* 00001110 */
+ 0x06, /* 00000110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 93 0x5d ']' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 94 0x5e '^' */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 95 0x5f '_' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 96 0x60 '`' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 97 0x61 'a' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 98 0x62 'b' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 99 0x63 'c' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 100 0x64 'd' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 00011100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 101 0x65 'e' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 102 0x66 'f' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 00011100 */
+ 0x36, /* 00110110 */
+ 0x32, /* 00110010 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 103 0x67 'g' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+
+ /* 104 0x68 'h' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x6c, /* 01101100 */
+ 0x76, /* 01110110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 105 0x69 'i' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 106 0x6a 'j' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 107 0x6b 'k' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x78, /* 01111000 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 108 0x6c 'l' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 109 0x6d 'm' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xec, /* 11101100 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 110 0x6e 'n' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 111 0x6f 'o' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 112 0x70 'p' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+
+ /* 113 0x71 'q' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x1e, /* 00011110 */
+ 0x00, /* 00000000 */
+
+ /* 114 0x72 'r' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x76, /* 01110110 */
+ 0x66, /* 01100110 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 115 0x73 's' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x38, /* 00111000 */
+ 0x0c, /* 00001100 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 116 0x74 't' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0xfc, /* 11111100 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x36, /* 00110110 */
+ 0x1c, /* 00011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 117 0x75 'u' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 118 0x76 'v' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 119 0x77 'w' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 120 0x78 'x' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 121 0x79 'y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+
+ /* 122 0x7a 'z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xcc, /* 11001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 123 0x7b '{' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x0e, /* 00001110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 124 0x7c '|' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 125 0x7d '}' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x70, /* 01110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x0e, /* 00001110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 126 0x7e '~' */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 127 0x7f '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 128 0x80 '€' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc2, /* 11000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 129 0x81 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 130 0x82 '‚' */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 131 0x83 'ƒ' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 132 0x84 '„' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 133 0x85 '…' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 134 0x86 '†' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 135 0x87 '‡' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 136 0x88 'ˆ' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 137 0x89 '‰' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 138 0x8a 'Š' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 139 0x8b '‹' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 140 0x8c 'Œ' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 141 0x8d '' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 142 0x8e 'Ž' */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 143 0x8f '' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 144 0x90 '' */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x66, /* 01100110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 145 0x91 '‘' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xec, /* 11101100 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x7e, /* 01111110 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x6e, /* 01101110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 146 0x92 '’' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3e, /* 00111110 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xfe, /* 11111110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xce, /* 11001110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 147 0x93 '“' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 148 0x94 '”' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 149 0x95 '•' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 150 0x96 '–' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 151 0x97 '—' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 152 0x98 '˜' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+
+ /* 153 0x99 '™' */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 154 0x9a 'š' */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 155 0x9b '›' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 156 0x9c 'œ' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x64, /* 01100100 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xe6, /* 11100110 */
+ 0xfc, /* 11111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 157 0x9d '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 158 0x9e 'ž' */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xf8, /* 11111000 */
+ 0xc4, /* 11000100 */
+ 0xcc, /* 11001100 */
+ 0xde, /* 11011110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 159 0x9f 'Ÿ' */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x1b, /* 00011011 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 160 0xa0 ' ' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 161 0xa1 '¡' */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 162 0xa2 '¢' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 163 0xa3 '£' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 164 0xa4 '¤' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 165 0xa5 '¥' */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xe6, /* 11100110 */
+ 0xf6, /* 11110110 */
+ 0xfe, /* 11111110 */
+ 0xde, /* 11011110 */
+ 0xce, /* 11001110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 166 0xa6 '¦' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x3e, /* 00111110 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 167 0xa7 '§' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 168 0xa8 '¨' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 169 0xa9 '©' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 170 0xaa 'ª' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 171 0xab '«' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0xe0, /* 11100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xdc, /* 11011100 */
+ 0x86, /* 10000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x3e, /* 00111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 172 0xac '¬' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0xe0, /* 11100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x66, /* 01100110 */
+ 0xce, /* 11001110 */
+ 0x9a, /* 10011010 */
+ 0x3f, /* 00111111 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 173 0xad '­' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 174 0xae '®' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x36, /* 00110110 */
+ 0x6c, /* 01101100 */
+ 0xd8, /* 11011000 */
+ 0x6c, /* 01101100 */
+ 0x36, /* 00110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 175 0xaf '¯' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xd8, /* 11011000 */
+ 0x6c, /* 01101100 */
+ 0x36, /* 00110110 */
+ 0x6c, /* 01101100 */
+ 0xd8, /* 11011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 176 0xb0 '°' */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+
+ /* 177 0xb1 '±' */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+
+ /* 178 0xb2 '²' */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+
+ /* 179 0xb3 '³' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 180 0xb4 '´' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 181 0xb5 'µ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 182 0xb6 '¶' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 183 0xb7 '·' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 184 0xb8 '¸' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 185 0xb9 '¹' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x06, /* 00000110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 186 0xba 'º' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 187 0xbb '»' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x06, /* 00000110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 188 0xbc '¼' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x06, /* 00000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 189 0xbd '½' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 190 0xbe '¾' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 191 0xbf '¿' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 192 0xc0 'À' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 193 0xc1 'Á' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 194 0xc2 'Â' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 195 0xc3 'Ã' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 196 0xc4 'Ä' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 197 0xc5 'Å' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 198 0xc6 'Æ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 199 0xc7 'Ç' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 200 0xc8 'È' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x30, /* 00110000 */
+ 0x3f, /* 00111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 201 0xc9 'É' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x30, /* 00110000 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 202 0xca 'Ê' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf7, /* 11110111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 203 0xcb 'Ë' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xf7, /* 11110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 204 0xcc 'Ì' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x30, /* 00110000 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 205 0xcd 'Í' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 206 0xce 'Î' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf7, /* 11110111 */
+ 0x00, /* 00000000 */
+ 0xf7, /* 11110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 207 0xcf 'Ï' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 208 0xd0 'Ð' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 209 0xd1 'Ñ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 210 0xd2 'Ò' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 211 0xd3 'Ó' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x3f, /* 00111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 212 0xd4 'Ô' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 213 0xd5 'Õ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 214 0xd6 'Ö' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 215 0xd7 '×' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xff, /* 11111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 216 0xd8 'Ø' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 217 0xd9 'Ù' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 218 0xda 'Ú' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 219 0xdb 'Û' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 220 0xdc 'Ü' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 221 0xdd 'Ý' */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+
+ /* 222 0xde 'Þ' */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+
+ /* 223 0xdf 'ß' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 224 0xe0 'à' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xdc, /* 11011100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 225 0xe1 'á' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xd8, /* 11011000 */
+ 0xcc, /* 11001100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 226 0xe2 'â' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 227 0xe3 'ã' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 228 0xe4 'ä' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 229 0xe5 'å' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 230 0xe6 'æ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+
+ /* 231 0xe7 'ç' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 232 0xe8 'è' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 233 0xe9 'é' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 234 0xea 'ê' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xee, /* 11101110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 235 0xeb 'ë' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1e, /* 00011110 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x3e, /* 00111110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 236 0xec 'ì' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 237 0xed 'í' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x03, /* 00000011 */
+ 0x06, /* 00000110 */
+ 0x7e, /* 01111110 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0xf3, /* 11110011 */
+ 0x7e, /* 01111110 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 238 0xee 'î' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 00011100 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x1c, /* 00011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 239 0xef 'ï' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 240 0xf0 'ð' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 241 0xf1 'ñ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 242 0xf2 'ò' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 243 0xf3 'ó' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 244 0xf4 'ô' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 245 0xf5 'õ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 246 0xf6 'ö' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 247 0xf7 '÷' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 248 0xf8 'ø' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 249 0xf9 'ù' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 250 0xfa 'ú' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 251 0xfb 'û' */
+ 0x00, /* 00000000 */
+ 0x0f, /* 00001111 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0xec, /* 11101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x3c, /* 00111100 */
+ 0x1c, /* 00011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 252 0xfc 'ü' */
+ 0x00, /* 00000000 */
+ 0x6c, /* 01101100 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 253 0xfd 'ý' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x32, /* 00110010 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 254 0xfe 'þ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 255 0xff 'ÿ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+};