From 7a3d3257e59e2ff50910a58e6ee6857c6c4da703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 18 Sep 2010 12:02:09 +0200 Subject: Import of openhackware-0.4.1 --- COPYING | 339 +++ Changelog | 165 ++ Makefile | 257 +++ README | 128 ++ TODO | 94 + Timestamp | 1 + src/bios.h | 580 +++++ src/bloc.c | 1236 +++++++++++ src/boot.S | 100 + src/boot.ld | 45 + src/bootinfos.c | 282 +++ src/char.c | 780 +++++++ src/dev/bus/adb.h | 102 + src/dev/char/char.h | 29 + src/dev/char/kbd.c | 122 ++ src/dev/char/kbd.h | 104 + src/dev/char/kbdadb.c | 482 ++++ src/dev/char/pckbd.c | 214 ++ src/libc/include/ctype.h | 113 + src/libc/include/endian.h | 514 +++++ src/libc/include/errno.h | 62 + src/libc/include/fcntl.h | 33 + src/libc/include/stddef.h | 38 + src/libc/include/stdint.h | 74 + src/libc/include/stdio.h | 43 + src/libc/include/stdlib.h | 50 + src/libc/include/string.h | 90 + src/libc/include/strings.h | 27 + src/libc/include/unistd.h | 43 + src/libc/src/errno.c | 25 + src/libc/src/format.c | 467 ++++ src/libc/src/malloc.c | 730 ++++++ src/libc/src/mem.c | 251 +++ src/libc/src/str.c | 430 ++++ src/libexec/chrp.c | 404 ++++ src/libexec/core.c | 151 ++ src/libexec/elf.c | 239 ++ src/libexec/exec.h | 40 + src/libexec/macho.c | 516 +++++ src/libexec/pef.c | 307 +++ src/libexec/prep.c | 45 + src/libexec/xcoff.c | 216 ++ src/libfs/core.c | 562 +++++ src/libfs/ext2.c | 32 + src/libfs/hfs.c | 2007 +++++++++++++++++ src/libfs/isofs.c | 32 + src/libfs/libfs.h | 129 ++ src/libfs/raw.c | 178 ++ src/libpart/apple.c | 305 +++ src/libpart/core.c | 289 +++ src/libpart/isofs.c | 257 +++ src/libpart/libpart.h | 66 + src/libpart/prep.c | 216 ++ src/main.c | 558 +++++ src/main.ld | 79 + src/mm.c | 145 ++ src/nvram.c | 450 ++++ src/of.c | 5235 ++++++++++++++++++++++++++++++++++++++++++++ src/pci.c | 2250 +++++++++++++++++++ src/start.S | 379 ++++ src/vectors.S | 466 ++++ src/vectors.ld | 45 + src/vga.c | 429 ++++ src/vgafont.h | 4627 +++++++++++++++++++++++++++++++++++++++ 64 files changed, 28704 insertions(+) create mode 100644 COPYING create mode 100644 Changelog create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 Timestamp create mode 100644 src/bios.h create mode 100644 src/bloc.c create mode 100644 src/boot.S create mode 100644 src/boot.ld create mode 100644 src/bootinfos.c create mode 100644 src/char.c create mode 100644 src/dev/bus/adb.h create mode 100644 src/dev/char/char.h create mode 100644 src/dev/char/kbd.c create mode 100644 src/dev/char/kbd.h create mode 100644 src/dev/char/kbdadb.c create mode 100644 src/dev/char/pckbd.c create mode 100644 src/libc/include/ctype.h create mode 100644 src/libc/include/endian.h create mode 100644 src/libc/include/errno.h create mode 100644 src/libc/include/fcntl.h create mode 100644 src/libc/include/stddef.h create mode 100644 src/libc/include/stdint.h create mode 100644 src/libc/include/stdio.h create mode 100644 src/libc/include/stdlib.h create mode 100644 src/libc/include/string.h create mode 100644 src/libc/include/strings.h create mode 100644 src/libc/include/unistd.h create mode 100644 src/libc/src/errno.c create mode 100644 src/libc/src/format.c create mode 100644 src/libc/src/malloc.c create mode 100644 src/libc/src/mem.c create mode 100644 src/libc/src/str.c create mode 100644 src/libexec/chrp.c create mode 100644 src/libexec/core.c create mode 100644 src/libexec/elf.c create mode 100644 src/libexec/exec.h create mode 100644 src/libexec/macho.c create mode 100644 src/libexec/pef.c create mode 100644 src/libexec/prep.c create mode 100644 src/libexec/xcoff.c create mode 100644 src/libfs/core.c create mode 100644 src/libfs/ext2.c create mode 100644 src/libfs/hfs.c create mode 100644 src/libfs/isofs.c create mode 100644 src/libfs/libfs.h create mode 100644 src/libfs/raw.c create mode 100644 src/libpart/apple.c create mode 100644 src/libpart/core.c create mode 100644 src/libpart/isofs.c create mode 100644 src/libpart/libpart.h create mode 100644 src/libpart/prep.c create mode 100644 src/main.c create mode 100644 src/main.ld create mode 100644 src/mm.c create mode 100644 src/nvram.c create mode 100644 src/of.c create mode 100644 src/pci.c create mode 100644 src/start.S create mode 100644 src/vectors.S create mode 100644 src/vectors.ld create mode 100644 src/vga.c create mode 100644 src/vgafont.h 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. + + + Copyright (C) 19yy + + 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. + + , 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 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 ) +* Fix OF property with no value (value len is zero). +* Update TODO list + +2005-02-18: +* Merge HFS rework by Thayne Harbaugh +* 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 + +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 's proposal + +2005-02-10: +* Merge Motorola Raven PCI bridge support on PREP + by Thayne Harbaugh +* Bugfix in pci code: pci_main was not initialized to NULL. + +2005-02-09: +* Merge fixes reported by Thayne Harbaugh + and Matthew S. Wood : + - 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 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 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) ) + +* 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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +#include +#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, §); + 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, §); + 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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +#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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 + * + * 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 +#include +#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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 + +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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 + +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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +/* size_t is defined here */ +#include + +#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 @@ +/* + * + * + * 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 + +void *malloc (size_t size); +void free (void *ptr); +void *realloc (void *ptr, size_t size); + +/* memset is declared here */ +#include + +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 @@ +/* + * + * + * 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 + +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 @@ +/* + * + * + * 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 + +#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 @@ +/* + * + * + * 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 + +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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +/* va_list is defined here */ +#include +/* size_t is defined here */ +#include +/* NULL is defined here */ +#include +/* write is defined here */ +#include +/* memcpy is defined here */ +/* memset is defined here */ +/* strlen is defined here */ +#include + +#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 = ""; + } + 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 @@ +/* + * + * + * 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 +/* memcpy is defined here */ +#include +/* set_errno is defined here */ +#include + +//#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 @@ +/* + * + * + * Open Hack'Ware BIOS: mem 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 +/* NULL is declared here */ +#include + +/* 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 @@ +/* + * + * + * Open Hack'Ware BIOS: str 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 +/* NULL is defined here */ +/* malloc is defined here */ +#include +/* toupper is defined here */ +#include + +/* 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 @@ +/* + * + * + * 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 +#include +#include +#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, "", 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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +#include +#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, §ion, sizeof(mach_section_t)) < 0) { + ERROR("Cannot load MACH-O section\n"); + return -1; + } + pos += sizeof(mach_section_t); + section.vmaddr = get_be32(§ion.vmaddr); + section.size = get_be32(§ion.size); + section.offset = get_be32(§ion.offset); + section.align = get_be32(§ion.align); + section.reloc_offset = get_be32(§ion.reloc_offset); + section.nreloc = get_be32(§ion.nreloc); + section.flags = get_be32(§ion.flags); + section.res1 = get_be32(§ion.res1); + section.res2 = get_be32(§ion.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 @@ +/* + * + * + * 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 +#include +#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, §ion, sizeof(PEF_section_t)) < 0) { + ERROR("Cannot read section %d\n", i); + return -1; + } + pos += sizeof(PEF_section_t); + addr = (void *)get_be32(§ion.address); + sections[i] = addr; + if (addr < first) + first = addr; + size = get_be32(§ion.total_size); + lpos = get_be32(§ion.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(§ion.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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 +#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 @@ +/* + * + * + * 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 + */ + +#include +#include +#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 @@ +/* + * + * + * 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 +#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 @@ +/* + * + * + * 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 "" + +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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 +#include +#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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +#include +#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 +#include +#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 +#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 @@ +/* + * + * + * 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 +#include +#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 +#include +#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", ®s, 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", ®s, 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", ®s, 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", + ®s, 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 +#include +#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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 @@ +/* + * + * + * 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 +#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 */ + +}; -- cgit v1.2.1