openhackware-0.4.1/0000755000175000017500000000000010244437123014041 5ustar guillemguillemopenhackware-0.4.1/Changelog0000644000175000017500000001263510225051170015653 0ustar guillemguillem# # # # 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 Changelogopenhackware-0.4.1/README0000644000175000017500000001242410222722565014727 0ustar guillemguillem=============================================================================== 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. =============================================================================== openhackware-0.4.1/COPYING0000644000175000017500000004307010222722565015103 0ustar guillemguillem 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. openhackware-0.4.1/TODO0000644000175000017500000000677210222722565014550 0ustar guillemguillem# # # # 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...). openhackware-0.4.1/Makefile0000644000175000017500000002042610222722565015510 0ustar guillemguillem# # # # 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: openhackware-0.4.1/Timestamp0000644000175000017500000000002710225054121015716 0ustar guillemguillem2005-04-06 at 21:44:49 openhackware-0.4.1/src/0000755000175000017500000000000010225054276014633 5ustar guillemguillemopenhackware-0.4.1/src/vectors.ld0000644000175000017500000000274610222722565016652 0ustar guillemguillem/* * * * 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) } } openhackware-0.4.1/src/libfs/0000755000175000017500000000000010225054315015724 5ustar guillemguillemopenhackware-0.4.1/src/libfs/raw.c0000644000175000017500000001123110222722565016665 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libfs/ext2.c0000644000175000017500000000204510222722565016761 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libfs/hfs.c0000644000175000017500000017541210222722565016670 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libfs/isofs.c0000644000175000017500000000205110222722565017217 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libfs/libfs.h0000644000175000017500000000660010222722565017204 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libfs/core.c0000644000175000017500000003666510222722565017046 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/vga.c0000644000175000017500000002670510222722565015566 0ustar guillemguillem/* * 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++; } } openhackware-0.4.1/src/vgafont.h0000644000175000017500000027404710222722565016466 0ustar guillemguillem/* * 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 */ }; openhackware-0.4.1/src/nvram.c0000644000175000017500000002736210222722565016134 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/mm.c0000644000175000017500000000743010222722565015414 0ustar guillemguillem/* * 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 openhackware-0.4.1/src/dev/0000755000175000017500000000000010225054277015412 5ustar guillemguillemopenhackware-0.4.1/src/dev/bus/0000755000175000017500000000000010225054303016171 5ustar guillemguillemopenhackware-0.4.1/src/dev/bus/adb.h0000644000175000017500000000524510222722565017107 0ustar guillemguillem/* * 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__) */ openhackware-0.4.1/src/dev/block/0000755000175000017500000000000010225054300016467 5ustar guillemguillemopenhackware-0.4.1/src/dev/bridge/0000755000175000017500000000000010225054301016632 5ustar guillemguillemopenhackware-0.4.1/src/dev/char/0000755000175000017500000000000010225054304016316 5ustar guillemguillemopenhackware-0.4.1/src/dev/char/char.h0000644000175000017500000000173110222722565017416 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/dev/char/pckbd.c0000644000175000017500000001612510222722565017562 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/dev/char/kbd.c0000644000175000017500000000724610222722565017243 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/dev/char/kbd.h0000644000175000017500000000670510222722565017247 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/dev/char/kbdadb.c0000644000175000017500000005554210222722565017714 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libpart/0000755000175000017500000000000010225054317016264 5ustar guillemguillemopenhackware-0.4.1/src/libpart/libpart.h0000644000175000017500000000431610222722565020102 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libpart/isofs.c0000644000175000017500000001760010222722565017563 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libpart/apple.c0000644000175000017500000002541210222722565017541 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libpart/prep.c0000644000175000017500000001713110222722565017405 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libpart/core.c0000644000175000017500000001602110222722565017364 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/bootinfos.c0000644000175000017500000001700610222722565017005 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/pci.c0000644000175000017500000017561510222722565015571 0ustar guillemguillem/* 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; } openhackware-0.4.1/src/libc/0000755000175000017500000000000010225054307015537 5ustar guillemguillemopenhackware-0.4.1/src/libc/include/0000755000175000017500000000000010225054311017155 5ustar guillemguillemopenhackware-0.4.1/src/libc/include/unistd.h0000644000175000017500000000257110222722565020653 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/stdlib.h0000644000175000017500000000245710222722565020631 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/string.h0000644000175000017500000000617310222722565020655 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/errno.h0000644000175000017500000000253310222722565020470 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/ctype.h0000644000175000017500000000433610222722565020472 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/stdint.h0000644000175000017500000000377110222722565020655 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/endian.h0000644000175000017500000003041410222722565020600 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/stdio.h0000644000175000017500000000271110222722565020463 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/strings.h0000644000175000017500000000162610222722565021036 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/fcntl.h0000644000175000017500000000176510222722565020457 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/include/stddef.h0000644000175000017500000000223110222722565020607 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libc/src/0000755000175000017500000000000010225054312016322 5ustar guillemguillemopenhackware-0.4.1/src/libc/src/str.c0000644000175000017500000001702110222722565017310 0ustar guillemguillem/* * * * 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 openhackware-0.4.1/src/libc/src/malloc.c0000644000175000017500000005343410222722565017757 0ustar guillemguillem/* * * * 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 } openhackware-0.4.1/src/libc/src/errno.c0000644000175000017500000000150210222722565017622 0ustar guillemguillem/* * * * 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; openhackware-0.4.1/src/libc/src/mem.c0000644000175000017500000001071410222722565017260 0ustar guillemguillem/* * * * 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 openhackware-0.4.1/src/libc/src/format.c0000644000175000017500000002735510222722565020003 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libexec/0000755000175000017500000000000010225054314016237 5ustar guillemguillemopenhackware-0.4.1/src/libexec/pef.c0000644000175000017500000002377610222722565017203 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libexec/exec.h0000644000175000017500000000322510222722565017345 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/libexec/chrp.c0000644000175000017500000003437410222722565017361 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libexec/elf.c0000644000175000017500000001607410222722565017170 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libexec/xcoff.c0000644000175000017500000002053110222722565017520 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libexec/macho.c0000644000175000017500000003710310222722565017505 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libexec/prep.c0000644000175000017500000000252610222722565017365 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/libexec/core.c0000644000175000017500000001101710222722565017342 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/bios.h0000644000175000017500000004422610225051226015740 0ustar guillemguillem/* * * * 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__) */ openhackware-0.4.1/src/of.c0000644000175000017500000047115110225050746015412 0ustar guillemguillem/* 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... */ /*****************************************************************************/ openhackware-0.4.1/src/boot.S0000644000175000017500000001064010222722565015723 0ustar guillemguillem/* * * * 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 ; openhackware-0.4.1/src/boot.ld0000644000175000017500000000273210222722565016123 0ustar guillemguillem/* * * * 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) } } openhackware-0.4.1/src/start.S0000644000175000017500000004222710222722565016123 0ustar guillemguillem/* * * * 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 ; openhackware-0.4.1/src/main.ld0000644000175000017500000000461610222722565016107 0ustar guillemguillem/* * 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) } } openhackware-0.4.1/src/main.c0000644000175000017500000003736310222722565015737 0ustar guillemguillem/* * 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; } openhackware-0.4.1/src/bloc.c0000644000175000017500000007371610225051274015727 0ustar guillemguillem/* * * * 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; } openhackware-0.4.1/src/vectors.S0000644000175000017500000004277510222722565016463 0ustar guillemguillem/* * * * 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 openhackware-0.4.1/src/char.c0000644000175000017500000004766510222722565015736 0ustar guillemguillem/* * * * 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; }