diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/SLOF | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/SLOF')
542 files changed, 78786 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/.gitignore b/qemu/roms/SLOF/.gitignore new file mode 100644 index 000000000..802365c2e --- /dev/null +++ b/qemu/roms/SLOF/.gitignore @@ -0,0 +1,14 @@ +*.o +*.fsi +*.a +*.dep +*.depend +*.bin +*.elf +*~ +/.target +board.code +dict.xt +build_info.img +paflof +paflof.unstripped diff --git a/qemu/roms/SLOF/INSTALL b/qemu/roms/SLOF/INSTALL new file mode 100644 index 000000000..058da63e1 --- /dev/null +++ b/qemu/roms/SLOF/INSTALL @@ -0,0 +1,72 @@ +Slimline Open Firmware - SLOF + +Copyright (C) 2005, 2012 IBM Corporation + + +INSTALL ON JS20/JS21 +=============================================================================== + + Detailed information about how to use SLOF on JS20 and JS21 can be found in + the document FlashingSLOF.pdf + + The JS20 and JS21 blades both have 2 "flashsides". They have a 8MB flash part + which is divided into a 4MB "temporary" side and a 4MB "permanent" side. + + The temporary side is the flashside used for the normal operation and the + permanent side is used as a backup if the temporary should ever fail. + + Therefore it is important that the permanent flash side is not changed so + that if ever required the original firmware can be restored. + + SLOF usually warns or in most cases does not easily allow to overwrite the + permanent side. + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! ! + ! NOTE: WHEN FLASHING A NEW FIRMWARE IMAGE YOU MIGHT ! + ! DESTROY YOUR FIRMWARE IMAGE AND LOOSE YOUR WARRANTY! ! + ! ! + ! YOU MAY NEED TO CALL SERVICE, IF THE FIRMWARE IMAGE ! + ! IS DESTROYED ! ! + ! ! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +REMOVING SLOF FROM JS20/JS21 +=============================================================================== + + If you want to boot the original firmware again, you need to boot the blade + from the management module. If auto-boot is enabled you have to press "s" + to reach the firmware prompt. + On the SLOF command line, type: + + 0 > other-firmware + + and it should get you back to running the original firmware. To permanently + get it back, after booting Linux from there, type + + $ update_flash -r + $ halt + + You will boot on the PERM side. To boot from the TEMP side again, you need to + restart the Blade System MGMT Processor. + + Following steps are needed on + Management Module -> Blade Tasks -> Power/Restart + + Power Off Blade + Restart Blade System Mgmt Processor + Power On Blade + + +INSTALL ON KVM/QEMU +=============================================================================== + + Recent versions of QEMU should already be shipped with a version of SLOF. + To upgrade SLOF in your QEMU installation, back-up the old firmware file + .../share/qemu/slof.bin from your QEMU installation, then simply copy the + new SLOF image (for example "boot_rom.bin" after building board-qemu) to + this location. + diff --git a/qemu/roms/SLOF/LICENSE b/qemu/roms/SLOF/LICENSE new file mode 100644 index 000000000..4830faff2 --- /dev/null +++ b/qemu/roms/SLOF/LICENSE @@ -0,0 +1,8 @@ +Copyright (c) 2004, 2008 IBM Corporation +All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of IBM nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/qemu/roms/SLOF/Makefile b/qemu/roms/SLOF/Makefile new file mode 100644 index 000000000..5389ee70c --- /dev/null +++ b/qemu/roms/SLOF/Makefile @@ -0,0 +1,133 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include make.rules + +STD_BOARDS = $(shell targets=""; \ + for a in `echo board-*`; do \ + if [ -e $$a/config ]; then \ + targets="$$targets $$a"; \ + else \ + cd $$a; \ + for b in `echo config* | sed -e s/config.//g`; do \ + if [ "X$$b" != "Xsimics" ]; then \ + if [ "X$$b" != "X`echo $$a|sed -e s/board-//g`" ]; then \ + targets="$$targets $$a-$$b"; \ + else \ + targets="$$targets $$b"; \ + fi fi \ + done; \ + cd ..; \ + fi; \ + done; \ + echo $$targets | sed -e s/board-//g) + +all: + @if [ ! -f .target ]; then \ + echo "Please specify a build target:"; \ + echo " $(STD_BOARDS)"; \ + exit 1; \ + fi + @$(MAKE) `cat .target` + +rom: + @echo "******* Build $(BOARD) System ********" + @echo $(BOARD) > .target + @$(MAKE) -C board-$(BOARD) + @$(RM) -f .crc_flash +rw: + @echo "******* Build $(BOARD) system (RISCWatch boot) ********" + @echo $(BOARD) > .target + @$(MAKE) -C board-$(BOARD) l2b + @$(RM) -f .crc_flash + +$(STD_BOARDS): + @echo "******** Building $@ system ********" + @if [ -f .target ]; then \ + if [ `cat .target` != $@ ]; then \ + echo "Configuration changed - cleaning up first..."; \ + $(MAKE) distclean; \ + echo $@ > .target; \ + fi; \ + else \ + echo $@ > .target; \ + fi + @b=`echo $@ | grep "-"`; \ + if [ -n "$$b" ]; then \ + subboard=$${b##*-}; \ + board=$${b%%-*}; \ + $(MAKE) -C board-$$board SUBBOARD=$$subboard; \ + else \ + $(MAKE) -C board-$@; \ + fi + @$(RM) .crc_flash + +test_all: + @for i in $(STD_BOARDS); do $(MAKE) distclean $$i; done + +driver: + @echo "******** Building $(BOARD) system ********" + @b=`echo $(BOARD) | grep "-"`; \ + if [ -n "$$b" ]; then \ + subboard=$${b##*-}; \ + board=$${b%%-*}; \ + DRIVER=1 $(MAKE) -C board-$$board SUBBOARD=$$subboard driver; \ + else \ + DRIVER=1 $(MAKE) -C board-$(BOARD) driver; \ + fi + @$(RM) -f .crc_flash .boot_xdr.ffs + +cli: + $(MAKE) -C clients + +# Rules for making clean: +clean_here: + $(RM) boot_rom.bin .boot_rom.ffs boot_xdr.bin .boot_xdr.ffs + $(RM) boot_l2-dd2.ad boot_l2b.bin .crc_flash + + +clean: clean_here + @if [ -e .target ]; then \ + tar=`cat .target`; \ + b=`echo $$tar | grep "-"`; \ + if [ -n "$$b" ]; then \ + subboard=$${b##*-}; \ + board=$${b%%-*}; \ + $(MAKE) -C board-$$board SUBBOARD=$$subboard clean; \ + else \ + pwd; \ + $(MAKE) -C board-$$tar clean; \ + fi \ + fi + +distclean: clean_here + @if [ -e .target ]; then \ + tar=`cat .target`; \ + b=`echo $$tar | grep "-"`; \ + if [ -n "$$b" ]; then \ + subboard=$${b##*-}; \ + board=$${b%%-*}; \ + $(MAKE) -C board-$$board SUBBOARD=$$subboard distclean; \ + else \ + $(MAKE) -C board-$$tar distclean; \ + fi; \ + $(RM) .target; \ + fi + +distclean_all: clean_here + @for dir in board-* ; do \ + $(MAKE) -C $$dir distclean || exit 1; \ + done + $(RM) .target + +cli-clean: + $(MAKE) -C clients clean diff --git a/qemu/roms/SLOF/Makefile.gen b/qemu/roms/SLOF/Makefile.gen new file mode 100644 index 000000000..2fdf23fb0 --- /dev/null +++ b/qemu/roms/SLOF/Makefile.gen @@ -0,0 +1,169 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +MAKEARG = BOARD=$(BOARD) PLATFORM=$(PLATFORM) FLAG=$(FLAG) TARG=$(TARG) + +BUILDS = tools_build romfs_build + +include ../make.rules + +ifdef DRIVER +RELEASE=$(shell cat ../VERSION) +export DRIVER_NAME=$(shell cat ../VERSION | sed -e "s/-/./g" | awk -F . '{ printf("%s%02d%02d%1s%02s",$$1,$$2,$$3,$$4,$$5); }') +else +ifneq (,$(wildcard ../.git)) +RELEASE=git-$(shell git rev-parse --short=16 HEAD) +else +ifneq (,$(shell cat ../VERSION)) +RELEASE="$(USER)@$(HOSTNAME) release $(shell cat ../VERSION)" +export DRIVER_NAME=HEAD +else +RELEASE="$(USER)@$(HOSTNAME)(private build)" +export DRIVER_NAME=HEAD +endif +endif +endif + + +DRVDATE=$(shell date +%Y-%h%d) + +FLASH_SIZE_MB = `echo $$[ $(FLASH_SIZE)/1024/1024 ]` + +DTB_ROMFS_FLAG ?= 0 +DTB_ROMFS_ADDR ?= 0 + +llfw_disassembly: + $(MAKE) -C $(LLFWBRDDIR) stage1.dis stage2.dis stageS.dis + +clients_build: + @echo " ====== Building clients ======" + $(MAKE) -C ../clients $(MAKEARG) + +other_licence_build: + $(MAKE) -C ../other-licence $(MAKEARG) + +tools_build: + $(MAKE) -C ../tools + +romfs_build: + $(MAKE) -C ../romfs/tools $(MAKEARG) + +../build_info.img: + @echo "$(CC)" > ../build_info.img + @$(CC) -v >> ../build_info.img 2>&1 + @$(LD) -V >> ../build_info.img 2>&1 + +../$(SUBBOARD).dtb: + @if [ -e dts/$(SUBBOARD).dts ]; then \ + dtc -q -I dts -O dtb dts/$(SUBBOARD).dts > $@; \ + fi + +boot_rom.bin: $(BUILDS) ../build_info.img ../$(SUBBOARD).dtb + @echo " ====== Building $@ ======" + @if [ -e $(ROMFSBRDDIR)/boot_rom.$(SUBBOARD).ffs ]; then \ + cat $(ROMFSBRDDIR)/boot_rom.$(SUBBOARD).ffs > ../.boot_rom.ffs; \ + else \ + cat $(ROMFSBRDDIR)/boot_rom.ffs > ../.boot_rom.ffs; \ + fi + @if [ -e $(PCDBRDDIR)/pcdfiles.ffs ]; then \ + cat $(PCDBRDDIR)/pcdfiles.ffs >> ../.boot_rom.ffs; \ + fi + cat $(SLOFBRDDIR)/OF.ffs >> ../.boot_rom.ffs + @echo build_info.img build_info.img 0 0 >> ../.boot_rom.ffs + @if [ -e ../$(SUBBOARD).dtb ]; then \ + echo dtb $(SUBBOARD).dtb $(DTB_ROMFS_FLAG) \ + $(DTB_ROMFS_ADDR) >> ../.boot_rom.ffs; \ + fi + cd .. && ./romfs/tools/build_romfs $(ROMFS_OPTIONS) .boot_rom.ffs $@ + cd .. && if [ -f $@.gz ]; then rm -f $@.gz; gzip -9 $@ ; fi + rm -f ../.boot_rom.*ffs + rm -f ../$(SUBBOARD).dtb + + +external_flasher: ../boot_rom.bin + ../tools/make-flasher-image.sh $(FLASH_SIZE) ../boot_rom.bin \ + ../boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin + +driver_dirs: + @rm -rf ../driver-$(RELEASE) + @mkdir -p ../driver-$(RELEASE)/{rom,l2b,disassemblies} + +driver_prep: + @echo "Building driver "$(RELEASE)" for $(BOARD)" + +copy_disassemblies: llfw_disassembly + cp $(LLFWBRDDIR)/stage1.dis \ + ../driver-$(RELEASE)/disassemblies/$(RELEASE)-stage1.dis + cp $(LLFWBRDDIR)/stage2.dis \ + ../driver-$(RELEASE)/disassemblies/$(RELEASE)-stage2.dis + cp $(LLFWBRDDIR)/stageS.dis \ + ../driver-$(RELEASE)/disassemblies/$(RELEASE)-stageS.dis + cp $(LLFWBRDDIR)/meminit.dis \ + ../driver-$(RELEASE)/disassemblies/$(RELEASE)-meminit.dis + @if [ -e ../clients/snk/client.dis ]; then cp ../clients/snk/client.dis \ + ../driver-$(RELEASE)/disassemblies/$(RELEASE)-client.dis; fi + +copy_driver: copy_disassemblies external_flasher + mv ../boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin \ + ../driver-$(RELEASE)/rom/$(RELEASE)-boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin + mv ../boot_rom.bin \ + ../driver-$(RELEASE)/rom/$(RELEASE)-boot_rom.bin + if [ -e ../boot_l2-dd2.ad ]; then \ + mv ../boot_l2-dd2.ad ../driver-$(RELEASE)/l2b/; \ + else \ + mv ../boot_l2.ad ../driver-$(RELEASE)/l2b/; \ + fi + mv ../boot_xdr.bin ../driver-$(RELEASE)/l2b/ + cp ../VERSION ../driver-$(RELEASE) + cd ../driver-$(RELEASE) && md5sum rom/*.bin > md5sum.txt + +tar_gz: copy_driver + @cp -a ../driver-$(RELEASE) ../driver-$(RELEASE)-$(DRVDATE)-devel + tar czf ../driver-$(RELEASE)-$(DRVDATE)-devel.tar.gz \ + ../driver-$(RELEASE)-$(DRVDATE)-devel > /dev/null 2>&1 + @rm -rf ../driver-$(RELEASE)-$(DRVDATE)-devel + @rm -rf ../driver-$(RELEASE)/disassemblies + @mv ../driver-$(RELEASE) ../driver-$(RELEASE)-$(DRVDATE) + tar czf ../driver-$(RELEASE)-$(DRVDATE).tar.gz \ + ../driver-$(RELEASE)-$(DRVDATE) > /dev/null 2>&1 + @rm -rf ../driver-$(RELEASE)-$(DRVDATE) + +clean_top: + @rm -f ../build_info.img + @rm -f ../.crc_flash + @rm -f ../$(SUBBOARD).dtb + +clean_gen: clean_top + $(MAKE) -C ../romfs/tools BOARD=$(BOARD) clean + $(MAKE) -C ../tools clean + $(MAKE) -C ../other-licence clean + $(MAKE) -C ../clients clean + @for dir in $(COMMON_LIBS); do \ + $(MAKE) -C ../lib/$$dir clean || exit 1; \ + done + +distclean_gen: clean_top + $(MAKE) -C ../romfs/tools BOARD=$(BOARD) distclean + $(MAKE) -C ../tools distclean + $(MAKE) -C ../other-licence distclean + $(MAKE) -C ../clients distclean + @for dir in $(COMMON_LIBS); do \ + $(MAKE) -C ../lib/$$dir distclean || exit 1; \ + done + +common-libs: + @echo " ====== Building common libraries ======" + $(MAKE) -C $(LIBCMNDIR) $(COMMON_LIBS) + +board-libs: + $(MAKE) -C lib $(MAKEARG) diff --git a/qemu/roms/SLOF/README b/qemu/roms/SLOF/README new file mode 100644 index 000000000..58e929427 --- /dev/null +++ b/qemu/roms/SLOF/README @@ -0,0 +1,246 @@ +Slimline Open Firmware - SLOF + +Copyright (C) 2004, 2012 IBM Corporation + + +Index +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +1.0 Introduction to Open Firmware +2.0 Using the source code +2.1 Build process +2.2 Overview of the source code +2.4 Extending the Forth engine +3.0 Limitations + + +1.0 Introduction to Slimline Open Firmware +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The IEEE Standard 1275-1994 [1], Standard for Boot (Initialization Configura- +tion) Firmware, Core Requirements and Practices, was the first non-proprietary +open standard for boot firmware that is usable on different processors and +buses. Firmware which complies with this standard (also known as Open Firmware) +includes a processor-independent device interface that allows add-in devices +to identify itself and to supply a single boot driver that can be used, +unchanged, on any CPU. In addition, Open Firmware includes a user interface +with powerful scripting and debugging support and a client interface that +allows an operating system and its loaders to use Open Firmware services +during the configuration and initialization process. Open Firmware stores +information about the hardware in a tree structure called the +"device tree". This device tree supports multiple interconnected system +buses and offers a framework for "plug and play"-type auto configuration +across different buses. It was designed to support a variety of different +processor Instruction Set Architectures (ISAs) and buses. + +The full documentation of this Standard can be found in [1]. + +Slimline Open Firmware (SLOF) is now an implementation of the IEEE 1275 +standard that is available under a BSD-style license. Please see the file +LICENSE for details. + + +2.0 Using the source code +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +This version of SLOF currently supports two major platforms ("boards" in the +SLOF jargon): + +- js2x : The PowerPC 970 based systems JS20, JS21 and the PowerStation +- qemu : Used as partition firmware for pseries machines running on KVM/QEMU + +The following sections will give you a short introduction about how to compile +and improve the source code. +Please read the file INSTALL for details about how to install the firmware on +your target system. + + +2.1 Build process +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + To build SLOF you need: + - Recent GNU tools, configured for powerpc64-linux + - GCC: 3.3.3 and newer are known to work + - Binutils: use a version as new as possible + - Subversion (for retrieving the x86 emulator) + + - set the CROSS variable + - something like export CROSS="powerpc64-unknown-linux-gnu-" + when using a cross compiler + or + - export CROSS="" + when using a native compiler + + - For building SLOF for the PowerStation, it is necessary to + download a x86 emulator which is used to execute the BIOS + of VGA card; to download the x86 emulator following steps are + required: + - cd other-licence/x86emu/ + - ./x86emu_download.sh # this downloads the x86 emulator sources + - cd - + + - Now you can compile the firmware. + - For building SLOF for JS20, JS21 or the PowerStation, type: + make js2x + You also might want to build the takeover executable by typing: + make -C board-js2x takeover + - For building SLOF as the partition firmware for KVM/QEMU, type: + make qemu + The resulting ROM image "boot_rom.bin" can then be found in the main + directory. + + +2.2 Overview of the source code +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The SLOF source code is structured into the following directories: + +- llfw : The Low-Level Firmware - this part is platform-specific firmware + that is responsible to boot the system from the reset vector to a + state where it is possible to run the Open Firmware Forth engine + (i.e. it sets up the necessary CPU registers, intializes the memory, + does some board-specific hardware configuration, etc.) + +- slof : The code for the Open Firmware environment, including the Forth + engine (called "Paflof") and the necessary Forth source files. + +- rtas : The Run-Time Abstraction Services, which can be used by the operating + system to access certain hardware without knowing the details. + See [2] for a description of these services. + +- clients : Code that runs on top of the Open Firmware client interface. + Currently, there are two clients: + - net-snk : Used for network bootloading (a TFTP client) + - takeover : A separate binary that can be used for bootstrapping + SLOF on a JS20/JS21 (see FlashingSLOF.pdf for details). + +- drivers : Driver code for various hardware (currently only NIC drivers). + +- lib : Libraries with common code. + +- romfs / tools : Tools that are required for building the firmware image. + +- board-* : The board directories contain all the code that is unique to the + corresponding platform. + + +2.3 The Open Firmware engine +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Open Firmware (OF) is based on the programming language Forth. +SLOF use Paflof as the Forth engine, which was originally developed by +Segher Boessenkool. Most parts of the Forth engine are implemented in C, by +using GNU extensions of ANSI C, (e.g. assigned goto, often misnamed "computed +goto"), resulting in a very efficient yet still quite portable engine. + +The basic Forth words, so-called primitives, are implemented with +a set of C macros. A set of .in and .code files are provided, which +define the semantic of the Forth primitives. A Perl script translates +these files into valid C code, which will be compiled into the Forth engine. +The complete Forth system composes of the basic Forth primitives and +a set of Forth words, which are compiled during the start of the Forth +system. + +Example: +Forth primitive 'dup' + + dup ( a -- a a) \ Duplicate top of stack element + + +prim.in: + cod(DUP) + +prim.code: + PRIM(DUP) cell x = TOS; PUSH; TOS = x; MIRP + +Generated code: + +static cell xt_DUP[] = { { .a = xt_DOTICK }, { .c = "\000\003DUP" }, + { .a = &&code_DUP }, }; + +code_DUP: { asm("#### " "DUP"); void *w = (cfa = (++ip)->a)->a; + cell x = (*dp); dp++; (*dp) = x; goto *w; } + +Without going into detail, it can be seen, that the data stack is +implemented in C as an array of cells, where dp is the pointer to the top of +stack. + +For the implementation of the Open Firmware, most of the code is added as +Forth code and bound to the engine. Also the system vectors for all kinds of +exceptions will be part of the image. Additionally a secondary boot-loader +or any other client application can be bound to the code as payload, +e.g. diagnostics and test programs. + +The Open Firmware image will be put together by the build +process, with a loader at the start of the image. This loader +is called by Low Level Firmware and loads at boot time the Open +Firmware to it's location in memory (see 1.3 Load process). Additionally +a secondary boot loader or any other client application can be bound +to the code as payload. + +The Low Level Firmware (LLFW) is responsible for setting up the +system in an initial state. This task includes the setup of the +CPUs, the system memory and all the buses as well as the serial port +itself. + + +2.4 Extending the Forth engine +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +In the following paragraphs it will be shown how to add +new primitive words (i.e., words implemented not by building +pre-existing Forth words together, but instead implemented in +C or assembler). With this, it is possible to adapt SLOF to +the specific needs of different hardware and architectures. + + +To add primitives: + + For a new primitive, following steps have to be done: + + + Definition of primitive name in <arch>.in + - cod(ABC) defines primitive ABC + + You can also use the following in a .in file, see existing + code for how to use these: + - con(ABC) defines constant ABC + - col(ABC) defines colon definition ABC + - dfr(ABC) defines defer definition ABC + + + Definition of the primitives effects in <arch>.code + - PRIM(ABC) ... MIRP + + The code for the primitive body is any C-code. With + the macros of prim.code the data and return stack of + the Forth engine can be appropriately manipulated. + + +3.0 Limitations of this package +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + On a JS20 the memory setup is very static and therefore there are + only very few combinations of memory DIMM placement actually work. + + Known booting configurations: + + * 4x 256 MB (filling all slots) -- only "0.5 GB" reported. + * 2x 1 GB, slots 3/4 -- only "0.5 GB" reported. + + Known failing configurations + + * 2x 256 MB, slots 3/4 + * 2x 256 MB, slots 1/2 + + On a JS20 SLOF wil always report 0.5 GB even if there is much more memory + available. + + On a JS21 all memory configurations should work. + + +Documentation ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +[1] IEEE 1275-1994 Standard, Standard for Boot (Initialization Configuration) + Firmware: Core Requirements and Practices + +[2] PAPR Standard, Power.org(TM) Standard for Power Architecture(R) Platform + Requirements (Workstation, Server), Version 2.4, December 7, 2009 diff --git a/qemu/roms/SLOF/VERSION b/qemu/roms/SLOF/VERSION new file mode 100644 index 000000000..20bdb2eb7 --- /dev/null +++ b/qemu/roms/SLOF/VERSION @@ -0,0 +1 @@ +20150429 diff --git a/qemu/roms/SLOF/board-js2x/Makefile b/qemu/roms/SLOF/board-js2x/Makefile new file mode 100644 index 000000000..f24a5046e --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/Makefile @@ -0,0 +1,81 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +BOARD_TARGETS = tools_build romfs_build clients_build stage1 subdirs + +SUBDIRS = slof rtas +COMMON_LIBS = libc libipmi libbootmsg libbases libnvram libelf libusb libbcm + +all: $(BOARD_TARGETS) + $(MAKE) boot_rom.bin + +.PHONY : subdirs $(SUBDIRS) clean distclean + +include config +include Makefile.dirs +include $(TOPCMNDIR)/make.rules +include $(TOPCMNDIR)/Makefile.gen + +subdirs: $(SUBDIRS) + +$(SUBDIRS): common-libs + @echo " ====== Building $@ ======" + $(MAKE) -C $@ $(MAKEARG) + +stage1: common-libs + @echo " ====== Building llfw ======" + $(MAKE) -C llfw RELEASE=-DRELEASE=\"\\\"$(RELEASE)\\\"\" + +clean_here: + rm -f ../slof/OF.ffs + rm -f ../boot_rom.bin + +clean: clean_here clean_gen + @for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir clean || exit 1; \ + done + rm -f ../boot_rom.bin ../js2*.img + @$(MAKE) -C llfw clean + @$(MAKE) -C $(TOPCMNDIR)/clients/takeover clean + +distclean: clean_here distclean_gen + @for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir distclean || exit 1; \ + done + rm -f ../boot_rom.bin ../js2*.img + $(MAKE) -C llfw clean + $(MAKE) -C $(TOPCMNDIR)/clients/takeover distclean + +takeover: all + $(MAKE) -C $(TOPCMNDIR)/clients/takeover + +.driver_dirs: + @rm -rf ../driver-$(RELEASE) + @mkdir -p ../driver-$(RELEASE) + +.tar_gz: .driver_dirs takeover external_flasher + @mv ../boot_rom.bin \ + ../driver-$(RELEASE)/$(RELEASE)-js2x.bin + @mv ../boot_rom-$(FLASH_SIZE_MB)MB-BigEndian.bin \ + ../driver-$(RELEASE)/$(RELEASE)-$(FLASH_SIZE_MB)MB-BigEndian.bin + @mv $(TOPCMNDIR)/clients/takeover/takeover.elf \ + ../driver-$(RELEASE)/$(RELEASE)-takeover.bin + @cp ../VERSION ../driver-$(RELEASE) + @cp changes.txt ../driver-$(RELEASE) + @cd ../driver-$(RELEASE) && md5sum * > md5sum.txt + @chmod 644 ../driver-$(RELEASE)/* + @mv ../driver-$(RELEASE) ../driver-$(RELEASE)-`date +%Y-%h%d` + @tar czf ../driver-$(RELEASE)-`date +%Y-%h%d`.tar.gz \ + ../driver-$(RELEASE)-`date +%Y-%h%d` > /dev/null 2>&1 + @rm -rf ../driver-$(RELEASE)-`date +%Y-%h%d` + +driver: driver_prep clean .tar_gz diff --git a/qemu/roms/SLOF/board-js2x/Makefile.dirs b/qemu/roms/SLOF/board-js2x/Makefile.dirs new file mode 100644 index 000000000..1493d3bf1 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/Makefile.dirs @@ -0,0 +1,41 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ +# +# This sub-Makefile contains the directory configuration variables. +# It can be included from all board specific subdirectories. +# + +# The board specific top directory: +export TOPBRDDIR ?= $(shell while ! test -e Makefile.dirs ; do cd .. ; done ; pwd ) + +# The board specific directories: +export INCLBRDDIR ?= $(TOPBRDDIR)/include +export LLFWBRDDIR ?= $(TOPBRDDIR)/llfw +export RTASBRDDIR ?= $(TOPBRDDIR)/rtas +export SLOFBRDDIR ?= $(TOPBRDDIR)/slof +export ROMFSBRDDIR ?= $(TOPBRDDIR)/romfs + +# The common top directory: +export TOPCMNDIR ?= $(shell cd $(TOPBRDDIR)/.. && pwd) + +# The common directories: +export INCLCMNDIR ?= $(TOPCMNDIR)/include +export LLFWCMNDIR ?= $(TOPCMNDIR)/llfw +export RTASCMNDIR ?= $(TOPCMNDIR)/rtas +export SLOFCMNDIR ?= $(TOPCMNDIR)/slof +export ROMFSCMNDIR ?= $(TOPCMNDIR)/romfs + +export LIBCMNDIR ?= $(TOPCMNDIR)/lib + +export TOOLSDIR ?= $(TOPCMNDIR)/tools +export CLIENTSDIR ?= $(TOPCMNDIR)/clients +export OTHERLICENCEDIR ?= $(TOPCMNDIR)/other-licence diff --git a/qemu/roms/SLOF/board-js2x/config b/qemu/roms/SLOF/board-js2x/config new file mode 100644 index 000000000..d6891e101 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/config @@ -0,0 +1,13 @@ +BOARD=js2x +TARG=ppc64 +export FLAG="-DBIOSEMU" +export CPUARCH=ppc970 +export CPUARCHDEF=-DCPU_PPC970 + +ifneq ($(wildcard ../other-licence/x86emu/*.c),) +export SNK_BIOSEMU_APPS=1 +else +export SNK_BIOSEMU_APPS=0 +endif + +FLASH_SIZE=8388608 diff --git a/qemu/roms/SLOF/board-js2x/include/bmc.h b/qemu/roms/SLOF/board-js2x/include/bmc.h new file mode 100644 index 000000000..39dff80b2 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/include/bmc.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __BMC_H +#define __BMC_H + +void (*bmc_system_reboot) (void); +void (*bmc_power_off) (void); + +short (*bmc_set_flashside) (short mode); +short (*bmc_get_flashside) (void); +int (*bmc_stop_bootwatchdog) (void); +int (*bmc_set_bootwatchdog) (unsigned short); + +uint32_t(*bmc_read_vpd) (uint8_t * dst, uint32_t len, uint32_t offset); +uint32_t(*bmc_write_vpd) (uint8_t * src, uint32_t len, uint32_t offset); + +uint32_t(*bmc_get_blade_descr) (uint8_t * dst, uint32_t maxlen, uint32_t * len); + +#endif /* __BMC_H */ diff --git a/qemu/roms/SLOF/board-js2x/include/hw.h b/qemu/roms/SLOF/board-js2x/include/hw.h new file mode 100644 index 000000000..27117c3f3 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/include/hw.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +uint16_t bswap16_load(uint64_t addr) ; +uint32_t bswap32_load(uint64_t addr) ; + +void bswap16_store(uint64_t addr, uint16_t val) ; +void bswap32_store(uint64_t addr, uint32_t val) ; + +uint8_t load8_ci(uint64_t addr) ; +uint16_t load16_ci(uint64_t addr) ; +uint32_t load32_ci(uint64_t addr) ; +uint64_t load64_ci(uint64_t addr) ; + +void store8_ci(uint64_t addr, uint8_t val) ; +void store16_ci(uint64_t addr, uint16_t val) ; +void store32_ci(uint64_t addr, uint32_t val) ; +void store64_ci(uint64_t addr, uint64_t val) ; diff --git a/qemu/roms/SLOF/board-js2x/include/nvramlog.h b/qemu/roms/SLOF/board-js2x/include/nvramlog.h new file mode 100644 index 000000000..5d6c5d1c9 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/include/nvramlog.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef NVRAMLOG_H + #define NVRAMLOG_H + +/* ---------------------------------------------------------------------------- + * NVRAM Log-Partition header design: + * + * Partition Header + * 00h - signature ( 1 byte) + * 01h - checksum ( 1 byte) + * 02h - length ( 2 byte) value = 1st_byte*256 + 2nd_byte + * 04h - name (12 byte) + * space for partiton header = 16 byte + * + * Log Header + * 10h - offset ( 2 byte) from Partition Header to Data Section + * 12h - flags ( 2 byte) control flags + * 14h - pointer ( 4 byte) pointer to first free byte in Data Section + * relative to the beginning of the data section + * 18h - zero ( 32 byte) reserved as stack for four 64 bit register + * 38h - reserved ( 8 byte) reserved for 64 bit CRC (not implemented yet) + * space for header = 64 byte + * Data Section + * 40h - cyclic data + * -------------------------------------------------------------------------------- */ + + // initial values + #define LLFW_LOG_BE0_SIGNATURE 0x51 // signature for general firmware usage + #define LLFW_LOG_BE0_NAME_PREFIX 0x69626D2C // first 4 bytes of name: "ibm," + #define LLFW_LOG_BE0_NAME 0x435055306C6F6700 // remaining 8 bytes : "CPU0log\0" + #define LLFW_LOG_BE0_LENGTH 0x2000 // Partition length in block of 16 bytes + #define LLFW_LOG_BE0_DATA_OFFSET 0x40 // offset in bytes between header and data + #define LLFW_LOG_BE0_FLAGS 0 // unused + + #define LLFW_LOG_BE1_SIGNATURE 0x51 // signature for general firmware usage + #define LLFW_LOG_BE1_NAME_PREFIX 0x69626D2C // first 4 bytes of name: "ibm," + #define LLFW_LOG_BE1_NAME 0x435055316C6F6700 // remaining 8 bytes : "CPU1log\0\0" + #define LLFW_LOG_BE1_LENGTH 0x500 // Partition length in block of 16 bytes + #define LLFW_LOG_BE1_DATA_OFFSET 0x40 // offset in bytes between header and data + #define LLFW_LOG_BE1_FLAGS 0x0 // unused + + // positions of the initial values + #define LLFW_LOG_POS_CHECKSUM 0x01 // 1 + #define LLFW_LOG_POS_LENGTH 0x02 // 2 + #define LLFW_LOG_POS_NAME 0x04 // 4 + #define LLFW_LOG_POS_DATA_OFFSET 0x10 // 16 + #define LLFW_LOG_POS_FLAGS 0x12 // 18 + #define LLFW_LOG_POS_POINTER 0x14 // 20 + + // NVRAM info + #define MAMBO_NVRAM_BASE 0x100000 // NVRAM Base for MAMBO + #define NVRAM_EMPTY_PATTERN 0x0000000000000000 // Pattern (64-bit) used to overwrite NVRAM + +#endif diff --git a/qemu/roms/SLOF/board-js2x/include/product.h b/qemu/roms/SLOF/board-js2x/include/product.h new file mode 100644 index 000000000..55e9132f8 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/include/product.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _PRODUCT_H +#define _PRODUCT_H + +/* This is also the name which is also put in the flash and should + * therefore not excedd the length of 32 bytes */ +#define PRODUCT_NAME "JS2XBlade" + +/* Generic identifier used in the flash */ +#define FLASHFS_MAGIC "magic123" + +/* Magic identifying the platform */ +#define FLASHFS_PLATFORM_MAGIC "JS2XBlade" + +/* also used in the flash */ +#define FLASHFS_PLATFORM_REVISION "1" + +#define BOOT_MESSAGE "Press \"s\" to enter Open Firmware.\r\n\r\n\0" + +#endif diff --git a/qemu/roms/SLOF/board-js2x/include/southbridge.h b/qemu/roms/SLOF/board-js2x/include/southbridge.h new file mode 100644 index 000000000..1edeb6d76 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/include/southbridge.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _SOUTHBRIDGE_H +#define _SOUTHBRIDGE_H + + +#define SB_FLASH_adr (0xff000000) // FLASH (EBC_CS0/Bank0) +#define SB_NVRAM_adr (0xff800000) // NonVolatile mapping +#define SB_NVRAM_FWONLY_adr (0xff8FF000) // NonVolatile mapping +#define NVRAM_LENGTH 0x100000 +#define NVRAM_FWONLY_LENGTH 0x1000 +#define SB_MAILBOX_adr 0 + +#define FLASH_LENGTH 0x400000 + +#define SB_IPMI_KCS_adr 0xF4000CA8 // IPMI KCS + +#endif diff --git a/qemu/roms/SLOF/board-js2x/llfw/Cboot.S b/qemu/roms/SLOF/board-js2x/llfw/Cboot.S new file mode 100644 index 000000000..d22f3c934 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/Cboot.S @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + .org 0 + + /* Boot Information, hardcoded to ColdReset */ + .quad 1 + /* start address */ + .quad 0x100 diff --git a/qemu/roms/SLOF/board-js2x/llfw/Makefile b/qemu/roms/SLOF/board-js2x/llfw/Makefile new file mode 100644 index 000000000..41cdc35c8 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/Makefile @@ -0,0 +1,61 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include ../../make.rules + +CPPFLAGS = -I$(INCLBRDDIR) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) \ + -I$(LIBCMNDIR)/libc/include +CFLAGS += -fno-builtin $(CPPFLAGS) -O2 -msoft-float $(MAMBO) +CFLAGS += $(BOOT) $(IOCONF) -Wa,-mregnames $(RELEASE) $(CPUARCHDEF) -Wall +ASFLAGS = $(BOOT) $(IOCONF) $(RELEASE)$(CPUARCHDEF) -Wa,-mregnames +LDFLAGS1 = -nostdlib -e__start -Tstage2.lds -N -Ttext=0x100 + + +STG1OBJ = startup.o boot_abort.o romfs.o hw.o io_generic.o board_io.o +STG1OBJ += stage2_head.o stage2.o comlib.o romfs_wrap.o nvramlog.o +STG1OBJ += u4mem.o + +all: stage1.bin stageS.bin Cboot.o + +stage1.bin: $(STG1OBJ) $(LIBCMNDIR)/libelf.a $(LIBCMNDIR)/libc.a + $(LD) $(LDFLAGS1) -o stage1.elf $^ + $(OBJCOPY) -O binary stage1.elf $@ + +stageS.bin: stage_s.o + $(LD) -nostdlib -N -Tstage_s.lds -o stage_s.elf stage_s.o + $(OBJCOPY) -O binary stage_s.elf stageS.bin + +romfs.o: ../../llfw/romfs.S + $(CC) $(CFLAGS) -c ../../llfw/romfs.S + +boot_abort.o: ../../llfw/boot_abort.S + $(CC) $(CFLAGS) -c ../../llfw/boot_abort.S + +nvramlog.o: ../../llfw/nvramlog.S + $(CC) $(CFLAGS) -c ../../llfw/nvramlog.S + +include $(LLFWCMNDIR)/clib/Makefile.inc + +include $(LLFWCMNDIR)/io_generic/Makefile.inc + +romfs_wrap.o: ../../llfw/romfs_wrap.c + $(CC) $(CFLAGS) -c ../../llfw/romfs_wrap.c + +Cboot.o: Cboot.S + $(CC) $(CFLAGS) -c $^ + $(OBJCOPY) -O binary Cboot.o Cboot.bin + +%.o: %.S + $(CC) $(CFLAGS) -c $^ + +clean: + rm -f *.o *.bin *.elf diff --git a/qemu/roms/SLOF/board-js2x/llfw/board_io.S b/qemu/roms/SLOF/board-js2x/llfw/board_io.S new file mode 100644 index 000000000..2f365883d --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/board_io.S @@ -0,0 +1,62 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <macros.h> +#include <cpu.h> + + .text + +C_ENTRY(copy_from_flash) +# size in GPR3 (multiple of 64), from GPR4, to GPR5 + mflr 24 ; mtctr 3 ; addi 4,4,-64 ; addi 5,5,-64 +0: SETCI(r0) + ldu 16,64(4) ; ld 17,8(4) ; ld 18,16(4) ; ld 19,24(4) + ld 20,32(4) ; ld 21,40(4) ; ld 22,48(4) ; ld 23,56(4) + CLRCI(r0) + stdu 16,64(5) ; std 17,8(5) ; std 18,16(5) ; std 19,24(5) + std 20,32(5) ; std 21,40(5) ; std 22,48(5) ; std 23,56(5) + sync ; icbi 0,2 ; bdnz 0b ; sync ; isync ; mtlr 24 ; blr + +/**************************************************************************** + * prints one character to serial console + * + * Input: + * R3 - character + * + * Returns: - + * + * Modifies Registers: + * R3, R4, R5, R6, R7 + ****************************************************************************/ +ENTRY(io_putchar) + mflr r7 + + SETCI(r0) + + # always use serial1 + li 4,0x3f8 ; oris 4,4,0xf400 + + # print one char +0: lbz 0,5(4) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(4) ; eieio + + # also print char to serial2 if on a JS21 + # read ID register: only if it is a PC87427 (JS21) also use serial2 + addi 4,4,-0x3f8 + li 5,0x20 ; stb 5,0x2e(4) ; lbz 5,0x2f(4) ; cmpdi 5,0xf2 ; bne 1f + + addi 4,4,0x2f8 +0: lbz 0,5(4) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(4) ; eieio + +1: CLRCI(r0) + + mtlr r7 + blr diff --git a/qemu/roms/SLOF/board-js2x/llfw/hw.c b/qemu/roms/SLOF/board-js2x/llfw/hw.c new file mode 100644 index 000000000..e01b583b1 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/hw.c @@ -0,0 +1,124 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> +#include <stdint.h> +#include <hw.h> + +uint16_t +bswap16_load(uint64_t addr) +{ + unsigned int val; + set_ci(); + asm volatile ("lhbrx %0, 0, %1":"=r" (val):"r"(addr)); + clr_ci(); + return val; +} + +uint32_t +bswap32_load(uint64_t addr) +{ + unsigned int val; + set_ci(); + asm volatile ("lwbrx %0, 0, %1":"=r" (val):"r"(addr)); + clr_ci(); + return val; +} + +void +bswap16_store(uint64_t addr, uint16_t val) +{ + set_ci(); + asm volatile ("sthbrx %0, 0, %1"::"r" (val), "r"(addr)); + clr_ci(); +} + +void +bswap32_store(uint64_t addr, uint32_t val) +{ + set_ci(); + asm volatile ("stwbrx %0, 0, %1"::"r" (val), "r"(addr)); + clr_ci(); +} + +uint8_t +load8_ci(uint64_t addr) +{ + uint8_t val; + set_ci(); + val = *(uint8_t *) addr; + clr_ci(); + return val; +} + +uint16_t +load16_ci(uint64_t addr) +{ + uint16_t val; + set_ci(); + val = *(uint16_t *) addr; + clr_ci(); + return val; +} + +uint32_t +load32_ci(uint64_t addr) +{ + uint32_t val; + set_ci(); + val = *(uint32_t *) addr; + clr_ci(); + return val; +} + +uint64_t +load64_ci(uint64_t addr) +{ + uint64_t val; + set_ci(); + val = *(uint64_t *) addr; + clr_ci(); + return val; +} + + +void +store8_ci(uint64_t addr, uint8_t val) +{ + set_ci(); + *(uint8_t *) addr = val; + clr_ci(); +} + +void +store16_ci(uint64_t addr, uint16_t val) +{ + set_ci(); + *(uint16_t *) addr = val; + clr_ci(); +} + +void +store32_ci(uint64_t addr, uint32_t val) +{ + set_ci(); + *(uint32_t *) addr = val; + clr_ci(); +} + +void +store64_ci(uint64_t addr, uint64_t val) +{ + set_ci(); + *(uint64_t *) addr = val; + clr_ci(); +} diff --git a/qemu/roms/SLOF/board-js2x/llfw/stage2.c b/qemu/roms/SLOF/board-js2x/llfw/stage2.c new file mode 100644 index 000000000..d05a49493 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/stage2.c @@ -0,0 +1,276 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <xvect.h> +#include <hw.h> +#include <stdio.h> +#include <romfs.h> +#include "memmap.h" +#include "stage2.h" +#include <termctrl.h> +#include "product.h" +#include "calculatecrc.h" +#include <cpu.h> +#include <libelf.h> +#include <string.h> + +uint64_t uart; +uint64_t gVecNum; +uint8_t u4Flag; + +uint64_t exception_stack_frame; + +typedef void (*pInterruptFunc_t) (void); + +pInterruptFunc_t vectorTable[0x2E << 1]; + +extern void proceedInterrupt(void); + +/* Prototypes for functions in this file: */ +void c_interrupt(uint64_t vecNum); +void set_exceptionVector(int num, void *func); +int io_getchar(char *ch); +void early_c_entry(uint64_t start_addr); + + +static void +exception_forward(void) +{ + uint64_t val; + + if (*(uint64_t *) XVECT_M_HANDLER) { + proceedInterrupt(); + } + + printf("\r\n exception %llx ", gVecNum); + asm volatile ("mfsrr0 %0":"=r" (val):); + printf("\r\nSRR0 = %08llx%08llx ", val >> 32, val); + asm volatile ("mfsrr1 %0":"=r" (val):); + printf(" SRR1 = %08llx%08llx ", val >> 32, val); + + asm volatile ("mfsprg %0,2":"=r" (val):); + printf("\r\nSPRG2 = %08llx%08llx ", val >> 32, val); + asm volatile ("mfsprg %0,3":"=r" (val):); + printf(" SPRG3 = %08llx%08llx \r\n", val >> 32, val); + while (1); +} + +void +c_interrupt(uint64_t vecNum) +{ + gVecNum = vecNum; + if (vectorTable[vecNum >> 7]) { + vectorTable[vecNum >> 7] (); + } else { + exception_forward(); + } +} + +void +set_exceptionVector(int num, void *func) +{ + vectorTable[num >> 7] = (pInterruptFunc_t) func; +} + +static void +io_init(void) +{ + // read ID register: only if it is a PC87427, enable serial2 + store8_ci(0xf400002e, 0x20); + if (load8_ci(0xf400002f) != 0xf2) { + uart = 0xf40003f8; + u4Flag = 0; + } else { + uart = 0xf40002f8; + u4Flag = 1; + } +} + +int +io_getchar(char *ch) +{ + int retVal = 0; + if ((load8_ci(uart + 5) & 0x01)) { + *ch = load8_ci(uart); + retVal = 1; + } + return retVal; +} + + +void copy_from_flash(uint64_t cnt, uint64_t src, uint64_t dest); + +const uint32_t CrcTableHigh[16] = { + 0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90, + 0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7, + 0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E, + 0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09 +}; +const uint32_t CrcTableLow[16] = { + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, + 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, + 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD +}; + +static unsigned long +check_flash_image(unsigned long rombase, unsigned long length, + unsigned long start_crc) +{ + + uint32_t AccumCRC = start_crc; + char val; + uint32_t Temp; + while (length-- > 0) { + val = load8_ci(rombase++); + Temp = ((AccumCRC >> 24) ^ val) & 0x000000ff; + AccumCRC <<= 8; + AccumCRC ^= CrcTableHigh[Temp / 16]; + AccumCRC ^= CrcTableLow[Temp % 16]; + } + + return AccumCRC; +} + +static void +load_file(uint64_t destAddr, char *name, uint64_t maxSize, uint64_t romfs_base) +{ + uint64_t *src, *dest, cnt; + struct romfs_lookup_t fileInfo; + c_romfs_lookup(name, romfs_base, &fileInfo); + if (maxSize) { + cnt = maxSize / 8; + } else { + cnt = (fileInfo.size_data + 7) / 8; + } + dest = (uint64_t *) destAddr; + src = (uint64_t *) fileInfo.addr_data; + while (cnt--) { + store64_ci((uint64_t) dest, *src); + dest++; + src++; + } + flush_cache((void *) destAddr, fileInfo.size_data); +} + +/*************************************************************************** + * Function: early_c_entry + * Input : start_addr + * + * Description: + **************************************************************************/ +void +early_c_entry(uint64_t start_addr) +{ + struct romfs_lookup_t fileInfo; + uint32_t crc; + void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); + uint64_t *boot_info; + exception_stack_frame = 0; + /* destination for the flash image; we copy it to RAM + * because from flash it is much too slow + * the flash is copied at 224MB - 4MB (max flash size) + * at 224MB starts SLOF + * at 256MB is the SLOF load-base */ + uint64_t romfs_base = 0xe000000 - 0x400000; + // romfs header values + struct stH *header = (struct stH *) (start_addr + 0x28); + //since we cannot read the fh_magic directly from flash as a string, we need to copy it to memory + uint64_t magic_val = 0; + uint64_t startVal = 0; + uint64_t flashlen = 0; + unsigned long ofw_addr; + + io_init(); + + flashlen = load64_ci((uint64_t) (&header->flashlen)); + + //copy fh_magic to magic_val since, we cannot use it as a string from flash + magic_val = load64_ci((uint64_t) (header->magic)); + + printf(" Check ROM = "); + if (strncmp((char *) &magic_val, FLASHFS_MAGIC, 8) == 0) { + // somehow, the first 8 bytes in flashfs are overwritten, if booting from drone... + // so if we find "IMG1" in the first 4 bytes, we skip the CRC check... + startVal = load64_ci((uint64_t) start_addr); + if (strncmp((char *) &startVal, "IMG1", 4) == 0) { + printf + ("start from RAM detected, skipping CRC check!\r\n"); + // for romfs accesses (c_romfs_lookup) to work, we must fix the first uint64_t to the value we expect... + store64_ci((uint64_t) start_addr, 0xd8); + } else { + //checking CRC in flash, we must use cache_inhibit + // since the crc is included as the last 32 bits in the image, the resulting crc should be 0 + crc = + check_flash_image((uint64_t) start_addr, + load64_ci((uint64_t) + (&header->flashlen)), + 0); + if (crc == 0) { + printf("OK\r\n"); + } else { + printf("failed!\r\n"); + while (1); + } + } + } else { + printf + ("failed (magic string is \"%.8s\" should be \"%.8s\")\r\n", + (char *) &magic_val, FLASHFS_MAGIC); + while (1); + } + + printf(" Press \"s\" to enter Open Firmware.\r\n\r\n"); + + if ((start_addr > 0xF0000000) && u4Flag) + u4memInit(); + + /* here we have real ram avail -> hopefully + * copy flash to ram; size is in 64 byte blocks */ + flashlen /= 64; + /* align it a bit */ + flashlen += 7; + flashlen &= ~7; + copy_from_flash(flashlen, start_addr, romfs_base); + /* takeover sometimes fails if the image running on the system + * has a different size; flushing the cache helps, because it is + * the right thing to do anyway */ + flush_cache((void *) romfs_base, flashlen * 64); + + c_romfs_lookup("bootinfo", romfs_base, &fileInfo); + boot_info = (uint64_t *) fileInfo.addr_data; + boot_info[1] = start_addr; + load_file(0x100, "xvect", 0, romfs_base); + load_file(SLAVELOOP_LOADBASE, "stageS", 0, romfs_base); + c_romfs_lookup("ofw_main", romfs_base, &fileInfo); + + elf_load_file((void *) fileInfo.addr_data, &ofw_addr, + NULL, flush_cache); + ofw_start = + (void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t)) + &ofw_addr; + // re-enable the cursor + printf("%s%s", TERM_CTRL_RESET, TERM_CTRL_CRSON); + /* ePAPR 0.5 + * r3 = R3 Effective address of the device tree image. Note: this + * address must be 8-byte aligned in memory. + * r4 = implementation dependent + * r5 = 0 + * r6 = 0x65504150 -- ePAPR magic value-to distinguish from + * non-ePAPR-compliant firmware + * r7 = implementation dependent + */ + asm volatile("isync; sync;" : : : "memory"); + ofw_start(0, romfs_base, 0, 0, 0); + // never return +} diff --git a/qemu/roms/SLOF/board-js2x/llfw/stage2.h b/qemu/roms/SLOF/board-js2x/llfw/stage2.h new file mode 100644 index 000000000..9ce3c8203 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/stage2.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __STAGE2_H +#define __STAGE2_H + +#ifndef __ASSEMBLER__ + +#include <stddef.h> + +void u4memInit(void); + +#endif /* __ASSEMBLER__ */ +#endif /* __STAGE2_H */ diff --git a/qemu/roms/SLOF/board-js2x/llfw/stage2.lds b/qemu/roms/SLOF/board-js2x/llfw/stage2.lds new file mode 100644 index 000000000..f91f0658a --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/stage2.lds @@ -0,0 +1,56 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) + +/* set the entry point */ +ENTRY ( __start ) + +SECTIONS { + .text : { + *(.text) + } + + . = ALIGN(8); + + .data : { + *(.data) + *(.rodata .rodata.*) + *(.got1) + *(.sdata) + *(.opd) + } + + /* FIXME bss at end ??? */ + + . = ALIGN(8); + __bss_start = .; + .bss : { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + } + + . = ALIGN(8); + __bss_end = .; + __bss_size = (__bss_end - __bss_start); + + __toc_start = .; + .got : + { + *(.toc .got) + } + . = ALIGN(8); + __toc_end = .; + __stack_end = . ; +} diff --git a/qemu/roms/SLOF/board-js2x/llfw/stage2_head.S b/qemu/roms/SLOF/board-js2x/llfw/stage2_head.S new file mode 100644 index 000000000..5460bfebb --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/stage2_head.S @@ -0,0 +1,91 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "macros.h" +#include "../../llfw/boot_abort.h" + +/*#################### defines #####################*/ +#define STACK_SIZE 0x4000 + +/*#################### code ########################*/ + .text + .globl .gluon_c_entry + .globl __toc_start + .globl __toc_end + .globl __stack_end + .globl __bss_start + .globl __bss_size + .globl __start + +ASM_ENTRY(__startC) + /* clear out bss section */ + LOAD64(r3, (__bss_start - 8)) + LOAD64(r4, __bss_size) + + /* divide __bss_size by 8 to get number */ + /* of dwords to clear */ + srwi. r4, r4, 3 + beq bsscdone + li r5, 0 + mtctr r4 +bssc: stdu r5, 8(r3) + bdnz bssc +bsscdone: + /* setup stack */ + LOAD64(r1, __stack_end + STACK_SIZE) + + /* save return address beside stack */ + addi r3, r1, 128 + mflr r0 + std r0, 0(r3) + + /* setup toc */ + bl toc_init + + /* ------------------------------------ */ + /* jump to c-code */ + /* r10 = cpu_init_slave address - r3 */ + /* r11 = slave_setup address - r4 */ + /* ------------------------------------ */ + mr r3, r10 + mr r4, r11 + bl .early_c_entry + + /* return to caller... */ + LOAD64(r1, __stack_end + STACK_SIZE) + addi r1, r1, 128 + ld r3, 0(r1) + mtlr r3 + blr + + /* #################################### */ + /* Basic Additional Functions */ + /* for extended lib functions see */ + /* external library */ + /* #################################### */ + .align 2 + + /* ------------------------------------ */ + /* updates toc in r2 */ + /* ------------------------------------ */ +ASM_ENTRY(toc_init) + LOAD64(r2, __toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + blr + + /* ------------------------------------ */ + /* stores arg#1 in r27 and stops */ + /* ------------------------------------ */ +ENTRY(do_panic) +ENTRY(halt_sys) + BOOT_ABORT_R3HINT(ABORT_CANIO, ALTBOOT, msg_e_ierror); diff --git a/qemu/roms/SLOF/board-js2x/llfw/stage_s.S b/qemu/roms/SLOF/board-js2x/llfw/stage_s.S new file mode 100644 index 000000000..202350f67 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/stage_s.S @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + .text + .org 0 /* after loading to mem this is at slaveloop_base */ +# . = 0x3f00 loaded to this addr + .globl __stage_s_entry + +__stage_s_entry: + bl $+4 + mflr r4 + li r3, 0xff + not r3, r3 + and r4, r4, r3 + li 0,1 ; std 0,0xf8(4) + li 0,0 ; std 0,0xa0(4) +slaveloop: + ori 28,28,0x100 + lis 0,10 + mtctr 0 + bdnz $ # do some waiting, to prevent flooding the buses + lwz 0,0xa0(4) + cmpw 0,28 + bne $-20 # wait for our flag + + lwz 0,0x80(4) + lwz 3,0xc0(4) + mtctr 0 + bctr # jump to specified address, with specified GPR3 + +# .quad 0 +# .quad 0 + + + diff --git a/qemu/roms/SLOF/board-js2x/llfw/stage_s.lds b/qemu/roms/SLOF/board-js2x/llfw/stage_s.lds new file mode 100644 index 000000000..200c1b33e --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/stage_s.lds @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) + +ENTRY( __stage_s_entry ) + +SECTIONS { + .text : { + *(.text) + } +} diff --git a/qemu/roms/SLOF/board-js2x/llfw/startup.S b/qemu/roms/SLOF/board-js2x/llfw/startup.S new file mode 100644 index 000000000..1357d3fd7 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/startup.S @@ -0,0 +1,708 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +# SLOF for JS20/JS21 -- ROM boot code. +# Initial entry point, copy code from flash to cache, memory setup. +# Also sets up serial console and optimizes some settings. + +#include "termctrl.h" +#include <product.h> +#include <xvect.h> +#include <cpu.h> +#include <macros.h> +#include <southbridge.h> + + .text + .globl __start +__start: + /* put rombase in sprg1 ***********************/ + + bl postHeader + .long 0xDEADBEE0 + .long 0x0 /* size */ + .long 0x0 /* crc */ + .long relTag - __start +postHeader: + mflr r3 + li r4, 0x7fff + not r4, r4 + and r3, r3, r4 + mtsprg 1, r3 /* romfs base */ + bl _start + + .org 0x150 - 0x100 +__startSlave: + bl setup_cpu + bl set_ci_bit +# b slaveWithNumber + b slave + + .org 0x180 - 0x100 +__startMaster: + li 3,0 + mtsprg 1, r3 /* romfs base */ + bl setup_cpu + bl set_ci_bit + b master + + + /* FIXME: Also need 0280, 0380, 0f20, etc. */ + + .irp i, 0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x0400,0x0500,0x0600,0x0700, \ + 0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00,0x0e00,0x0f00, \ + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \ + 0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \ + 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \ + 0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00 + . = \i + + /* enable this if you get exceptions before the console works */ + /* this will allow using the hardware debugger to see where */ + /* it traps, and with what register values etc. */ + // b $ + + mtsprg 0, r0 + mfctr r0 + mtsprg 2,r0 + mflr r0 +// 10 + mtsprg 3,r0 + ld r0, (\i + 0x160)(0) + mtctr r0 + li r0, \i + 0x100 +// 20 + bctr + + . = \i + 0x60 + + .quad intHandler2C + + .endr + + + . = XVECT_M_HANDLER - 0x100 + .quad 0x00 + . = XVECT_S_HANDLER - 0x100 + + .quad 0 + + + + .org 0x4000 - 0x100 +_start: + # optimize HID register settings + bl setup_cpu + bl set_ci_bit + + # read semaphore, run as slave if not the first to do so + li 3,0 ; oris 3,3,0xf800 ; lwz 3,0x60(3) ; andi. 3,3,1 ; beq slave +master: + # setup flash, serial + bl setup_sio + + # early greet + li r3, 10 + bl putc + li 3,13 ; bl putc ; li 3,10 ; bl putc ; li 3,'S' ; bl putc + + + #do we run from ram ? + mfsprg r3, 1 /* rombase */ + cmpdi r3,0 /* rombase is 0 when running from RAM */ + + bne copy_to_cache + + # wait a bit, start scripts are slow... need to get all cores running! + lis 3,0x4000 ; mtctr 3 ; bdnz $ + + # copy 4MB from 0 to temp memory + lis 4,0x8 ; mtctr 4 ; lis 4,0x200 ; li 3,0 ; addi 4,4,-8 ; addi 3,3,-8 +0: ldu 5,8(3) ; stdu 5,8(4) ; bdnz 0b + + lis 4,0x200 + mtsprg 1, r4 + + lis 4,0x1 + lis 3,0x20 ; addi 3,3,0x200-8 ; + FLUSH_CACHE(r3, r4) + + lis 4,0x200 + addi 4,4,copy_to_cache@l + mtctr 4 + bctr + +# make all data accesses cache-inhibited +set_ci_bit: + SETCI(r0) + blr + +# make all data accesses cacheable +clr_ci_bit: + CLRCI(r0) + blr + +# write a character to the serial port +putc: +# always write to serial1 +0: lbz 0,5(13) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(13) ; eieio + +# read ID register: only if it is a PC87427 (JS21) also use serial2 + li 4,0 ; oris 4,4,0xf400 + li 5,0x20 ; stb 5,0x2e(4) ; lbz 5,0x2f(4); cmpdi 5,0xf2 ; bne 1f + + addi 4,4,0x2f8 +0: lbz 0,5(4) ; andi. 0,0,0x20 ; beq 0b ; stb 3,0(4) ; eieio + +1: blr + +# transfer from running from flash to running from cache +return_cacheable: + # find and set address to start running from cache, set msr value + mflr 3 ; rldicl 3,3,0,44 +jump_cacheable: + mtsrr0 3 ; + mfmsr 3 ; ori 3,3,0x1000 ; mtsrr1 3 # enable MCE, as well + + # set cacheable insn fetches, jump to cache + mfspr 3,HID1 ; rldicl 3,3,32,0 ; oris 3,3,0x0020 ; rldicl 3,3,32,0 + sync ; mtspr HID1,3 ; mtspr HID1,3 ; rfid ; b . + + + + +copy_to_cache: + # zero the whole cache + # also, invalidate the insn cache, to clear parity errors + # 128kB @ 0MB (boot code and vectors from 0x0 up to 0x20000) + li 4,0x400 ; mtctr 4 ; li 5,0x0 ; bl clr_ci_bit +0: dcbz 0,5 ; sync ; icbi 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b + + # 0x2000 to 0x100000/0x80000 (smaller on 970/970FX) + li 4,0x1C00 ; mfpvr 0 ; srdi 0,0,16 ; cmpdi 0,0x0044 ; bge 0f ; li 4,0xC00 +0: + mtctr 4 ; li 5,0x2000 +0: dcbz 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b ; bl set_ci_bit + + # find base address + bcl 20,31,$+4 ; mflr 31 ; rldicr 31,31,0,43 + + # copy 1kB from 0x4000 + li 4,0x80 ; mtctr 4 ; + li 5,0x3ff8 + addi 3,31,0x3ff8 +0: ldu 4,8(3) ; bl clr_ci_bit ; stdu 4,8(5) ; bl set_ci_bit ; bdnz 0b + # now start executing from cache -- insn cache is huge speed boost + + bl return_cacheable + + li 3,'L' ; bl putc + + # copy 128kB of flash to cache + li 4,0x800 ; mtctr 4 ; li 5,0x200-64 ; addi 3,31,0x200-64 ; +0: ldu 16,64(3) ; ld 17,8(3) ; ld 18,16(3) ; ld 19,24(3) + ld 20,32(3) ; ld 21,40(3) ; ld 22,48(3) ; ld 23,56(3) + bl clr_ci_bit + stdu 16,64(5) ; std 17,8(5) ; std 18,16(5) ; std 19,24(5) + std 20,32(5) ; std 21,40(5) ; std 22,48(5) ; std 23,56(5) + icbi 0,5 ; bl set_ci_bit ; bdnz 0b ; isync + + + li 3,'O' ; bl putc + + lis 4,0x20 + mfsprg r3,1 + cmpd r3,r4 + beq 1f + + // at 0xf8000000 we decide if it is u3 or u4 + li 4,0 ; oris 4,4,0xf800 ; lwz 3,0(4) ; srdi 3,3,4 ; cmpdi 3,3 ; bne 0f + bl setup_mem_u3 + bl setup_mem_size + b 1f +0: + +1: + li 3,'F' ; bl putc + + # setup nvram logging only when not running from RAM + mfsprg r3, 1 /* rombase */ + cmpdi r3, 0 /* rombase is 0 when running from RAM */ + beq 0f + + // at 0xf8000000 we decide if it is u3 or u4 + li r4, 0 + oris r4, r4, 0xf800 + lwz r3, 0(r4) + srdi r3, r3, 4 + cmpdi r3, 3 /* 3 means js20; no nvram logging on js20 */ + beq 0f + + bl io_log_init +0: + + #bl print_mem + + # data is cacheable by default from now on + bl clr_ci_bit + + + /* give live sign *****************************/ + bl 0f + .ascii TERM_CTRL_RESET + .ascii TERM_CTRL_CRSOFF + .ascii " **********************************************************************" + .ascii "\r\n" + .ascii TERM_CTRL_BRIGHT + .ascii PRODUCT_NAME + .ascii " Starting\r\n" + .ascii TERM_CTRL_RESET + .ascii " Build Date = ", __DATE__, " ", __TIME__ + .ascii "\r\n" + .ascii " FW Version = " , RELEASE + .ascii "\r\n\0" + .align 2 +0: mflr r3 + bl io_print + + # go! + li r3,__startC@l + mtctr r3 + mfsprg r10, 1 + bctrl + +relTag: + .ascii RELEASE + .ascii "\0" + .align 2 + +slave: + + # get cpu number + li 3,0 ; oris 3,3,0xf800 ; lwz 28,0x50(3) + +slaveWithNumber: + # create our slave loop address + sldi 3,28,24 ; oris 3,3,0x3000 + + # invalidate the insn cache, to clear parity errors + # clear the L2 cache as well, to get ECC right + li 4,0x2000 ; mfpvr 0 ; srdi 0,0,16 ; cmpdi 0,0x0044 ; bge 0f ; li 4,0x1000 +0: mtctr 4 ; mr 5,3 ; bl clr_ci_bit + +0: dcbz 0,5 ; sync ; icbi 0,5 ; sync ; isync ; addi 5,5,0x80 ; bdnz 0b + + + # write a "b $" insn in there + lis 4,0x4800 ; stw 4,0(3) +/* + mr 5,3 + + # jump there + bl set_ci_bit + li 13,0 ; oris 13,13,0xf400 + # device address + addi 13,13,0x2f8 + li 3,'O' ; add 3,3,28 ; bl putc + bl clr_ci_bit + mr 3,5 +*/ + b jump_cacheable + + + + +# allow the flash chip to be accessed faster +# initialize the 16550-compatible uart on serial port 1 of the sio +setup_sio: + + # i/o base address + li 3,0 ; oris 3,3,0xf400 + + # i/o base address + li 3,0 ; oris 3,3,0xf400 + + # put x-bus in turbo mode + li 4,0xf1 ; stb 4,0x400(3) ; eieio + + + # select sio serial1 + li 4,7 ; stb 4,0x2e(3) ; eieio ; li 4,3 ; stb 4,0x2f(3) ; eieio + + # set base address to 3f8 + li 4,0x60 ; stb 4,0x2e(3) ; eieio ; li 4,3 ; stb 4,0x2f(3) ; eieio + + # enable device + li 4,0x30 ; stb 4,0x2e(3) ; eieio ; li 4,1 ; stb 4,0x2f(3) ; eieio + + # read ID register: only if it is a PC87427, enable serial2 + li 4,0x20 ; stb 4,0x2e(3) ; eieio ; lbz 4,0x2f(3) ; cmpdi 4,0xf2 ; bne 0f + + # select sio serial2 + li 4,7 ; stb 4,0x2e(3) ; eieio ; li 4,2 ; stb 4,0x2f(3) ; eieio + + # set base address to 2f8 + li 4,0x60 ; stb 4,0x2e(3) ; eieio ; li 4,2 ; stb 4,0x2f(3) ; eieio + + # enable device + li 4,0x30 ; stb 4,0x2e(3) ; eieio ; li 4,1 ; stb 4,0x2f(3) ; eieio + + # uart @0x2f8 + addi 3,3,0x2f8 + + # disable interrupts, fifo off + li 4,0 ; stb 4,1(3) ; eieio ; stb 4,2(3) ; eieio + + # set serial speed + li 4,0x80 ; stb 4,3(3) ; eieio + li 4,115200/19200 ; stb 4,0(3) ; eieio ; li 4,0 ; stb 4,1(3) ; eieio + + # set 8-N-1, set RTS and DTR + li 4,3 ; stb 4,3(3) ; eieio ; stb 4,4(3) ; eieio + + eieio + + addi 3,3,-0x2f8 + + # uart @0x3f8 +0: addi 3,3,0x3f8 + + # disable interrupts, fifo off + li 4,0 ; stb 4,1(3) ; eieio ; stb 4,2(3) ; eieio + + # set serial speed + li 4,0x80 ; stb 4,3(3) ; eieio + li 4,115200/19200 ; stb 4,0(3) ; eieio ; li 4,0 ; stb 4,1(3) ; eieio + + # set 8-N-1, set RTS and DTR + li 4,3 ; stb 4,3(3) ; eieio ; stb 4,4(3) ; eieio + + eieio + + # save UART base for putc routine +0: mr 13,3 + + blr + + + + +# set the HID registers of the 970 for optimally executing from flash +setup_cpu: + + /* clear all the HV cruft */ + li r0, 0 + sync + mtspr HID4, r0 + isync + + /* enable dpm, disable attn insn, enable external mce + * first, try external time base; if clock doesn't run, switch to + * internal */ + li r0, 1 /* do the setup for external timebase */ + rldicl r0, r0, 44, 0 /* bit 19 has to be set */ + oris r0, r0, 0x8000 /* Enable external machine check */ + /* interrupts (preferred state */ + /* equals `1'). */ + sync + mtspr HID0, r0 + isync + + mftb r3 /* read the timebase */ + li r1, 0x4000 /* wait long enough for the external */ + mtctr r1 /* timebase (14MHz) to tick a bit */ + bdnz $ /* 0x4000 seems to be enough (for now) */ + mftb r4 /* read the timebase a second time */ + cmpld r3, r4 /* see if it changed */ + bne 0f + /* timebase did not change, do the setup for internal */ + rldicl r0, r0, 19, 1 + rldicl r0, r0, 45, 0 + sync + mtspr HID0, r0 + isync + +0: + /* enable insn prefetch, speculative table walks */ + mfspr r0, HID1 + rldicl r0, r0, 20, 0 + ori r0, r0, 0x1002 + mfsprg r3, 1 /* read rombase */ + cmpdi r3, 0 /* check if running from ram */ + bne 0f + /* running from ram */ + /* Enable instruction fetch cacheability control */ + ori r0, r0, 0x200 +0: + rldicl r0, r0, 44, 0 + sync + mtspr HID1, r0 + isync + + /* enable cache parity */ + mfspr r0, HID4 + oris r0, r0, 0xfff0 + xoris r0, r0, 0xfff0 + sync + mtspr HID4, r0 + isync + + /* exception offset at 0 */ + li r3, 0 + mtspr HIOR, r3 + + blr + +C_ENTRY(proceedInterrupt) + + ld r3,exception_stack_frame@got(r2) + ld r1,0(r3) + + .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \ + 27, 28, 29, 30, 31 + ld r\i, 0x30+\i*8 (r1) + .endr + + ld r14,0x138(r1); + mtsrr0 r14 + + ld r14,0x140(r1); + mtsrr1 r14 + + ld r14,0x148(r1); + mtcr r14 + + + ld 0,XVECT_M_HANDLER(0) + mtctr 0 + + ld r0,0x30(r1); # restore vector number + ld r1,0x38(r1); + + bctr + +intHandler2C: + mtctr r1 # save old stack pointer + lis r1,0x4 + stdu r1, -0x160(r1) + .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \ + 27, 28, 29, 30, 31 + std r\i, 0x30+\i*8 (r1) + .endr + + std r0,0x30(r1); # save vector number + + mfctr r14 + std r14,0x38(r1); # save old r1 + + mfsrr0 r14 + std r14,0x138(r1); + + mfsrr1 r14 + std r14,0x140(r1); + + mfcr r14 + std r14,0x148(r1); + + mfxer r14 + std r14,0x150(r1); + + bl toc_init + + ld r3,exception_stack_frame@got(r2) + std r1,0(r3) + + + mr r3,r0 + bl .c_interrupt + + ld r14,0x138(r1); + mtsrr0 r14 + + ld r14,0x140(r1); + mtsrr1 r14 + + ld r14,0x148(r1); + mtcr r14 + + ld r14,0x150(r1); + mtxer r14 + + + .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \ + 27, 28, 29, 30, 31 + ld r\i, 0x30+\i*8 (r1) + .endr + + ld r1,0x38(r1); + + mfsprg r0,2 + mtctr r0 + mfsprg r0,3 + mtlr r0 + mfsprg r0,0 + rfid + +/* Set exception handler for given exception vector. + r3: exception vector offset + r4: exception handler +*/ + .globl .set_exception +.set_exception: + .globl set_exception +set_exception: + ld r4,0x0(r4) + .globl .set_exception_asm +.set_exception_asm: + .globl set_exception_asm +set_exception_asm: + std r4, 0x60(r3) # fixme diff 1f - 0b + blr + + +setup_mem_u3: + li 4,0x2000 ; oris 4,4,0xf800 + + # MemTimingParam -- CAS lat 2.5 / 4 (read-to-read / read-to-write) + lis 3,0x49e1 ; ori 3,3,0xa000 ; stw 3,0x50(4) + + # MRSRegCntl -- CAS lat 2.5 + li 3,0x6a ; stw 3,0xf0(4) + + # MemBusConfig -- 128 bit bus + lis 3,0x8500 ; stw 3,0x190(4) + + # CKDelAdj -- clock delay 75 + lis 3,0x12c3 ; ori 3,3,0x30cc ; stw 3,0x520(4) + + # IOModeCntl -- no termination on differential and 3-state drivers + lis 3,0x0350 ; stw 3,0x530(4) + + li 3,18 ; mtctr 3 ; addi 5,4,0x5f0 +0: # DQSDelAdj -- read delay offset -10 + lis 3,0x3d8f ; ori 3,3,0x6000 ; stwu 3,0x10(5) + + # DQSDataDelAdj -- write delay offset -32, write data delay offset +15 + lis 3,0x380e ; ori 3,3,0x003c ; stwu 3,0x10(5) + bdnz 0b + + # MemProgCntl -- set all + lis 3,0xc000 ; stw 3,0xe0(4) + + eieio + + blr + + +# read dimm SPDs, program memory size and type +setup_mem_size: + mflr 14 + + li 15,0 ; oris 15,15,0xf800 ; li 17,0 + li 3,0xa0 ; li 4,3 ; li 5,3 ; bl i2c_read + mr 16,4 ; cmpdi 3,0 ; beq 0f ; li 16,0 +0: li 3,0xa2 ; li 4,3 ; li 5,3 ; bl i2c_read + cmpd 16,4 ; bne 0f ; cmpdi 3,0 ; beq 1f +0: li 16,0x1e00 +1: #li 3,0xd ; bl print_byte ; li 3,0xa ; bl print_byte + #mr 3,16 ; bl print_hex + + #li 3,0x20 ; bl print_byte + sldi 3,16,7 ; add 3,3,16 ; rlwinm 3,3,10,0,6 ; subis 3,3,0x3c00 + stw 3,0x21c0(15) ; andi. 0,16,2 ; beq 0f ; stw 3,0x21e0(15) +0: #bl print_hex + sldi 3,16,8 ; add 3,3,16 ; rldicl 3,3,48,56 ; li 0,8 ; slw 3,0,3 + # slw, not sld, so that empty/bad banks translate into size 0 + stw 17,0x21d0(15) ; bl add17173 ; stw 17,0x21f0(15) + andi. 0,16,2 ; beq 0f ; bl add17173 +0: #bl print_hex + + li 3,0xa4 ; li 4,3 ; li 5,3 ; bl i2c_read + mr 16,4 ; cmpdi 3,0 ; beq 0f ; li 16,0 +0: li 3,0xa6 ; li 4,3 ; li 5,3 ; bl i2c_read + cmpd 16,4 ; bne 0f ; cmpdi 3,0 ; beq 1f +0: li 16,0x1e00 +1: #li 3,0xd ; bl print_byte ; li 3,0xa ; bl print_byte + #mr 3,16 ; bl print_hex + + #li 3,0x20 ; bl print_byte + sldi 3,16,7 ; add 3,3,16 ; rlwinm 3,3,10,0,6 ; subis 3,3,0x3c00 + stw 3,0x2200(15) ; andi. 0,16,2 ; beq 0f ; stw 3,0x2220(15) +0: #bl print_hex + sldi 3,16,8 ; add 3,3,16 ; rldicl 3,3,48,56 ; li 0,8 ; slw 3,0,3 + stw 17,0x2210(15) ; bl add17173 ; stw 17,0x2230(15) + andi. 0,16,2 ; beq 0f ; bl add17173 +0: #bl print_hex + #mr 3,17 ; bl print_hex + stw 17,0x2250(15) ; stw 17,0x2270(15) + stw 17,0x2290(15) ; stw 17,0x22b0(15) + + mtlr 14 + blr + + + + +# print GPR3 as 8-digit hex. uses GPR18,19 +print_hex: + mflr 18 ; mr 19,3 ; li 3,8 ; mtctr 3 +1: rlwinm 3,19,4,28,31 ; sldi 19,19,4 + cmpdi 3,0xa ; blt 0f ; addi 3,3,0x27 +0: addi 3,3,0x30 ; bl putc + bdnz 1b ; mtlr 18 ; blr + + +# i2c stuff uses GPR20..GPR24 + +# terminate any i2c transaction, at any point during that transaction +i2c_stop: +0: lwz 3,0x30(20) ; stw 3,0x30(20) ; andi. 3,3,4 ; beq 0b + mr 3,21 ; mr 4,22 ; mtlr 24 ; eieio ; blr + +# do a combined-mode read +# in: GPR3 = addr, GPR4 = subaddr, GPR5 = len +# out: GPR3 = error, GPR4 = result (right-aligned, msb) +i2c_read: + mflr 24 + li 20,0x1000 ; oris 20,20,0xf800 # uni-n i2c base + mr 21,3 ; mr 22,4 ; mr 23,5 # save params + li 4,0xc ; stw 4,0(20) # set mode (combined) + ori 4,21,1 ; stw 4,0x50(20) # set addr, read + stw 22,0x60(20) # set subaddr + li 4,2 ; stw 4,0x10(20) ; eieio # start address phase + li 21,1 # error + li 22,0 # result accumulator +0: lwz 3,0x30(20) ; andi. 3,3,2 ; beq 0b # wait until sent + lwz 3,0x20(20) ; andi. 3,3,2 ; beq i2c_stop # check result + li 4,1 ; cmpdi 23,1 ; bne 0f ; li 4,0 +0: stw 4,0x10(20) # AAK for next byte (or not) + li 4,2 ; stw 4,0x30(20) ; eieio # ack address phase +i2c_read_loop: + lwz 3,0x30(20) ; andi. 3,3,1 ; beq 1f # if byte recv'd: + subi 23,23,1 ; sldi 22,22,8 # shift byte accum + lwz 3,0x70(20) ; rlwimi 22,3,0,24,31 # get byte + cmpdi 23,0 ; bne 0f ; li 21,0 ; b i2c_stop # all done +0: li 4,1 ; cmpdi 23,1 ; bne 0f ; li 4,0 +0: stw 4,0x10(20) # AAK for next byte (or not) + li 4,1 ; stw 4,0x30(20) ; eieio # ack data phase +1: lwz 3,0x30(20) ; andi. 3,3,4 ; beq i2c_read_loop + li 4,0 ; stw 4,0x10(20) ; eieio ; b i2c_stop # stop bit received + +add17173: # add GPR3 into GPR17; if passing 2GB (0x10000000), add another 2GB. + lis 0,0x1000 ; cmpld 17,0 ; add 17,17,3 ; bgtlr + cmpld 17,0 ; blelr ; add 17,17,0 ; blr + +io_log_init: + LOAD64(r3, SB_NVRAM_adr) + b checkinitLog diff --git a/qemu/roms/SLOF/board-js2x/llfw/u4mem.c b/qemu/roms/SLOF/board-js2x/llfw/u4mem.c new file mode 100644 index 000000000..68bba56df --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/llfw/u4mem.c @@ -0,0 +1,4065 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <stdint.h> +#include <hw.h> +#include <stdio.h> +#include "stage2.h" +#include <cpu.h> +#include <string.h> + +/* + * compiler switches + ******************************************************************************* + */ +#define U4_DEBUG +#define U4_INFO +//#define U4_SHOW_REGS + +int io_getchar(char *); + +/* + * version info + */ +static const uint32_t VER = 2; +static const uint32_t SUBVER = 1; + +/* + * local macros + ******************************************************************************* + */ +// bit shifting in Motorola/IBM bit enumeration format (yaks...) +#define IBIT( nr ) ( (uint32_t) 0x80000000 >> (nr) ) +#define BIT( nr ) ( (uint32_t) 0x1 << (nr) ) + +/* + * macros to detect the current board layout + */ +#define IS_MAUI ( ( load8_ci( 0xf4000682 ) >> 4 ) == 0 ) +#define IS_BIMINI ( ( load8_ci( 0xf4000682 ) >> 4 ) == 1 ) +#define IS_KAUAI ( ( load8_ci( 0xf4000682 ) >> 4 ) == 2 ) + +/* + * local constants + ******************************************************************************* + */ + +/* + * u4 base address + */ +#define U4_BASE_ADDR ((uint64_t) 0xf8000000 ) +#define u4reg( reg ) (U4_BASE_ADDR + (uint64_t) (reg)) + +/* + * I2C registers + */ +#define I2C_MODE_R u4reg(0x1000) +#define I2C_CTRL_R u4reg(0x1010) +#define I2C_STAT_R u4reg(0x1020) +#define I2C_ISR_R u4reg(0x1030) +#define I2C_ADDR_R u4reg(0x1050) +#define I2C_SUBA_R u4reg(0x1060) +#define I2C_DATA_R u4reg(0x1070) + +/* + * clock control registers & needed bits/masks + */ +#define ClkCntl_R u4reg(0x0800) +#define PLL2Cntl_R u4reg(0x0860) + +/* + * clock control bits & masks + */ +#define CLK_DDR_CLK_MSK (IBIT(11) | IBIT(12) | IBIT(13)) + +/* + * memory controller registers + */ +#define RASTimer0_R u4reg(0x2030) +#define RASTimer1_R u4reg(0x2040) +#define CASTimer0_R u4reg(0x2050) +#define CASTimer1_R u4reg(0x2060) +#define MemRfshCntl_R u4reg(0x2070) +#define MemProgCntl_R u4reg(0x20b0) +#define Dm0Cnfg_R u4reg(0x2200) +#define Dm1Cnfg_R u4reg(0x2210) +#define Dm2Cnfg_R u4reg(0x2220) +#define Dm3Cnfg_R u4reg(0x2230) +#define MemWrQCnfg_R u4reg(0x2270) +#define MemArbWt_R u4reg(0x2280) +#define UsrCnfg_R u4reg(0x2290) +#define MemRdQCnfg_R u4reg(0x22a0) +#define MemQArb_R u4reg(0x22b0) +#define MemRWArb_R u4reg(0x22c0) +#define MemBusCnfg_R u4reg(0x22d0) +#define MemBusCnfg2_R u4reg(0x22e0) +#define ODTCntl_R u4reg(0x23a0) +#define MemModeCntl_R u4reg(0x2500) +#define MemPhyModeCntl_R u4reg(0x2880) +#define CKDelayL_R u4reg(0x2890) +#define CKDelayU_R u4reg(0x28a0) +#define IOPadCntl_R u4reg(0x29a0) +#define ByteWrClkDelC0B00_R u4reg(0x2800) +#define ByteWrClkDelC0B01_R u4reg(0x2810) +#define ByteWrClkDelC0B02_R u4reg(0x2820) +#define ByteWrClkDelC0B03_R u4reg(0x2830) +#define ByteWrClkDelC0B04_R u4reg(0x2900) +#define ByteWrClkDelC0B05_R u4reg(0x2910) +#define ByteWrClkDelC0B06_R u4reg(0x2920) +#define ByteWrClkDelC0B07_R u4reg(0x2930) +#define ByteWrClkDelC0B16_R u4reg(0x2980) +#define ByteWrClkDelC0B08_R u4reg(0x2a00) +#define ByteWrClkDelC0B09_R u4reg(0x2a10) +#define ByteWrClkDelC0B10_R u4reg(0x2a20) +#define ByteWrClkDelC0B11_R u4reg(0x2a30) +#define ByteWrClkDelC0B12_R u4reg(0x2b00) +#define ByteWrClkDelC0B13_R u4reg(0x2b10) +#define ByteWrClkDelC0B14_R u4reg(0x2b20) +#define ByteWrClkDelC0B15_R u4reg(0x2b30) +#define ByteWrClkDelC0B17_R u4reg(0x2b80) +#define ReadStrobeDelC0B00_R u4reg(0x2840) +#define ReadStrobeDelC0B01_R u4reg(0x2850) +#define ReadStrobeDelC0B02_R u4reg(0x2860) +#define ReadStrobeDelC0B03_R u4reg(0x2870) +#define ReadStrobeDelC0B04_R u4reg(0x2940) +#define ReadStrobeDelC0B05_R u4reg(0x2950) +#define ReadStrobeDelC0B06_R u4reg(0x2960) +#define ReadStrobeDelC0B07_R u4reg(0x2970) +#define ReadStrobeDelC0B16_R u4reg(0x2990) +#define ReadStrobeDelC0B08_R u4reg(0x2a40) +#define ReadStrobeDelC0B09_R u4reg(0x2a50) +#define ReadStrobeDelC0B10_R u4reg(0x2a60) +#define ReadStrobeDelC0B11_R u4reg(0x2a70) +#define ReadStrobeDelC0B12_R u4reg(0x2b40) +#define ReadStrobeDelC0B13_R u4reg(0x2b50) +#define ReadStrobeDelC0B14_R u4reg(0x2b60) +#define ReadStrobeDelC0B15_R u4reg(0x2b70) +#define ReadStrobeDelC0B17_R u4reg(0x2b90) +#define MemInit00_R u4reg(0x2100) +#define MemInit01_R u4reg(0x2110) +#define MemInit02_R u4reg(0x2120) +#define MemInit03_R u4reg(0x2130) +#define MemInit04_R u4reg(0x2140) +#define MemInit05_R u4reg(0x2150) +#define MemInit06_R u4reg(0x2160) +#define MemInit07_R u4reg(0x2170) +#define MemInit08_R u4reg(0x2180) +#define MemInit09_R u4reg(0x2190) +#define MemInit10_R u4reg(0x21a0) +#define MemInit11_R u4reg(0x21b0) +#define MemInit12_R u4reg(0x21c0) +#define MemInit13_R u4reg(0x21d0) +#define MemInit14_R u4reg(0x21e0) +#define MemInit15_R u4reg(0x21f0) +#define CalConf0_R u4reg(0x29b0) +#define CalConf1_R u4reg(0x29c0) +#define MeasStatusC0_R u4reg(0x28f0) +#define MeasStatusC1_R u4reg(0x29f0) +#define MeasStatusC2_R u4reg(0x2af0) +#define MeasStatusC3_R u4reg(0x2bf0) +#define CalC0_R u4reg(0x28e0) +#define CalC1_R u4reg(0x29e0) +#define CalC2_R u4reg(0x2ae0) +#define CalC3_R u4reg(0x2be0) +#define RstLdEnVerniersC0_R u4reg(0x28d0) +#define RstLdEnVerniersC1_R u4reg(0x29d0) +#define RstLdEnVerniersC2_R u4reg(0x2ad0) +#define RstLdEnVerniersC3_R u4reg(0x2bd0) +#define ExtMuxVernier0_R u4reg(0x28b0) +#define ExtMuxVernier1_R u4reg(0x28c0) +#define OCDCalCmd_R u4reg(0x2300) +#define OCDCalCntl_R u4reg(0x2310) +#define MCCR_R u4reg(0x2440) +#define MSRSR_R u4reg(0x2410) +#define MSRER_R u4reg(0x2420) +#define MSPR_R u4reg(0x2430) +#define MSCR_R u4reg(0x2400) +#define MEAR0_R u4reg(0x2460) +#define MEAR1_R u4reg(0x2470) +#define MESR_R u4reg(0x2480) +#define MRSRegCntl_R u4reg(0x20c0) +#define EMRSRegCntl_R u4reg(0x20d0) +#define APIMemRdCfg_R u4reg(0x30090) +#define APIExcp_R u4reg(0x300a0) + +/* + * common return values + */ +#define RET_OK 0 +#define RET_ERR -1 +#define RET_ACERR_CE -1 +#define RET_ACERR_UEWT -2 +#define RET_ACERR_UE -3 + +/* + * 'DIMM slot populated' indicator + */ +#define SL_POP 1 + +/* + * spd buffer size + */ +#define SPD_BUF_SIZE 0x40 + +/* + * maximum number of DIMM banks & DIMM groups + */ +#define NUM_SLOTS 8 +#define NUM_BANKS ( NUM_SLOTS / 2 ) +#define MAX_DGROUPS ( NUM_SLOTS / 2 ) +#define SLOT_ADJ() ( ( IS_MAUI ) ? NUM_SLOTS / 4 : NUM_SLOTS / 2 ) + +/* + * values needed for auto calibration + */ +#define MAX_DRANKS NUM_SLOTS +#define MAX_BLANE 18 +#define MAX_RMD 0xf + +/* + * maximum number of supported CAS latencies + */ +#define NUM_CL 3 + +/* + * min/max supported CL values by U4 + */ +#define U4_MIN_CL 3 +#define U4_MAX_CL 5 + +/* + * DIMM constants + */ +#define DIMM_TYPE_MSK BIT(0) +#define DIMM_ORG_x4 BIT(0) +#define DIMM_ORG_x8 BIT(1) +#define DIMM_ORG_x16 BIT(2) +#define DIMM_ORG_MIXx8x16 BIT(30) +#define DIMM_ORG_UNKNOWN 0 +#define DIMM_WIDTH 72 +#define DIMM_BURSTLEN_4 BIT(2) + +/* + * L2 cache size + */ +#define L2_CACHE_SIZE (uint32_t) 0x100000 + +/* + * scrub types + */ +#define IMMEDIATE_SCRUB IBIT(0) +#define IMMEDIATE_SCRUB_WITH_FILL ( IBIT(0) | IBIT(1) ) +#define BACKGROUND_SCRUB ( IBIT(1) | ( 0x29 << 16 ) ) + +/* + * I2C starting slave addresses of the DIMM banks + */ +#define I2C_START 0x50 + +/* + * Index to the speed dependend DIMM settings + */ +enum +{ + SPEED_IDX_400 = 0, + SPEED_IDX_533, + SPEED_IDX_667, + NUM_SPEED_IDX +}; + +/* + * number of read/write strobes of the U4 + */ +#define NUM_STROBES 18 + +/* + * 2GB hole definition + */ +static const uint64_t _2GB = (uint64_t) 0x80000000; + +/* + * local types + ******************************************************************************* + */ +/* + * DIMM definition + */ +typedef struct +{ + uint32_t m_pop_u32; // set if bank is populated + uint32_t m_bank_u32; // bank number + uint32_t m_clmsk_u32; // mask of supported CAS latencies + uint32_t m_clcnt_u32; // number of supporetd CAS latencies + uint32_t m_clval_pu32[NUM_CL]; // values of supporeted CAS latencies + uint32_t m_speed_pu32[NUM_CL]; // speed (Mhz) at CAS latency of same index + uint32_t m_size_u32; // chip size in Mb + uint32_t m_rank_u32; // # of ranks, total size = chip size*rank + uint32_t m_orgmsk_u32; // data organisation (x4, x8, x16) (mask) + uint32_t m_orgval_u32; // data organisation (value) + uint32_t m_width_u32; // data width + uint32_t m_ecc_u32; // set if ecc + uint32_t m_type_u32; // rdimm or udimm + uint32_t m_burst_u32; // supported burst lengths + uint32_t m_bankcnt_u32; // number of banks + + /* + * the following timing values are all in 1/100ns + */ + uint32_t m_tCK_pu32[NUM_CL]; + uint32_t m_tRAS_u32; + uint32_t m_tRTP_u32; + uint32_t m_tRP_u32; + uint32_t m_tWR_u32; + uint32_t m_tRRD_u32; + uint32_t m_tRC_u32; + uint32_t m_tRCD_u32; + uint32_t m_tWTR_u32; + uint32_t m_tREF_u32; + uint32_t m_tRFC_u32; +} dimm_t; + +/* + * DIMM group definition + */ +typedef struct +{ + uint32_t m_size_u32; // group size in MB + uint32_t m_start_u32; // in 128Mb granularity + uint32_t m_end_u32; // in 128Mb granularity + uint32_t m_ss_u32; // single sided/double sided + uint32_t m_csmode_u32; // selected CS mode for this group + uint32_t m_add2g_u32; + uint32_t m_sub2g_u32; + uint32_t m_memmd_u32; // selected mem mode for this group + uint32_t m_dcnt_u32; // number of DIMMs in group + dimm_t *m_dptr[NUM_SLOTS]; +} dgroup_t; + +/* + * auto calibration result structure + */ +typedef struct +{ + uint32_t m_MemBusCnfg_u32; + uint32_t m_MemBusCnfg2_u32; + uint32_t m_RstLdEnVerniers_pu32[4]; +} auto_calib_t; + +/* + * ECC error structure + */ +typedef struct +{ + int32_t m_err_i32; + uint32_t m_uecnt_u32; // number of uncorrectable errors + uint32_t m_cecnt_u32; // number of correctable errors + uint32_t m_rank_u32; // erroneous rank + uint32_t m_col_u32; // erroneous column + uint32_t m_row_u32; // erroneous row + uint32_t m_bank_u32; // erroneous bank +} eccerror_t; + +/* + * U4 register setup structure + */ +typedef struct +{ + /* + * external MUX delays + */ + uint32_t RRMux; + uint32_t WRMux; + uint32_t WWMux; + uint32_t RWMux; + + /* + * default Wr/Rd Queue & Arbiter register settings + */ + uint32_t MemRdQCnfg; + uint32_t MemWrQCnfg; + uint32_t MemQArb; + uint32_t MemRWArb; + + /* + * misc fixed register values + */ + uint32_t ODTCntl; + uint32_t IOPadCntl; + uint32_t MemPhyModeCntl; + uint32_t OCDCalCntl; + uint32_t OCDCalCmd; + uint32_t CKDelayL; + uint32_t CKDelayU; + uint32_t MemBusCnfg; + uint32_t CAS1Dly0; + uint32_t CAS1Dly1; + uint32_t ByteWrClkDel[NUM_STROBES]; + uint32_t ReadStrobeDel[NUM_STROBES]; +} reg_statics_t; + +/* + * local variables + ******************************************************************************* + */ +static dimm_t m_dimm[NUM_SLOTS]; +static dimm_t m_gendimm; +static uint32_t m_dcnt_u32; +static dimm_t *m_dptr[NUM_SLOTS]; +static uint32_t m_bankoff_u32; +static uint32_t m_bankpop_u32[NUM_BANKS]; +static uint32_t m_dclidx_u32; +static uint32_t m_dgrcnt_u32; +static dgroup_t m_dgroup[MAX_DGROUPS]; +static dgroup_t *m_dgrptr[MAX_DGROUPS]; +static uint64_t m_memsize_u64; // memsize in bytes + +/* + * local functions + ******************************************************************************* + */ +static void +progbar( void ) +{ + static uint8_t bar[] = + { '|', '/', '-', '\\', 0 }; + static uint32_t idx = 0; + + printf( "\b%c", bar[idx] ); + + if( bar[++idx] == 0 ) { + idx = 0; + } + +} + +static void +or32_ci( uint64_t r, uint32_t m ) +{ + uint32_t v; + + v = load32_ci( r ); + v |= m; + store32_ci( r, v ); +} + +static void +and32_ci( uint64_t r, uint32_t m ) +{ + uint32_t v; + + v = load32_ci( r ); + v &= m; + store32_ci( r, v ); +} + +static void +dly( uint64_t volatile f_wait_u64 ) \ +{ + while( f_wait_u64 ) { + f_wait_u64--; + } +} + +/* + * local i2c access functions + */ +static void +i2c_term( void ) +{ + uint32_t l_stat_u32; + + /* + * clear out all pending int's and wait + * for the stop condition to occur + */ + do { + l_stat_u32 = load32_ci( I2C_ISR_R ); + store32_ci( I2C_ISR_R, l_stat_u32 ); + } while( ( l_stat_u32 & IBIT(29) ) == 0 ); + +} + +static int32_t +i2c_read( uint32_t f_addr_u32, uint32_t f_suba_u32, uint8_t *f_buf_pu08, uint32_t f_len_u32 ) +{ + uint32_t l_val_u32; + int32_t l_ret_i32 = 1; + + /* + * parameter check + */ + if( ( f_addr_u32 > (uint32_t) 0x7f ) || + ( f_suba_u32 > (uint32_t) 0xff ) || + ( f_len_u32 == (uint32_t) 0x00 ) ) { + return RET_ERR; + } + + /* + * set I2C Interface to combined mode + */ + store32_ci( I2C_MODE_R, IBIT(28) | IBIT(29) ); + + /* + * set address, subaddress & read mode + */ + store32_ci( I2C_ADDR_R, ( f_addr_u32 << 1 ) | (uint32_t) 0x1 ); + store32_ci( I2C_SUBA_R, f_suba_u32 ); + + /* + * start address transmission phase + */ + store32_ci( I2C_CTRL_R, IBIT(30) ); + + /* + * wait for address transmission to finish + */ + do { + l_val_u32 = load32_ci( I2C_ISR_R ); + } while( ( l_val_u32 & IBIT(30) ) == 0 ); + + /* + * check for success + */ + if( ( load32_ci( I2C_STAT_R ) & IBIT(30) ) == 0 ) { + i2c_term(); + return RET_ERR; + } else { + // send ack + store32_ci( I2C_CTRL_R, IBIT(31) ); + // clear int + store32_ci( I2C_ISR_R, IBIT(30) ); + } + + /* + * read data + */ + while( l_ret_i32 > 0 ) { + l_val_u32 = load32_ci( I2C_ISR_R ); + + if( ( l_val_u32 & IBIT(31) ) != 0 ) { + // data was received + *f_buf_pu08 = ( uint8_t ) load32_ci( I2C_DATA_R ); + + f_buf_pu08++; + f_len_u32--; + + /* + * continue when there is more data to read or + * exit if not + */ + if( f_len_u32 != 0 ) { + // send ack + store32_ci( I2C_CTRL_R, IBIT(31) ); + // clear int + store32_ci( I2C_ISR_R, IBIT(31) ); + } else { + // send nack + store32_ci( I2C_CTRL_R, 0 ); + // set exit flag + l_ret_i32 = RET_OK; + } + + } else if( ( l_val_u32 & IBIT(29) ) != 0 ) { + // early stop condition + // set exit flag + l_ret_i32 = RET_ERR; + } + + }; + + i2c_term(); + + return( l_ret_i32 ); +} + +static uint32_t +i2c_get_slot( uint32_t i2c_addr ) +{ + uint32_t slot; + + slot = ( i2c_addr - I2C_START ) / 2; + + if( ( i2c_addr & 0x1 ) != 0 ) { + slot += SLOT_ADJ(); + } + + return slot; +} + +/* + * 'serial presence detect' interpretation functions + */ +static uint32_t +ddr2_get_dimm_rank( uint8_t *f_spd_pu08 ) +{ + static const int RANK_IDX = (int) 5; + + return (uint32_t) ( f_spd_pu08[RANK_IDX] & 0x3 ) + 1; +} + +static uint32_t +ddr2_get_dimm_size( uint8_t *f_spd_pu08 ) +{ + static const int SIZE_IDX = (int) 31; + uint8_t l_smsk_u08; + uint32_t i; + + l_smsk_u08 = ( f_spd_pu08[SIZE_IDX] << 3 ) | + ( f_spd_pu08[SIZE_IDX] >> 5 ); + + for( i = 0; ( ( l_smsk_u08 & ( (uint8_t) 0x1 << i ) ) == 0 ) ; i++ ); + + return (uint32_t) 0x80 << i; +} + +static uint32_t +ddr2_get_dimm_type( uint8_t *f_spd_pu08 ) +{ + static const int TYPE_IDX = (int) 20; + + return (uint32_t) f_spd_pu08[TYPE_IDX] & DIMM_TYPE_MSK; +} + +static uint32_t +ddr2_get_dimm_org( uint8_t *f_spd_pu08, uint32_t /*out*/ *f_omsk_pu32 ) +{ + static const int ORG_IDX = (int) 13; + uint32_t l_ret_u32 = (uint32_t) f_spd_pu08[ORG_IDX]; + + if( l_ret_u32 == 4 ) { + *f_omsk_pu32 = DIMM_ORG_x4; + } else if( l_ret_u32 == 8 ) { + *f_omsk_pu32 = DIMM_ORG_x8; + *f_omsk_pu32 |= DIMM_ORG_MIXx8x16; + } else if( l_ret_u32 == 16 ) { + *f_omsk_pu32 = DIMM_ORG_x16; + *f_omsk_pu32 |= DIMM_ORG_MIXx8x16; + } else { + *f_omsk_pu32 = DIMM_ORG_UNKNOWN; + l_ret_u32 = (uint32_t) ~0; + } + + return l_ret_u32; +} + +static uint32_t +ddr2_get_dimm_width( uint8_t *f_spd_pu08 ) +{ + static const int WIDTH_IDX = (int) 6; + + return (uint32_t) f_spd_pu08[WIDTH_IDX]; +} + +static uint32_t +ddr2_get_dimm_ecc( uint8_t *f_spd_pu08 ) +{ + static const int ECC_IDX = (int) 11; + + return ( f_spd_pu08[ECC_IDX] & BIT(1) ) != 0; +} + +static uint32_t +ddr2_get_dimm_burstlen( uint8_t *f_spd_pu08 ) +{ + static const int BURST_IDX = (int) 16; + + return (uint32_t) f_spd_pu08[BURST_IDX]; +} + +static void +ddr2_get_dimm_speed( dimm_t *f_dimm, uint8_t *f_spd_pu08 ) +{ + static const int SPEED_IDX[] = { 25, 23, 9 }; + static const uint32_t NS[] = { 25, 33, 66, 75 }; + uint8_t l_tmp_u08; + uint32_t l_dspeed_u32; + uint32_t idx = 0; + uint32_t i; + + for( i = NUM_CL - f_dimm->m_clcnt_u32; i < NUM_CL; i++ ) { + l_tmp_u08 = f_spd_pu08[SPEED_IDX[i]]; + l_dspeed_u32 = (uint32_t) ( l_tmp_u08 >> 4 ) * 100; + l_tmp_u08 &= (uint8_t) 0xf; + + if( l_tmp_u08 >= (uint8_t) 10 ) { + l_dspeed_u32 += NS[l_tmp_u08 - 10]; + } else { + l_dspeed_u32 += (uint32_t) l_tmp_u08 * 10; + } + + f_dimm->m_tCK_pu32[idx] = l_dspeed_u32; + f_dimm->m_speed_pu32[idx] = (uint32_t) 2000000 / l_dspeed_u32; + f_dimm->m_speed_pu32[idx] += (uint32_t) 5; + f_dimm->m_speed_pu32[idx] /= (uint32_t) 10; + idx++; + } + +} + +static void +ddr2_get_dimm_timings( dimm_t *f_dimm, uint8_t *f_spd_pu08 ) +{ + static const uint32_t NS[] = { 00, 25, 33, 50, 66, 75, 00, 00 }; + static const uint32_t USMUL = (uint32_t) 390625; + static const int tREF_IDX = (int) 12; + static const int tRP_IDX = (int) 27; + static const int tRRD_IDX = (int) 28; + static const int tRCD_IDX = (int) 29; + static const int tRAS_IDX = (int) 30; + static const int tWR_IDX = (int) 36; + static const int tWTR_IDX = (int) 37; + static const int tRTP_IDX = (int) 38; + static const int tRC_IDX = (int) 41; // & 40 + static const int tRFC_IDX = (int) 42; // & 40 + + uint32_t l_tmp_u32; + + f_dimm->m_tRP_u32 = (uint32_t) f_spd_pu08[tRP_IDX] * 25; + f_dimm->m_tRRD_u32 = (uint32_t) f_spd_pu08[tRRD_IDX] * 25; + f_dimm->m_tRCD_u32 = (uint32_t) f_spd_pu08[tRCD_IDX] * 25; + f_dimm->m_tWR_u32 = (uint32_t) f_spd_pu08[tWR_IDX] * 25; + f_dimm->m_tWTR_u32 = (uint32_t) f_spd_pu08[tWTR_IDX] * 25; + f_dimm->m_tRTP_u32 = (uint32_t) f_spd_pu08[tRTP_IDX] * 25; + f_dimm->m_tRAS_u32 = (uint32_t) f_spd_pu08[tRAS_IDX] * 100; + + l_tmp_u32 = (uint32_t) ( f_spd_pu08[tRC_IDX - 1] >> 4 ); + l_tmp_u32 &= (uint32_t) 0x7; + f_dimm->m_tRC_u32 = (uint32_t) f_spd_pu08[tRC_IDX] * 100 + + NS[l_tmp_u32]; + + l_tmp_u32 = (uint32_t) f_spd_pu08[tRFC_IDX - 2]; + l_tmp_u32 &= (uint32_t) 0xf; + f_dimm->m_tRFC_u32 = (uint32_t) 256 * ( l_tmp_u32 & (uint32_t) 0x1 ); + f_dimm->m_tRFC_u32 += (uint32_t) f_spd_pu08[tRFC_IDX]; + f_dimm->m_tRFC_u32 *= 100; + l_tmp_u32 >>= 1; + f_dimm->m_tRFC_u32 += NS[l_tmp_u32]; + + l_tmp_u32 = (uint32_t) f_spd_pu08[tREF_IDX]; + l_tmp_u32 &= (uint32_t) 0x7f; + + if( l_tmp_u32 == 0 ) { + l_tmp_u32 = (uint32_t) 2; + } else if( l_tmp_u32 <= (uint32_t) 2 ) { + l_tmp_u32--; + } + + f_dimm->m_tREF_u32 = ( l_tmp_u32 + 1 ) * USMUL; +} + +static uint32_t +ddr2_get_banks( uint8_t *f_spd_pu08 ) +{ + static const int BANK_IDX = (int) 17; + + return (uint32_t) f_spd_pu08[BANK_IDX]; +} + +static uint32_t +ddr2_get_cl_mask( uint8_t *f_spd_pu08 ) +{ + static const int CL_IDX = (int) 18; + + return (uint32_t) f_spd_pu08[CL_IDX]; +} + +static void +ddr2_get_cl( dimm_t *f_dimm ) +{ + uint32_t l_clcnt_u32 = 0; + uint32_t i; + + for( i = 0; ( i < 8 ) && ( l_clcnt_u32 < NUM_CL ) ; i++ ) { + + if( ( f_dimm->m_clmsk_u32 & ( (uint32_t) 0x1 << i ) ) != 0 ) { + f_dimm->m_clval_pu32[l_clcnt_u32] = i; + l_clcnt_u32++; + } + + } + + f_dimm->m_clcnt_u32 = l_clcnt_u32; +} + +static uint32_t +ddr2_cl2speed( dimm_t *f_dimm, uint32_t f_cl_u32, uint32_t *f_tCK_pu32 ) +{ + uint32_t i; + + for(i = 0; (i < NUM_CL) && (f_dimm->m_clval_pu32[i] != f_cl_u32); i++); + + if( i == NUM_CL ) { + return (uint32_t) ~0; + } + + *f_tCK_pu32 = f_dimm->m_tCK_pu32[i]; + + return f_dimm->m_speed_pu32[i]; +} + +static void +ddr2_setupDIMM( dimm_t *f_dimm, uint32_t f_bank_u32, uint8_t *f_spd_pu08 ) +{ + f_dimm->m_pop_u32 = SL_POP; + f_dimm->m_bank_u32 = f_bank_u32; + f_dimm->m_size_u32 = ddr2_get_dimm_size( f_spd_pu08 ); + f_dimm->m_rank_u32 = ddr2_get_dimm_rank( f_spd_pu08 ); + f_dimm->m_type_u32 = ddr2_get_dimm_type( f_spd_pu08 ); + f_dimm->m_orgval_u32 = ddr2_get_dimm_org( f_spd_pu08, &f_dimm->m_orgmsk_u32 ); + f_dimm->m_width_u32 = ddr2_get_dimm_width( f_spd_pu08 ); + f_dimm->m_ecc_u32 = ddr2_get_dimm_ecc( f_spd_pu08 ); + f_dimm->m_burst_u32 = ddr2_get_dimm_burstlen( f_spd_pu08 ); + f_dimm->m_clmsk_u32 = ddr2_get_cl_mask( f_spd_pu08 ); + f_dimm->m_bankcnt_u32 = ddr2_get_banks( f_spd_pu08 ); + + ddr2_get_cl( f_dimm ); + ddr2_get_dimm_speed( f_dimm, f_spd_pu08 ); + ddr2_get_dimm_timings( f_dimm, f_spd_pu08 ); +} + +static int32_t +ddr2_checkSPD( uint8_t *f_spd_pu08 ) +{ + uint8_t crc = 0; + uint32_t i; + + for( i = 0; i < SPD_BUF_SIZE - 1; i++ ) { + crc += f_spd_pu08[i]; + } + + if( crc != f_spd_pu08[i] ) { + return RET_ERR; + } + + return RET_OK; +} + +static int32_t +ddr2_readSPDs( void ) +{ + static const uint32_t MAX_SPD_FAIL = 3; + uint8_t l_spdbuf_pu08[SPD_BUF_SIZE]; + uint32_t l_bankfail_u32 = 0; + uint32_t l_spdfail_u32 = 0; + int32_t l_i2c_i32 = RET_OK; + int32_t l_spd_i32 = RET_OK; + int32_t ret = RET_OK; + uint32_t i; + + /* + * read spd's and detect populated slots + */ + for( i = 0; i < NUM_SLOTS; i++ ) { + /* + * indicate slot as empty + */ + m_dimm[i].m_pop_u32 = 0; + + /* + * check whether bank is switched off + */ + if( ( m_bankoff_u32 & ( 0x1 << ( i / 2 ) ) ) != 0 ) { + continue; + } + + /* + * read SPD data + */ + + /* + * reset SPD fail counter + */ + l_spdfail_u32 = MAX_SPD_FAIL; + l_spd_i32 = RET_OK; + + while( l_spdfail_u32 != 0 ) { + l_i2c_i32 = i2c_read( I2C_START + i, 0x0, l_spdbuf_pu08, SPD_BUF_SIZE ); + + if( l_i2c_i32 == RET_OK ) { + l_spd_i32 = ddr2_checkSPD( l_spdbuf_pu08 ); + + if( l_spd_i32 == RET_OK ) { + l_spdfail_u32 = 0; + } else { + l_spdfail_u32--; + } + + } else { + l_spdfail_u32--; + } + + } + + if( l_spd_i32 != RET_OK ) { + #ifdef U4_INFO + printf( "\r\n [ERROR -> SPD read failure in slot %u]", + i2c_get_slot( I2C_START + i ) ); + #endif + + l_bankfail_u32 |= ( 0x1 << ( i / 2 ) ); + ret = RET_ERR; + } else if( l_i2c_i32 == RET_OK ) { + /* + * slot is populated + */ + ddr2_setupDIMM( &m_dimm[i], i / 2, l_spdbuf_pu08 ); + + m_dptr[m_dcnt_u32] = &m_dimm[i]; + m_dcnt_u32++; + } + + } + + if( ret != RET_OK ) { + m_bankoff_u32 |= l_bankfail_u32; + #ifdef U4_INFO + printf( "\r\n" ); + #endif + } + + return ret; +} + +static int32_t +ddr2_setupDIMMcfg( void ) +{ + uint32_t l_tmp_u32; + uint32_t l_tmp0_u32; + uint32_t l_tmp1_u32; + uint32_t i, j, e, b; + + /* + * check wether on board DIMM slot population is valid + */ + e = 0; + b = 0; + for( i = 0; i < NUM_SLOTS; i += 2 ) { + + switch( m_dimm[i].m_pop_u32 + m_dimm[i+1].m_pop_u32 ) { + case 0: { + m_bankpop_u32[i/2] = 0; + break; + } + + case 2 * SL_POP: { + m_bankpop_u32[i/2] = !0; + b++; + break; + } + + default: { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> only 1 DIMM installed in bank %u]", i/2 ); + #endif + e++; + } + + } + + } + + /* + * return on error + */ + if( e != 0 ) { + #ifdef U4_DEBUG + printf( "\r\n" ); + #endif + return RET_ERR; + } + + if( b == 0 ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> no (functional) memory installed]\r\n" ); + #endif + return RET_ERR; + } + + /* + * check DIMM compatibility + * configuration is 128 bit data/128 bit bus + * -all DIMMs must be organized as x4 + * -all DIMMs must be 72 bit wide with ECC + * -all DIMMs must be registered DIMMs (RDIMMs) + * -paired DIMMs must have the same # of ranks, size & organization + */ + + /* + * check DIMM ranks & sizes + */ + e = 0; + for( i = 0; i < NUM_SLOTS; i += 2 ) { + + if( ( m_bankpop_u32[i/2] != 0 ) && + ( ( m_dimm[i].m_rank_u32 != m_dimm[i+1].m_rank_u32 ) || + ( m_dimm[i].m_size_u32 != m_dimm[i+1].m_size_u32 ) ) ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> installed DIMMs in bank %u have different ranks/sizes]", i/2 ); + #endif + e++; + } + + } + + /* + * return on error + */ + if( e != 0 ) { + #ifdef U4_DEBUG + printf( "\r\n" ); + #endif + return RET_ERR; + } + + /* + * check valid DIMM organisation (must be x4) + */ + e = 0; + for( i = 0; i < m_dcnt_u32; i++ ) { + + if( ( m_dptr[i]->m_orgmsk_u32 & DIMM_ORG_x4 ) == 0 ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> wrong DIMM organisation in bank %u]", + m_dptr[i]->m_bank_u32 ); + #endif + e++; + } + + } + + /* + * return on error + */ + if( e != 0 ) { + #ifdef U4_DEBUG + printf( "\r\n" ); + #endif + return RET_ERR; + } + + e = (uint32_t) ~0; + for( i = 0; i < m_dcnt_u32; i++ ) { + e &= m_dptr[i]->m_type_u32; + } + + /* + * return on error + */ + if( e == 0 ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> installed DIMMs are of different type]\r\n" ); + #endif + return RET_ERR; + } + + /* + * setup generic dimm + */ + m_gendimm.m_type_u32 = e; + + /* + * check valid width, ecc & burst length + */ + e = 0; + for( i = 0; i < m_dcnt_u32; i++ ) { + + if( m_dptr[i]->m_width_u32 != DIMM_WIDTH ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> invalid DIMM width in bank %u]", + m_dptr[i]->m_bank_u32 ); + #endif + e++; + } + + if( m_dptr[i]->m_ecc_u32 == 0 ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> DIMM(s) do not support ECC in bank %u]", + m_dptr[i]->m_bank_u32 ); + #endif + e++; + } + + if( ( m_dptr[i]->m_burst_u32 & DIMM_BURSTLEN_4 ) == 0 ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> DIMM(s) have invalid burst length in bank %u]", + m_dptr[i]->m_bank_u32 ); + #endif + e++; + } + + } + + /* + * return on error + */ + if( e != 0 ) { + #ifdef U4_DEBUG + printf( "\r\n" ); + #endif + return RET_ERR; + } + + /* + * setup generic dimm + */ + m_gendimm.m_width_u32 = m_dptr[0]->m_width_u32; + m_gendimm.m_ecc_u32 = m_dptr[0]->m_ecc_u32; + m_gendimm.m_burst_u32 = m_dptr[0]->m_burst_u32; + + /* + * success + */ + m_gendimm.m_pop_u32 = SL_POP; + + /* + * setup timing parameters + */ + + /* + * find smallest common CL value + */ + l_tmp_u32 = (uint32_t) ~0; + for( i = 0; i < m_dcnt_u32; i++ ) { + l_tmp_u32 &= m_dptr[i]->m_clmsk_u32; + } + + m_gendimm.m_clmsk_u32 = l_tmp_u32; + ddr2_get_cl( &m_gendimm ); + + /* + * find fastest common DIMM speed for all common CL values + */ + for( i = 0; i < m_gendimm.m_clcnt_u32; i++ ) { + m_gendimm.m_speed_pu32[i] = (uint32_t) ~0; + + for( j = 0; j < m_dcnt_u32; j++ ) { + l_tmp0_u32 = + ddr2_cl2speed( m_dptr[j], + m_gendimm.m_clval_pu32[i], + &l_tmp1_u32 ); + + if( m_gendimm.m_speed_pu32[i] > l_tmp0_u32 ) { + m_gendimm.m_speed_pu32[i] = l_tmp0_u32; + m_gendimm.m_tCK_pu32[i] = l_tmp1_u32; + } + + } + + } + + /* + * check wether cl values are supported by U4 + */ + for( i = 0; i < m_gendimm.m_clcnt_u32; i++ ) { + + if( ( m_gendimm.m_clval_pu32[i] >= U4_MIN_CL ) && + ( m_gendimm.m_clval_pu32[i] <= U4_MAX_CL ) ) { + break; + } + + } + + if( i == m_gendimm.m_clcnt_u32 ) { + #ifdef U4_DEBUG + printf( "\r\n [ERROR -> DIMM's CL values not supported]\r\n" ); + #endif + return RET_ERR; + } + + /* + * choose cl/speed values to use: prefer speed over CL + * i holds smallest supported cl value of u4 already + */ + l_tmp_u32 = 0; + while( i < m_gendimm.m_clcnt_u32 ) { + + if( l_tmp_u32 < m_gendimm.m_speed_pu32[i] ) { + l_tmp_u32 = m_gendimm.m_speed_pu32[i]; + m_dclidx_u32 = i; + } + + i++; + } + + /* + * choose largest number of banks + */ + m_gendimm.m_bankcnt_u32 = 0; + + for( i = 0; i < m_dcnt_u32; i++ ) { + + if( m_gendimm.m_bankcnt_u32 < m_dptr[i]->m_bankcnt_u32 ) { + m_gendimm.m_bankcnt_u32 = m_dptr[i]->m_bankcnt_u32; + } + + } + + /* + * setup fastest possible timing parameters for all DIMMs + */ + m_gendimm.m_tRP_u32 = 0; + m_gendimm.m_tRRD_u32 = 0; + m_gendimm.m_tRCD_u32 = 0; + m_gendimm.m_tWR_u32 = 0; + m_gendimm.m_tWTR_u32 = 0; + m_gendimm.m_tRTP_u32 = 0; + m_gendimm.m_tRAS_u32 = 0; + m_gendimm.m_tRC_u32 = 0; + m_gendimm.m_tRFC_u32 = 0; + m_gendimm.m_tREF_u32 = (uint32_t) ~0; + + for( i = 0; i < m_dcnt_u32; i++ ) { + + if( m_gendimm.m_tRP_u32 < m_dptr[i]->m_tRP_u32 ) { + m_gendimm.m_tRP_u32 = m_dptr[i]->m_tRP_u32; + } + + if( m_gendimm.m_tRRD_u32 < m_dptr[i]->m_tRRD_u32 ) { + m_gendimm.m_tRRD_u32 = m_dptr[i]->m_tRRD_u32; + } + + if( m_gendimm.m_tRCD_u32 < m_dptr[i]->m_tRCD_u32 ) { + m_gendimm.m_tRCD_u32 = m_dptr[i]->m_tRCD_u32; + } + + if( m_gendimm.m_tWR_u32 < m_dptr[i]->m_tWR_u32 ) { + m_gendimm.m_tWR_u32 = m_dptr[i]->m_tWR_u32; + } + + if( m_gendimm.m_tWTR_u32 < m_dptr[i]->m_tWTR_u32 ) { + m_gendimm.m_tWTR_u32 = m_dptr[i]->m_tWTR_u32; + } + + if( m_gendimm.m_tRTP_u32 < m_dptr[i]->m_tRTP_u32 ) { + m_gendimm.m_tRTP_u32 = m_dptr[i]->m_tRTP_u32; + } + + if( m_gendimm.m_tRAS_u32 < m_dptr[i]->m_tRAS_u32 ) { + m_gendimm.m_tRAS_u32 = m_dptr[i]->m_tRAS_u32; + } + + if( m_gendimm.m_tRC_u32 < m_dptr[i]->m_tRC_u32 ) { + m_gendimm.m_tRC_u32 = m_dptr[i]->m_tRC_u32; + } + + if( m_gendimm.m_tRFC_u32 < m_dptr[i]->m_tRFC_u32 ) { + m_gendimm.m_tRFC_u32 = m_dptr[i]->m_tRFC_u32; + } + + if( m_gendimm.m_tREF_u32 > m_dptr[i]->m_tREF_u32 ) { + m_gendimm.m_tREF_u32 = m_dptr[i]->m_tREF_u32; + } + + } + + return RET_OK; +} + +static void +u4_group2dimmsDS( dimm_t *f_dimm0, dimm_t *f_dimm1 ) +{ + dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32]; + + /* + * known conditions at this point: + * -at least 2 slots are populated + * -the 2 DIMMs are equal + * -DIMMs are double sided (2 ranks) + * + * RESULT: + * 1 group of 2 ranks (2 ranks/2 DIMMs) + * -> CS mode 1 (one double sided DIMM pair) + */ + l_dgr->m_size_u32 = 2 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 ); + l_dgr->m_ss_u32 = 0; + l_dgr->m_csmode_u32 = 1; + l_dgr->m_dcnt_u32 = 2; + l_dgr->m_dptr[0] = f_dimm0; + l_dgr->m_dptr[1] = f_dimm1; + + m_dgrcnt_u32++; +} + +static void +u4_group2dimmsSS( dimm_t *f_dimm0, dimm_t *f_dimm1 ) +{ + dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32]; + + /* + * known conditions at this point: + * -at least 2 slots are populated + * -the 2 DIMMs are equal + * -DIMMs are single sided (1 rank) + * + * RESULT: + * 1 group of 1 rank (1 rank/2 DIMMs) + * -> CS mode 0 (one single sided DIMM pair) + */ + l_dgr->m_size_u32 = 2 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 ); + l_dgr->m_ss_u32 = 1; + l_dgr->m_csmode_u32 = 0; + l_dgr->m_dcnt_u32 = 2; + l_dgr->m_dptr[0] = f_dimm0; + l_dgr->m_dptr[1] = f_dimm1; + + m_dgrcnt_u32++; +} + +static void +u4_group4dimmsDS( dimm_t *f_dimm0, dimm_t *f_dimm1, + dimm_t *f_dimm2, dimm_t *f_dimm3 ) +{ + dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32]; + + /* + * known conditions at this point: + * -4 slots are populated + * -all 4 DIMMs are equal + * -DIMMs are double sided (2 ranks) + * + * RESULT: + * 1 group of 4 ranks (2 ranks/2 DIMMs) + * -> CS mode 2 (two double sided DIMM pairs) + */ + l_dgr->m_size_u32 = 4 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 ); + l_dgr->m_ss_u32 = 0; + l_dgr->m_csmode_u32 = 2; + l_dgr->m_dcnt_u32 = 4; + l_dgr->m_dptr[0] = f_dimm0; + l_dgr->m_dptr[1] = f_dimm1; + l_dgr->m_dptr[2] = f_dimm2; + l_dgr->m_dptr[3] = f_dimm3; + + m_dgrcnt_u32++; +} + +static void +u4_group4dimmsSS( dimm_t *f_dimm0, dimm_t *f_dimm1, + dimm_t *f_dimm2, dimm_t *f_dimm3 ) +{ + dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32]; + + /* + * known conditions at this point: + * -4 slots are populated + * -all 4 DIMMs are equal + * -DIMMs are single sided (1 rank) + * + * RESULT: + * 1 group of 2 ranks (1 rank/2 DIMMs) + * -> CS mode 1 (two single sided DIMM pairs) + */ + l_dgr->m_size_u32 = 4 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 ); + l_dgr->m_ss_u32 = 1; + l_dgr->m_csmode_u32 = 1; + l_dgr->m_dcnt_u32 = 4; + l_dgr->m_dptr[0] = f_dimm0; + l_dgr->m_dptr[1] = f_dimm1; + l_dgr->m_dptr[2] = f_dimm2; + l_dgr->m_dptr[3] = f_dimm3; + + m_dgrcnt_u32++; +} + +static void +u4_group8dimmsDS( dimm_t *f_dimm0, dimm_t *f_dimm1, + dimm_t *f_dimm2, dimm_t *f_dimm3, + dimm_t *f_dimm4, dimm_t *f_dimm5, + dimm_t *f_dimm6, dimm_t *f_dimm7 ) +{ + dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32]; + + /* + * known conditions at this point: + * -8 slots are populated + * -all 8 DIMMs are equal + * -DIMMs are double sided (2 ranks) + * + * RESULT: + * 1 group of 8 ranks (2 ranks/2 DIMMs) + * -> CS mode 3 (four double sided DIMM pairs) + */ + l_dgr->m_size_u32 = 8 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 ); + l_dgr->m_ss_u32 = 0; + l_dgr->m_csmode_u32 = 3; + l_dgr->m_dcnt_u32 = 8; + l_dgr->m_dptr[0] = f_dimm0; + l_dgr->m_dptr[1] = f_dimm1; + l_dgr->m_dptr[2] = f_dimm2; + l_dgr->m_dptr[3] = f_dimm3; + l_dgr->m_dptr[4] = f_dimm4; + l_dgr->m_dptr[5] = f_dimm5; + l_dgr->m_dptr[6] = f_dimm6; + l_dgr->m_dptr[7] = f_dimm7; + + m_dgrcnt_u32++; +} + +static void +u4_group8dimmsSS( dimm_t *f_dimm0, dimm_t *f_dimm1, + dimm_t *f_dimm2, dimm_t *f_dimm3, + dimm_t *f_dimm4, dimm_t *f_dimm5, + dimm_t *f_dimm6, dimm_t *f_dimm7 ) +{ + dgroup_t *l_dgr = &m_dgroup[m_dgrcnt_u32]; + + /* + * known conditions at this point: + * -8 slots are populated + * -all 8 DIMMs are equal + * -DIMMs are single sided (1 rank) + * + * RESULT: + * 1 group of 4 ranks (1 rank/2 DIMMs) + * -> CS mode 2 (four single sided DIMM pairs) + */ + l_dgr->m_size_u32 = 8 * ( f_dimm0->m_size_u32 * f_dimm0->m_rank_u32 ); + l_dgr->m_ss_u32 = 1; + l_dgr->m_csmode_u32 = 2; + l_dgr->m_dcnt_u32 = 8; + l_dgr->m_dptr[0] = f_dimm0; + l_dgr->m_dptr[1] = f_dimm1; + l_dgr->m_dptr[2] = f_dimm2; + l_dgr->m_dptr[3] = f_dimm3; + l_dgr->m_dptr[4] = f_dimm4; + l_dgr->m_dptr[5] = f_dimm5; + l_dgr->m_dptr[6] = f_dimm6; + l_dgr->m_dptr[7] = f_dimm7; + + m_dgrcnt_u32++; +} + +static int32_t +u4_Dcmp( dimm_t *f_dimm0, dimm_t *f_dimm1 ) +{ + + if( ( f_dimm0->m_size_u32 == f_dimm1->m_size_u32 ) && + ( f_dimm0->m_rank_u32 == f_dimm1->m_rank_u32 ) ) { + return RET_OK; + } + + return RET_ERR; +} + +static void +u4_group1banks( uint32_t *bidx ) +{ + uint32_t didx = 2 * bidx[0]; + + /* + * known conditions at this point: + * -either DIMMs 0 & 4 or + * DIMMs 1 & 5 or + * DIMMs 2 & 6 or + * DIMMs 3 & 7 are populated + * -3 (bimini)/1 (maui) pair of slots is empty + * -installed DIMMs are equal + */ + + /* + * double/single sided setup + */ + if( m_dimm[didx].m_rank_u32 == 1 ) { + u4_group2dimmsSS( &m_dimm[didx], &m_dimm[didx+1] ); + } else { + u4_group2dimmsDS( &m_dimm[didx], &m_dimm[didx+1] ); + } + +} + +static void +u4_group2banks( uint32_t *bidx ) +{ + uint32_t didx0 = 2 * bidx[0]; + uint32_t didx1 = 2 * bidx[1]; + + /* + * known conditions at this point: + * -4 slots are populated + */ + + /* + * check wether DIMM banks may be grouped + */ + if( ( ( ( bidx[0] + bidx[1] ) & 0x1 ) != 0 ) && + ( u4_Dcmp( &m_dimm[didx0], &m_dimm[didx1] ) == 0 ) ) { + /* + * double/single sided setup + * NOTE: at this point all DIMMs have the same amount + * of ranks, therefore only the # of ranks on DIMM 0 is checked + */ + if( m_dimm[didx0].m_rank_u32 == 1 ) { + u4_group4dimmsSS( &m_dimm[didx0], &m_dimm[didx0+1], + &m_dimm[didx1], &m_dimm[didx1+1]); + } else { + u4_group4dimmsDS( &m_dimm[didx0], &m_dimm[didx0+1], + &m_dimm[didx1], &m_dimm[didx1+1]); + } + + } else { + u4_group1banks( &bidx[0] ); + u4_group1banks( &bidx[1] ); + } + +} + +static void +u4_group3banks( uint32_t *bidx ) +{ + + if( ( bidx[0] == 0 ) && ( bidx[1] == 1 ) ) { + u4_group2banks( &bidx[0] ); + u4_group1banks( &bidx[2] ); + } else if( ( bidx[1] == 2 ) && ( bidx[2] == 3 ) ) { + u4_group2banks( &bidx[1] ); + u4_group1banks( &bidx[0] ); + } + +} + +static void +u4_group4banks( uint32_t *bidx ) +{ + uint32_t didx0 = 2 * bidx[0]; + uint32_t didx1 = 2 * bidx[1]; + uint32_t didx2 = 2 * bidx[2]; + uint32_t didx3 = 2 * bidx[3]; + + if( ( u4_Dcmp( &m_dimm[didx0], &m_dimm[didx1] ) == RET_OK ) && + ( u4_Dcmp( &m_dimm[didx2], &m_dimm[didx3] ) == RET_OK ) && + ( u4_Dcmp( &m_dimm[didx0], &m_dimm[didx2] ) == RET_OK ) ) { + + if( m_dimm[didx0].m_rank_u32 == 1 ) { + u4_group8dimmsSS( &m_dimm[didx0], &m_dimm[didx0+1], + &m_dimm[didx1], &m_dimm[didx1+1], + &m_dimm[didx2], &m_dimm[didx2+1], + &m_dimm[didx3], &m_dimm[didx3+1] ); + } else { + u4_group8dimmsDS( &m_dimm[didx0], &m_dimm[didx0+1], + &m_dimm[didx1], &m_dimm[didx1+1], + &m_dimm[didx2], &m_dimm[didx2+1], + &m_dimm[didx3], &m_dimm[didx3+1] ); + } + + } else { + u4_group2banks( &bidx[0] ); + u4_group2banks( &bidx[2] ); + } + +} + +static void +u4_sortDIMMgroups( void ) +{ + uint32_t i, j; + + /* + * setup global group pointers + */ + for( i = 0; i < m_dgrcnt_u32; i++ ) { + m_dgrptr[i] = &m_dgroup[i]; + } + + /* + * use a simple bubble sort to sort groups by size (descending) + */ + for( i = 0; i < ( m_dgrcnt_u32 - 1 ); i++ ) { + + for( j = i + 1; j < m_dgrcnt_u32; j++ ) { + + if( m_dgrptr[i]->m_size_u32 < m_dgrptr[j]->m_size_u32 ) { + dgroup_t *l_sgr; + + l_sgr = m_dgrptr[i]; + m_dgrptr[i] = m_dgrptr[j]; + m_dgrptr[j] = l_sgr; + } + + } + + } + +} + +static void +u4_calcDIMMcnfg( void ) +{ + static const uint32_t _2GB = (uint32_t) 0x00800; + static const uint32_t _4GB = (uint32_t) 0x01000; + static const uint32_t _64GB = (uint32_t) 0x10000; + uint32_t l_start_u32 = (uint32_t) 0; + uint32_t l_end_u32 = (uint32_t) 0; + uint32_t l_add2g_u32 = (uint32_t) 1; + uint32_t l_sub2g_u32 = (uint32_t) 1; + uint32_t i; + + /* + * setup DIMM group parameters + */ + for( i = 0; i < m_dgrcnt_u32; i++ ) { + l_end_u32 = l_start_u32 + m_dgrptr[i]->m_size_u32; + + if( m_dgrptr[i]->m_size_u32 > _2GB ) { + + if( l_end_u32 < _64GB ) { + l_add2g_u32 = ( l_end_u32 >> 11 ); + } else { + l_add2g_u32 = 1; + } + + if( l_start_u32 == 0 ) { + l_sub2g_u32 = 1; + } else { + l_sub2g_u32 = ( l_start_u32 >> 11 ); + } + + } else if( l_add2g_u32 != 1 ) { + l_start_u32 += _2GB; + l_end_u32 += _2GB; + l_add2g_u32 = 1; + l_sub2g_u32 = 1; + } + + /* + * save values for the group + */ + m_dgrptr[i]->m_start_u32 = ( l_start_u32 >> 7 ); // = /128 + m_dgrptr[i]->m_end_u32 = ( l_end_u32 >> 7 ); + m_dgrptr[i]->m_add2g_u32 = l_add2g_u32; + m_dgrptr[i]->m_sub2g_u32 = l_sub2g_u32; + + /* + * continue with next group + */ + if( l_end_u32 != _2GB ) { + l_start_u32 = l_end_u32; + } else { + l_start_u32 = _4GB; + } + + } + +} + +static int32_t +u4_calcDIMMmemmode( void ) +{ + static const uint32_t MAX_ORG = (uint32_t) 0x10; + static const uint32_t MIN_BASE = (uint32_t) 0x80; + static const uint32_t MAX_MODE = (uint32_t) 0x10; + static const uint32_t MODE_ADD = (uint32_t) 0x04; + dimm_t *l_dptr; + uint32_t l_modeoffs_u32; + uint32_t l_sizebase_u32; + int32_t ret = RET_OK; + uint32_t i, j; + + /* + * loop through all DIMM groups and calculate memmode setting + */ + for( i = 0; i < m_dgrcnt_u32; i++ ) { + l_dptr = m_dgrptr[i]->m_dptr[0]; // all dimms in one group are equal! + + l_modeoffs_u32 = MAX_ORG / l_dptr->m_orgval_u32; + l_modeoffs_u32 /= (uint32_t) 2; + l_sizebase_u32 = ( MIN_BASE << l_modeoffs_u32 ); + + j = 0; + while( ( l_sizebase_u32 != l_dptr->m_size_u32 ) && + ( j < MAX_MODE ) ) { + l_sizebase_u32 <<= 1; + j += (uint32_t) MODE_ADD; + } + + // return on error + if( j >= MAX_MODE ) { + #ifdef U4_INFO + uint32_t b, k, l; + printf( "\r\n [ERROR -> unsupported memory type in bank(s)" ); + + l = 0; + for( k = 0; k < m_dgrptr[i]->m_dcnt_u32; k++ ) { + b = m_dgrptr[i]->m_dptr[k]->m_bank_u32; + + if( ( l & ( 1 << b ) ) == 0 ) { + printf( " %u", b ); + l |= ( 1 << b ); + } + + } + + printf( "]\r\n" ); + #endif + + ret = RET_ERR; + } else { + m_dgrptr[i]->m_memmd_u32 = l_modeoffs_u32 + j; + } + + } + + return ret; +} + +static void +u4_setupDIMMgroups( void ) +{ + static const uint64_t _1MB = (uint64_t) 0x100000; + uint32_t l_bcnt_u32; + uint32_t l_bidx_u32[NUM_BANKS]; + uint32_t i; + + /* + * calculate number of populated banks + * IMPORTANT: array must be in ascending order! + */ + l_bcnt_u32 = 0; + for( i = 0; i < NUM_BANKS; i++ ) { + + if( m_bankpop_u32[i] != 0 ) { + l_bidx_u32[l_bcnt_u32] = i; + l_bcnt_u32++; + } + + } + + switch( l_bcnt_u32 ) { + case 4: u4_group4banks( &l_bidx_u32[0] ); break; + case 3: u4_group3banks( &l_bidx_u32[0] ); break; + case 2: u4_group2banks( &l_bidx_u32[0] ); break; + case 1: u4_group1banks( &l_bidx_u32[0] ); break; + } + + /* + * sort DIMM groups by size (descending) + */ + u4_sortDIMMgroups(); + + /* + * calculate overall memory size in bytes + * (group size is in MB) + */ + m_memsize_u64 = 0; + for( i = 0; i < m_dgrcnt_u32; i++ ) { + m_memsize_u64 += (uint64_t) m_dgrptr[i]->m_size_u32 * _1MB; + } + +} + +static int32_t +u4_setup_core_clock( void ) +{ + static const uint32_t MCLK = (uint32_t) 266; + static const uint32_t CDIV = (uint32_t) 66; + static const uint32_t CMAX = (uint32_t) 7; + static const uint32_t MERR = (uint32_t) 10; + uint32_t volatile l_cclk_u32; + uint32_t volatile l_pll2_u32; + uint32_t i, s; + + #ifdef U4_INFO + printf( " [core clock reset: ]" ); + #endif + + /* + * calculate speed value + */ + s = m_gendimm.m_speed_pu32[m_dclidx_u32]; + s -= MCLK; + s /= CDIV; + + /* + * insert new core clock value + */ + l_cclk_u32 = load32_ci( ClkCntl_R ); + l_cclk_u32 &= ~CLK_DDR_CLK_MSK; + l_cclk_u32 |= ( s << 18 ); + + + // return on error + if( s > CMAX ) { + #ifdef U4_INFO + printf( "\b\b\b\bERR\r\n" ); + #endif + return RET_ERR; + } + + /* + * reset core clock + */ + store32_ci( ClkCntl_R, l_cclk_u32 ); + dly( 0x1000000 ); + or32_ci( PLL2Cntl_R, IBIT(0) ); + dly( 0x1000000 ); + + /* + * wait for reset to finish + */ + do { + l_pll2_u32 = load32_ci( PLL2Cntl_R ); + } while( ( l_pll2_u32 & IBIT(0) ) != 0 ); + + /* + * wait for stable PLL + */ + s = 0; + do { + l_pll2_u32 = ( load32_ci( PLL2Cntl_R ) & IBIT(2) ); + + for( i = 0; i < 4; i++ ) { + l_pll2_u32 &= ( load32_ci( PLL2Cntl_R ) & IBIT(2) ); + l_pll2_u32 &= ( load32_ci( PLL2Cntl_R ) & IBIT(2) ); + l_pll2_u32 &= ( load32_ci( PLL2Cntl_R ) & IBIT(2) ); + dly( 0x10000 ); + } + + } while( ( l_pll2_u32 == 0 ) && ( s++ < MERR ) ); + + if( s >= MERR ) { + #ifdef U4_INFO + printf( "\b\b\b\bERR\r\n" ); + #endif + return RET_ERR; + } + + #ifdef U4_INFO + printf( "\b\b\bOK\r\n" ); + #endif + + return RET_OK; +} + +static void +u4_auto_calib_init( void ) +{ + static const uint32_t SEQ[] = { + 0xb1000000, 0xd1000000, 0xd1000000, 0xd1000000, + 0xd1000000, 0xd1000000, 0xd1000000, 0xd1000000, + 0xd1000000, 0xd1000000, 0xd1000000, 0xd1000000, + 0xd1000000, 0xd1000000, 0xd1000400, 0x00000000, + }; + + uint64_t i; + uint32_t j; + + for( i = MemInit00_R, j = 0; i <= MemInit15_R; i += 0x10, j++ ) { + store32_ci( i, SEQ[j] ); + } + +} + +#if 0 +static uint32_t +u4_RSL_BLane( uint32_t f_Rank_u32, uint32_t f_BLane_u32 ) +{ + static const uint32_t MemProgCntl_V = (uint32_t) 0x80000500; + static const uint32_t CalConf0_V = (uint32_t) 0x0000aa10; + uint32_t l_MemProgCntl_u32; + uint32_t l_CalConf0_u32; + uint32_t l_MeasStat_u32; + uint32_t l_CalC_u32; + uint64_t MeasStat_R; + uint64_t CalC_R; + uint64_t VerC_R; + uint32_t shft; + uint32_t v; + + if( f_BLane_u32 < 4 ) { + MeasStat_R = MeasStatusC0_R; + CalC_R = CalC0_R; + VerC_R = RstLdEnVerniersC0_R; + } else if( f_BLane_u32 < 8 ) { + f_BLane_u32 -= 4; + MeasStat_R = MeasStatusC1_R; + CalC_R = CalC1_R; + VerC_R = RstLdEnVerniersC1_R; + } else if( f_BLane_u32 < 12 ) { + f_BLane_u32 -= 8; + MeasStat_R = MeasStatusC2_R; + CalC_R = CalC2_R; + VerC_R = RstLdEnVerniersC2_R; + } else if( f_BLane_u32 == 16 ) { + f_BLane_u32 = 4; + MeasStat_R = MeasStatusC1_R; + CalC_R = CalC1_R; + VerC_R = RstLdEnVerniersC1_R; + } else if( f_BLane_u32 == 17 ) { + f_BLane_u32 = 4; + MeasStat_R = MeasStatusC3_R; + CalC_R = CalC3_R; + VerC_R = RstLdEnVerniersC3_R; + } else { + f_BLane_u32 -= 12; + MeasStat_R = MeasStatusC3_R; + CalC_R = CalC3_R; + VerC_R = RstLdEnVerniersC3_R; + } + + shft = (uint32_t) 28 - ( f_BLane_u32 * 4 ); + + /* + * start auto calibration logic & wait for completion + */ + or32_ci( MeasStat_R, IBIT(0) ); + + do { + l_MeasStat_u32 = load32_ci( MeasStat_R ); + } while( ( l_MeasStat_u32 & IBIT(0) ) == 1 ); + + l_CalConf0_u32 = CalConf0_V; + store32_ci( CalConf0_R, l_CalConf0_u32 ); + + for( v = 0x000; v < (uint32_t) 0x100; v++ ) { + store32_ci( VerC_R, ( v << 24 ) | ( v << 16 ) ); + + l_MemProgCntl_u32 = MemProgCntl_V; + l_MemProgCntl_u32 |= + ( (uint32_t) 0x00800000 >> f_Rank_u32 ); + store32_ci( MemProgCntl_R, l_MemProgCntl_u32 ); + + do { + l_MemProgCntl_u32 = load32_ci( MemProgCntl_R ); + } while( ( l_MemProgCntl_u32 & IBIT(1) ) == 0 ); + + l_CalC_u32 = ( ( load32_ci( CalC_R ) >> shft ) & + (uint32_t) 0xf ); + + if( l_CalC_u32 != (uint32_t) 0xa ) { + v--; + break; + } + + } + + if( v == (uint32_t) 0x100 ) { + v = (uint32_t) ~1; + } + + return v; +} +#endif + +static uint32_t +u4_RMDF_BLane( uint32_t f_Rank_u32, uint32_t f_BLane_u32 ) +{ + static const uint32_t MemProgCntl_V = (uint32_t) 0x80000f00; + static const uint32_t CalConf0_V = (uint32_t) 0x0000ac10; + uint32_t l_MemProgCntl_u32; + uint32_t l_CalConf0_u32; + uint32_t l_MeasStat_u32; + uint32_t l_CalC_u32; + uint64_t MeasStat_R; + uint64_t CalC_R; + uint64_t VerC_R; + uint32_t shft; + uint32_t v; + + if( f_BLane_u32 < 4 ) { + MeasStat_R = MeasStatusC0_R; + CalC_R = CalC0_R; + VerC_R = RstLdEnVerniersC0_R; + } else if( f_BLane_u32 < 8 ) { + f_BLane_u32 -= 4; + MeasStat_R = MeasStatusC1_R; + CalC_R = CalC1_R; + VerC_R = RstLdEnVerniersC1_R; + } else if( f_BLane_u32 < 12 ) { + f_BLane_u32 -= 8; + MeasStat_R = MeasStatusC2_R; + CalC_R = CalC2_R; + VerC_R = RstLdEnVerniersC2_R; + } else if( f_BLane_u32 == 16 ) { + f_BLane_u32 = 4; + MeasStat_R = MeasStatusC1_R; + CalC_R = CalC1_R; + VerC_R = RstLdEnVerniersC1_R; + } else if( f_BLane_u32 == 17 ) { + f_BLane_u32 = 4; + MeasStat_R = MeasStatusC3_R; + CalC_R = CalC3_R; + VerC_R = RstLdEnVerniersC3_R; + } else { + f_BLane_u32 -= 12; + MeasStat_R = MeasStatusC3_R; + CalC_R = CalC3_R; + VerC_R = RstLdEnVerniersC3_R; + } + + shft = (uint32_t) 28 - ( f_BLane_u32 * 4 ); + + /* + * start auto calibration logic & wait for completion + */ + or32_ci( MeasStat_R, IBIT(0) ); + + do { + l_MeasStat_u32 = load32_ci( MeasStat_R ); + } while( ( l_MeasStat_u32 & IBIT(0) ) == 1 ); + + l_CalConf0_u32 = CalConf0_V; + l_CalConf0_u32 |= ( f_BLane_u32 << 5 ); + store32_ci( CalConf0_R, l_CalConf0_u32 ); + + for( v = 0x000; v < (uint32_t) 0x100; v++ ) { + store32_ci( VerC_R, ( v << 24 ) | ( v << 16 ) ); + + l_MemProgCntl_u32 = MemProgCntl_V; + l_MemProgCntl_u32 |= + ( (uint32_t) 0x00800000 >> f_Rank_u32 ); + store32_ci( MemProgCntl_R, l_MemProgCntl_u32 ); + + do { + l_MemProgCntl_u32 = load32_ci( MemProgCntl_R ); + } while( ( l_MemProgCntl_u32 & IBIT(1) ) == 0 ); + + l_CalC_u32 = ( ( load32_ci( CalC_R ) >> shft ) & + (uint32_t) 0xf ); + + if( l_CalC_u32 != (uint32_t) 0xa ) { + v--; + break; + } + + } + + if( v == (uint32_t) 0x100 ) { + v = (uint32_t) ~1; + } + + return v; +} + +static int32_t +u4_RMDF_Rank( uint32_t f_Rank_u32, + uint32_t *f_Buf_pu32 ) +{ + int32_t l_Err_pi32 = 0; + uint32_t b; + + for( b = 0; ( b < MAX_BLANE ) && ( l_Err_pi32 == 0 ); b++ ) { + f_Buf_pu32[b] = u4_RMDF_BLane( f_Rank_u32, b ); + + if( f_Buf_pu32[b] == (uint32_t) ~0 ) { + f_Buf_pu32[b] = 0; + l_Err_pi32++; + } else if( f_Buf_pu32[b] == (uint32_t) ~1 ) { + f_Buf_pu32[b] = (uint32_t) 0xff; + l_Err_pi32++; + } + + } + + return l_Err_pi32; +} + +static int32_t +u4_auto_calib_MemBus( auto_calib_t *f_ac_pt ) +{ + uint32_t RdMacDly, RdMacCnt; + uint32_t ResMuxDly, ResMuxCnt; + uint32_t RdPipeDly; + uint32_t l_Buf_pu32[MAX_DRANKS][MAX_BLANE]; + uint32_t l_Rnk_pu32[MAX_DRANKS]; + uint32_t l_Ver_u32; + int32_t l_Err_i32; + uint32_t bidx; + uint32_t n, r, b; + + /* + * read starting delays out of the MemBus register + */ + RdMacDly = ( load32_ci( MemBusCnfg_R ) >> 28 ) & 0xf; + ResMuxDly = ( load32_ci( MemBusCnfg_R ) >> 24 ) & 0xf; + + /* + * initialize ranks as not populated + */ + for( r = 0; r < MAX_DRANKS; r++ ) { + l_Rnk_pu32[r] = 0; + } + + /* + * run through every possible delays of + * RdMacDly, ResMuxDly & RdPipeDly until + * the first working configuration is found + */ + RdPipeDly = 0; + do { + and32_ci( MemBusCnfg2_R, ~0x3 ); + or32_ci( MemBusCnfg2_R, RdPipeDly ); + + RdMacCnt = RdMacDly; + ResMuxCnt = ResMuxDly; + + /* + * RdMacDly >= ResMuxDly + */ + do { + and32_ci( MemBusCnfg_R, ( 1 << 24 ) - 1 ); + or32_ci( MemBusCnfg_R, ( RdMacCnt << 28 ) | + ( ResMuxCnt << 24 ) ); + and32_ci( MemBusCnfg2_R, ( 1 << 28 ) - 1 ); + or32_ci( MemBusCnfg2_R, ( RdMacCnt << 28 ) ); + + /* + * check the current value for every installed + * DIMM on each side for every bytelane + */ + l_Err_i32 = 0; + for( n = 0; + ( n < NUM_SLOTS ) && + ( l_Err_i32 == 0 ); + n += 2 ) { + + if( m_dimm[n].m_pop_u32 ) { + /* + * run through all 18 bytelanes of every rank + */ + for( r = n; + ( r < n + m_dimm[n].m_rank_u32 ) && + ( l_Err_i32 == 0 ); + r++ ) { + l_Rnk_pu32[r] = 1; + + l_Err_i32 = + u4_RMDF_Rank( r, + &l_Buf_pu32[r][0] ); + } + + } + + } + + /* + * decrementation before exit is wanted! + */ + RdMacCnt--; + ResMuxCnt--; + } while( ( ResMuxCnt > 0 ) && + ( l_Err_i32 != 0 ) ); + + if( l_Err_i32 != 0 ) { + RdPipeDly++; + } + + } while( ( RdPipeDly < 4 ) && + ( l_Err_i32 != 0 ) ); + + /* + * if l_Err_pi32 == 0 the auto calibration passed ok + */ + if( l_Err_i32 != 0 ) { + return RET_ERR; + } + + /* + * insert delay values into return struct + */ + and32_ci( MemBusCnfg_R, ( 1 << 24 ) - 1 ); + or32_ci( MemBusCnfg_R, ( RdMacCnt << 28 ) | + ( ResMuxCnt << 24 ) ); + and32_ci( MemBusCnfg2_R, ( ( 1 << 28 ) - 1 ) & ~0x3 ); + or32_ci( MemBusCnfg2_R, ( RdMacCnt << 28 ) | RdPipeDly ); + + f_ac_pt->m_MemBusCnfg_u32 = load32_ci( MemBusCnfg_R ); + f_ac_pt->m_MemBusCnfg2_u32 = load32_ci( MemBusCnfg2_R ); + + /* + * calculate the average vernier setting for the + * bytelanes which share one vernier + */ + for( b = 0; b < MAX_BLANE - 2; b += 2 ) { + n = 0; + l_Ver_u32 = 0; + + for( r = 0; r < MAX_DRANKS; r++ ) { + /* + * calculation is done or populated ranks only + */ + if( l_Rnk_pu32[r] != 0 ) { + /* + * calculate average value + */ + l_Ver_u32 += l_Buf_pu32[r][b]; + l_Ver_u32 += l_Buf_pu32[r][b+1]; + n += 2; + + if( b == 4 ) { + l_Ver_u32 += l_Buf_pu32[r][16]; + n++; + } else if( b == 12 ) { + l_Ver_u32 += l_Buf_pu32[r][17]; + n++; + } + + } + + } + + /* + * average the values + */ + l_Ver_u32 /= n; + + /* + * set appropriate vernier register for + * the current bytelane + */ + bidx = ( b >> 2 ); + if( ( b & (uint32_t) 0x3 ) == 0 ) { + l_Ver_u32 <<= 24; + f_ac_pt->m_RstLdEnVerniers_pu32[bidx] = l_Ver_u32; + } else { + l_Ver_u32 <<= 16; + f_ac_pt->m_RstLdEnVerniers_pu32[bidx] |= l_Ver_u32; + } + + } + + return RET_OK; +} + +static int32_t +u4_auto_calib( auto_calib_t *f_ac_pt ) +{ + uint32_t l_MemBusCnfg_S; + uint32_t l_MemBusCnfg2_S; + uint32_t l_RstLdEnVerniers_S[4]; + int32_t l_Ret_i32; + + /* + * save manipulated registers + */ + l_MemBusCnfg_S = load32_ci( MemBusCnfg_R ); + l_MemBusCnfg2_S = load32_ci( MemBusCnfg2_R ); + l_RstLdEnVerniers_S[0] = load32_ci( RstLdEnVerniersC0_R ); + l_RstLdEnVerniers_S[1] = load32_ci( RstLdEnVerniersC1_R ); + l_RstLdEnVerniers_S[2] = load32_ci( RstLdEnVerniersC2_R ); + l_RstLdEnVerniers_S[3] = load32_ci( RstLdEnVerniersC3_R ); + + u4_auto_calib_init(); + l_Ret_i32 = u4_auto_calib_MemBus( f_ac_pt ); + + /* + * restore manipulated registers + */ + store32_ci( MemBusCnfg_R, l_MemBusCnfg_S ); + store32_ci( MemBusCnfg2_R, l_MemBusCnfg2_S ); + store32_ci( RstLdEnVerniersC0_R, l_RstLdEnVerniers_S[0] ); + store32_ci( RstLdEnVerniersC1_R, l_RstLdEnVerniers_S[1] ); + store32_ci( RstLdEnVerniersC2_R, l_RstLdEnVerniers_S[2] ); + store32_ci( RstLdEnVerniersC3_R, l_RstLdEnVerniers_S[3] ); + + return l_Ret_i32; +} + +static int32_t +u4_checkeccerr( eccerror_t *f_ecc_pt ) +{ + uint32_t l_val_u32; + int32_t ret = RET_OK; + + l_val_u32 = load32_ci( MESR_R ); + l_val_u32 >>= 29; + + if( ( l_val_u32 & (uint32_t) 0x7 ) != 0 ) { + + if( ( l_val_u32 & (uint32_t) 0x4 ) != 0 ) { + /* UE */ + ret = RET_ACERR_UE; + } else if( ( l_val_u32 & (uint32_t) 0x1 ) != 0 ) { + /* UEWT */ + ret = RET_ACERR_UEWT; + } else { + /* CE */ + ret = RET_ACERR_CE; + } + + } + + f_ecc_pt->m_err_i32 = ret; + + l_val_u32 = load32_ci( MEAR1_R ); + f_ecc_pt->m_uecnt_u32 = ( ( l_val_u32 >> 24 ) & (uint32_t) 0xff ); + f_ecc_pt->m_cecnt_u32 = ( ( l_val_u32 >> 16 ) & (uint32_t) 0xff ); + + l_val_u32 = load32_ci( MEAR0_R ); + f_ecc_pt->m_rank_u32 = ( ( l_val_u32 >> 29 ) & (uint32_t) 0x7 ); + f_ecc_pt->m_col_u32 = ( ( l_val_u32 >> 18 ) & (uint32_t) 0x7ff ); + f_ecc_pt->m_row_u32 = ( ( l_val_u32 >> 0 ) & (uint32_t) 0x7fff ); + f_ecc_pt->m_bank_u32 = ( ( l_val_u32 >> 15 ) & (uint32_t) 0x7 ); + + return ret; +} + +static uint32_t +u4_CalcScrubEnd( void ) +{ + uint64_t l_scrend_u64 = m_memsize_u64; + + /* + * check for memory hole at 2GB + */ + if( l_scrend_u64 > _2GB ) { + l_scrend_u64 += _2GB; + } + + l_scrend_u64 -= 0x40; + l_scrend_u64 /= 0x10; + + return( (uint32_t) l_scrend_u64 ); +} + +static int32_t +u4_Scrub( uint32_t f_scrub_u32, uint32_t f_pattern_u32, eccerror_t *f_eccerr_pt ) +{ + uint32_t i; + int32_t ret; + + /* + * setup scrub parameters + */ + store32_ci( MSCR_R, 0 ); // stop scrub + store32_ci( MSRSR_R, 0x0 ); // set start + store32_ci( MSRER_R, u4_CalcScrubEnd() ); // set end + store32_ci( MSPR_R, f_pattern_u32 ); // set pattern + + /* + * clear out ECC error registers + */ + store32_ci( MEAR0_R, 0x0 ); + store32_ci( MEAR1_R, 0x0 ); + store32_ci( MESR_R, 0x0 ); + + /* + * Setup Scrub Type + */ + store32_ci( MSCR_R, f_scrub_u32 ); + + if( f_scrub_u32 != BACKGROUND_SCRUB ) { + /* + * wait for scrub to complete + */ + do { + progbar(); + dly( 15000000 ); + i = load32_ci( MSCR_R ); + } while( ( i & f_scrub_u32 ) != 0 ); + + ret = u4_checkeccerr( f_eccerr_pt ); + } else { + ret = RET_OK; + } + + return ret; +} + +static eccerror_t +u4_InitialScrub( void ) +{ + eccerror_t l_eccerr_st[2]; + int32_t l_err_i32[2] = { 0, 0 }; + + l_err_i32[0] = u4_Scrub( IMMEDIATE_SCRUB_WITH_FILL, 0x0, &l_eccerr_st[0] ); + + if( l_err_i32[0] >= -1 /*CE*/ ) { + l_err_i32[1] = u4_Scrub( IMMEDIATE_SCRUB, 0x0, &l_eccerr_st[1] ); + } + + if( l_err_i32[0] < l_err_i32[1] ) { + return l_eccerr_st[0]; + } else { + return l_eccerr_st[1]; + } + +} + +/* + * RND: calculates Timer cycles from the given frequency + * divided by the clock frequency. Values are rounded + * up to the nearest integer value if the division is not even. + */ +#define RND( tXXX ) ( ( ( tXXX ) + tCK - 1 ) / tCK ) + +static void +u4_MemInitSequence( uint32_t tRP, uint32_t tWR, uint32_t tRFC, uint32_t CL, + uint32_t tCK, uint32_t TD ) +{ + /* + * DIMM init sequence + */ + static const uint32_t INI_SEQ[] = { + 0xa0000400, 0x80020000, 0x80030000, 0x80010404, + 0x8000100a, 0xa0000400, 0x90000000, 0x90000000, + 0x8ff0100a, 0x80010784, 0x80010404, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 + }; + + uint32_t l_MemInit_u32; + uint64_t r; + uint32_t i; + + for( r = MemInit00_R, i = 0; r <= MemInit15_R; r += 0x10, i++ ) { + l_MemInit_u32 = INI_SEQ[i]; + + switch( i ) { + case 0: + case 5: { + l_MemInit_u32 |= ( ( RND( tRP ) - TD ) << 20 ); + break; + } + case 3: { + store32_ci( EMRSRegCntl_R, l_MemInit_u32 & + (uint32_t) 0xffff ); + break; + } + case 4: { + l_MemInit_u32 |= IBIT(23); + } + case 8: { + l_MemInit_u32 |= ( ( RND( tWR ) - 1 ) << 9 ); + l_MemInit_u32 |= ( CL << 4 ); + + store32_ci( MRSRegCntl_R, l_MemInit_u32 & + (uint32_t) 0xffff ); + break; + } + case 6: + case 7: { + l_MemInit_u32 |= ( ( RND( tRFC ) - TD ) << 20 ); + break; + } + + } + + store32_ci( r, l_MemInit_u32 ); + +#ifdef U4_SHOW_REGS + printf( "\r\nMemInit%02d (0x%04X): 0x%08X", i, (uint16_t) r, l_MemInit_u32 ); +#endif + } +#ifdef U4_SHOW_REGS + printf( "\r\n" ); +#endif + /* + * Kick off memory init sequence & wait for completion + */ + store32_ci( MemProgCntl_R, IBIT(0) ); + + do { + i = load32_ci( MemProgCntl_R ); + } while( ( i & IBIT(1) ) == 0 ); + +} + +/* + * static DIMM configuartion settings + */ +static reg_statics_t reg_statics_maui[NUM_SPEED_IDX] = { + { /* 400 Mhz */ + .RRMux = 1, + .WRMux = 1, + .WWMux = 1, + .RWMux = 1, + + .MemRdQCnfg = 0x20020820, + .MemWrQCnfg = 0x40041040, + .MemQArb = 0x00000000, + .MemRWArb = 0x30413cc0, + + .ODTCntl = 0x60000000, + .IOPadCntl = 0x001a4000, + .MemPhyModeCntl = 0x00000000, + .OCDCalCntl = 0x00000000, + .OCDCalCmd = 0x00000000, + + .CKDelayL = 0x34000000, + .CKDelayU = 0x34000000, + + .MemBusCnfg = 0x00000050 | + ( ( MAX_RMD << 28 ) | + ( ( MAX_RMD - 2 ) << 24 ) ), + + .CAS1Dly0 = 0, + .CAS1Dly1 = 0, + + .ByteWrClkDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + }, + { /* 533 Mhz */ + .RRMux = 1, + .WRMux = 1, + .WWMux = 1, + .RWMux = 1, + + .MemRdQCnfg = 0x20020820, + .MemWrQCnfg = 0x40041040, + .MemQArb = 0x00000000, + .MemRWArb = 0x30413cc0, + + .ODTCntl = 0x60000000, + .IOPadCntl = 0x001a4000, + .MemPhyModeCntl = 0x00000000, + .OCDCalCntl = 0x00000000, + .OCDCalCmd = 0x00000000, + + .CKDelayL = 0x18000000, + .CKDelayU = 0x18000000, + + .MemBusCnfg = 0x00002070 | + ( ( MAX_RMD << 28 ) | + ( ( MAX_RMD - 3 ) << 24 ) ), + + .CAS1Dly0 = 0, + .CAS1Dly1 = 0, + + .ByteWrClkDel = { + + 0x12000000, 0x12000000, 0x12000000 , 0x12000000, + 0x12000000, 0x12000000, 0x12000000 , 0x12000000, + 0x12000000, 0x12000000, 0x12000000 , 0x12000000, + 0x12000000, 0x12000000, 0x12000000 , 0x12000000, + 0x12000000, 0x12000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000 , 0x00000000, + 0x00000000, 0x00000000, 0x00000000 , 0x00000000, + 0x00000000, 0x00000000, 0x00000000 , 0x00000000, + 0x00000000, 0x00000000, 0x00000000 , 0x00000000, + 0x00000000, 0x00000000 + } + + }, + { /* 667 Mhz */ + .RRMux = 1, + .WRMux = 1, + .WWMux = 1, + .RWMux = 3, + + .MemRdQCnfg = 0x20020820, + .MemWrQCnfg = 0x40041040, + .MemQArb = 0x00000000, + .MemRWArb = 0x30413cc0, + + .ODTCntl = 0x60000000, + .IOPadCntl = 0x001a4000, + .MemPhyModeCntl = 0x00000000, + .OCDCalCntl = 0x00000000, + .OCDCalCmd = 0x00000000, + + .CKDelayL = 0x0a000000, + .CKDelayU = 0x0a000000, + + .MemBusCnfg = 0x000040a0 | + ( ( MAX_RMD << 28 ) | + ( ( MAX_RMD - 3 ) << 24 ) ), + + .CAS1Dly0 = 2, + .CAS1Dly1 = 2, + + .ByteWrClkDel = { + + 0x12000000, 0x12000000, 0x12000000, 0x12000000, + 0x12000000, 0x12000000, 0x12000000, 0x12000000, + 0x12000000, 0x12000000, 0x12000000, 0x12000000, + 0x12000000, 0x12000000, 0x12000000, 0x12000000, + 0x12000000, 0x12000000 +/* + 0x31000000, 0x31000000, 0x31000000, 0x31000000, + 0x31000000, 0x31000000, 0x31000000, 0x31000000, + 0x31000000, 0x31000000, 0x31000000, 0x31000000, + 0x31000000, 0x31000000, 0x31000000, 0x31000000, + 0x31000000, 0x31000000 +*/ + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + } +}; + +static reg_statics_t reg_statics_bimini[NUM_SPEED_IDX] = { + { /* 400 Mhz */ + .RRMux = 2, + .WRMux = 2, + .WWMux = 2, + .RWMux = 2, + + .MemRdQCnfg = 0x20020820, + .MemWrQCnfg = 0x40041040, + .MemQArb = 0x00000000, + .MemRWArb = 0x30413cc0, + + .ODTCntl = 0x40000000, + .IOPadCntl = 0x001a4000, + .MemPhyModeCntl = 0x00000000, + .OCDCalCntl = 0x00000000, + .OCDCalCmd = 0x00000000, + + .CKDelayL = 0x00000000, + .CKDelayU = 0x28000000, + + .MemBusCnfg = 0x00552070 | + ( ( MAX_RMD << 28 ) | + ( ( MAX_RMD - 2 ) << 24 ) ), + + .CAS1Dly0 = 0, + .CAS1Dly1 = 0, + + .ByteWrClkDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + }, + { /* 533 Mhz */ + .RRMux = 3, + .WRMux = 3, + .WWMux = 3, + .RWMux = 3, + + .MemRdQCnfg = 0x20020820, + .MemWrQCnfg = 0x40041040, + .MemQArb = 0x00000000, + .MemRWArb = 0x30413cc0, + + .ODTCntl = 0x40000000, + .IOPadCntl = 0x001a4000, + .MemPhyModeCntl = 0x00000000, + .OCDCalCntl = 0x00000000, + .OCDCalCmd = 0x00000000, + + .CKDelayL = 0x00000000, + .CKDelayU = 0x20000000, + + .MemBusCnfg = 0x00644190 | + ( ( MAX_RMD << 28 ) | + ( ( MAX_RMD - 3 ) << 24 ) ), + + .CAS1Dly0 = 2, + .CAS1Dly1 = 2, + + .ByteWrClkDel = { + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + }, + { /* 667 Mhz */ + .RRMux = 3, + .WRMux = 3, + .WWMux = 3, + .RWMux = 3, + + .MemRdQCnfg = 0x20020820, + .MemWrQCnfg = 0x40041040, + .MemQArb = 0x00000000, + .MemRWArb = 0x30413cc0, + + .ODTCntl = 0x40000000, + .IOPadCntl = 0x001a4000, + .MemPhyModeCntl = 0x00000000, + .OCDCalCntl = 0x00000000, + .OCDCalCmd = 0x00000000, + + .CKDelayL = 0x00000000, + .CKDelayU = 0x00000000, + + .MemBusCnfg = 0x00666270 | + ( ( MAX_RMD << 28 ) | + ( ( MAX_RMD - 3 ) << 24 ) ), + + .CAS1Dly0 = 2, + .CAS1Dly1 = 2, + + .ByteWrClkDel = { + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000, 0x14000000, 0x14000000, + 0x14000000, 0x14000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + } +}; + +static reg_statics_t reg_statics_kauai[NUM_SPEED_IDX] = { + { /* 400 Mhz */ + .RRMux = 0, + .WRMux = 0, + .WWMux = 0, + .RWMux = 0, + + .MemRdQCnfg = 0, + .MemWrQCnfg = 0, + .MemQArb = 0, + .MemRWArb = 0, + + .ODTCntl = 0, + .IOPadCntl = 0, + .MemPhyModeCntl = 0, + .OCDCalCntl = 0, + .OCDCalCmd = 0, + + .CKDelayL = 0, + .CKDelayU = 0, + + .MemBusCnfg = 0, + + .CAS1Dly0 = 0, + .CAS1Dly1 = 0, + + .ByteWrClkDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + }, + { /* 533 Mhz */ + .RRMux = 0, + .WRMux = 0, + .WWMux = 0, + .RWMux = 0, + + .MemRdQCnfg = 0, + .MemWrQCnfg = 0, + .MemQArb = 0, + .MemRWArb = 0, + + .ODTCntl = 0, + .IOPadCntl = 0, + .MemPhyModeCntl = 0, + .OCDCalCntl = 0, + .OCDCalCmd = 0, + + .CKDelayL = 0, + .CKDelayU = 0, + + .MemBusCnfg = 0, + + .CAS1Dly0 = 0, + .CAS1Dly1 = 0, + + .ByteWrClkDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + }, + { /* 667 Mhz */ + .RRMux = 0, + .WRMux = 0, + .WWMux = 0, + .RWMux = 0, + + .MemRdQCnfg = 0, + .MemWrQCnfg = 0, + .MemQArb = 0, + .MemRWArb = 0, + + .ODTCntl = 0, + .IOPadCntl = 0, + .MemPhyModeCntl = 0, + .OCDCalCntl = 0, + .OCDCalCmd = 0, + + .CKDelayL = 0, + .CKDelayU = 0, + + .MemBusCnfg = 0, + + .CAS1Dly0 = 0, + .CAS1Dly1 = 0, + + .ByteWrClkDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + }, + .ReadStrobeDel = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000 + } + + } +}; + +static int32_t +u4_start( eccerror_t *f_ecc_pt ) +{ + /* + * maximum runs for auto calibration + */ + static const uint32_t MAX_ACERR = (uint32_t) 5; + + /* + * fixed u4/DIMM timer/timing values for calculation + */ + static const uint32_t TD = (uint32_t) 2; // u4 delay cycles for loading a timer + static const uint32_t AL = (uint32_t) 0; // additional latency (fix) + static const uint32_t BL = (uint32_t) 4; // burst length (fix) + + uint32_t SPEED = m_gendimm.m_speed_pu32[m_dclidx_u32]; + uint32_t CL = m_gendimm.m_clval_pu32[m_dclidx_u32]; + uint32_t RL = AL + CL; + uint32_t WL = RL - 1; + uint32_t tCK = m_gendimm.m_tCK_pu32[m_dclidx_u32]; + uint32_t tRAS = m_gendimm.m_tRAS_u32; + uint32_t tRTP = m_gendimm.m_tRTP_u32; + uint32_t tRP = m_gendimm.m_tRP_u32; + uint32_t tWR = m_gendimm.m_tWR_u32; + uint32_t tRRD = m_gendimm.m_tRRD_u32; + uint32_t tRC = m_gendimm.m_tRC_u32; + uint32_t tRCD = m_gendimm.m_tRCD_u32; + uint32_t tWTR = m_gendimm.m_tWTR_u32; + uint32_t tRFC = m_gendimm.m_tRFC_u32; + uint32_t tREF = m_gendimm.m_tREF_u32; + + reg_statics_t *rst = 0; + + uint32_t l_RAS0_u32; + uint32_t l_RAS1_u32; + uint32_t l_CAS0_u32; + uint32_t l_CAS1_u32; + uint32_t l_MemRfshCntl_u32; + uint32_t l_UsrCnfg_u32; + uint32_t l_DmCnfg_u32; + + uint32_t l_MemArbWt_u32; + uint32_t l_MemRWArb_u32; + uint32_t l_MemBusCnfg_u32; + + auto_calib_t l_ac_st; + int32_t l_ac_i32; + uint32_t l_acerr_i32; + uint32_t sidx; + uint32_t i, j, t0, t1; + + /* + * set index for different 400/533/667 Mhz setup + */ + switch( SPEED ) { + case 400: + case 533: + case 667: { + sidx = SPEED; + sidx -= 400; + sidx /= 133; + break; + } + + default: { + #ifdef U4_DEBUG2 + printf( "\r\n-> DIMM speed of %03u not supported\r\n", + m_gendimm.m_speed_pu32[m_dclidx_u32] ); + #endif + return RET_ERR; + } + + } + + /* + * setup pointer to the static register settings + */ + if( IS_MAUI ) { + rst = ®_statics_maui[sidx]; + } else if( IS_BIMINI ) { + rst = ®_statics_bimini[sidx]; + } else if( IS_KAUAI ) { + rst = ®_statics_kauai[sidx]; + } + + /* + * Switch off Fast Path by default for all DIMMs + * running with more than 400Mhz + */ + if( SPEED == 400 ) { + or32_ci( APIMemRdCfg_R, IBIT(30) ); + #ifdef U4_INFO + printf( " [fastpath : ON]\r\n" ); + #endif + } else { + and32_ci( APIMemRdCfg_R, ~IBIT(30) ); + #ifdef U4_INFO + printf( " [fastpath : OFF]\r\n" ); + #endif + } + + + #ifdef U4_INFO + printf( " [register setup : ]" ); + #endif + + /* + * setup RAS/CAS timers2 + * NOTE: subtract TD from all values because of the delay + * caused by reloading timers (see spec) + */ + + /* + * RAS Timer 0 + */ + // TiAtP = RND(tRAS) -> RAS0[0:4] + l_RAS0_u32 = ( ( RND( tRAS ) - TD ) << 27 ); + // TiRtP = AL + BL/2 - 2 + RND(tRTP) -> RAS01[5:9] + l_RAS0_u32 |= ( ( AL + BL/2 - 2 + RND( tRTP ) - TD ) << 22 ); + // TiWtP = WL + BL/2 + RND(tWR) -> RAS0[10:14] + l_RAS0_u32 |= ( ( WL + BL/2 + RND( tWR ) - TD ) << 17 ); + // TiPtA = RND(tRP) -> RAS0[15:19] + l_RAS0_u32 |= ( ( RND( tRP ) - TD ) << 12 ); + // TiPAtA = RND(tRP) or + // RND(tRP) + 1 for 8 bank devices -> RAS0[20:24] + if( m_gendimm.m_bankcnt_u32 <= 4 ) { + l_RAS0_u32 |= ( ( RND( tRP ) - TD ) << 7 ); + } else { + l_RAS0_u32 |= ( ( RND( tRP ) + 1 - TD ) << 7 ); + } + + /* + * RAS Timer 1 + */ + // TiRAPtA = AL + BL/2 - 2 + RND(tRTP + tRP) -> RAS1[0:4] + l_RAS1_u32 = ( ( AL + BL/2 - 2 + RND( tRTP + tRP ) - TD ) << 27 ); + // TiWAPtA = CL + AL + BL/2 - 1 + RND(tWR + tRP) -> RAS1[5:9] + l_RAS1_u32 |= ( ( CL + AL + BL/2 - 1 + RND( tWR + tRP ) - TD ) << 22 ); + // TiAtARk = tRRD -> RAS1[10:14] + l_RAS1_u32 |= ( ( RND( tRRD ) - TD ) << 17 ); + // TiAtABk = tRC -> RAS1[15:19] + l_RAS1_u32 |= ( ( RND( tRC ) - TD ) << 12 ); + // TiAtRW = tRCD -> RAS1[20:24] + l_RAS1_u32 |= ( ( RND( tRCD ) - TD ) << 7 ); + // TiSAtARk Win = 4 * tRRD + 2 -> RAS1[25:29] + l_RAS1_u32 |= ( ( RND( 4 * tRRD ) + 2 - TD ) << 2 ); + + /* + * CAS Timer 0 + */ + // TiRtRRk = BL/2 -> CAS0[0:4] + l_CAS0_u32 = ( ( BL/2 - TD ) << 27 ); + // TiRtRDm = BL/2 + 1 -> CAS0[5:9] + l_CAS0_u32 |= ( ( BL/2 + 1 - TD ) << 22 ); + // TiRtRSy = BL/2 + RRMux -> CAS0[10:14] + l_CAS0_u32 |= ( ( BL/2 + rst->RRMux - TD ) << 17 ); + // TiWtRRk = CL - 1 + BL/2 + tWTR ->CAS0[15:19] + l_CAS0_u32 |= ( ( CL - 1 + BL/2 + RND( tWTR ) - TD ) << 12 ); + // TiWtRDm = BL/2 + 1 -> CAS0[20:24] + l_CAS0_u32 |= ( ( BL/2 + 1 - TD ) << 7 ); + // TiWtRSy = BL/2 + WRMux -> CAS0[25:29] + l_CAS0_u32 |= ( ( BL/2 + rst->WRMux - TD ) << 2 ); + + /* + * CAS Timer 1 + */ + // TiWtWRk = BL/2 -> CAS1[0:4] + l_CAS1_u32 = ( ( BL/2 - TD ) << 27 ); + // TiWtWDm = BL/2 + 1 -> CAS1[5:9] + l_CAS1_u32 |= ( ( BL/2 + 1 - TD ) << 22 ); + // TiWtWSy = BL/2 + WWMux -> CAS1[10:14] + l_CAS1_u32 |= ( ( BL/2 + rst->WWMux - TD ) << 17 ); + // TiRtWRk = BL/2 + 2 -> CAS1[15:19] + l_CAS1_u32 |= ( ( BL/2 + 2 + rst->CAS1Dly0 - TD ) << 12 ); + // TiRtWDm = BL/2 + 2 -> CAS1[20:24] + l_CAS1_u32 |= ( ( BL/2 + 2 + rst->CAS1Dly1 - TD ) << 7 ); + // TiRtWSy = BL/2 + RWMux + 1 -> CAS1[25:29] + l_CAS1_u32 |= ( ( BL/2 + rst->RWMux + 1 - TD ) << 2 ); + + store32_ci( RASTimer0_R, l_RAS0_u32 ); + store32_ci( RASTimer1_R, l_RAS1_u32 ); + store32_ci( CASTimer0_R, l_CAS0_u32 ); + store32_ci( CASTimer1_R, l_CAS1_u32 ); + + /* + * Mem Refresh Control register + */ + l_MemRfshCntl_u32 = ( ( ( tREF / tCK ) / 16 ) << 23 ); + l_MemRfshCntl_u32 |= ( ( RND( tRFC ) - TD ) << 8 ); + store32_ci( MemRfshCntl_R, l_MemRfshCntl_u32 ); + + /* + * setup DmXCnfg registers + */ + store32_ci( Dm0Cnfg_R, (uint32_t) 0x0 ); + store32_ci( Dm1Cnfg_R, (uint32_t) 0x0 ); + store32_ci( Dm2Cnfg_R, (uint32_t) 0x0 ); + store32_ci( Dm3Cnfg_R, (uint32_t) 0x0 ); + + /* + * create DmCnfg & UsrCnfg values out of group data + */ + l_UsrCnfg_u32 = 0; + for( i = 0; i < m_dgrcnt_u32; i++ ) { + l_DmCnfg_u32 = ( m_dgrptr[i]->m_add2g_u32 << 27 ); + l_DmCnfg_u32 |= ( m_dgrptr[i]->m_sub2g_u32 << 19 ); + l_DmCnfg_u32 |= ( m_dgrptr[i]->m_memmd_u32 << 12 ); + l_DmCnfg_u32 |= ( m_dgrptr[i]->m_start_u32 << 3 ); + l_DmCnfg_u32 |= ( m_dgrptr[i]->m_ss_u32 << 1 ); + l_DmCnfg_u32 |= IBIT(31); // enable bit + + /* + * write value into DmXCnfg registers + */ + for( j = 0; j < m_dgrptr[i]->m_dcnt_u32; j++ ) { + t0 = m_dgrptr[i]->m_dptr[j]->m_bank_u32; + t1 = Dm0Cnfg_R + 0x10 * t0; + + if( load32_ci( t1 ) == 0 ) { + store32_ci( t1, l_DmCnfg_u32 ); + l_UsrCnfg_u32 |= + ( m_dgrptr[i]->m_csmode_u32 << ( 30 - 2 * t0 ) ); + } + + } + + } + + /* + * setup UsrCnfg register + *- cs mode is selected above + *- Interleave on L2 cache line + *- Usually closed page policy + */ + l_UsrCnfg_u32 |= IBIT(8); // interleave on L2 cache line + l_UsrCnfg_u32 &= ~IBIT(9); // usually closed + l_UsrCnfg_u32 |= IBIT(10); + store32_ci( UsrCnfg_R, l_UsrCnfg_u32 ); + + /* + * Memory Arbiter Weight Register + */ + // CohWt -> MemAWt[0:1] + l_MemArbWt_u32 = ( (uint32_t) 1 << 30 ); + // NCohWt -> MemAWt[2:3] + l_MemArbWt_u32 |= ( (uint32_t) 1 << 28 ); + // ScrbWt -> MemAWt[4:5] + l_MemArbWt_u32 |= ( (uint32_t) 0 << 26 ); + store32_ci( MemArbWt_R, l_MemArbWt_u32 ); + + /* + * misc fixed register setup + */ + store32_ci( ODTCntl_R, rst->ODTCntl ); + store32_ci( IOPadCntl_R, rst->IOPadCntl ); + store32_ci( MemPhyModeCntl_R, rst->MemPhyModeCntl ); + store32_ci( OCDCalCntl_R, rst->OCDCalCntl ); + store32_ci( OCDCalCmd_R, rst->OCDCalCmd ); + + /* + * CK Delay registers + */ + store32_ci( CKDelayL_R, rst->CKDelayL ); + store32_ci( CKDelayU_R, rst->CKDelayU ); + + /* + * read/write strobe delays + */ + store32_ci( ByteWrClkDelC0B00_R, rst->ByteWrClkDel[ 0] ); + store32_ci( ByteWrClkDelC0B01_R, rst->ByteWrClkDel[ 1] ); + store32_ci( ByteWrClkDelC0B02_R, rst->ByteWrClkDel[ 2] ); + store32_ci( ByteWrClkDelC0B03_R, rst->ByteWrClkDel[ 3] ); + store32_ci( ByteWrClkDelC0B04_R, rst->ByteWrClkDel[ 4] ); + store32_ci( ByteWrClkDelC0B05_R, rst->ByteWrClkDel[ 5] ); + store32_ci( ByteWrClkDelC0B06_R, rst->ByteWrClkDel[ 6] ); + store32_ci( ByteWrClkDelC0B07_R, rst->ByteWrClkDel[ 7] ); + store32_ci( ByteWrClkDelC0B16_R, rst->ByteWrClkDel[16] ); + store32_ci( ByteWrClkDelC0B08_R, rst->ByteWrClkDel[ 8] ); + store32_ci( ByteWrClkDelC0B09_R, rst->ByteWrClkDel[ 9] ); + store32_ci( ByteWrClkDelC0B10_R, rst->ByteWrClkDel[10] ); + store32_ci( ByteWrClkDelC0B11_R, rst->ByteWrClkDel[11] ); + store32_ci( ByteWrClkDelC0B12_R, rst->ByteWrClkDel[12] ); + store32_ci( ByteWrClkDelC0B13_R, rst->ByteWrClkDel[13] ); + store32_ci( ByteWrClkDelC0B14_R, rst->ByteWrClkDel[14] ); + store32_ci( ByteWrClkDelC0B15_R, rst->ByteWrClkDel[15] ); + store32_ci( ByteWrClkDelC0B17_R, rst->ByteWrClkDel[17] ); + store32_ci( ReadStrobeDelC0B00_R, rst->ReadStrobeDel[ 0] ); + store32_ci( ReadStrobeDelC0B01_R, rst->ReadStrobeDel[ 1] ); + store32_ci( ReadStrobeDelC0B02_R, rst->ReadStrobeDel[ 2] ); + store32_ci( ReadStrobeDelC0B03_R, rst->ReadStrobeDel[ 3] ); + store32_ci( ReadStrobeDelC0B04_R, rst->ReadStrobeDel[ 4] ); + store32_ci( ReadStrobeDelC0B05_R, rst->ReadStrobeDel[ 5] ); + store32_ci( ReadStrobeDelC0B06_R, rst->ReadStrobeDel[ 6] ); + store32_ci( ReadStrobeDelC0B07_R, rst->ReadStrobeDel[ 7] ); + store32_ci( ReadStrobeDelC0B16_R, rst->ReadStrobeDel[16] ); + store32_ci( ReadStrobeDelC0B08_R, rst->ReadStrobeDel[ 8] ); + store32_ci( ReadStrobeDelC0B09_R, rst->ReadStrobeDel[ 9] ); + store32_ci( ReadStrobeDelC0B10_R, rst->ReadStrobeDel[10] ); + store32_ci( ReadStrobeDelC0B11_R, rst->ReadStrobeDel[11] ); + store32_ci( ReadStrobeDelC0B12_R, rst->ReadStrobeDel[12] ); + store32_ci( ReadStrobeDelC0B13_R, rst->ReadStrobeDel[13] ); + store32_ci( ReadStrobeDelC0B14_R, rst->ReadStrobeDel[14] ); + store32_ci( ReadStrobeDelC0B15_R, rst->ReadStrobeDel[15] ); + store32_ci( ReadStrobeDelC0B17_R, rst->ReadStrobeDel[17] ); + + /* + * Mem Bus Configuration + * initial setup used in auto calibration + * final values will be written after + * auto calibration has finished + */ + l_MemBusCnfg_u32 = rst->MemBusCnfg; + +/* values calculation has been dropped, static values are used instead + // WdbRqDly = 2 * (CL - 3) (registered DIMMs) -> MBC[16:19] + l_MemBusCnfg_u32 += ( ( 2 * ( CL - 3 ) ) << 12 ); + // RdOEOnDly = 0 (typically) + l_MemBusCnfg_u32 += ( ( 0 ) << 8 ); + // RdOEOffDly = (2 * CL) - 4 -> MBC[24:27] + // NOTE: formula is not working, changed to: + // RdOEOffDly = (2 * CL) - 1 + l_MemBusCnfg_u32 += ( ( ( 2 * CL ) - 1 ) << 4 ); +*/ + + store32_ci( MemBusCnfg_R, l_MemBusCnfg_u32 ); + store32_ci( MemBusCnfg2_R, rst->MemBusCnfg & (uint32_t) 0xf0000000 ); + + /* + * reset verniers registers + */ + store32_ci( RstLdEnVerniersC0_R, 0x0 ); + store32_ci( RstLdEnVerniersC1_R, 0x0 ); + store32_ci( RstLdEnVerniersC2_R, 0x0 ); + store32_ci( RstLdEnVerniersC3_R, 0x0 ); + store32_ci( ExtMuxVernier0_R, 0x0 ); + store32_ci( ExtMuxVernier1_R, 0x0 ); + + /* + * Queue Configuration + */ + store32_ci( MemRdQCnfg_R, rst->MemRdQCnfg ); + store32_ci( MemWrQCnfg_R, rst->MemWrQCnfg ); + store32_ci( MemQArb_R, rst->MemQArb ); + store32_ci( MemRWArb_R, rst->MemRWArb ); + + #ifdef U4_INFO + printf( "\b\b\bOK\r\n" ); + #endif + + /* + * start up clocks & wait for pll2 to stabilize + */ + #ifdef U4_INFO + printf( " [start DDR clock : ]" ); + #endif + + store32_ci( MemModeCntl_R, IBIT(0) | IBIT(8) ); + dly( 50000000 ); + + #ifdef U4_INFO + printf( "\b\b\bOK\r\n" ); + + #endif + + /* + * memory initialization sequence + */ + #ifdef U4_INFO + printf( " [memory init : ]" ); + #endif + u4_MemInitSequence( tRP, tWR, tRFC, CL, tCK, TD ); + #ifdef U4_INFO + printf( "\b\b\bOK\r\n" ); + #endif + + /* + * start ECC before auto calibration to enable ECC bytelane + */ + store32_ci( MCCR_R, IBIT(0) ); + dly( 15000000 ); + + /* + * start up auto calibration + */ + #ifdef U4_INFO + printf( " [auto calibration: ]\b" ); + #endif + + /* + * start auto calibration + */ + l_acerr_i32 = 0; + do { + progbar(); + + l_ac_i32 = u4_auto_calib( &l_ac_st ); + + if( l_ac_i32 != 0 ) { + l_acerr_i32++; + } + + dly( 15000000 ); + } while( ( l_ac_i32 != 0 ) && + ( l_acerr_i32 <= MAX_ACERR ) ); + + if( l_acerr_i32 > MAX_ACERR ) { + #ifdef U4_INFO + printf( "\b\b\bERR\r\n" ); + #endif + return RET_ERR; + } + + /* + * insert auto calibration results + */ + store32_ci( MemBusCnfg_R, l_ac_st.m_MemBusCnfg_u32 ); + store32_ci( MemBusCnfg2_R, l_ac_st.m_MemBusCnfg2_u32 ); + store32_ci( RstLdEnVerniersC0_R, l_ac_st.m_RstLdEnVerniers_pu32[0] ); + store32_ci( RstLdEnVerniersC1_R, l_ac_st.m_RstLdEnVerniers_pu32[1] ); + store32_ci( RstLdEnVerniersC2_R, l_ac_st.m_RstLdEnVerniers_pu32[2] ); + store32_ci( RstLdEnVerniersC3_R, l_ac_st.m_RstLdEnVerniers_pu32[3] ); + + /* + * insert final timing value into MemRWArb + */ + l_MemRWArb_u32 = ( ( l_ac_st.m_MemBusCnfg_u32 >> 28 /*RdMacDel*/) + 1 ); + l_MemRWArb_u32 *= 10; // needed for rounding + l_MemRWArb_u32 /= 2; // due to spec + l_MemRWArb_u32 += 9; // round up + l_MemRWArb_u32 /= 10; // value is rounded now + l_MemRWArb_u32 = l_MemRWArb_u32 + 6 - WL - TD; + l_MemRWArb_u32 |= rst->MemRWArb; + store32_ci( MemRWArb_R, l_MemRWArb_u32 ); + + progbar(); + dly( 15000000 ); + + /* + * do initial scrubbing + */ + *f_ecc_pt = u4_InitialScrub(); + + switch( f_ecc_pt->m_err_i32 ) { + case RET_OK: { + #ifdef U4_INFO + printf( "\b\bOK\r\n" ); + #endif + break; + } + + case RET_ACERR_CE: { + #ifdef U4_INFO + printf( "\b\b\b\bWEAK][correctable errors during scrub (%u)]\r\n", + f_ecc_pt->m_cecnt_u32 ); + #endif + break; + } + + case RET_ACERR_UEWT: + case RET_ACERR_UE: { + #ifdef U4_INFO + printf( "\b\b\bERR][uncorrectable errors during scrub (%u)]\r\n", + f_ecc_pt->m_uecnt_u32 ); + #endif + return RET_ACERR_UE; + } + + } + + /* + * start continuous background scrub + */ + #ifdef U4_INFO + printf( " [background scrub: ]" ); + #endif + + u4_Scrub( BACKGROUND_SCRUB, 0, NULL ); + + #ifdef U4_INFO + printf( "\b\b\bOK\r\n" ); + #endif + + /* + * finally clear API Exception register + * (read to clear) + */ + load32_ci( APIExcp_R ); + + return RET_OK; +} + +#undef RND + +#if 0 +void +u4_memtest(uint8_t argCnt, char *pArgs[], uint64_t flags) +{ + #define TEND 99 + #define TCHK 100 + static const uint64_t _2GB = (uint64_t) 0x80000000; + static const uint64_t _start = (uint64_t) 0x08000000; // 128Mb + static const uint64_t _bsize = (uint64_t) 0x08000000; // 128MB + static const uint64_t _line = (uint64_t) 128; + static const uint64_t _256MB = (uint64_t) 0x10000000; + + static const uint64_t PATTERN[] = { + 0x9090909090909090, 0x0020002000200020, + 0x0c0c0c0c0c0c0c0c, 0x8080808080808080, + 0x1004010004001041, 0x0000000000000000 + }; + + uint64_t mend = (uint64_t) 0x200000000;//m_memsize_u64; + uint64_t numblocks = ( mend - _start ) / _bsize; // 128Mb blocks + uint64_t numlines = _bsize / _line; + uint64_t tstate = 0; + uint64_t tlast = 0; + uint64_t pidx = 0; + uint64_t rotr = 0; + uint64_t rotl = 0; + uint64_t block; + uint64_t line; + uint64_t addr; + uint64_t i; + uint64_t check = 0; + uint64_t dcnt; + uint64_t uerr = 0; + uint64_t cerr = 0; + uint64_t merr = 0; + char c; + + printf( "\n\nU4 memory test" ); + printf( "\n--------------" ); + + /* + * mask out UEC & CEC + */ + or32_ci( MCCR_R, IBIT(6) | IBIT(7) ); + + while( PATTERN[pidx] ) { + + switch( tstate ) + { + case 0: { + printf( "\npattern fill 0x%08X%08X: ", (uint32_t) (PATTERN[pidx] >> 32), (uint32_t) PATTERN[pidx] ); + + /* + * first switch lines, then blocks. This way the CPU + * is not able to cache data + */ + for( line = 0, dcnt = 0; line < numlines; line++ ) { + + for( block = 0; block < numblocks; block++ ) { + + for( i = 0; i < _line; i += 8 ) { + addr = _start + + ( block * _bsize ) + + ( line * _line ) + + i; + + if( addr >= _2GB ) { + addr += _2GB; + } + + *( (uint64_t *) addr ) = PATTERN[pidx]; + + /* + * print out a dot every 256Mb + */ + dcnt += 8; + if( dcnt == _256MB ) { + dcnt = 0; + printf( "*" ); + + if( io_getchar( &c ) ) { + goto mtend; + } + + } + + } + + } + + } + + check = PATTERN[pidx]; + tlast = 0; + tstate = TCHK; + } break; + + case 1: { + uint64_t one; + + /* + * new check pattern + + */ + one = ( ( check & 0x1 ) != 0 ); + check >>= 1; + if( one ) { + check |= 0x8000000000000000; + } + + printf( "\nrotate right 0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check ); + + /* + * first switch lines, then blocks. This way the CPU + * is not able to cache data + */ + for( line = 0, dcnt = 0; line < numlines; line++ ) { + + for( block = 0; block < numblocks; block++ ) { + + for( i = 0; i < _line; i += 8 ) { + addr = _start + + ( block * _bsize ) + + ( line * _line ) + + i; + + if( addr >= _2GB ) { + addr += _2GB; + } + + *( (uint64_t *) addr ) >>= 1; + + if( one ) { + *( (uint64_t *) addr ) |= + (uint64_t) 0x8000000000000000; + } + + /* + * print out a dot every 256Mb + */ + dcnt += 8; + if( dcnt == _256MB ) { + dcnt = 0; + printf( "*" ); + + if( io_getchar( &c ) ) { + goto mtend; + } + + } + + } + + } + + } + + tlast = 1; + tstate = TCHK; + } break; + + case 2: { + + if( rotr < 6 ) { + rotr++; + tstate = 1; + } else { + rotr = 0; + tstate = 3; + } + + } break; + + case 3: { + /* + * new check pattern + */ + check ^= (uint64_t) ~0; + + printf( "\ninverting 0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check ); + + /* + * first switch lines, then blocks. This way the CPU + * is not able to cache data + */ + for( line = 0, dcnt = 0; line < numlines; line++ ) { + + for( block = 0; block < numblocks; block++ ) { + + for( i = 0; i < _line; i += 8 ) { + addr = _start + + ( block * _bsize ) + + ( line * _line ) + + i; + + if( addr >= _2GB ) { + addr += _2GB; + } + + *( (uint64_t *) addr ) ^= (uint64_t) ~0; + + /* + * print out a dot every 256Mb + */ + dcnt += 8; + if( dcnt == _256MB ) { + dcnt = 0; + printf( "*" ); + + if( io_getchar( &c ) ) { + goto mtend; + } + + } + + } + + } + + } + + tlast = 3; + tstate = TCHK; + } break; + + case 4: { + uint64_t one; + + /* + * new check pattern + */ + one = ( ( check & 0x8000000000000000 ) != 0 ); + check <<= 1; + if( one ) { + check |= 0x1; + } + + printf( "\nrotate left 0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check ); + + /* + * first switch lines, then blocks. This way the CPU + * is not able to cache data + */ + for( line = 0, dcnt = 0; line < numlines; line++ ) { + + for( block = 0; block < numblocks; block++ ) { + + for( i = 0; i < _line; i += 8 ) { + addr = _start + + ( block * _bsize ) + + ( line * _line ) + + i; + + if( addr >= _2GB ) { + addr += _2GB; + } + + *( (uint64_t *) addr ) <<= 1; + + if( one ) { + *( (uint64_t *) addr ) |= + (uint64_t) 0x1; + } + + /* + * print out a dot every 256Mb + */ + dcnt += 8; + if( dcnt == _256MB ) { + dcnt = 0; + printf( "*" ); + + if( io_getchar( &c ) ) { + goto mtend; + } + + } + + } + + } + + } + + tlast = 4; + tstate = TCHK; + } break; + + case 5: { + + if( rotl < 6 ) { + rotl++; + tstate = 4; + } else { + rotl = 0; + tstate = 6; + } + + } break; + + case 6: { + /* + * new check pattern + */ + check *= ~check; + printf( "\nmultiply 0x%08X%08X: ", (uint32_t) (check >> 32), (uint32_t) check ); + + /* + * first switch lines, then blocks. This way the CPU + * is not able to cache data + */ + for( line = 0, dcnt = 0; line < numlines; line++ ) { + + for( block = 0; block < numblocks; block++ ) { + + for( i = 0; i < _line; i += 8 ) { + addr = _start + + ( block * _bsize ) + + ( line * _line ) + + i; + + if( addr >= _2GB ) { + addr += _2GB; + } + + *( (uint64_t *) addr ) *= ~( *( (uint64_t *) addr ) ); + + /* + * print out a dot every 256Mb + */ + dcnt += 8; + if( dcnt == _256MB ) { + dcnt = 0; + printf( "*" ); + + if( io_getchar( &c ) ) { + goto mtend; + } + + } + + } + + } + + } + + tlast = TEND - 1; + tstate = TCHK; + } break; + + case TEND: { + pidx++; + tstate = 0; + } break; + + case TCHK: { + uint64_t err; + /* + * check data + */ + printf( "\nchecking : " ); + + for( line = 0, dcnt = 0; line < numlines; line++ ) { + + for( block = 0; block < numblocks; block++ ) { + + for( i = 0; i < _line; i += 8 ) { + addr = _start + + ( block * _bsize ) + + ( line * _line ) + + i; + + if( addr >= _2GB ) { + addr += _2GB; + } + + err = ( *( (uint64_t *) addr ) != check ); + + if( err ) { + merr++; + } + + /* + * print out a dot every 256Mb + */ + dcnt += 8; + if( dcnt == _256MB ) { + dcnt = 0; + + if( err ) { + printf( "X" ); + } else { + printf( "*" ); + } + + if( io_getchar( &c ) ) { + goto mtend; + } + + } + + } + + } + + } + + err = (uint64_t) load32_ci( MEAR1_R ); + uerr += ( err >> 24 ) & (uint64_t) 0xff; + cerr += ( err >> 16 ) & (uint64_t) 0xff; + + printf( " (UE: %02llX, CE: %02llX)", ( err >> 24 ) & (uint64_t) 0xff, ( err >> 16 ) & (uint64_t) 0xff ); + + tstate = tlast + 1; + tlast = TCHK; + } break; + + } + + } + +mtend: + printf( "\n\nmemory test results" ); + printf( "\n-------------------" ); + printf( "\nuncorrectable errors: %u", (uint32_t) uerr ); + printf( "\ncorrectable errors : %u", (uint32_t) cerr ); + printf( "\nread/write errors : %u\n", (uint32_t) merr ); + + and32_ci( MCCR_R, ~( IBIT(6) | IBIT(7) ) ); +} +#endif + +#if 0 +void +u4_dump(uint8_t argCnt, char *pArgs[], uint64_t flags) +{ + printf( "\r\n*** u4 register dump ***\r\n\n" ); + printf( "register (offset): value\r\n" ); + printf( "----------------------------------\r\n" ); + printf( "Clock Control (0x%04X): 0x%08X\r\n", (uint16_t) ClkCntl_R, load32_ci( ClkCntl_R ) ); + printf( "PLL2 Control (0x%04X): 0x%08X\r\n", (uint16_t) PLL2Cntl_R, load32_ci( PLL2Cntl_R ) ); + printf( "MemModeCntl (0x%04X): 0x%08X\r\n", (uint16_t) MemModeCntl_R, load32_ci( MemModeCntl_R ) ); + printf( "RASTimer0 (0x%04X): 0x%08X\r\n", (uint16_t) RASTimer0_R, load32_ci( RASTimer0_R ) ); + printf( "RASTimer1 (0x%04X): 0x%08X\r\n", (uint16_t) RASTimer1_R, load32_ci( RASTimer1_R ) ); + printf( "CASTimer0 (0x%04X): 0x%08X\r\n", (uint16_t) CASTimer0_R, load32_ci( CASTimer0_R ) ); + printf( "CASTimer1 (0x%04X): 0x%08X\r\n", (uint16_t) CASTimer1_R, load32_ci( CASTimer1_R ) ); + printf( "MemRfshCntl (0x%04X): 0x%08X\r\n", (uint16_t) MemRfshCntl_R, load32_ci( MemRfshCntl_R ) ); + printf( "Dm0Cnfg (0x%04X): 0x%08X\r\n", (uint16_t) Dm0Cnfg_R, load32_ci( Dm0Cnfg_R ) ); + printf( "Dm1Cnfg (0x%04X): 0x%08X\r\n", (uint16_t) Dm1Cnfg_R, load32_ci( Dm1Cnfg_R ) ); + printf( "Dm2Cnfg (0x%04X): 0x%08X\r\n", (uint16_t) Dm2Cnfg_R, load32_ci( Dm2Cnfg_R ) ); + printf( "Dm3Cnfg (0x%04X): 0x%08X\r\n", (uint16_t) Dm3Cnfg_R, load32_ci( Dm3Cnfg_R ) ); + printf( "UsrCnfg (0x%04X): 0x%08X\r\n", (uint16_t) UsrCnfg_R, load32_ci( UsrCnfg_R ) ); + printf( "MemArbWt (0x%04X): 0x%08X\r\n", (uint16_t) MemArbWt_R, load32_ci( MemArbWt_R ) ); + printf( "ODTCntl (0x%04X): 0x%08X\r\n", (uint16_t) ODTCntl_R, load32_ci( ODTCntl_R ) ); + printf( "IOPadCntl (0x%04X): 0x%08X\r\n", (uint16_t) IOPadCntl_R, load32_ci( IOPadCntl_R ) ); + printf( "MemPhyMode (0x%04X): 0x%08X\r\n", (uint16_t) MemPhyModeCntl_R, load32_ci( MemPhyModeCntl_R ) ); + printf( "OCDCalCntl (0x%04X): 0x%08X\r\n", (uint16_t) OCDCalCntl_R, load32_ci( OCDCalCntl_R ) ); + printf( "OCDCalCmd (0x%04X): 0x%08X\r\n", (uint16_t) OCDCalCmd_R, load32_ci( OCDCalCmd_R ) ); + printf( "CKDelayL (0x%04X): 0x%08X\r\n", (uint16_t) CKDelayL_R, load32_ci( CKDelayL_R ) ); + printf( "CKDelayH (0x%04X): 0x%08X\r\n", (uint16_t) CKDelayU_R, load32_ci( CKDelayU_R ) ); + printf( "MemBusCnfg (0x%04X): 0x%08X\r\n", (uint16_t) MemBusCnfg_R, load32_ci( MemBusCnfg_R ) ); + printf( "MemBusCnfg2 (0x%04X): 0x%08X\r\n", (uint16_t) MemBusCnfg2_R, load32_ci( MemBusCnfg2_R ) ); + printf( "MemRdQCnfg (0x%04X): 0x%08X\r\n", (uint16_t) MemRdQCnfg_R, load32_ci( MemRdQCnfg_R ) ); + printf( "MemWrQCnfg (0x%04X): 0x%08X\r\n", (uint16_t) MemWrQCnfg_R, load32_ci( MemWrQCnfg_R ) ); + printf( "MemQArb (0x%04X): 0x%08X\r\n", (uint16_t) MemQArb_R, load32_ci( MemQArb_R ) ); + printf( "MemRWArb (0x%04X): 0x%08X\r\n", (uint16_t) MemRWArb_R, load32_ci( MemRWArb_R ) ); + printf( "ByteWrClkDel (0x%04X): 0x%08X\r\n", (uint16_t) ByteWrClkDelC0B00_R, load32_ci( ByteWrClkDelC0B00_R ) ); + printf( "ReadStrobeDel (0x%04X): 0x%08X\r\n", (uint16_t) ReadStrobeDelC0B00_R, load32_ci( ReadStrobeDelC0B00_R ) ); + printf( "RstLdEnVerC0 (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC0_R, load32_ci( RstLdEnVerniersC0_R ) ); + printf( "RstLdEnVerC1 (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC1_R, load32_ci( RstLdEnVerniersC1_R ) ); + printf( "RstLdEnVerC2 (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC2_R, load32_ci( RstLdEnVerniersC2_R ) ); + printf( "RstLdEnVerC3 (0x%04X): 0x%08X\r\n", (uint16_t) RstLdEnVerniersC3_R, load32_ci( RstLdEnVerniersC3_R ) ); + printf( "APIMemRdCfg (0x%04X): 0x%08X\r\n", (uint16_t) APIMemRdCfg_R, load32_ci( APIMemRdCfg_R ) ); + printf( "scrub start (0x%04X): 0x%08X\r\n", (uint16_t) MSRSR_R, load32_ci( MSRSR_R ) ); + printf( "scrub end (0x%04X): 0x%08X\r\n", (uint16_t) MSRER_R, load32_ci( MSRER_R ) ); +} +#endif + +static int32_t +u4_memBegin( eccerror_t *f_ecc_pt ) +{ + int32_t i; + + #ifdef U4_INFO + printf( "\r\n" ); + printf( "U4 DDR2 memory controller setup V%u.%u\r\n", + VER, SUBVER ); + printf( "------------------------------------\r\n" ); + printf( "> detected board : " ); + + if( IS_MAUI ) { + printf( "MAUI" ); + } else if( IS_BIMINI ) { + printf( "BIMINI" ); + } else if( IS_KAUAI ) { + printf( "KAUAI" ); + } else { + printf( "unknown!" ); + return RET_ERR; + } + #endif + + do { + /* + * initialize variables + */ + m_memsize_u64 = 0; + m_dcnt_u32 = 0; + m_dgrcnt_u32 = 0; + m_dclidx_u32 = 0; + + for( i = 0; i < NUM_SLOTS; i++ ) { + m_dptr[i] = NULL; + memset( ( void * ) &m_dimm[i], 0, sizeof( dimm_t ) ); + } + + for( i = 0; i < MAX_DGROUPS; i++ ) { + m_dgrptr[i] = NULL; + memset( ( void * ) &m_dgroup[i], 0, sizeof( dimm_t ) ); + } + + /* + * start configuration + */ + #ifdef U4_INFO + printf( "\r\n> detected DIMM configuration : " ); + #endif + + i = ddr2_readSPDs(); + + if( i != RET_OK ) { + #ifdef U4_INFO + printf( "\r\n-------------------------------------------------------------" ); + printf( "\r\n switching off memory bank(s) due to SPD integrity failure" ); + printf( "\r\n-------------------------------------------------------------\r\n" ); + #endif + } + + } while( i != RET_OK ); + + /* + * check DIMM configuration + */ + if( ddr2_setupDIMMcfg() != RET_OK ) { + #ifdef U4_INFO + printf( "> initialization failure.\r\n" ); + #endif + return RET_ERR; + } + + /* + * create DIMM groups + */ + u4_setupDIMMgroups(); + + /* + * start configuration of u4 + */ + u4_calcDIMMcnfg(); + + if( u4_calcDIMMmemmode() != RET_OK ) { + #ifdef U4_INFO + printf( "> initialization failure.\r\n" ); + #endif + return RET_ERR; + } + + #ifdef U4_INFO + printf( "%uMb @ %uMhz, CL %u\r\n", + (uint32_t) ( m_memsize_u64 / 0x100000 ), + m_gendimm.m_speed_pu32[m_dclidx_u32], + m_gendimm.m_clval_pu32[m_dclidx_u32] ); + + printf( "> initializing memory :\r\n" ); + #endif + + if( u4_setup_core_clock() != RET_OK ) { + #ifdef U4_INFO + printf( "> initialization failure.\r\n" ); + #endif + return RET_ERR; + } + + i = u4_start( f_ecc_pt ); + if( i != RET_OK ) { + #ifdef U4_INFO + printf( "> initialization failure.\r\n" ); + #endif + return i; + } + + #ifdef U4_INFO + printf( " [flush cache : ]" ); + #endif + + flush_cache( 0x0, L2_CACHE_SIZE ); + + #ifdef U4_INFO + printf( "\b\b\bOK\r\n" ); + printf( "> initialization complete.\r\n" ); + #endif + +#ifdef U4_SHOW_REGS + u4_dump(0,0,0); +#endif + + return RET_OK; +} + + +#if 0 +static int32_t scrubstarted = 0; +void +u4_scrubStart(uint8_t argCnt, char *pArgs[], uint64_t flags ) +{ + scrubstarted = 1; + + /* + * setup scrub parameters + */ + store32_ci( MSCR_R, 0 ); // stop scrub + store32_ci( MSRSR_R, 0x0 ); // set start + store32_ci( MSRER_R, 0x1c ); // set end + store32_ci( MSPR_R, 0x0 ); // set pattern + + /* + * clear out ECC error registers + */ + store32_ci( MEAR0_R, 0x0 ); + store32_ci( MEAR1_R, 0x0 ); + store32_ci( MESR_R, 0x0 ); + + /* + * Setup Scrub Type + */ + store32_ci( MSCR_R, IBIT(1) ); + printf( "\r\nscrub started\r\n" ); +} +#endif + +#if 0 +void +u4_scrubEnd(uint8_t argCnt, char *pArgs[], uint64_t flags ) +{ + store32_ci( MSCR_R, 0 ); // stop scrub + scrubstarted = 0; + printf( "\r\nscrub stopped\r\n" ); +} +#endif + +#if 0 +void +u4_memwr(uint8_t argCnt, char *pArgs[], uint64_t flags ) +{ + uint32_t i; + uint32_t v = 0; + + for( i = 0; i < 0x200; i += 4 ) { + + if( ( i & 0xf ) == 0 ) { + v = ~v; + } + + store32_ci( i, v ); + } + +} +#endif + +void +u4memInit() +{ + static uint32_t l_isInit_u32 = 0; + eccerror_t l_ecc_t; + int32_t ret; + + /* + * do not initialize memory more than once + */ + if( l_isInit_u32 ) { + #ifdef U4_INFO + printf( "\r\n\nmemory already initialized\r\n" ); + #endif + return; + } else { + l_isInit_u32 = 1; + } + + /* + * enable all DIMM banks on first run + */ + m_bankoff_u32 = 0; + + do { + ret = u4_memBegin( &l_ecc_t ); + + if( ret < RET_ERR ) { + uint32_t l_bank_u32 = l_ecc_t.m_rank_u32 / 2; + printf( "\r\n-----------------------------------------------------" ); + printf( "\r\n switching off memory bank %u due to memory failure", l_bank_u32 ); + printf( "\r\n-----------------------------------------------------" ); + m_bankoff_u32 |= ( 1 << l_bank_u32 ); + } + + } while( ret < RET_ERR ); + +} diff --git a/qemu/roms/SLOF/board-js2x/romfs/boot_rom.ffs b/qemu/roms/SLOF/board-js2x/romfs/boot_rom.ffs new file mode 100644 index 000000000..fe54cb673 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/romfs/boot_rom.ffs @@ -0,0 +1,22 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +# FFile-Name Real Filename Flags ROM-Offset i/a +#--------------|-------------------------------|---------------|-------------- +header romfs/header.img 0 0 +stage1 board-js2x/llfw/stage1.bin 1 0x100 +xvect slof/xvect.bin 0 0 +ofw_main board-js2x/slof/paflof 0 0 +stageS board-js2x/llfw/stageS.bin 0 0 +bootinfo board-js2x/llfw/Cboot.bin 0 0 +rtas board-js2x/rtas/rtas.bin 0 0 +snk clients/net-snk.client 0 0 diff --git a/qemu/roms/SLOF/board-js2x/rtas/Makefile b/qemu/roms/SLOF/board-js2x/rtas/Makefile new file mode 100644 index 000000000..5ab5c34c7 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/Makefile @@ -0,0 +1,89 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include ../Makefile.dirs + +include $(TOPBRDDIR)/config +include $(TOPCMNDIR)/make.rules + + +LDFLAGS = -nostdlib +CPPFLAGS = -I. -I$(LIBCMNDIR)/libc/include -I$(LIBCMNDIR)/libipmi -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(RTASCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) +ASFLAGS = -Wa,-mregnames $(FLAG) +CFLAGS += -Wall -Wextra -O2 -msoft-float -ffreestanding $(FLAG) + +# Board specific RTAS files: +BOARD_SRC_ASM = +BOARD_SRC_C = rtas_flash.c rtas_board.c rtas_pci.c \ + rtas_out.c rtas_table.c +BOARD_SRCS = $(BOARD_SRC_ASM) $(BOARD_SRC_C) +BOARD_OBJ = $(BOARD_SRC_ASM:%.S=%.o) $(BOARD_SRC_C:%.c=%.o) $(BOARD_OCO:%.oco=%.o) +BOARD_OCO = i2c_bmc.oco ipmi_oem.oco + + +# Common RTAS files (from $(RTASCMNDIR) directory): +RTAS_SRC_ASM = rtas_entry.S rtas_common.S reloc.S +RTAS_SRC_C = rtas_call.c +RTAS_SRCS = $(RTAS_SRC_ASM) $(RTAS_SRC_C) +RTAS_OBJ = $(RTAS_SRC_ASM:%.S=%.o) $(RTAS_SRC_C:%.c=%.o) + +RTAS_FLASH_SRC = block_lists.c +RTAS_FLASH_OBJ = $(RTAS_FLASH_SRC:%.c=$(RTASCMNDIR)/flash/%.o) + +# Additional object files: +EXTRA_OBJ = ../llfw/hw.o ../../lib/libc.a ../../lib/libipmi.a + +OBJS = $(RTAS_OBJ:%=$(RTASCMNDIR)/%) $(BOARD_OBJ) $(EXTRA_OBJ) \ + $(RTAS_FLASH_OBJ) + + +all: Makefile.dep rtas.bin + +rtas.bin: rtas + $(OBJCOPY) -O binary $< $@ + +rtas: $(RTASCMNDIR)/rtas.lds $(OBJS) reloc_table.o + $(LD) $(LDFLAGS) -o $@ -T $(RTASCMNDIR)/rtas.lds $(OBJS) reloc_table.o + +reloc_table.o: $(TOOLSDIR)/gen_reloc_table $(OBJS) + $(TOOLSDIR)/create_reloc_table.sh --ld "$(ONLY_LD)" --ldflags "$(LDFLAGS)" \ + --lds "$(RTASCMNDIR)/rtas.lds" --objcopy "$(OBJCOPY)" $(OBJS) + +$(TOOLSDIR)/gen_reloc_table: $(TOOLSDIR)/gen_reloc_table.c + $(MAKE) -C $(TOOLSDIR) gen_reloc_table + +../../lib/libc.a: + $(MAKE) -C ../../lib + +clean: + $(MAKE) -C ../../lib clean + rm -f $(OBJS) reloc_table.o rtas rtas.bin + +distclean : clean + rm -f Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(BOARD_SRCS) > Makefile.dep + $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(RTAS_SRCS:%=$(RTASCMNDIR)/%) \ + | sed -e '/:/s,^,$(RTASCMNDIR)/,' >> Makefile.dep +Makefile.dep: + $(MAKE) depend + +# Include dependency file if available: +ifneq (,$(wildcard Makefile.dep)) +include Makefile.dep +endif +%.o: %.oco + cp -f $< $@ diff --git a/qemu/roms/SLOF/board-js2x/rtas/i2c_bmc.oco b/qemu/roms/SLOF/board-js2x/rtas/i2c_bmc.oco Binary files differnew file mode 100644 index 000000000..004e7f2e5 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/i2c_bmc.oco diff --git a/qemu/roms/SLOF/board-js2x/rtas/ipmi_oem.oco b/qemu/roms/SLOF/board-js2x/rtas/ipmi_oem.oco Binary files differnew file mode 100644 index 000000000..ae401eafe --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/ipmi_oem.oco diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_board.c b/qemu/roms/SLOF/board-js2x/rtas/rtas_board.c new file mode 100644 index 000000000..7f7409d9f --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_board.c @@ -0,0 +1,218 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <rtas.h> +#include "rtas_board.h" +#include <bmc.h> +#include <rtas_i2c_bmc.h> +#include <rtas_ipmi_bmc.h> +#include "libipmi.h" +#include <hw.h> + +void io_init(void); +short reg_get_flashside(void); +void rtas_init(void); + +typedef struct { + uint64_t r3; + uint64_t addr; + volatile uint64_t id; +} slave_t; + +volatile slave_t rtas_slave_interface; + +static void +rtas_slave_loop(volatile slave_t * pIface) +{ + uint64_t mask = pIface->id; + pIface->id = 0; + while (pIface->id != mask); { + int dly = 0x1000; + while (dly--); + } + pIface->id = 0; + asm volatile (" mr 3,%0 ; mtctr %1 ; bctr " + ::"r"(pIface->r3), "r"(pIface->addr)); +} + +void +rtas_fetch_slaves(rtas_args_t * pArgs) +{ + int retVal = 0; + int idx = 0; + uint32_t mask = pArgs->args[0] & 0xFFFFFFFE; + uint64_t *rtas_slave_loop_ptr = (uint64_t *)rtas_slave_loop; + while (mask) { + if (mask & 0x1) { + rtas_slave_interface.id = idx | 0x100; + *(int *) 0x3fc0 = (int)(unsigned long) &rtas_slave_interface; // r3 + *(int *) 0x3f80 = *rtas_slave_loop_ptr; // addr + *(int *) 0x3fa0 = idx | 0x100; // pid + while (rtas_slave_interface.id); + } + mask >>= 1; + idx++; + } + pArgs->args[pArgs->nargs] = retVal; +} + +void +rtas_start_cpu(rtas_args_t * pArgs) +{ + int retVal = 0; + int idx = pArgs->args[0]; // pid + rtas_slave_interface.r3 = pArgs->args[2]; // r3 + rtas_slave_interface.addr = pArgs->args[1]; // addr + asm(" sync "); + rtas_slave_interface.id = idx | 0x100; // pid + while (rtas_slave_interface.id); + pArgs->args[pArgs->nargs] = retVal; +} + +void +rtas_read_vpd(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = + bmc_read_vpd((uint8_t *) (uint64_t) pArgs->args[2], pArgs->args[1], + pArgs->args[0]); +} + +void +rtas_write_vpd(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = + bmc_write_vpd((uint8_t *) (uint64_t) pArgs->args[2], pArgs->args[1], + pArgs->args[0]); +} + +void +rtas_set_indicator(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = -1; +} + +void +rtas_event_scan(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = -1; +} + +void +rtas_stop_bootwatchdog(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = bmc_stop_bootwatchdog(); +} + +void +rtas_set_bootwatchdog(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = bmc_set_bootwatchdog(pArgs->args[0]); +} + +void +rtas_set_flashside(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = bmc_set_flashside(pArgs->args[0]); +} + +void +rtas_get_flashside(rtas_args_t * pArgs) +{ + int retVal = bmc_get_flashside(); + pArgs->args[pArgs->nargs] = retVal; +} + +void +rtas_flash_test(rtas_args_t * pArgs) +{ + pArgs->args[pArgs->nargs] = -1; +} + +void +rtas_system_reboot(rtas_args_t * pArgs) +{ + bmc_system_reboot(); + pArgs->args[pArgs->nargs] = -1; +} + +void +rtas_power_off(rtas_args_t * pArgs) +{ + bmc_power_off(); + pArgs->args[pArgs->nargs] = -1; +} + +void +rtas_get_blade_descr(rtas_args_t * pArgs) +{ + uint8_t *buffer = (uint8_t *) (uint64_t) pArgs->args[0]; + uint32_t maxlen = pArgs->args[1]; + uint32_t retlen = 0; + uint32_t retval = bmc_get_blade_descr(buffer, maxlen, &retlen); + pArgs->args[pArgs->nargs] = retlen; + pArgs->args[pArgs->nargs + 1] = retval; +} + +// for JS20 cannot read blade descr +static uint32_t +dummy_get_blade_descr(uint8_t *dst, uint32_t maxlen, uint32_t *len) +{ + // to not have a warning we need to do _something_ with *dst and maxlen... + *dst = *dst; + maxlen = maxlen; + *len = 0; + return -1; +} + +/* read flashside from register */ +short +reg_get_flashside(void) +{ + short retVal; + uint8_t val = load8_ci(0xf4003fe3); + if (val & 0x80) { + // temp + retVal = 1; + } else { + // perm + retVal = 0; + } + return retVal; +} + +void +rtas_init(void) +{ + io_init(); + if (u4Flag) { + bmc_system_reboot = ipmi_system_reboot; + bmc_power_off = ipmi_power_off; + bmc_set_flashside = ipmi_set_flashside; + bmc_get_flashside = reg_get_flashside; + bmc_stop_bootwatchdog = ipmi_oem_stop_bootwatchdog; + bmc_set_bootwatchdog = ipmi_oem_set_bootwatchdog; + bmc_read_vpd = ipmi_oem_read_vpd; + bmc_write_vpd = ipmi_oem_write_vpd; + bmc_get_blade_descr = ipmi_oem_get_blade_descr; + } else { + bmc_system_reboot = i2c_system_reboot; + bmc_power_off = i2c_power_off; + bmc_set_flashside = i2c_set_flashside; + bmc_get_flashside = i2c_get_flashside; + bmc_stop_bootwatchdog = i2c_stop_bootwatchdog; + bmc_set_bootwatchdog = i2c_set_bootwatchdog; + bmc_read_vpd = i2c_read_vpd; + bmc_write_vpd = i2c_write_vpd; + bmc_get_blade_descr = dummy_get_blade_descr; + } +} diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_board.h b/qemu/roms/SLOF/board-js2x/rtas/rtas_board.h new file mode 100644 index 000000000..06766e143 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_board.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __RTAS_BOARD_H +#define __RTAS_BOARD_H + +#include <stddef.h> + +extern volatile unsigned char u4Flag; + +void rtas_ibm_read_pci_config(rtas_args_t * pArgs); +void rtas_ibm_write_pci_config(rtas_args_t * pArgs); +void rtas_read_pci_config(rtas_args_t * pArgs); +void rtas_write_pci_config(rtas_args_t * pArgs); +void rtas_system_reboot(rtas_args_t * pArgs); +void rtas_power_off(rtas_args_t * pArgs); +void rtas_display_character(rtas_args_t * pArgs); +void rtas_flash_test(rtas_args_t * pArgs); +void rtas_ibm_update_flash_64_and_reboot(rtas_args_t * pArgs); +void rtas_set_indicator(rtas_args_t * pArgs); +void rtas_event_scan(rtas_args_t * pArgs); +void rtas_ibm_manage_flash_image(rtas_args_t * pArgs); +void rtas_ibm_validate_flash_image(rtas_args_t * pArgs); +void rtas_update_flash(rtas_args_t * pArgs); +void rtas_set_flashside(rtas_args_t * pArgs); +void rtas_get_flashside(rtas_args_t * pArgs); +void rtas_dump_flash(rtas_args_t * pArgs); +void rtas_start_cpu(rtas_args_t * pArgs); +void rtas_read_vpd(rtas_args_t * pArgs); +void rtas_write_vpd(rtas_args_t * pArgs); +void rtas_fetch_slaves(rtas_args_t * pArgs); +void rtas_stop_bootwatchdog(rtas_args_t * pArgs); +void rtas_get_blade_descr(rtas_args_t * pArgs); +void rtas_set_bootwatchdog(rtas_args_t * pArgs); + +#endif /* __RTAS_BOARD_H */ diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c b/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c new file mode 100644 index 000000000..189878da9 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c @@ -0,0 +1,614 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <hw.h> +#include <rtas.h> +#include "rtas_board.h" +#include <bmc.h> +#include "rtas_flash.h" +#include <flash/block_lists.h> +#include "product.h" +#include "calculatecrc.h" + +#undef DEBUG + +#ifdef DEBUG +#define dprintf(_x ...) printf(_x) +#else +#define dprintf(_x ...) +#endif + +static uint64_t size; +static uint64_t flashOffset; + +unsigned char manage_flash_buffer[BUFSIZE*2]; +unsigned long check_flash_image(unsigned long rombase, unsigned long length, + unsigned long start_crc); + +#ifdef DEBUG +static void +dump_blocklist(uint64_t *bl, int version) +{ + uint64_t bl_size; + uint8_t *addr = (uint8_t *)bl; + + if (version == 1) { + /* version 1 blocklist */ + bl_size = *bl & 0x00FFFFFFFFFFFFFFUL; + + } else { + bl_size = *bl; + } + + printf("\n\rblocklist_dump %lx", bl_size); + while (bl_size) { + unsigned int tmpCnt = bl_size; + unsigned char x; + if (tmpCnt > 8) + tmpCnt = 8; + printf("\n\r%08x: ", addr); + /* print hex */ + while (tmpCnt--) { + set_ci(); + x = *addr++; + clr_ci(); + printf("%02x ", x); + } + tmpCnt = bl_size; + if (tmpCnt > 8) + tmpCnt = 8; + bl_size -= tmpCnt; + /* reset addr ptr to print ascii */ + addr = addr - tmpCnt; + /* print ascii */ + while (tmpCnt--) { + set_ci(); + x = *addr++; + clr_ci(); + if ((x < 32) || (x >= 127)) { + /* non-printable char */ + x = '.'; + } + printf("%c", x); + } + } + printf("\r\n"); +} +#endif + +void +rtas_dump_flash(rtas_args_t *rtas_args) +{ + int retVal = 0; + unsigned int size = rtas_args->args[0]; + unsigned int offset = rtas_args->args[1]; + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + printf("\n\rflash_dump %x %x", size, offset); + flash += offset; + while (size) { + unsigned int tmpCnt = size; + unsigned char x; + if (tmpCnt > 16) + tmpCnt = 16; + printf("\n\r%p: ", flash); + /* print hex */ + while (tmpCnt--) { + set_ci(); + x = *flash++; + clr_ci(); + printf("%02x ", x); + } + tmpCnt = size; + if (tmpCnt > 16) + tmpCnt = 16; + size -= tmpCnt; + /* reset flash ptr to print ascii */ + flash = flash - tmpCnt; + /* print ascii */ + while (tmpCnt--) { + set_ci(); + x = *flash++; + clr_ci(); + if ((x < 32) || (x >= 127)) { + /* non-printable char */ + x = '.'; + } + printf("%c", x); + } + } + printf("\r\n"); + rtas_args->args[rtas_args->nargs] = retVal; +} + + +static void +print_block(int i) +{ + int counter = 8; + + while (counter--) + printf("\b"); + printf("%08x", i); +} + + + +/* To enter data mode after flash has been in programming mode + * a 0xFF has to be written */ +static void +enter_data_mode(void) +{ + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + set_ci(); + *flash = 0xFF; + eieio(); + clr_ci(); +} + + +static void +erase_flash_block(unsigned long offset) +{ + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + flash += offset; + set_ci(); + *flash = 0x20; + eieio(); + *flash = 0xd0; + eieio(); + while (!(*flash & 0x80)) ; + clr_ci(); +} + + +void +write_flash(unsigned long offset, unsigned char *data) +{ + int cnt = 32; + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + flash += (offset + flashOffset); + set_ci(); + while (cnt) { + if (!((uint64_t)flash & 0x1F)) { + while (cnt) { + uint64_t tmpcnt = cnt; + if (tmpcnt > 0x20) + tmpcnt = 0x20; + do { + *flash = 0xE8; + eieio(); + } while (!(*flash & 0x80)); + cnt -= tmpcnt; + *flash = tmpcnt - 1; + while (tmpcnt--) { + *flash++ = *data++; + } + *flash = 0xD0; + eieio(); + while (!(*flash & 0x80)) ; + } + break; + } + *flash = 0x40; + eieio(); + *flash++ = *data++; + eieio(); + while (!(*flash & 0x80)) ; + cnt--; + } + clr_ci(); +} + +static void +write_flash_page(unsigned long offset, unsigned short *data) +{ + int i = 0; + + for (i = 0; i < BUFSIZE; i += 32, offset += 32) { + write_flash(offset, ((unsigned char *)data + i)); + } +} + +/* + * 0 reject temporary image + * 1 commit temporary image + * */ +static int +copy_flash(short mode) +{ + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + uint64_t blockCnt; + uint64_t hash = 0; + short notmode = mode ^ 0x1; + + if (bmc_set_flashside(notmode) != notmode) { + return -1; + } + printf("\r\nErasing Flash: 0x "); + + for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += FLASH_BLOCK_SIZE) { + print_block(blockCnt); + erase_flash_block(blockCnt); + } + enter_data_mode(); + progress = FLASHSIZE / 38; + print_writing(); + + for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += BUFSIZE) { + uint64_t *srcPtr = (uint64_t *)(flash + blockCnt); + uint64_t *destPtr = (uint64_t *)manage_flash_buffer; + uint64_t cnt = BUFSIZE / 8; + if (bmc_set_flashside(mode) != mode) { + return -1; + } + enter_data_mode(); + set_ci(); + while (cnt--) { + *destPtr++ = *srcPtr++; + } + clr_ci(); + + if (bmc_set_flashside(notmode) != notmode) { + return -1; + } + write_flash_page(blockCnt, + (unsigned short *)manage_flash_buffer); + + /* progress output... */ + print_progress(); + if (blockCnt > hash * progress) { + print_hash(); + hash++; + } + } + enter_data_mode(); + if (bmc_set_flashside(mode) != mode) { + return -1; + } + printf("\b#\n"); + return 0; +} + +/* + * Function: ibm_manage_flash_image + * Input: + * r3: rtas parm structure + * token: 46 + * in: 1 + * out: 1 + * parm0: 0 reject temporary image + * 1 commit temporary image + * Output: + * parm1: Status (hw -1, busy -2, parameter error -3 + * -9001 cannot overwrite the active firmware image) + * + */ + +void +rtas_ibm_manage_flash_image(rtas_args_t *rtas_args) +{ + int side; + int result = 0; + short mode = rtas_args->args[0]; + + if (mode < 0 || mode > 1) { + rtas_args->args[rtas_args->nargs] = -3; + return; + } + side = bmc_get_flashside(); + if (side == 0) { + /* we are on the permanent side */ + if (mode != 0) { + rtas_args->args[rtas_args->nargs] = -9001; + return; + } + } else if (side == 1) { + /* we are on the temporary side */ + if (mode != 1) { + rtas_args->args[rtas_args->nargs] = -9001; + return; + } + } else { + rtas_args->args[rtas_args->nargs] = -1; + return; + } + + result = copy_flash(mode); + bmc_set_flashside(mode); + enter_data_mode(); + rtas_args->args[rtas_args->nargs] = result; +} + +/** + * check, if we find the FLASHFS_MAGIC token in bl + **/ +static uint8_t +check_magic(uint64_t *bl, int version) +{ + struct stH *pHeader; + + if (version == 1) { + /* version 1 blocklist */ + /* if block list size <= 0x10, it is only block list header */ + /* and address of block list extension, so look at the extension... */ + while ((*bl & 0x00FFFFFFFFFFFFFFUL) <= 0x10) + bl = (uint64_t *)bl[1]; + + /* block list item 2 _should_ be the address of our flashfs image */ + pHeader = (struct stH *)(bl[2] + 0x28); + /* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */ + return strncmp(pHeader->magic, FLASHFS_MAGIC, 8); + } else { + /* block list item 1 _should_ be the address of our flashfs image */ + pHeader = (struct stH *)(bl[1] + 0x28); + /* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */ + return strncmp(pHeader->magic, FLASHFS_MAGIC, 8); + } +} + +static void +get_image_name(char *buffer, int maxsize) +{ + volatile struct stH *flash_header = (volatile struct stH *)(SB_FLASH_adr + 0x28); + /* since we cannot read the fh_magic directly from flash as a string, we need to copy it to memory */ + uint64_t magic_val = 0; + uint64_t addr; + + /* copy fh_magic to magic_val since, we cannot use it as a string from flash */ + magic_val = load64_ci((uint64_t)(flash_header->magic)); + if (strncmp((char *)&magic_val, FLASHFS_MAGIC, 8)) { + /* magic does not match */ + sprintf(buffer, "Unknown"); + buffer[maxsize - 1] = '\0'; + return; + } + addr = (uint64_t)flash_header->version; + while (--maxsize) { + *buffer = load8_ci(addr++); + if (!*buffer++) + return; + } + *buffer = '\0'; +} + +/** + * validate_flash_image + * this function checks if the flash will be updated with the given image + * @param args[0] - buffer with minimum 4K of the image to flash + * @param args[1] - size of the buffer + * @param args[2] - status: + * 0 success + * -1 hw + * -2 busy + * -3 parameter error + * @param args[3] - update result token + */ +void +rtas_ibm_validate_flash_image(rtas_args_t *rtas_args) +{ + dprintf("\nrtas_ibm_validate_flash_image\n"); + unsigned long new_image = rtas_args->args[0]; + char *ret_str = (char *)new_image; + struct stH *flash_header = (struct stH *)(new_image + 0x28); + char current_temp_version[16]; + char current_perm_version[16]; + char new_version[16]; + int side = bmc_get_flashside(); + + /* fill args[0] with the current values which is needed + * in an error case */ + + bmc_set_flashside(0); + get_image_name(current_perm_version, sizeof(current_perm_version)); + bmc_set_flashside(1); + get_image_name(current_temp_version, sizeof(current_temp_version)); + bmc_set_flashside(side); + + /* check if the candidate image if valid for this platform */ + if (strncmp(flash_header->magic, FLASHFS_MAGIC, 8)) { + /* magic does not match */ + rtas_args->args[rtas_args->nargs] = 0; + /* No update done, the candidate image is + * not valid for this platform */ + rtas_args->args[rtas_args->nargs + 1] = 2; + sprintf(ret_str, "MI %s %s\xaMI %s %s", + current_temp_version, current_perm_version, + current_temp_version, current_perm_version); + return; + } + + if (strncmp(flash_header->platform_name, (char *)sig_org, 32)) { + /* this image if for a different board */ + rtas_args->args[rtas_args->nargs] = 0; + /* No update done, the candidate image is + * not valid for this platform */ + rtas_args->args[rtas_args->nargs + 1] = 2; + sprintf(ret_str, "MI %s %s\xaMI %s %s", + current_temp_version, current_perm_version, + current_temp_version, current_perm_version); + return; + } + + /* check header crc */ + if (check_flash_image(rtas_args->args[0], 0x88, 0)) { + /* header crc failed */ + rtas_args->args[rtas_args->nargs] = 0; + /* No update done, the candidate image is + * not valid for this platform */ + rtas_args->args[rtas_args->nargs + 1] = 2; + sprintf(ret_str, "MI %s %s\xaMI %s %s", + current_temp_version, current_perm_version, + current_temp_version, current_perm_version); + return; + } + memcpy(new_version, flash_header->version, 16); + sprintf(ret_str, "MI %s %s\xaMI %s %s", current_temp_version, + current_perm_version, new_version, current_perm_version); + rtas_args->args[rtas_args->nargs] = 0; + + if (strncmp(new_version, current_temp_version, 16) >= 0) + rtas_args->args[rtas_args->nargs + 1] = 0; + else + rtas_args->args[rtas_args->nargs + 1] = 6; +} + +/* + * Function: ibm_update_flash_64 + * Input: + * r3: rtas parm structure + * token: 7 + * in: 1 + * out: 1 + * parm0: A real pointer to a block list + * Output: + * parm1: Status (hw -1, bad image -3, programming failed -4) + * + * Description: flash if addresses above 4GB have to be addressed + */ +void +rtas_update_flash(rtas_args_t *rtas_args) +{ + void *bl = (void *)(uint64_t)rtas_args->args[0]; + int version = get_block_list_version((unsigned char *)bl); + uint64_t erase_size; + unsigned int i; + int perm_check = 1; + +#ifdef DEBUG + dump_blocklist(bl, version); +#endif + + /* from SLOF we pass a second (unofficial) parameter, if this parameter is 1, we do not + * check wether we are on permanent side. Needed for update-flash -c to work! */ + if ((rtas_args->nargs > 1) && (rtas_args->args[1] == 1)) + perm_check = 0; + + /* check magic string */ + printf("\r\nChecking magic string : "); + if (check_magic(bl, version) != 0) { + printf("failed!\n"); + rtas_args->args[rtas_args->nargs] = -3; /* bad image */ + return; + } + printf("succeeded!\n"); + + /* check platform */ + printf("Checking platform : "); + if (check_platform(bl, 0x48, version) == -1) { + printf("failed!\n"); + rtas_args->args[rtas_args->nargs] = -3; /* bad image */ + return; + } + printf("succeeded!\n"); + + /* checkcrc */ + printf("Checking CRC : "); + /* the actual CRC is included at the end of the flash image, thus the resulting CRC must be 0! */ + if (image_check_crc(bl, version) != 0) { + printf("failed!\n"); + rtas_args->args[1] = -3; /* bad image */ + return; + } + printf("succeeded!\n"); + + /* check if we are running on P + * if so, let's switch to temp and flash temp */ + if (bmc_get_flashside() == 0 && perm_check) { + printf("Set flashside: "); + bmc_set_flashside(1); + printf("Temp!\n"); + } + +#ifdef DEBUG + rtas_args_t ra; + ra.args[0] = 0x100; /* size; */ + ra.args[1] = flashOffset; + ra.nargs = 2; + + rtas_dump_flash(&ra); + printf("\n"); +#endif + + size = get_size(bl, version); + erase_size = (size + (FLASH_BLOCK_SIZE - 1)) & ~(FLASH_BLOCK_SIZE - 1); + dprintf("Erasing: size: %#x, erase_size: %#x, FLASH_BLOCK_SIZE: %#x\n", + size, erase_size, FLASH_BLOCK_SIZE); + + progress = size / 39; + printf("Erasing : 0x%08x", 0); + for (i = 0; i < erase_size; i += FLASH_BLOCK_SIZE) { + print_block(i); + erase_flash_block(i); + } + + enter_data_mode(); +#ifdef DEBUG + rtas_dump_flash(&ra); + printf("\n"); +#endif + print_writing(); + write_block_list(bl, version); + printf("\b#\n"); + enter_data_mode(); + +#ifdef DEBUG + rtas_dump_flash(&ra); + printf("\n"); +#endif + + /* checkcrc */ + printf("Recheck CRC : "); + if (check_flash_image(FLASH + flashOffset, size, 0) != 0) { + /* failed */ + printf("failed!\n\r"); + dprintf("flash_addr: %#x, flashOffset: %#x, size: %#x\n", FLASH, + flashOffset, size); + dprintf("crc: %#x\n", + check_flash_image(FLASH + flashOffset, size, 0)); + rtas_args->args[rtas_args->nargs] = -4; /* programming failed */ + return; + } + printf("succeeded!\n"); + rtas_args->args[rtas_args->nargs] = 0; +} + +/* + * Function: ibm_update_flash_64_and_reboot + * Input: + * r3: rtas parm structure + * token: 27 + * in: 1 + * out: 1 + * parm0: A real pointer to a block list + * Output: + * parm1: Status (hw -1, bad image -3, programming failed -4) + * Currently -4 and -1 are not returned + * + * Description: flash and reboot if addresses above 4GB have to be addressed + */ +void +rtas_ibm_update_flash_64_and_reboot(rtas_args_t *rtas_args) +{ + rtas_update_flash(rtas_args); + dprintf("rc: %#d\n", rtas_args->args[rtas_args->nargs]); + if (rtas_args->args[rtas_args->nargs] == 0) { + rtas_system_reboot(rtas_args); + } +} diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.h b/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.h new file mode 100644 index 000000000..3eec45d27 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <southbridge.h> + +#define FLASHSIZE FLASH_LENGTH +#define FLASH SB_FLASH_adr +#define BUFSIZE 4096 +#define FLASH_BLOCK_SIZE 0x20000 + +void write_flash(unsigned long offset, unsigned char *data); diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_i2c_bmc.h b/qemu/roms/SLOF/board-js2x/rtas/rtas_i2c_bmc.h new file mode 100644 index 000000000..e46de880e --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_i2c_bmc.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __RTAS_I2C_BMC_H +#define __RTAS_I2C_BMC_H + +#include <stddef.h> + +void i2c_system_reboot (void); +void i2c_power_off (void); +short i2c_set_flashside (short mode); +short i2c_get_flashside (void); +int i2c_stop_bootwatchdog (void); +uint32_t i2c_read_vpd (uint8_t *dst, uint32_t len, uint32_t offset); +uint32_t i2c_write_vpd (uint8_t *src, uint32_t len, uint32_t offset); +int i2c_set_bootwatchdog(unsigned short seconds); + +#endif /* __RTAS_I2C_BMC_H */ diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_ipmi_bmc.h b/qemu/roms/SLOF/board-js2x/rtas/rtas_ipmi_bmc.h new file mode 100644 index 000000000..00532d4c9 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_ipmi_bmc.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __RTAS_IPMI_BMC_H +#define __RTAS_IPMI_BMC_H + +#include <stddef.h> + +short ipmi_set_flashside (short mode); +short ipmi_get_flashside (void); + +#endif /* __RTAS_IPMI_BMC_H */ diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_out.c b/qemu/roms/SLOF/board-js2x/rtas/rtas_out.c new file mode 100644 index 000000000..ce4c00bd2 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_out.c @@ -0,0 +1,120 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <rtas.h> +#include <hw.h> +#include "rtas_board.h" + +volatile unsigned char *uart; +volatile unsigned char u4Flag; + +void io_init(void); +unsigned long check_flash_image(unsigned long rombase, unsigned long length, + unsigned long start_crc); + +void +io_init(void) +{ + // read ID register: only if it is a PC87427, enable serial2 + store8_ci(0xf400002e, 0x20); + if (load8_ci(0xf400002f) != 0xf2) { + uart = (volatile unsigned char *) 0xf40003f8; + u4Flag = 0; + } else { + uart = (volatile unsigned char *) 0xf40002f8; + u4Flag = 1; + } +} + +static void +display_char(char ch) +{ + volatile int i = 0; + volatile unsigned char *uart = (volatile unsigned char *) 0xf40002f8; + int cnt = 2; + while (cnt--) { + set_ci(); + while (!(uart[5] & 0x20)) { + i++; + } + uart[0] = ch; + clr_ci(); + uart += 0x100; + } +} + +ssize_t +write(int fd __attribute((unused)), const void *buf, size_t cnt) +{ + while (cnt--) { + display_char(*(char *) buf); + if (*(char *) buf++ == '\n') + display_char('\r'); + } + return 0; +} + +void * +sbrk(int incr __attribute((unused))) +{ + return (void *) -1; +} + + + +void +rtas_display_character(rtas_args_t * pArgs) +{ + int retVal = 0; + display_char((char) pArgs->args[0]); + pArgs->args[1] = retVal; +} + +unsigned long +check_flash_image(unsigned long rombase, unsigned long length, + unsigned long start_crc) +{ + const uint32_t CrcTableHigh[16] = { + 0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90, + 0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7, + 0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E, + 0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09 + }; + const uint32_t CrcTableLow[16] = { + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, + 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, + 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD + }; + + char *Buffer = (char *) rombase; + uint32_t AccumCRC = start_crc; + char val; + uint32_t Temp; + while (length-- > 0) { + set_ci(); + val = *Buffer; + clr_ci(); + Temp = ((AccumCRC >> 24) ^ val) & 0x000000ff; + AccumCRC <<= 8; + AccumCRC ^= CrcTableHigh[Temp / 16]; + AccumCRC ^= CrcTableLow[Temp % 16]; + ++Buffer; + } + return AccumCRC; +} diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_pci.c b/qemu/roms/SLOF/board-js2x/rtas/rtas_pci.c new file mode 100644 index 000000000..55dbf5336 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_pci.c @@ -0,0 +1,116 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <stdint.h> +#include <rtas.h> +#include <hw.h> +#include "rtas_board.h" + +void +rtas_ibm_read_pci_config (rtas_args_t *rtas_args) +{ + int retVal = 0; + uint64_t addr = ((uint64_t) rtas_args->args[1]) << 32; // high 32 bits of PHB UID + addr |= (rtas_args->args[2] & 0xFFFFFFFF); // low 32 bits of PHB UID + addr |= (rtas_args->args[0] & 0x00FFFFFF); // bus, devfn, offset + unsigned int size = rtas_args->args[3]; + + /* Check for bus != 0 on PCI/PCI-X (PHB UID = 0xf2000000) */ + if (((addr & 0xf2000000) == 0xf2000000) && (addr & 0xff0000)) + addr += 0x1000000; + + if (size == 1) + rtas_args->args[5] = load8_ci(addr); + else if (size == 2) + rtas_args->args[5] = bswap16_load(addr); + else if (size == 4) + rtas_args->args[5] = bswap32_load(addr); + else + retVal = -3; /* Bad arguments */ + + rtas_args->args[4] = retVal; +} + +void +rtas_ibm_write_pci_config (rtas_args_t *rtas_args) +{ + int retVal = 0; + uint64_t addr = ((uint64_t) rtas_args->args[1]) << 32; // high 32 bits of PHB UID + addr |= (rtas_args->args[2] & 0xFFFFFFFF); // low 32 bits of PHB UID + addr |= (rtas_args->args[0] & 0x00FFFFFF); // bus, devfn, offset + unsigned int size = rtas_args->args[3]; + + addr |= 0xf2000000; + + /* Check for bus != 0 on PCI/PCI-X (PHB UID = 0xf2000000) */ + if (((addr & 0xf2000000) == 0xf2000000) && (addr & 0xff0000)) + addr += 0x1000000; + + if (size == 1) + store8_ci(addr, rtas_args->args[4]); + else if (size == 2) + bswap16_store(addr, rtas_args->args[4]); + else if (size == 4) + bswap32_store(addr, rtas_args->args[4]); + else + retVal = -3; /* Bad arguments */ + + rtas_args->args[5] = retVal; +} + +void +rtas_read_pci_config (rtas_args_t *rtas_args) +{ + int retVal = 0; + unsigned long addr = rtas_args->args[0]; + unsigned int size = rtas_args->args[1]; + addr |= 0xf2000000; + + /* Check for bus != 0 */ + if (addr & 0xff0000) + addr += 0x1000000; + + if (size == 1) + rtas_args->args[3] = load8_ci(addr); + else if (size == 2) + rtas_args->args[3] = bswap16_load(addr); + else if (size == 4) + rtas_args->args[3] = bswap32_load(addr); + else + retVal = -3; /* Bad arguments */ + + rtas_args->args[2] = retVal; +} + +void +rtas_write_pci_config (rtas_args_t *rtas_args) +{ + int retVal = 0; + unsigned long addr = rtas_args->args[0]; + unsigned int size = rtas_args->args[1]; + + addr |= 0xf2000000; + + /* Check for bus != 0 */ + if (addr & 0xff0000) + addr += 0x1000000; + + if (size == 1) + store8_ci(addr, rtas_args->args[2]); + else if (size == 2) + bswap16_store(addr, rtas_args->args[2]); + else if (size == 4) + bswap32_store(addr, rtas_args->args[2]); + else + retVal = -3; /* Bad arguments */ + + rtas_args->args[3] = retVal; +} diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_table.c b/qemu/roms/SLOF/board-js2x/rtas/rtas_table.c new file mode 100644 index 000000000..fed4032af --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_table.c @@ -0,0 +1,45 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <rtas.h> +#include "rtas_table.h" +#include "rtas_board.h" + +const rtas_funcdescr_t rtas_func_tab[] = { + {"ibm,read-pci-config", rtas_ibm_read_pci_config, 0}, + {"ibm,write-pci-config", rtas_ibm_write_pci_config, 0}, + {"system-reboot", rtas_system_reboot, 0}, + {"power-off", rtas_power_off, 0}, + {"set-indicator", rtas_set_indicator, 0}, + {"rtas-flash-test", rtas_flash_test, RTAS_TBLFLG_INTERNAL}, + {"ibm,update-flash-64-and-reboot", rtas_ibm_update_flash_64_and_reboot, 0}, + {"display-character", rtas_display_character, 0}, + {"event-scan", rtas_event_scan, 0}, + {"ibm,manage-flash-image", rtas_ibm_manage_flash_image, 0}, + {"ibm,validate-flash-image", rtas_ibm_validate_flash_image, 0}, + {"ibm,update-flash-64", rtas_update_flash, 0}, + {"rtas-set-flashside", rtas_set_flashside, 0}, + {"rtas-get-flashside", rtas_get_flashside, 0}, + {"rtas-dump-flash", rtas_dump_flash, RTAS_TBLFLG_INTERNAL}, + {"start-cpu", rtas_start_cpu, 0}, + {"msg-read-vpd", rtas_read_vpd, RTAS_TBLFLG_INTERNAL}, + {"msg-write-vpd", rtas_write_vpd, RTAS_TBLFLG_INTERNAL}, + {"read-pci-config", rtas_read_pci_config, 0}, + {"write-pci-config", rtas_write_pci_config, 0}, + {"rtas-fetch-slaves", rtas_fetch_slaves, RTAS_TBLFLG_INTERNAL}, + {"rtas-stop-bootwatchdog", rtas_stop_bootwatchdog, RTAS_TBLFLG_INTERNAL}, + {"rtas-set-bootwatchdog", rtas_set_bootwatchdog, RTAS_TBLFLG_INTERNAL}, + {"rtas-get-blade-descr", rtas_get_blade_descr, RTAS_TBLFLG_INTERNAL}, +}; + +const int rtas_func_tab_size = sizeof(rtas_func_tab) / sizeof(rtas_func_tab[0]); diff --git a/qemu/roms/SLOF/board-js2x/slof/Makefile b/qemu/roms/SLOF/board-js2x/slof/Makefile new file mode 100644 index 000000000..ab3e683a4 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/Makefile @@ -0,0 +1,111 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +include ../Makefile.dirs + +include $(TOPBRDDIR)/config +include $(TOPCMNDIR)/make.rules + + +all: Makefile.dep OF.ffs paflof $(SLOFCMNDIR)/xvect.bin + +CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libnvram \ + -I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libbcm +SLOF_LIBS = \ + $(LIBCMNDIR)/libbootmsg.a \ + $(LIBCMNDIR)/libelf.a \ + $(LIBCMNDIR)/libusb.a \ + $(LIBCMNDIR)/libnvram.a \ + $(LIBCMNDIR)/libbcm.a +BOARD_SLOF_IN = \ + $(LIBCMNDIR)/libbootmsg/bootmsg.in \ + $(LIBCMNDIR)/libelf/libelf.in \ + $(LIBCMNDIR)/libusb/usb.in \ + $(LIBCMNDIR)/libbases/libbases.in \ + $(LIBCMNDIR)/libnvram/libnvram.in \ + $(LIBCMNDIR)/libnativeio/nativeio.in \ + $(LIBCMNDIR)/libbcm/bcm.in +BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code) + +include $(SLOFCMNDIR)/Makefile.inc + +FPPINCLUDES = -I. -I$(SLOFCMNDIR)/fs -I$(SLOFCMNDIR) + +USB_FFS_FILES = \ + $(SLOFCMNDIR)/fs/devices/pci-class_0c.fs \ + $(SLOFCMNDIR)/fs/usb/dev-hci.fs \ + $(SLOFCMNDIR)/fs/usb/slofdev.fs \ + $(SLOFCMNDIR)/fs/usb/dev-parent-calls.fs \ + $(SLOFCMNDIR)/fs/usb/dev-keyb.fs \ + $(SLOFCMNDIR)/fs/usb/dev-mouse.fs \ + $(SLOFCMNDIR)/fs/usb/dev-storage.fs \ + $(SLOFCMNDIR)/fs/usb/dev-hub.fs + +# Files that should go into the ROM fs (and so have to be listed in OF.ffs): +OF_FFS_FILES = \ + $(SLOFBRDDIR)/u4-mem.fs \ + $(SLOFBRDDIR)/attu.fs \ + $(SLOFBRDDIR)/cpu.fs \ + $(SLOFBRDDIR)/ioapic.fs \ + $(SLOFBRDDIR)/pci-bridge_1022_7460.fs \ + $(SLOFBRDDIR)/pci-device_1014_028c.fs \ + $(SLOFBRDDIR)/pci-device_1014_02bd.fs \ + $(SLOFBRDDIR)/pci-device_1022_7468.fs \ + $(SLOFBRDDIR)/pci-device_1022_7469.fs \ + $(SLOFBRDDIR)/pci-device_1022_7451.fs \ + $(SLOFBRDDIR)/pci-device_14e4_16a8.fs \ + $(SLOFBRDDIR)/bcm57xx.fs \ + $(SLOFBRDDIR)/pci-class_03.fs \ + $(SLOFBRDDIR)/vga-display.fs \ + $(SLOFBRDDIR)/freq.fs \ + $(SLOFBRDDIR)/pci-device_1002_515e.fs \ + $(SLOFBRDDIR)/citrine.fs \ + $(SLOFBRDDIR)/citrine-disk.fs \ + $(SLOFBRDDIR)/sio.fs \ + $(SLOFBRDDIR)/tpm.fs \ + $(SLOFBRDDIR)/ipmi-kcs.fs \ + $(SLOFCMNDIR)/fs/ide.fs \ + $(SLOFCMNDIR)/fs/fbuffer.fs \ + $(SLOFCMNDIR)/fs/graphics.fs \ + $(SLOFCMNDIR)/fs/generic-disk.fs \ + $(SLOFCMNDIR)/fs/scsi-disk.fs \ + $(SLOFCMNDIR)/fs/scsi-host-helpers.fs \ + $(SLOFCMNDIR)/fs/scsi-probe-helpers.fs \ + $(SLOFCMNDIR)/fs/scsi-support.fs \ + $(SLOFCMNDIR)/fs/pci-device.fs \ + $(SLOFCMNDIR)/fs/pci-bridge.fs \ + $(SLOFCMNDIR)/fs/pci-properties.fs \ + $(SLOFCMNDIR)/fs/pci-config-bridge.fs \ + $(SLOFCMNDIR)/fs/update_flash.fs \ + $(SLOFCMNDIR)/fs/xmodem.fs \ + $(SLOFCMNDIR)/fs/devices/pci-device_10de_0141.fs \ + $(SLOFCMNDIR)/fs/devices/pci-class_02.fs \ + $(SLOFBRDDIR)/default-font.bin + +# Uncomment the following line to enable the USB code: +OF_FFS_FILES += $(USB_FFS_FILES) + +OF_FFS_FILES := $(OF_FFS_FILES:%.fs=%.fsi) + +OF.ffs: Makefile $(SLOFCMNDIR)/Makefile.inc $(OF_FFS_FILES) + $(MAKE) create_OF_ffs + +# Rules for cleaning up: +.PHONY: clean_here clean distclean + +clean_here: + rm -f *.o OF.fsi OF.ffs + +clean: clean_here clean_slof + +distclean: clean_here distclean_slof diff --git a/qemu/roms/SLOF/board-js2x/slof/OF.fs b/qemu/roms/SLOF/board-js2x/slof/OF.fs new file mode 100644 index 000000000..3e3773580 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/OF.fs @@ -0,0 +1,557 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ The master file. Everything else is included into here. + +hex + +' ll-cr to cr + +\ as early as possible we want to know if it is js20, js21 or bimini +\ u3 = js20; u4 = js21/bimini +\ the difference if bimini or js21 will be done later depending if +\ obsidian or citrine is found +\ f8000000 is probably the place of the u3/u4 version +f8000000 rl@ CONSTANT uni-n-version +uni-n-version 4 rshift dup 3 = CONSTANT u3? 4 = CONSTANT u4? +\ if (f4000682 >> 4) == 1... it is a bimini... +f4000682 rb@ 4 rshift 1 = CONSTANT bimini? + +\ to decide wether vga initialisation using bios emulation should be attempted, +\ we need to know wether a vga-device was found during pci-scan. +\ If it is found, this value will be set to the device's phandle +0 value vga-device-node? + +\ planar-id reads back GPIO 29 30 31 and returns it as one value +\ if planar-id >= 5 it should be GA2 else it is GA1 (JS20 only) +defer planar-id ( -- planar-id ) + +: (planar-id) ( -- planar-id) + \ default implementation of planar-id just returns 8 + \ the highest possible planar id for JS20 is 7 + 8 +; + +' (planar-id) to planar-id + +#include "header.fs" + +\ I/O accesses. +#include "io.fs" + +\ XXX: Enable first UART on JS20, scripts forget to do this. Sigh. +3 7 siocfg! 1 30 siocfg! + +#include "serial.fs" + +cr + +#include "base.fs" + +\ Little-endian accesses. Also known as `wrong-endian'. +#include <little-endian.fs> + +\ do not free-mem if address is not within the heap +\ workaround for NVIDIA card +: free-mem ( addr len -- ) + over heap-start heap-end within IF + free-mem + ELSE + 2drop + THEN +; + +: #join ( lo hi #bits -- x ) lshift or ; +: #split ( x #bits -- lo hi ) 2dup rshift dup >r swap lshift xor r> ; + +: blink ; + +: reset-dual-emit ; + +: console-clean-fifo ; + +: bootmsg-nvupdate ; + +: asm-cout 2drop drop ; + +#include "logging.fs" + +: log-string 2drop ; + +#include "bootmsg.fs" + +000 cp + +\ disable the nvram logging until we know if we are +\ running from ram/takeover/js20 or in normal mode on js21 +: (nvramlog-write-byte) drop ; +' (nvramlog-write-byte) to nvramlog-write-byte + +#include "exception.fs" + +: mm-log-warning 2drop ; + +: write-mm-log ( data length type -- status ) + 3drop 0 +; + +080 cp + +#include "rtc.fs" + +100 cp + +\ Input line editing. +#include "accept.fs" + +120 cp + +#include "dump.fs" + +cistack ciregs >r1 ! \ kernel wants a stack :-) + +#include "romfs.fs" + +140 cp +#include "flash.fs" + +\ 1 temp; 0 perm; let's default to temp +1 VALUE flashside? + +\ claim the memory used by copy of the flash +flash-header IF + romfs-base dup flash-image-size 0 claim drop +THEN + +s" bootinfo" romfs-lookup drop c + l@ CONSTANT start-addr +start-addr flash-addr <> CONSTANT takeover? + +takeover? u3? or 0= IF + \ we want nvram logging to work + ['] .nvramlog-write-byte to nvramlog-write-byte +THEN + +160 cp + +u4? IF f8002100 rl@ 0= ELSE false THEN ?INCLUDE u4-mem.fs +u3? IF + planar-id 5 >= IF + 40000 to nvram-size + ELSE + \ change nvram-size to 8000 for GA1 blades + 8000 to nvram-size + THEN +THEN + + +takeover? IF + \ potentially coming from phype + u4? IF + \ takeover on JS21 is using some nvram area + \ which might be available + \ on JS20 the nvram is too small and + \ we just overwrite the nvram + sec-nvram-base to nvram-base + THEN + sec-nvram-size to nvram-size + \ in takeover mode the nvram is probably not mapped + \ to the exact location where the nvram starts + \ doing a small check to see if we have a partition + \ starting with 70; this test is far from perfect but + \ takeover is not the most common mode of running slof + nvram-base rb@ 70 <> IF 0 nvram-base rb! THEN +THEN + +200 cp + +#include <slof-logo.fs> +#include <banner.fs> + +: .banner .slof-logo .banner ; + +\ Get the secondary CPUs into our own spinloop. +f8000050 rl@ CONSTANT master-cpu +\ cr .( The master cpu is #) master-cpu . + +VARIABLE cpu-mask +: get-slave ( n -- online? ) + 0 3ff8 ! 18 lshift 30000000 or 48003f02 over l! icbi 10000 0 DO LOOP 3ff8 @ ; +: mark-online ( n -- ) 1 swap lshift cpu-mask @ or cpu-mask ! ; +: get-slaves 40 0 DO i get-slave IF i mark-online THEN LOOP ; +: cpu-report ( -- ) + cpu-mask @ 40 0 DO dup 1 and IF ." #" i . THEN 1 rshift LOOP drop +; + +220 cp +master-cpu mark-online get-slaves + +DEFER disable-watchdog ( -- ) +DEFER find-boot-sector ( -- ) + + +240 cp +\ Timebase frequency, in Hz. +\ -1 VALUE tb-frequency +d# 14318378 VALUE tb-frequency \ default value - needed for "ms" to work +-1 VALUE cpu-frequency + +#include "helper.fs" +260 cp + +#include <timebase.fs> + +270 cp + +#include <fcode/evaluator.fs> + +280 cp + +\ rtas-config is not used +0 CONSTANT rtas-config + +#include "rtas.fs" +290 cp +s" update_flash.fs" included +2a0 cp +cpu-mask @ rtas-fetch-cpus drop + +: of-start-cpu rtas-start-cpu ; + +' power-off to halt +' rtas-system-reboot to reboot + +: other-firmware rtas-get-flashside 0= IF 1 ELSE 0 THEN rtas-set-flashside reboot ; +: disable-boot-watchdog rtas-stop-bootwatchdog drop ; +' disable-boot-watchdog to disable-watchdog + +true value bmc? +false value debug-boot? + +\ for JS21/Bimini try to detect BMC... if kcs (io @ca8) status is not ff... +u4? IF ca8 4 + io-c@ ff = IF false to bmc? true to debug-boot? THEN THEN + +VARIABLE memnode + +\ Hook to help loading our secondary boot loader. +DEFER disk-read ( lba cnt addr -- ) +0 VALUE disk-off + +create vpd-cb 24 allot +create vpd-bootlist 4 allot +2c0 cp +#include "ipmi-vpd.fs" +2e0 cp +#include <quiesce.fs> +300 cp +#include <usb/usb-static.fs> +320 cp +#include <scsi-loader.fs> +#include <root.fs> +360 cp +#include "tree.fs" + +: .system-information ( -- ) + s" " type cr + s" SYSTEM INFORMATION" type cr + s" Processor = " type s" cpu" get-chosen IF + drop l@ >r pvr@ s" pvr>name" r> $call-method type + s" @ " type cpu-frequency d# 1000000 / + decimal . hex s" MHz" type + THEN cr s" I/O Bridge = " type u3? IF + s" U3" ELSE s" U4" THEN type + f8000000 rl@ 4 rshift s" (" type 1 0.r s" ." type + f8000000 rl@ f and 1 0.r s" )" type cr + s" SMP Size = " type cpu-mask @ cnt-bits 1 0.r + s" (" type cpu-report 8 emit s" )" type + cr s" Boot-Date = " type .date cr + s" Memory = " type s" memory" get-chosen IF + drop l@ s" mem-report" rot $call-method THEN + cr s" Board Type = " type u3? IF + s" JS20(GA" type planar-id 5 >= IF + s" 2)" ELSE s" 1)" THEN type + ELSE bimini? IF s" Bimini" ELSE s" JS21" THEN type THEN + s" (" type .vpd-machine-type [char] / emit + .vpd-machine-serial [char] / emit + .vpd-hw-revision 8 emit s" )" type cr + s" MFG Date = " type .vpd-manufacturer-date cr + s" Part No. = " type .vpd-part-number cr + s" FRU No. = " type .vpd-fru-number cr + s" FRU Serial = " type .vpd-cardprefix-serial .vpd-card-serial cr + s" UUID = " type .vpd-uuid cr + s" Flashside = " type rtas-get-flashside 0= IF + ." 0 (permanent)" + ELSE + ." 1 (temporary)" THEN cr + s" Version = " type + takeover? IF + romfs-base 38 + a type + ELSE + slof-build-id here swap rmove + here slof-build-id nip type cr + s" Build Date = " type bdate2human type + THEN + cr cr +; + +800 cp + +#include "nvram.fs" +takeover? not u4? and IF + \ if were are not in takeover mode the nvram should look + \ something like this: + \ type size name + \ ======================== + \ 51 20000 ibm,CPU0log + \ 51 5000 ibm,CPU1log + \ 70 1000 common + \ 7f da000 <free-space> + \ the partition with the type 51 should have been added + \ by LLFW... if it does not exist then something went + \ wrong and we just destroy the whole thing + 51 get-nvram-partition IF 0 0 nvram-c! ELSE 2drop THEN +THEN + +880 cp + +\ dmesg/dmesg2 not available if running in takeover/ram mode or on js20 +: dmesg ( -- ) u3? takeover? or 0= IF dmesg THEN ; +: dmesg2 ( -- ) u3? takeover? or 0= IF dmesg2 THEN ; + +#include "envvar.fs" +check-for-nvramrc + +8a0 cp +\ The client interface. +#include "client.fs" +\ ELF binary file format. +#include "elf.fs" +#include <loaders.fs> + +8a8 cp + +\ check wether a VGA device was found during pci scan, if it was +\ try to initialize it and create the needed device-nodes +0 value biosemu-vmem +100000 value biosemu-vmem-size +0 value screen-info + +: init-vga-devices ( -- ) + vga-device-node? 0= use-biosemu? 0= OR IF + EXIT + THEN + s" VGA Device found: " type vga-device-node? node>path type s" initializing..." type cr + \ claim virtual memory for biosemu of 1MB + biosemu-vmem-size 4 claim to biosemu-vmem + \ claim memory for screen-info struct (140 bytes) + d# 140 4 claim to screen-info + \ remember current-node (it might be node 0 so we cannot use get-node) + current-node @ + \ change into vga device node + vga-device-node? set-node + \ run biosemu to initialize the vga card + \ s" Time before biosemu:" type .date cr + vga-device-node? node>path ( pathstr len ) + s" biosemu " biosemu-vmem $cathex ( pathstr len paramstr len ) + 20 char-cat \ add a space ( pathstr len paramstr len ) + biosemu-vmem-size $cathex \ add VMEM Size ( pathstr len paramstr len ) + 20 char-cat \ add a space ( pathstr len paramstr len ) + 2swap $cat ( paramstr+path len ) + biosemu-debug 0<> IF + 20 char-cat biosemu-debug $cathex \ add biosemu-debug as param + ( paramstr+path+biosemu-debug len ) + THEN + .(client-exec) IF + ." biosemu client exec failed!" cr + set-node \ restore old current-node + EXIT + THEN + \ s" Time after biosemu:" type .date cr + s" VGA initialization: detecting displays..." type cr + \ try to get info for two monitors + 2 0 DO + \ setup screen-info struct as input to get_vbe_info + s" DDC" 0 char-cat screen-info swap move \ null-terminated "DDC" as signature + d# 140 screen-info 4 + w! \ reserved size in bytes (see claim above) + i screen-info 6 + c! \ monitor number + \ 320 screen-info 7 + w! \ max. screen width (800) + 500 screen-info 7 + w! \ max. screen width (1280) + \ following line would be the right thing to do, however environment seems not setup yet... + \ screen-#columns char-width * 500 min 280 max screen-info 7 + w! \ max. screen width, calculated from environment variable screen-#columns, but max. 1280, min. 640... + 8 screen-info 9 + c! \ requested color depth (8bpp) + \ d# 16 screen-info 9 + c! \ requested color depth (16bpp) + \ execute get_vbe_info from load-base + \ s" Time before client exec:" type .date cr + \ since node>path overwrites strings created with s" + \ we need to call it before assembling the parameter string + vga-device-node? node>path ( pathstr len ) + s" get_vbe_info " biosemu-vmem $cathex ( pathstr len paramstr len ) + 20 char-cat \ add a space ( pathstr len paramstr len ) + biosemu-vmem-size $cathex \ add VMEM Size ( pathstr len paramstr len ) + 20 char-cat \ add a space ( pathstr len paramstr len ) + 2swap $cat ( paramstr+path len ) + 20 char-cat + screen-info $cathex + .(client-exec) 0= + \ s" Time after client exec:" type .date cr + screen-info c@ 0<> AND IF + s" display " type i . s" found..." type + \ screen found + \ create device entry + get-node node>name \ get current nodes name (e.g. "vga") ( str len ) + i \ put display-num on the stack ( str len displaynum ) + new-device \ create new device + s" vga-display.fs" included + finish-device + s" created." type cr + THEN + LOOP + \ return to where we were before changing to vga device node + set-node + \ release the claimed memory + screen-info d# 140 release + biosemu-vmem biosemu-vmem-size release + + s" VGA initialization done." type cr +; + +init-vga-devices + +: enable-framebuffer-output ( -- ) +\ enable output on framebuffer + s" screen" find-alias ?dup IF + \ we need to open/close the screen device once + \ before "ticking" display-emit to emit + open-dev close-node + s" display-emit" $find IF + to emit + ELSE + 2drop + THEN + THEN +; + +enable-framebuffer-output + +8b0 cp + +\ do not let the usb scan overwrite the atapi cdrom alias +\ pci-cdrom-num TO cdrom-alias-num +usb-scan + +: create-aliases ( -- ) + s" net" s" net1" find-alias ?dup IF set-alias ELSE 2drop THEN + s" disk" s" disk0" find-alias ?dup IF set-alias ELSE 2drop THEN + s" cdrom" s" cdrom0" find-alias ?dup IF set-alias ELSE 2drop THEN +; + +create-aliases + +8ff cp + +.system-information + +: directserial +u3? IF + s" /ht/isa/serial@3f8" io +ELSE + s" direct-serial?" evaluate IF s" /ht/isa/serial@2f8" io ELSE s" /ht/isa/serial@3f8" io THEN +THEN +; + +directserial + +\ on bimini we want to automatically enable screen and keyboard, if they are detected... +bimini? IF + key? IF + cr ." input available on current console input device, not switching input / output." cr + ELSE + \ this enables the framebuffer as primary output device + s" screen" find-alias IF drop + s" screen" output + \ at this point serial output is theoretically disabled + ." screen detected and set as default output device" cr + THEN + \ enable USB keyboard + s" keyboard" find-alias IF drop + s" keyboard" input + \ at this point serial input is disabled + ." keyboard detected and set as default input device" cr cr cr + s" Press 's' to enter Open Firmware." type cr + 500 ms + THEN + THEN +THEN + +: .flashside + cr ." The currently active flashside is: " + rtas-get-flashside 0= IF ." 0 (permanent)" ELSE + ." 1 (temporary)" THEN +; + +bmc? IF disable-watchdog THEN + +: flashsave ( "{filename}" -- rc ) + (parse-line) dup 0> IF + s" netsave " \ command + get-flash-base $cathex \ Flash base addr + s" 400000 " $cat \ Flash size (4MB) + 2swap $cat \ add parameters from (parse-line) + evaluate + ELSE + cr + ." Usage: flashsave [bootp|dhcp,]filename[,siaddr][,ciaddr][,giaddr][,bootp-retries][,tftp-retries][,use_ci]" + cr 2drop + THEN +; + +#include <vpd-bootlist.fs> + +\ for the blades we read the bootlist from the VPD +bimini? takeover? or 0= IF ['] vpd-boot-import to read-bootlist THEN + +\ for the bimini, we try to boot from disk, if it exists, +\ only if "boot-device" is not set in the nvram +: bimini-bootlist + \ check nvram + s" boot-device" evaluate swap drop ( boot-device-strlen ) + 0= IF + \ no boot-device set in NVRAM, check if disk is available and set it... + \ clear boot-device list + 0 0 set-boot-device + s" disk" find-alias ?dup IF + \ alias found, use it as default + add-boot-device + THEN + THEN +; + +bimini? IF ['] bimini-bootlist to read-bootlist THEN + +#include <start-up.fs> + +#include <boot.fs> + +cr .( Welcome to Open Firmware) +cr +#include "copyright-oss.fs" +cr + +\ this CATCH is to ensure the code bellow always executes: boot may ABORT! +' start-it CATCH drop + +#include <history.fs> +nvram-history? [IF] +." loading shell history .. " +history-load +." done" cr +[THEN] + diff --git a/qemu/roms/SLOF/board-js2x/slof/attu.fs b/qemu/roms/SLOF/board-js2x/slof/attu.fs new file mode 100644 index 000000000..cc1225296 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/attu.fs @@ -0,0 +1,101 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ U4 "Attu" PCIe root complex. + +\ See the PCI OF binding document. + +new-device + +s" pciex" device-name s" pci" device-type +s" U4-pcie" compatible +s" U4" encode-string s" model" property + +\ spare out 0xc0000000-0xefffffff for pcie +f8070200 rl@ fffffff0 and f8070200 rl! +\ enable io memory for pcie @ c0000000-efffffff +70000003 f80903f0 rl!-le + +3 encode-int s" #address-cells" property +2 encode-int s" #size-cells" property + +s" /mpic" find-node encode-int s" interrupt-parent" property +\ XXX should have interrupt map, etc. this works for now though. + +: decode-unit 2 hex-decode-unit 3 #join 8 lshift 0 0 rot F00000 + ; +: encode-unit nip nip ff00 and 8 rshift 3 #split + over IF 2 ELSE nip 1 THEN hex-encode-unit ; + +f1000000 CONSTANT my-puid +\ Configuration space accesses. +: >config f1000000 + ; +: config-l! >config rl!-le ; +: config-l@ >config rl@-le ; +: config-w! >config rw!-le ; +: config-w@ >config rw@-le ; +: config-b! >config rb! ; +: config-b@ >config rb@ ; + +: config-dump ( addr size -- ) ['] config-l@ 4 (dump) ; + +\ 16MB of configuration space +f1000000 encode-64 1000000 encode-64+ s" reg" property + +\ 4MB of I/O space. +01000000 encode-int 00000000 encode-int+ 00000000 encode-int+ +00000000 encode-int+ f0000000 encode-int+ +00000000 encode-int+ 00400000 encode-int+ + +\ 1.75GB of memory space @ c0000000. +02000000 encode-int+ c0000000 encode-64+ +c0000000 encode-64+ 30000000 encode-64+ s" ranges" property + +\ Host bridge, so full bus range. +f0 encode-int ff encode-int+ s" bus-range" property + +: open true ; +: close ; + +\ : probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- ) +s" /mpic" find-node my-puid pci-irq-init drop + +00fff1f0 18 config-l! + +ff F0 f0000000 e8000000 e8000000 c0000000 100000000 f000 +my-puid probe-pci-host-bridge + +\ \ PCIe debug / fixup +: find-pcie-cap ( devfn -- offset | 0 ) + >r 34 BEGIN r@ + config-b@ dup ff <> over and WHILE + dup r@ + config-b@ 10 = IF + r> drop EXIT + THEN 1+ + REPEAT r> 2drop 0 +; + + : (set-ps) ( ps addr -- ) + 8 + >r 5 lshift r@ config-w@ ff1f and or r> config-w! ; + : set-ps ( ps -- ) + log2 7 - + 10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF + + 2dup (set-ps) THEN drop LOOP drop ; + + : (set-rr) ( rr addr -- ) + 8 + >r c lshift r@ config-w@ 8fff and or r> config-w! ; + : set-rr ( rr -- ) + log2 7 - + 10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF + + 2dup (set-rr) THEN drop LOOP drop ; + +80 set-ps 80 set-rr + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/bcm57xx.fs b/qemu/roms/SLOF/board-js2x/slof/bcm57xx.fs new file mode 100644 index 000000000..c8e6f5aa9 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/bcm57xx.fs @@ -0,0 +1,75 @@ +\ ***************************************************************************** +\ * Copyright (c) 2013 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle bcm57xx device + +s" network" device-type + +my-space pci-alias-net + +VARIABLE obp-tftp-package + +0 VALUE bcm57xx-priv +0 VALUE open-count + +: open ( -- okay? ) + open-count 0= IF + open IF + bcm57xx-open dup not IF ." bcm57xx-open failed" EXIT THEN + drop dup TO bcm57xx-priv + 6 encode-bytes s" local-mac-address" property + true + ELSE + false + THEN + ELSE + true + THEN + my-args s" obp-tftp" $open-package obp-tftp-package ! + open-count 1 + to open-count +; + + +: close ( -- ) + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + bcm57xx-priv bcm57xx-close + close + THEN + THEN + s" close" obp-tftp-package @ $call-method +; + +: read ( buf len -- actual ) + dup IF + bcm57xx-read + ELSE + nip + THEN +; + +: write ( buf len -- actual ) + dup IF + bcm57xx-write + ELSE + nip + THEN +; + +: load ( addr -- len ) + s" load" obp-tftp-package @ $call-method +; + +: ping ( -- ) + s" ping" obp-tftp-package @ $call-method +; diff --git a/qemu/roms/SLOF/board-js2x/slof/citrine-disk.fs b/qemu/roms/SLOF/board-js2x/slof/citrine-disk.fs new file mode 100644 index 000000000..146e7ece3 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/citrine-disk.fs @@ -0,0 +1,79 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +( max-#blocks rsrc id -- ) + +new-device + +lwsplit swap wbsplit rot set-unit + +s" disk" device-name s" block" device-type + +CONSTANT resource-id +CONSTANT max-#blocks +get-parent CONSTANT ppack + + +: our-disk-read ( lba count addr -- ) + >r >r >r resource-id r> r> r> s" do-read" ppack $call-static ; + +0 pci-alias-disk + +\ Requiered interface for deblocker + +200 CONSTANT block-size +40000 CONSTANT max-transfer + +: read-blocks ( addr block# #blocks -- #read ) +\ my-unit s" dev-read-blocks" $call-parent + \ check if the read is within max-#blocks + 2dup + max-#blocks 1 + > IF + \ 2drop drop 0 \ return 0 + \ returning 0 would be correct (maybe?) but it confuses the deblocker... + \ so i erase whatever would have been read and return the "expected" #read + dup >r + swap drop \ drop block# (not needed) + block-size * erase \ erase at addr #blocks * block-size + r> \ return #read + ELSE + dup >r rot our-disk-read r> + THEN +; + +INSTANCE VARIABLE deblocker + +: open ( -- okay? ) + 0 0 s" deblocker" $open-package dup deblocker ! dup IF + s" disk-label" find-package IF + my-args rot interpose + THEN + THEN 0<> ; + +: close ( -- ) + deblocker @ close-package ; + +: seek ( pos.lo pos.hi -- status ) + 2dup lxjoin max-#blocks 1 + block-size * > IF + \ illegal seek, return -1 + 2drop -1 + ELSE + s" seek" deblocker @ $call-method + THEN +; + +: read ( addr len -- actual ) + s" read" deblocker @ $call-method ; + + +finish-device + diff --git a/qemu/roms/SLOF/board-js2x/slof/citrine-flash.fs b/qemu/roms/SLOF/board-js2x/slof/citrine-flash.fs new file mode 100644 index 000000000..5842b07c9 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/citrine-flash.fs @@ -0,0 +1,36 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ we do all flash accesses as 8-bit + +9f000000 CONSTANT citrine-flash-addr + +: >citrine-flash citrine-flash-addr + ; +: citrine-flash@ >citrine-flash rb@ ; +: citrine-flash! >citrine-flash rb! ; +: wait-for-citrine-flash-ready BEGIN 0 citrine-flash@ 80 and UNTIL ; +: erase-citrine-flash-block ( offset -- ) + cr dup 8 .r ." Erasing..." + 20 over citrine-flash! d0 swap citrine-flash! wait-for-citrine-flash-ready ; +: write-citrine-flash ( data offset -- ) + over ff = IF 2drop EXIT THEN + 40 over citrine-flash! citrine-flash! wait-for-citrine-flash-ready ; +: write-citrine-flash-block ( addr offset -- ) \ always writes 128kB! + ." Writing..." + 20000 0 DO over i + c@ over i + write-citrine-flash LOOP 2drop + ." Done." ; +: citrine-flash ( addr offset size -- ) + BEGIN dup 0 > WHILE >r dup erase-citrine-flash-block + 2dup write-citrine-flash-block >r 20000 + r> 20000 + r> 20000 - REPEAT + drop 2drop -1 0 citrine-flash! ; + diff --git a/qemu/roms/SLOF/board-js2x/slof/citrine.fs b/qemu/roms/SLOF/board-js2x/slof/citrine.fs new file mode 100644 index 000000000..ad6777699 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/citrine.fs @@ -0,0 +1,245 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Citrine storage controller. +2dup type + +device-name s" ide" device-type + + +3 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +: decode-unit 3 hex-decode-unit ; +: encode-unit 3 hex-encode-unit ; + + +: >ioa [ 10 config-l@ -10 and ] LITERAL + ; +: ioa@ >ioa rl@-le ; +: ioa! >ioa rl!-le ; + + +\ Clear request completion doorbell. +2 228 ioa! + +\ status +CREATE ioasa 200 allot ioasa 200 erase \ can reduce to 8 later + +\ request/response queue +CREATE rrq 100 allot rrq 100 erase \ can be smaller + +\ data descriptor +CREATE ioadl 8 allot + +\ control block +CREATE ioarcb 80 allot ioarcb 80 erase +ioarcb dup l! +60708090 ioarcb c + l! \ user handle +ioadl ioarcb 2c + l! \ read ioadl +ioasa ioarcb 34 + l! 200 ioarcb 38 + w! + +\ ioa config data (max. 16 devices) +CREATE ioacfg 404 allot ioacfg 404 erase +CREATE setsupbuff 2c allot + setsupbuff 2c erase + 2c setsupbuff w! + 1 setsupbuff 3 + c! + +: wait-ready ( -- ) + 82800000 214 ioa! + 80000000 BEGIN dup 224 ioa@ cr .s dup 8000000 and IF + cr ." Unit check on SAS-Controller detected" + cr 42c ioa@ . + 8 110 ioa! + BEGIN cr 0 config-l@ dup . ffffffff <> UNTIL +\ ABORT" Unit check on SAS-Controller detected" + THEN + and + UNTIL drop +; + +\ wait-ready + +: wait-ioa ( int-mask -- ) BEGIN dup 224 ioa@ and UNTIL drop ; +: init-ioa ( -- ) 82800000 214 ioa! 80000000 wait-ioa ; +: do-request ( -- ) ioasa 20 erase ioarcb 404 ioa! + 2 wait-ioa 2 228 ioa! +; + +: setup-ioarcb ( rsrc type addr len -- ) + tuck 49000000 or ioadl l! ioadl 4 + l! \ setup ioadl + ioarcb 20 + l! ioadl ioarcb 2c + l! 8 ioarcb 30 + l! \ set len, ioadl addr + ioarcb 3e + c! ioarcb 8 + l! \ set type and resource + ioarcb 40 + 40 erase ; + +: setup-wrioarcb ( rsrc type addr len -- ) + tuck 49000000 or ioadl l! ioadl 4 + l! \ setup ioadl + ioarcb 1C + l! ioadl ioarcb 24 + l! 8 ioarcb 28 + l! \ set len, ioadl addr + ioarcb 3e + c! ioarcb 8 + l! \ set type and resource + ioarcb 40 + 40 erase ; + +: setup-idrrq ( rrq len -- ) + c4 ioarcb 42 + c! 8 lshift ioarcb 48 + l! ioarcb 44 + l! ; +: do-idrrq ( -- ) -1 1 0 0 setup-ioarcb rrq 100 setup-idrrq do-request ; + +: setup-query ( len -- ) c5 ioarcb 42 + c! 8 lshift ioarcb 48 + l! ; +: do-query ( -- ) -1 1 ioacfg 404 setup-ioarcb 404 setup-query do-request ; + +: setup-startUnit ( -- ) 1b ioarcb 42 + c! 3 ioarcb 46 + c! ; +: do-startUnit ( hndl -- ) 0 0 0 setup-ioarcb setup-startUnit do-request ; + +: setup-setsupported ( len -- ) 80 ioarcb 40 + c! fb ioarcb 42 + c! 8 lshift ioarcb 48 + l! ; +: do-setsupported ( -- ) -1 1 setsupbuff 2c setup-wrioarcb 2c setup-setsupported do-request ; + +\ ******************************** +\ read capacity +\ ******************************** +CREATE cap 8 allot + +: setup-cap ( -- ) 25 ioarcb 42 + c! cap 8 erase ; +: do-cap ( rsrc addr -- ) + >r 0 r> 8 setup-ioarcb setup-cap do-request ; + +: .id ( id -- ) ." @" lwsplit 2 0.r ." ," wbsplit 2 0.r ." ," 2 0.r ; + +: .cap ( rsrc -- ) + cap do-cap cap l@ cap 4 + l@ * d# 50000000 + d# 100000000 / + base @ >r decimal d# 10 /mod 4 .r ." ." 0 .r ." GB" r> base ! ; + +\ ******************************** +\ Test Unit Ready +\ ******************************** +: setup-test-unit-ready ( -- ) + 00 ioarcb 42 + c! \ SCSI cmd: Test-Unit-Ready +; + +: do-test-unit-ready ( rsrc -- ) + 0 0 0 setup-ioarcb ( rsrc type addr len -- ) + setup-test-unit-ready + do-request +; + +\ ******************************** +\ Check devices +\ ******************************** +: check-device ( ioacfg-entry -- ) + dup 2 + w@ 2001 and 0<> \ generic or raid disk + IF \ is an IOA resource ? + dup 8 + l@ ( ioacfg-entry rsrc ) \ get resource handle + 8 0 + DO ( ioacfg-entry rsrc ) + dup do-test-unit-ready ( ioacfg-entry rsrc ) + ioasa l@ 0= \ read returned status + IF + LEAVE + THEN + LOOP + drop ( ioacfg-entry ) + THEN + drop ( ) +; + +: check-devices ( -- ) + ioacfg 4 + ( ioacfg-entry ) \ config block for 16 devices + ioacfg c@ 0 \ amount of detected devices + ?DO + dup + check-device ( ioacfg-entry ) + 40 + + LOOP + drop +; + +\ ******************************** +\ Show Devices +\ ******************************** +: show-device ( ioacfg-entry -- ) + cr ." " dup 2 + w@ + dup 8000 and IF ." Controller :" THEN + dup 2000 and IF ." Disk (RAID Member):" THEN + dup 0002 and IF ." Disk (Volume Set) :" THEN + 0001 and IF ." Disk (Generic) :" THEN + space dup 4 + l@ ffffff and dup ffffff <> IF + .id + ELSE drop 9 spaces THEN space + dup 1c + 8 type space dup 24 + 10 type + dup 2 + w@ 8000 and 0= IF + space dup 8 + l@ .cap + THEN drop +; + +: show-devices ( -- ) + ioacfg 4 + ioacfg c@ 0 + ?DO dup show-device 40 + LOOP drop +; + +: setup-read ( lba len -- ) \ len is in blocks + 28 ioarcb 42 + c! + swap ioarcb 44 + l! + 8 lshift ioarcb 48 + l! +; + +: do-read ( hndl lba len addr -- ) \ len is in blocks + over >r rot >r swap 0 -rot 200 * ( 0 hndl addr len* ) + setup-ioarcb r> r> ( lba len ) + setup-read do-request +; + +: make-subnode ( rsrc-type rsrc-handle id -- ) + rot 2 and IF \ only device which are part of a RAID should be started + over do-startUnit \ at least on citrine there are problems starting + \ Generic SCSI devices + THEN do-setsupported + dup ffffff <> IF + \ we need max-#blocks for citrine-disk.fs + ( rsrc id ) + over cap do-cap cap l@ ( rsrc id max-#blocks ) + swap rot swap ( max-#block rsrc id ) \ this is what citrine-disk.fs expects... + s" citrine-disk.fs" included + ELSE + 2drop + THEN +; + +: make-subnodes ( -- ) + ioacfg 4 + ioacfg c@ 0 ?DO dup 2 + w@ dup ( ioacfg rsrc-type rsrc-type ) + A000 \ 8000 = Resource Subtype is IOA Focal Point. + \ 2000 = Device is a member of a data redundancy group (eg. RAID). + \ (1000 = Device is designated for use as a hot spare. + \ Unfortunately obsidian reports disk which are not part of + \ of a RAID also as hot space even if they are not.) + \ all these devices should not appeat in DT + \ SIS40 page 60 + and 0= IF + swap dup ( rsrc-type ioacfg ioacfg ) + 8 + l@ over 4 + l@ ( rsrc-type ioacfg rsrc-handle rsrc-addr ) + ffffff and 2swap swap 2swap ( ioacfg rsrc-type rsrc-handle rsrc-addr ) + make-subnode ELSE drop THEN 40 + LOOP drop ; + +: do-it ( -- ) + init-ioa do-idrrq + do-query + check-devices + show-devices +; + +: setup-shutdown ( -- ) + f7 ioarcb 42 + c! 0 ioarcb 48 + l! 0 ioarcb 44 + l! ; +: do-shutdown ( -- ) -1 1 0 0 setup-ioarcb setup-shutdown do-request ; + +: open true ; +: close ; + +: start ['] do-it CATCH IF cr ." Citrine disabled" ELSE make-subnodes THEN ; + +cr start cr cr diff --git a/qemu/roms/SLOF/board-js2x/slof/copyright-oss.fs b/qemu/roms/SLOF/board-js2x/slof/copyright-oss.fs new file mode 100644 index 000000000..06f9a3ada --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/copyright-oss.fs @@ -0,0 +1,16 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +cr .( Copyright (c) char ) emit .( 2004, 2008 IBM Corporation All rights reserved.) +cr .( This program and the accompanying materials are made available) +cr .( under the terms of the BSD License available at) +cr .( http://www.opensource.org/licenses/bsd-license.php) diff --git a/qemu/roms/SLOF/board-js2x/slof/cpu.fs b/qemu/roms/SLOF/board-js2x/slof/cpu.fs new file mode 100644 index 000000000..bee07d108 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/cpu.fs @@ -0,0 +1,44 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ CPU node. Pretty minimal... + +( cpu# -- ) +new-device set-space + +: pvr>name s" PowerPC," rot 10 rshift CASE + 39 OF s" 970" ENDOF + 3c OF s" 970FX" ENDOF + 44 OF 1 my-space 1 xor lshift cpu-mask @ and IF + s" 970MP" ELSE s" 970GX" THEN ENDOF + \ On GX CPUs, the sibling is missing, numbering is the same. + dup dup OF 0 <# # # # # [char] # hold #> ENDOF ENDCASE $cat ; + +pvr@ pvr>name device-name +s" cpu" device-type + +my-space encode-int s" reg" property + +tb-frequency encode-int s" timebase-frequency" property +cpu-frequency encode-int s" clock-frequency" property + + 8000 encode-int s" d-cache-size" property + 80 encode-int s" d-cache-line-size" property +10000 encode-int s" i-cache-size" property + 80 encode-int s" i-cache-line-size" property + +: open true ; +: close ; + + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/dart.fs b/qemu/roms/SLOF/board-js2x/slof/dart.fs new file mode 100644 index 000000000..8fdac83f9 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/dart.fs @@ -0,0 +1,31 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ CPC9x5 DART. + +new-device + +s" dart" 2dup device-name device-type +u3? IF s" u3-dart" compatible THEN +u4? IF s" u4-dart" compatible THEN + +0 encode-int f8033000 encode-int+ +0 encode-int+ 7000 encode-int+ s" reg" property + +: open true ; +: close ; + +\ Now clear and disable the DART. +20000000 f8033000 rl! + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/flash.fs b/qemu/roms/SLOF/board-js2x/slof/flash.fs new file mode 100644 index 000000000..110f5c86b --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/flash.fs @@ -0,0 +1,43 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ we do all flash accesses as 8-bit + +ff000000 CONSTANT flash-addr + +: >flash flash-addr + ; +: flash@ >flash rb@ ; +: flash! >flash rb! ; +: wait-for-flash-ready BEGIN 0 flash@ 80 and UNTIL ; +: erase-flash-block ( offset -- ) + cr dup 8 .r ." Erasing..." + 20 over flash! d0 swap flash! wait-for-flash-ready ; +: write-flash ( data offset -- ) + 40 over flash! flash! wait-for-flash-ready ; +: write-flash-buffer ( addr offset -- ) + e8 over flash! wait-for-flash-ready 1f over flash! + 20 0 DO over i + c@ over i + flash! LOOP + d0 over flash! wait-for-flash-ready 2drop ; +: write-flash-block ( addr offset -- ) \ always writes 128kB! + ." Writing..." + 20000 0 DO over i + over i + write-flash-buffer 20 +LOOP 2drop + ." Done." ; +: flash ( addr offset size -- ) + BEGIN dup 0 > WHILE >r dup erase-flash-block 2dup write-flash-block + >r 20000 + r> 20000 + r> 20000 - REPEAT drop 2drop -1 0 flash! ; + +: flash-it get-load-base 0 e0000 flash ; +: flash4 get-load-base 0 400000 flash ; + +\ for update-flash +: flash-image-size ( addr -- size ) 30 + rx@ ; diff --git a/qemu/roms/SLOF/board-js2x/slof/freq.fs b/qemu/roms/SLOF/board-js2x/slof/freq.fs new file mode 100644 index 000000000..9f1d36d78 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/freq.fs @@ -0,0 +1,39 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Use the HPET to calculate various frequencies. + +\ Make HPET run. +1 10 hpet! + +\ Set PMC1 to count CPU cycles. +f00 mmcr0! + +d# 1000000000000000 4 hpet@ / CONSTANT hpet-freq + +: get-times tbl@ pmc1@ f0 hpet@ ; + +\ Calculate the CPU and TB frequencies. +: calibrate get-times dup >r swap >r swap >r hpet-freq d# 100 / + >r + BEGIN get-times dup r@ < WHILE 3drop REPEAT r> drop + rot r> - ffffffff and \ TB + rot r> - ffffffff and \ CPU + rot r> - >r \ HPET + hpet-freq * r@ / swap + hpet-freq * r> / ; + +: round-to tuck 2/ + over / * ; +calibrate TO tb-frequency d# 100000000 round-to TO cpu-frequency + +\ Stop HPET. +0 10 hpet! diff --git a/qemu/roms/SLOF/board-js2x/slof/header.fs b/qemu/roms/SLOF/board-js2x/slof/header.fs new file mode 100644 index 000000000..be2b7221c --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/header.fs @@ -0,0 +1,19 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +get-flash-base VALUE flash-addr + +get-nvram-base CONSTANT nvram-base +get-nvram-size CONSTANT nvram-size +ff8f9000 CONSTANT sec-nvram-base \ save area from phype.... not really known +2000 CONSTANT sec-nvram-size diff --git a/qemu/roms/SLOF/board-js2x/slof/helper.fs b/qemu/roms/SLOF/board-js2x/slof/helper.fs new file mode 100644 index 000000000..34d60da1f --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/helper.fs @@ -0,0 +1,28 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: slof-build-id ( -- str len ) + flash-header 10 + a +; + +: slof-revision s" 001" ; + +: read-version-and-date + flash-header 0= IF + s" " encode-string + ELSE + flash-header 10 + 10 + here swap rmove + here 10 + s" , " $cat + bdate2human $cat encode-string THEN +; diff --git a/qemu/roms/SLOF/board-js2x/slof/ht.fs b/qemu/roms/SLOF/board-js2x/slof/ht.fs new file mode 100644 index 000000000..8f818a825 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/ht.fs @@ -0,0 +1,189 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Hypertransport. + +\ See the PCI OF binding document. + +new-device + +s" ht" 2dup device-name device-type +s" u3-ht" compatible +s" U3" encode-string s" model" property + +3 encode-int s" #address-cells" property +2 encode-int s" #size-cells" property + +s" /mpic" find-node encode-int s" interrupt-parent" property + +4000 encode-int 0 encode-int+ 0 encode-int+ +1 encode-int+ s" /mpic" find-node encode-int+ +10 encode-int+ 0 encode-int+ +s" interrupt-map" property + +f800 encode-int 0 encode-int+ 0 encode-int+ +7 encode-int+ s" interrupt-map-mask" property + +: decode-unit 2 hex-decode-unit 3 lshift or + 8 lshift 0 0 rot ; +: encode-unit nip nip ff00 and 8 rshift dup 7 and swap 3 rshift + over IF 2 ELSE nip 1 THEN hex-encode-unit ; + +f2000000 CONSTANT my-puid +\ Configuration space accesses. +: >config dup ffff > IF 1000000 + THEN f2000000 + ; + +\ : config-l! >config cr ." config-l! " 2dup . space . rl!-le ; +\ : config-l@ >config cr ." config-l@ " dup . rl@-le space dup . ; +\ : config-w! >config cr ." config-w! " 2dup . space . rw!-le ; +\ : config-w@ >config cr ." config-w@ " dup . rw@-le space dup . ; +\ : config-b! >config cr ." config-b! " 2dup . space . rb! ; +\ : config-b@ >config cr ." config-b@ " dup . rb@ space dup . ; + +: config-l! >config rl!-le ; +: config-l@ >config rl@-le ; +: config-w! >config rw!-le ; +: config-w@ >config rw@-le ; +: config-b! >config rb! ; +: config-b@ >config rb@ ; + +: config-dump ( addr size -- ) ['] config-l@ 4 (dump) ; + + +\ 16MB of configuration space, separate for type 0 and type 1. +00000000 encode-int f2000000 encode-int+ +00000000 encode-int+ 02000000 encode-int+ s" reg" property + +\ 4MB of I/O space. +01000000 encode-int 00000000 encode-int+ 00000000 encode-int+ +00000000 encode-int+ f4000000 encode-int+ +00000000 encode-int+ 00400000 encode-int+ + +\ 1 GB of memory space @ 80000000 +02000000 encode-int+ 00000000 encode-int+ 80000000 encode-int+ +00000000 encode-int+ 80000000 encode-int+ +00000000 encode-int+ 40000000 encode-int+ s" ranges" property + +\ Host bridge, so full bus range. +0 encode-int ff encode-int+ s" bus-range" property + +: enable-ht-apic-space 3c0300fe f8070200 rl! ; +enable-ht-apic-space + +\ spare out 0xc0000000-0xefffffff for pcie +f8070200 rl@ fffffff0 and f8070200 rl! +\ enable io memory for pcie @ c0000000-efffffff +70000003 f80903f0 rl!-le + + +\ Workaround for "takeover" boot on JS20: the top 8131 is programmed to be +\ device #1f, while it should be #01. +u3? IF f800 config-l@ 74501022 = IF 41 f8c2 config-w! THEN THEN + +\ Assign BUIDs. + +: find-ht-primary + 34 BEGIN config-b@ dup 0= ABORT" No HT capability block found!" + dup config-l@ e00000ff and 8 = IF 2 + EXIT THEN 1 + AGAIN ; + +: assign-buid ( this -- next ) + find-ht-primary dup >r config-w@ 5 rshift 1f and over r> config-b! + ; + +: assign-buids ( -- ) + 1 BEGIN 0 config-l@ ffffffff <> WHILE assign-buid REPEAT drop ; + +assign-buids + +: ldtstop f8000840 rl@ 40000 or f8000840 rl! ; +: delay 100000 0 DO LOOP ; +: wait-for-done BEGIN f8070110 rl@ 30 and UNTIL + BEGIN 8b4 config-l@ 30 and UNTIL ; +: ldtstop1 f8000840 rl@ dup 20000 or f8000840 rl! delay + f8000840 rl! wait-for-done ; +: warm 400000 f8070300 rl! 0 f8070300 rl! ; + +: dumpht cr f8070110 rl@ 8 0.r space 8b4 config-l@ 8 0.r + space f8070122 rb@ 2 0.r space 8bd config-b@ 2 0.r ; + +: clearht f8070110 dup rl@ swap rl! + f8070120 dup rl@ swap rl! + 08b4 dup config-l@ swap config-l! + 08bc dup config-l@ swap config-l! ; + +: setwidth dup f8070110 rb! 8b7 config-b! ; +: set8 00 setwidth ; +: set16 11 setwidth ; + +: setfreq dup f8070122 rb! 8bd config-b! ; +: set200 0 setfreq ; +: set300 1 setfreq ; +: set400 2 setfreq ; +: set500 3 setfreq ; +: set600 4 setfreq ; +: set800 5 setfreq ; +: set1000 6 setfreq ; +: set1200 7 setfreq ; +: set1400 8 setfreq ; +: set1600 9 setfreq ; + +: ht>freq 2 + dup 6 > IF 2* 6 - THEN d# 100 * ; +\ XXX: looks only at the U3/U4 side for max. link speed and width. +clearht f8070111 rb@ setwidth +f8070120 rw@ 2log dup .( Switching top HT bus to ) ht>freq 0 d# .r .( MHz...) cr +setfreq u3? IF ldtstop THEN u4? IF ldtstop1 THEN + +: open true ; +: close ; + +\ : probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- ) +s" /mpic" find-node my-puid pci-irq-init drop +1f 0 c0000000 b8000000 b8000000 80000000 100000000 10000 +my-puid probe-pci-host-bridge + +: msi + f80040f0 010854 config-l! 0 010858 config-l! + ffff 01085c config-w! 81 010852 config-b! +; + +\ This works. Needs cleaning up though; and we need to communicate the +\ MSI address range to the client program. (We keep the default range +\ at fee00000 for now). +: msi-on 7 1 DO 10000 i 800 * a0 + config-l! LOOP ; +msi-on + +\ PCIe debug / fixup +: find-pcie-cap ( devfn -- offset | 0 ) + >r 34 BEGIN r@ + config-b@ dup ff <> over and WHILE + dup r@ + config-b@ 10 = IF + r> drop EXIT + THEN 1+ + REPEAT r> 2drop 0 +; + +: (set-ps) ( ps addr -- ) + 8 + >r 5 lshift r@ config-w@ ff1f and or r> config-w! ; +: set-ps ( ps -- ) + log2 7 - + 10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF + + 2dup (set-ps) THEN drop LOOP drop ; + +: (set-rr) ( rr addr -- ) + 8 + >r c lshift r@ config-w@ 8fff and or r> config-w! ; +: set-rr ( rr -- ) + log2 7 - + 10000 0 DO i 8 lshift dup find-pcie-cap ?dup IF + + 2dup (set-rr) THEN drop LOOP drop ; + +100 set-ps 200 set-rr +100 set-ps 200 set-rr + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/i2c.fs b/qemu/roms/SLOF/board-js2x/slof/i2c.fs new file mode 100644 index 000000000..044bde92d --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/i2c.fs @@ -0,0 +1,77 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +new-device + +s" i2c" 2dup device-name device-type +s" u4-i2c" compatible + +0 encode-int f8001000 encode-int+ +0 encode-int+ 1000 encode-int+ s" reg" property + +: >i2c f8001000 + ; +: i2c@ >i2c rl@ ; +: i2c! >i2c rl! ; + +: .i2c 80 0 DO i i2c@ . 10 +LOOP ; + +\ 0 mode 1 ctrl 2 stat 3 isr 4 ier 5 addr 6 suba 7 data +\ 8 rev 9 risetime a bittime + +\ 0 mode: 08 +\ 1 ctrl: 8 = start 4 = stop 2 = xaddr 1 = aak +\ 2 stat: 2 = lastaak 1 = busy +\ 3 isr: 8 = istart 4 = istop 2 = iaddr 1 = idata +\ 4 ier: -- +\ 5 addr: a1..a7 +\ 6 suba: offset +\ 7 data: data + +: i2c-addr ( addr -- ) 50 i2c! 2 10 i2c! BEGIN 30 i2c@ 2 and UNTIL ; +: i2c-subaddr ( suba -- ) 60 i2c! ; +: i2c-stop ( -- ) BEGIN 30 i2c@ dup 30 i2c! 4 and UNTIL ; +: i2c-nak? ( -- failed? ) 20 i2c@ 2 and 0= dup IF i2c-stop THEN ; +: i2c-short? ( -- failed? ) 30 i2c@ 4 and 0<> dup IF 0 10 i2c! i2c-stop THEN ; +: i2c-aak-if-more ( n -- ) 1 <> 1 and 10 i2c! ; + +: (read) ( buf len addr -- error? ) + 1 or i2c-addr i2c-nak? IF 2drop true EXIT THEN + dup i2c-aak-if-more 2 30 i2c! + BEGIN + 30 i2c@ 1 and IF + 1- >r 70 i2c@ over c! char+ r> + dup 0= IF i2c-stop 2drop false EXIT THEN + dup i2c-aak-if-more 1 30 i2c! THEN + i2c-short? IF 2drop true EXIT THEN + AGAIN ; + +: i2c-read ( buf len addr -- error? ) + 4 0 i2c! (read) ; +: i2c-sub-read ( buf len addr suba -- error? ) + c 0 i2c! i2c-subaddr (read) ; + +: i2c-write ( buf len addr -- error? ) + 4 0 i2c! i2c-addr i2c-nak? IF 2drop true EXIT THEN + over c@ 70 i2c! 2 30 i2c! + BEGIN + 30 i2c@ 1 and IF + 1- >r char+ r> i2c-nak? IF 2drop true EXIT THEN + dup 0= IF 4 10 i2c! i2c-stop nip EXIT THEN + over c@ 70 i2c! 1 30 i2c! THEN + i2c-short? IF 2drop true EXIT THEN + AGAIN ; + +: open true ; +: close ; + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/io.fs b/qemu/roms/SLOF/board-js2x/slof/io.fs new file mode 100644 index 000000000..f3889840c --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/io.fs @@ -0,0 +1,26 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ I/O accesses. + +\ Legacy I/O accesses. +: >io f4000000 + ; + +: io-c! >io rb! ; +: io-c@ >io rb@ ; + +: io-w! >io rw! ; +: io-w@ >io rw@ ; + +\ Accessing the SIO config registers. +: siocfg! 2e io-c! 2f io-c! ; +: siocfg@ 2e io-c! 2f io-c@ ; diff --git a/qemu/roms/SLOF/board-js2x/slof/ioapic.fs b/qemu/roms/SLOF/board-js2x/slof/ioapic.fs new file mode 100644 index 000000000..685d6dfed --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/ioapic.fs @@ -0,0 +1,36 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ( ioapic-addr -- ) +\ IO-APIC setup. + +CONSTANT ioapic + +: ioapic@ ( offset -- x ) ioapic rb! ioapic 10 + rl@-le ; +: ioapic! ( x offset -- ) ioapic rb! ioapic 10 + rl!-le ; + +: init-ioapic ( irq# -- ) + 1a000 or 1 ioapic@ 10 rshift 1+ 0 ?DO + 0 i 2* 11 + ioapic! dup + \ move all ISA IRQs to 40 and higher, + \ as to not conflict with U3/U4 internal + \ IRQs. ISA IRQs are positive edge. + dup ff and 0c < IF a000 - 40 + THEN + i 2* 10 + ioapic! 1+ LOOP drop +; + +: dump-ioapic ( -- ) + 1 ioapic@ 10 rshift 1+ + dup cr . ." irqs" 0 ?DO + cr i 2 0.r space i 2* 11 + ioapic@ 8 0.r + i 2* 10 + ioapic@ 8 0.r LOOP +; diff --git a/qemu/roms/SLOF/board-js2x/slof/ipmi-kcs.fs b/qemu/roms/SLOF/board-js2x/slof/ipmi-kcs.fs new file mode 100644 index 000000000..cf9d5af5a --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/ipmi-kcs.fs @@ -0,0 +1,57 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ IPMI KCS interface to the BMC. + +new-device + ca8 1 set-unit + + : open true ; + : close ; + + create descr-buf 100 allot + + : rtas-get-bmc-version ( -- adr len ) + descr-buf 100 rtas-get-blade-descr ( len status ) + IF + drop 0 0 + ELSE + descr-buf 9 + swap 11 - ( adr len ) + THEN + ; + + ' rtas-get-bmc-version to bmc-version + + s" system-controller" 2dup device-name device-type + \ s" IBM,BMC." get-build-name $cat encode-string s" model" property + \ s" IBM,BMC.12345" encode-string s" model" property + s" IBM,BMC." bmc-version $cat encode-string s" model" property + 0 0 s" ranges" property + + new-device + + : open true ; + : close ; + + s" ipmi" 2dup device-name device-type + s" ipmi-kcs" compatible + + 1 encode-int ca8 encode-int+ 1 encode-int+ s" reg" property + 4 encode-int s" reg-spacing" property + s" IBM,BMC." bmc-version $cat encode-string s" model" property + + s" ipmi" get-node node>path set-alias + + finish-device + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/ipmi-vpd.fs b/qemu/roms/SLOF/board-js2x/slof/ipmi-vpd.fs new file mode 100644 index 000000000..bfb3e5014 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/ipmi-vpd.fs @@ -0,0 +1,98 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: vpd-read-bootlist ( -- ) + 837 4 vpd-bootlist rtas-read-vpd IF vpd-bootlist 4 erase THEN +; + +: vpd-write-bootlist ( offset len data -- ) + 837 4 vpd-bootlist rtas-write-vpd +; + +: .vpd-machine-type + e 7 vpd-cb rtas-read-vpd drop + 0 vpd-cb 7 + c! + vpd-cb zcount type +; + +: .vpd-machine-serial + 15 7 vpd-cb rtas-read-vpd drop + 0 vpd-cb 7 + c! + vpd-cb zcount type +; + +: .vpd-card-serial + 54 6 vpd-cb rtas-read-vpd drop + 0 vpd-cb 6 + c! + vpd-cb zcount type +; +: .vpd-cardprefix-serial + 5a 6 vpd-cb rtas-read-vpd drop + 0 vpd-cb 6 + c! + vpd-cb zcount type +; + +: .vpd-hw-revision + 65 1 vpd-cb rtas-read-vpd drop + vpd-cb c@ . +; + +: .vpd-part-number + 3c c vpd-cb rtas-read-vpd drop + vpd-cb c type +; + +: .vpd-fru-number + 48 c vpd-cb rtas-read-vpd drop + vpd-cb c type +; + +: .vpd-manufacturer-date + 6b 4 vpd-cb rtas-read-vpd drop + 0 vpd-cb 4 + c! + vpd-cb zcount type +; + +: .vpd-uuid + 9f 10 vpd-cb rtas-read-vpd drop + 10 0 do i vpd-cb + c@ 2 0.r loop +; + +: vpd-read-model ( -- addr len ) + 60 4 vpd-cb rtas-read-vpd drop vpd-cb 4 -leading s" ," $cat + e 7 vpd-cb rtas-read-vpd drop vpd-cb 4 $cat s" -" $cat vpd-cb 4 + 3 $cat +; + +: .vpd + ." ===================== VPD =====================" + cr ." Machine Type : " .vpd-machine-type + cr ." Machine Serial No. : " .vpd-machine-serial + cr ." Hardware Revision : " .vpd-hw-revision + cr ." Manuf. Date : " .vpd-manufacturer-date + cr ." Part Number : " .vpd-part-number + cr ." FRU Number : " .vpd-fru-number + cr ." FRU Serial No. : " .vpd-cardprefix-serial .vpd-card-serial + cr ." UUID : " .vpd-uuid +; + +: vpd-write-revision-and-build-id ( -- ) + 406 24 vpd-cb rtas-read-vpd drop 0 + vpd-cb 1a + zcount bdate2human drop a string=ci 0= + IF bdate2human drop a vpd-cb 1a + zplace drop 1 THEN + vpd-cb zcount slof-revision string=ci 0= + IF slof-revision vpd-cb zplace drop 1 THEN + vpd-cb 4 + zcount slof-build-id string=ci 0= + IF slof-build-id vpd-cb 4 + rzplace drop 1 THEN + 1 = IF 406 24 vpd-cb rtas-write-vpd drop THEN +; + +vpd-write-revision-and-build-id diff --git a/qemu/roms/SLOF/board-js2x/slof/memory.fs b/qemu/roms/SLOF/board-js2x/slof/memory.fs new file mode 100644 index 000000000..b1b7aaa91 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/memory.fs @@ -0,0 +1,52 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ The /memory node. + +\ See 3.7.6. +new-device + +s" memory" 2dup device-name device-type + +: mem-size-u3 20000000 ; +: (mem-size-u4) ( # -- size ) + 4 lshift f8002200 + rl@ dup 1 and 0= IF drop 0 EXIT THEN + dup c000 and e rshift over 3000 and c rshift + 10000000 swap lshift + swap 2 and 0= IF 2* THEN ; +: mem-size-u4 0 4 0 DO i (mem-size-u4) + LOOP ; +: mem-size u3? IF mem-size-u3 THEN u4? IF mem-size-u4 THEN ; +: mem-speed-u4 f8000800 rl@ 12 rshift 7 and 4 + d# 200 * 3 / ; +: mem-speed-u3 f8000f60 rl@ c rshift f and d# 100 * 3 / ; +: mem-speed u3? IF mem-speed-u3 THEN u4? IF mem-speed-u4 THEN ; + + +: encode-our-reg + 0 encode-int 0 encode-int+ + mem-size dup >r 80000000 > IF + 0 encode-int+ 80000000 encode-int+ + 1 encode-int+ 0 encode-int+ r> 80000000 - >r THEN + r@ 20 rshift encode-int+ r> ffffffff and encode-int+ ; +encode-our-reg s" reg" property +0 mem-size release \ Make our memory available + + +: mem-report + base @ decimal mem-size 1e rshift 0 .r + mem-size 3fffffff and IF ." .5" THEN ." GB of RAM @ " + mem-speed . ." MHz" base ! ; + +get-node memnode ! + +: open true ; +: close ; + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/mpic.fs b/qemu/roms/SLOF/board-js2x/slof/mpic.fs new file mode 100644 index 000000000..a9523445d --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/mpic.fs @@ -0,0 +1,31 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +new-device + +s" mpic" device-name s" interrupt-controller" device-type +s" open-pic" compatible +0 0 s" interrupt-controller" property + +2 encode-int s" #interrupt-cells" property + +0 encode-int f8040000 encode-int+ +0 encode-int+ 30000 encode-int+ s" reg" property + +: enable-mpic 6 f80000e0 rl! ; +enable-mpic + +: open true ; +: close ; + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-aliases.fs b/qemu/roms/SLOF/board-js2x/slof/pci-aliases.fs new file mode 100644 index 000000000..f017e4a55 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-aliases.fs @@ -0,0 +1,85 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Starting alias number for net devices after the onboard devices. +2 VALUE pci-net-num +\ Starting alias number for disks after the onboard devices. +0 VALUE pci-disk-num +\ Starting alias number for cdroms after the onboard devices. +0 VALUE pci-cdrom-num + +\ define a new alias for this device +: pci-set-alias ( str-addr str-len num -- ) + $cathex strdup \ create alias name + get-node node>path \ get path string + set-alias \ and set the alias +; + +\ define a new net alias +: unknown-enet ( -- pci-net-num ) + pci-net-num dup 1+ TO pci-net-num +; +: pci-alias-net ( config-addr -- ) + u3? IF + pci-device-vec c@ CASE + 2 OF pci-device-vec-len 1 >= IF + pci-device-vec 1+ c@ CASE + 1 OF dup pci-addr2fn 1 >= IF 1 ELSE 0 THEN ENDOF + dup OF unknown-enet ENDOF + ENDCASE + ELSE + unknown-enet + THEN + ENDOF + dup OF unknown-enet ENDOF + ENDCASE + ELSE + pci-device-vec c@ CASE + 2 OF pci-device-vec-len 1 >= IF + pci-device-vec 1+ c@ CASE + 4 OF dup pci-addr2fn 1 >= IF 1 ELSE 0 THEN ENDOF + dup OF unknown-enet ENDOF + ENDCASE + ELSE + unknown-enet + THEN + ENDOF + dup OF unknown-enet ENDOF + ENDCASE + THEN + swap drop \ forget the config address + + s" net" rot pci-set-alias \ create the alias +; + +\ define a new disk alias +: pci-alias-disk ( config-addr -- ) + drop \ forget the config address + pci-disk-num dup 1+ TO pci-disk-num \ increase the pci-disk-num + s" disk" rot pci-set-alias \ create the alias +; +\ define a new cdrom alias +: pci-alias-cdrom ( config-addr -- ) + drop \ forget the config address + pci-cdrom-num dup 1+ TO pci-cdrom-num \ increase the pci-cdrom-num + s" cdrom" rot pci-set-alias \ create the alias +; + +\ define the alias for the calling device +: pci-alias ( config-addr -- ) + dup pci-class@ + 10 rshift CASE + 01 OF pci-alias-disk ENDOF + 02 OF pci-alias-net ENDOF + dup OF drop ENDOF + ENDCASE +; diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-bridge_1022_7460.fs b/qemu/roms/SLOF/board-js2x/slof/pci-bridge_1022_7460.fs new file mode 100644 index 000000000..87b583088 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-bridge_1022_7460.fs @@ -0,0 +1,203 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ AMD 8111 I/O hub. + +\ See the documentation at http://www.amd.com ; the datasheet for this chip is +\ document #24674. + +\ Config space access functions - we're touching multiple device numbers and +\ device functions below, so we've got to add our own my-space base here: +: config-b@ dup 1000 < IF my-space + THEN config-b@ ; +: config-w@ dup 1000 < IF my-space + THEN config-w@ ; +: config-l@ dup 1000 < IF my-space + THEN config-l@ ; +: config-b! dup 1000 < IF my-space + THEN config-b! ; +: config-w! dup 1000 < IF my-space + THEN config-w! ; +: config-l! dup 1000 < IF my-space + THEN config-l! ; + +\ First, some master config. Not all of this logically belongs to just +\ one function, and certainly not to the LPC bridge; also, we'll +\ initialize all functions in "downstream" order, and this code has to be +\ run first. So do it now. + +00 842 config-b! \ Disable 8237 & 8254 & 8259's. We're not a PC. +u3? IF + 80 847 config-b! \ Disable EHCI, as it is terminally broken. +THEN +03 848 config-b! \ Enable LPC, IDE; disable I2C, SMM, AC'97 functions. +01 849 config-b! \ Enable USB, disable 100Mb enet. +01 84b config-b! \ Enable IO-APIC. + +fec00000 s" ioapic.fs" included +00 init-ioapic + +\ Program PNPIRQ[0,1,2] as IRQ #D,E,F; switch those GPIOs to low-active. + 0b 848 config-b! \ enable devB:3 +7000 b58 config-l! \ map PMxx at pci i/o 7000 + d1 b41 config-b! \ enable access to PMxx space + +\ on JS20 the planar id is encoded in GPIO 29, 30 and 31 +\ >=5 is GA2 else it is GA1 +: (planar-id) ( -- planar-id) + [ 70dd io-c@ 5 rshift 1 and ] LITERAL + [ 70de io-c@ 5 rshift 2 and ] LITERAL + [ 70df io-c@ 5 rshift 4 and ] LITERAL + + + 7 xor +; + +u3? IF ['] (planar-id) to planar-id THEN + +8 70d3 io-c! 8 70d4 io-c! 8 70d5 io-c! \ set the pins to low-active + bimini? IF 5 70c4 io-c! THEN \ on bimini set gpio4 as output and high to power up USB + fec b44 config-w! \ set PNPIRQ pnpirq2 -> f , pnpirq1 -> e pnpirq0 -> c + 51 b41 config-b! \ disable access to PMxx space + 03 848 config-b! \ disable devB:3 + +\ The function of the PCI controller BARs change depending on the mode the +\ controller is in. +\ And the default is legacy mode. Gross. +05 909 config-b! \ Enable native PCI mode. +03 940 config-b! \ Enable both ports. + +\ Enable HPET on 8111, at address fe000000. +fe000001 8a0 config-l! + +: >hpet fe000000 + ; +: hpet@ >hpet rl@-le ; +: hpet! >hpet rl!-le ; + +INCLUDE freq.fs + +\ Disable HPET. +0 8a0 config-l! + +\ 8111 has only 16 bits of PCI I/O space. Get the address in range. +8000 next-pci-io ! + +\ before disabling EHCI it needs to be reset + +\ first we are setting up the BAR0, so that we can talk to the +\ memory mapped controller; not using the PCI scan because we just +\ want a temporary setup + +: really-disable-broken-amd8111-ehci ( -- ) + \ this word only works on U4 systems (JS21/Bimini) + \ yeah, hardcoded! + f2000000 to puid + + \ the PCI scan would assign pci-next-mmio to that device + \ let's just take that address + pci-next-mmio @ 100000 #aligned + \ pci-bus-number 10 lshift 210 or could be something like 70210 + \ 7: pci-bus-number + \ 2: device function + \ 10: offset 10 (bar 0) + pci-bus-number 10 lshift 210 or rtas-config-l! + + \ enable memory space + pci-bus-number 10 lshift 204 or dup rtas-config-l@ 2 or swap rtas-config-l! + + pci-next-mmio @ 100000 #aligned ( base ) + + \ Sequence prescribed for resetting the EHCI contoller + + \ If Run/Stop bit (ECAP30 bit 0) is 1 + \ Set Run/Stop bit to 0 + \ wait 2ms + + dup 30 + rl@ 1 and 1 = IF + dup 30 + rl@ 1 or + over 30 + rl! + 2 ms + THEN + + \ While HCHalted bit (ECAP34 bit 12) is 0 (still running, wait forever) + \ wait 2ms + + BEGIN dup 34 + rl@ 1000 and 0= 2 ms UNTIL + + \ Set HCReset bit (ECAP30 bit 1) + + dup 30 + 2 swap rl! + + \ While HCReset bit is 1 (wait forever for reset to complete) + \ wait 2ms + + BEGIN dup 30 + rl@ 2 and 0= 2 ms UNTIL drop + + \ now it is really disabled + + \ disable memory space access again + 2100000 pci-bus-number 10 lshift 204 or rtas-config-l! + + 80 847 config-b! \ Disable EHCI, as it is terminally broken. +; + +my-space pci-class-name type cr + +\ copied from pci-properties.fs and pci-scan.fs +\ changed to disable the EHCI completely just before the scan +\ and after mem/IO transactions have been enabled + +\ Setup the Base and Limits in the Bridge +\ and scan the bus(es) beyond that Bridge +: pci-bridge-probe-amd8111 ( addr -- ) + dup pci-bridge-set-bases \ SetUp all Base Registers + dup pci-bridge-range-props \ Setup temporary "range + pci-bus-number 1+ TO pci-bus-number \ increase number of busses found + pci-device-vec-len 1+ TO pci-device-vec-len \ increase the device-slot vector depth + dup \ stack config-addr for pci-bus! + FF swap \ Subordinate Bus Number ( for now to max to open all subbusses ) + pci-bus-number swap \ Secondary Bus Number ( the new busnumber ) + dup pci-addr2bus swap \ Primary Bus Number ( the current bus ) + pci-bus! \ and set them into the bridge + pci-enable \ enable mem/IO transactions + + \ at this point we can talk to the broken EHCI controller + really-disable-broken-amd8111-ehci + + dup pci-bus-scnd@ func-pci-probe-bus \ and probe the secondary bus + dup pci-bus-number swap pci-bus-subo! \ set SubOrdinate Bus Number to current number of busses + pci-device-vec-len 1- TO pci-device-vec-len \ decrease the device-slot vector depth + dup pci-bridge-set-limits \ SetUp all Limit Registers + drop \ forget the config-addr +; + +\ used to set up all unknown Bridges. +\ If a Bridge has no special handling for setup +\ the device file (pci-bridge_VENDOR_DEVICE.fs) can call +\ this word to setup busses and scan beyond. +: pci-bridge-generic-setup-amd8111 ( addr -- ) + pci-device-slots >r \ save the slot array on return stack + dup pci-common-props \ set the common properties before scanning the bus + s" pci" device-type \ the type is allways "pci" + dup pci-bridge-probe-amd8111 \ find all device connected to it + dup assign-all-bridge-bars \ set up all memory access BARs + dup pci-set-irq-line \ set the interrupt pin + dup pci-set-capabilities \ set up the capabilities + pci-bridge-props \ and generate all properties + r> TO pci-device-slots \ and reset the slot array +; + +: amd8111-bridge-setup + my-space + u3? takeover? or IF + \ if it is js20 or we are coming from takeover + \ we just do the normal setup + pci-bridge-generic-setup + ELSE + pci-bridge-generic-setup-amd8111 + THEN + s" pci" device-name +; + +amd8111-bridge-setup diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-capabilities.fs b/qemu/roms/SLOF/board-js2x/slof/pci-capabilities.fs new file mode 100644 index 000000000..a50714a6b --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-capabilities.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ----------------------------------------------------------------------------- +\ Set the msi address for a device +: pci-set-msi ( cap-addr -- ) + drop +; + +\ Set up all known capabilities for this board to the plugged devices +: pci-set-capabilities ( config-addr -- ) + dup 05 pci-cap-find ?dup IF pci-set-msi THEN + drop +; diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-class_03.fs b/qemu/roms/SLOF/board-js2x/slof/pci-class_03.fs new file mode 100644 index 000000000..05c8eb62d --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-class_03.fs @@ -0,0 +1,55 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space pci-class-name type + +my-space pci-device-generic-setup + +my-space pci-class-name device-type + +\ add legacy I/O Ports / Memory regions to assigned-addresses +\ see PCI Bus Binding Revision 2.1 Section 7. +s" reg" get-my-property +IF + \ "reg" does not exist, create new + encode-start +ELSE + \ "reg" does exist, copy it + encode-bytes +THEN +\ I/O Range 0x3B0-0x3BB +my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space +3b0 encode-64+ \ addr +c encode-64+ \ size +\ I/O Range 0x3C0-0x3DF +my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space +3c0 encode-64+ \ addr +20 encode-64+ \ size +\ the U4 does not support memory accesses to this region... so we dont put it into "reg" +\ maybe with some clever hacking of the address map registers it will be possible to access +\ these regions?? +\ Memory Range 0xA0000-0xBFFFF +\ my-space a2000000 or encode-int+ \ non-relocatable, <1MB Memory space +\ a0000 encode-64+ \ addr +\ 20000 encode-64+ \ size + +s" reg" property \ store "reg" property + +\ check wether we have already found a vga-device (vga-device-node? != 0) and if +\ this device has Expansion ROM +vga-device-node? 0= 30 config-l@ 0<> AND IF + \ remember this vga device's phandle + get-node to vga-device-node? +THEN + +cr + diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-device_1002_515e.fs b/qemu/roms/SLOF/board-js2x/slof/pci-device_1002_515e.fs new file mode 100644 index 000000000..39a02ded0 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-device_1002_515e.fs @@ -0,0 +1,501 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space pci-class-name type + +my-space assign-all-device-bars +my-space pci-device-props +my-space pci-set-irq-line + +7 4 config-w! + +\ Special notice from ATI: +\ ATI TECHNOLOGIES INC. ("ATI") HAS NOT ASSISTED IN THE CREATION OF, +\ AND DOES NOT ENDORSE THE USE OF, THIS SOFTWARE. ATI WILL NOT BE +\ RESPONSIBLE OR LIABLE FOR ANY ACTUAL OR ALLEGED DAMAGE OR LOSS +\ CAUSED BY OR IN CONNECTION WITH THE USE OF, OR RELIANCE ON, +\ THIS SOFTWARE. + +\ Description: This FCODE driver initializes the RN50 (ES1000) ATI +\ adaptor. + +-1 value mem-addr +-1 value regs-addr +false value is_installed + +: reg-rl@ regs-addr + rl@-le ; +: reg-rl! regs-addr + rl!-le ; +: map-in " map-in" $call-parent ; +: map-out " map-out" $call-parent ; +: pc@ ( offset -- byte ) regs-addr + rb@ ; +: pc! ( byte offset -- ) regs-addr + rb! ; + +0 value phys_low +0 value phys_mid +0 value phys_high +0 value phys_len + +: MAP-CSR-BASE ( -- ) + " assigned-addresses" get-my-property 0= if + begin dup 0> while ( prop-addr len ) + \ Get the phys-hi mid low and the low order 32 bits of the length + + decode-phys to phys_high to phys_mid to phys_low decode-int drop decode-int to phys_len + + phys_high H# FF and \ See which BAR this refers to + case + h# 10 of phys_low phys_mid phys_high h# 1000000 map-in to mem-addr endof + h# 18 of phys_low phys_mid phys_high phys_len map-in to regs-addr endof + endcase + repeat + ( prop-addr 0 ) 2drop + then + + ; + +: enable-card my-space 4 + dup config-b@ 3 or swap config-b! ; + +: EARLY-MAP ( -- ) + + " reg" get-my-property 0= if + begin dup 0> while ( prop-addr len ) + + \ Get the phys-hi mid low and the low order 32 bits of the length + + decode-phys to phys_high to phys_mid to phys_low decode-int drop decode-int to phys_len + + phys_high H# FF and \ See which BAR this refers to + case + h# 10 of phys_low phys_mid phys_high H# 1000000 map-in to mem-addr endof + h# 18 of phys_low phys_mid phys_high h# 1000 map-in to regs-addr endof + endcase + repeat + ( prop-addr 0 ) 2drop + then + ; + +: EARLY-UNMAP ( -- ) + + mem-addr -1 <> if + mem-addr h# 1000000 map-out + -1 to mem-addr + then + + regs-addr -1 <> if + regs-addr h# 1000 map-out + -1 to regs-addr + then + + ; + +CREATE INIT1_ARRAY +H# 0F8 ( CONFIG_MEMSIZE ) L, H# 00000000 L, H# 01000000 L, +H# 1C0 ( MPP_TB_CONFIG ) L, H# 00FFFFFF L, H# 07000000 L, +H# 030 ( BUS_CNTL ) L, H# 00000000 L, H# 5133A3B0 L, +H# 0EC ( RBBM_CNTL ) L, H# 00000000 L, h# 00004443 L, +H# 1D0 ( DEBUG_CNTL ) L, H# FFFFFFFD L, H# 00000002 L, +H# 050 ( CRTC_GEN_CNTL ) L, H# 00000000 L, H# 04000000 L, +H# 058 ( DAC_CNTL ) L, H# 00000000 L, H# FF604102 L, +H# 168 ( PAD_CTLR_STRENGTH ) L, H# FFFEFFFF L, H# 00001200 L, +H# 178 ( MEM_REFRESH_CNTL ) L, H# 00000000 L, H# 88888888 L, +H# 17C ( MEM_READ_CNTL ) L, H# 00000000 L, H# B7C20000 L, +H# 188 ( MC_DEBUG ) L, H# FFFFFFFF L, H# 00000000 L, +H# D00 ( DISP_MISC_CNTL) L, H# 00FFFFFF L, H# 5B000000 L, +H# 88C ( TV_DAC_CNTL ) L, H# F800FCEF L, H# 00490200 L, +H# D04 ( DAC_MACRO_CNTL) L, H# 00000000 L, H# 00000905 L, +H# 284 ( FP_GEN_CNTL ) L, H# FFFFFFFF L, H# 00000008 L, +H# 030 ( BUS_CNTL ) L, H# FFFFFFEF L, H# 00000000 L, + +here INIT1_ARRAY - /L / CONSTANT INIT1_LENGTH + + +CREATE INIT2_ARRAY + +H# 140 ( MEM_CNTL ) L, H# 00000000 L, H# 38001A01 L, 0 L, +H# 158 ( MEM_SDRAM_MODE_REG ) L, H# E0000000 L, H# 08320032 L, 0 L, +H# 144 ( MEM_TIMING_CNTL ) L, H# 00000000 L, H# 20123833 L, 0 L, +H# 14C ( MC_AGP_LOCATION ) L, H# 00000000 L, H# 000FFFF0 L, 0 L, +H# 148 ( MC_FB_LOCATION ) L, H# 00000000 L, H# FFFF0000 L, 0 L, +H# 154 ( MEM_INIT_LAT_TIMER ) L, H# 00000000 L, H# 34444444 L, 0 L, +H# 18C ( MC_CHP_IO_OE_CNTL ) L, H# 00000000 L, H# 0A540002 L, 0 L, +H# 910 ( FCP_CNTL ) L, H# 00000000 L, H# 00000004 L, 0 L, +H# 010 ( BIOS_0_SCRATCH ) L, H# FFFFFFFB L, H# 00000004 L, 0 L, +H# D64 ( DISP_OUTPUT_CNTL ) L, H# FFFFFBFF L, H# 00000000 L, 0 L, +H# 2A8 ( TMDS_PLL_CNTL ) L, H# 00000000 L, H# 00000A1B L, 0 L, +H# 800 ( TV_MASTER_CNTL ) L, H# BFFFFFFF L, H# 40000000 L, 0 L, +H# D10 ( DISP_TEST_DBUG_CTL ) L, H# EFFFFFFF L, H# 10000000 L, 0 L, +H# 4DC ( OV0_FLAG_CNTRL ) L, H# FFFFFEFF L, H# 00000100 L, 0 L, +H# 034 ( BUS_CNTL1 ) L, H# 73FFFFFF L, H# 84000000 L, 0 L, +H# 174 ( AGP_CNTL ) L, H# FFEFFF00 L, H# 001E0000 L, 0 L, +H# 18C ( MC_CHP_IO_OE_CNTL ) L, H# FFFFFFF9 L, H# 00000006 L, h# 000A L, +H# 18C ( MC_CHP_IO_OE_CNTL ) L, H# FFFFFFFB L, H# 00000000 L, H# 000A L, +H# 18C ( MC_CHP_IO_OE_CNTL ) L, H# FFFFFFFD L, H# 00000000 L, 0 L, + +here INIT2_ARRAY - /L / CONSTANT INIT2_LENGTH + +CREATE PLLINIT_ARRAY + +H# 0D L, H# FFFFFFFF L, H# FFFF8000 L, 0 L, +H# 12 L, H# FFFFFFFF L, H# 00350000 L, 0 L, +H# 08 L, H# FFFFFFFF L, H# 00000000 L, 0 L, +H# 2D L, H# FFFFFFFF L, H# 00000000 L, 0 L, +H# 1F L, H# FFFFFFFF L, H# 0000000A L, 5 L, +H# 03 L, H# FFFFFFFF L, H# 0000003C L, 0 L, +H# 0A L, H# FFFFFFFF L, H# 00252504 L, 0 L, +H# 25 L, H# FFFFFFFF L, H# 00000005 L, 0 L, +H# 0E L, H# FFFFFFFF L, H# 04756400 L, 0 L, +H# 0C L, H# FFFFFFFF L, H# 04006401 L, 0 L, +H# 02 L, H# FFFFFFFF L, H# 0000A703 L, 0 L, +H# 0F L, H# FFFFFFFF L, H# 0000051C L, 0 L, +H# 10 L, H# FFFFFFFF L, H# 04000400 L, 5 L, +H# 0E L, H# FFFFFFFD L, H# 00000000 L, 5 L, +H# 0E L, H# FFFFFFFE L, H# 00000000 L, 5 L, +H# 12 L, H# FFFFFFFF L, H# 00350012 L, 5 L, +H# 0F L, H# FFFFFFFE L, H# 00000000 L, 6 L, +H# 10 L, H# FFFFFFFE L, H# 00000000 L, 5 L, +H# 10 L, H# FFFEFFFF L, H# 00000000 L, 6 L, +H# 0F L, H# FFFFFFFD L, H# 00000000 L, 5 L, +H# 10 L, H# FFFFFFFD L, H# 00000000 L, 5 L, +H# 10 L, H# FFFDFFFF L, H# 00000000 L, d# 10 L, +H# 0C L, H# FFFFFFFE L, H# 00000000 L, 6 L, +H# 0C L, H# FFFFFFFD L, H# 00000000 L, 5 L, +h# 0D L, H# FFFFFFFF L, H# FFFF8007 L, 5 L, +H# 08 L, H# FFFFFF3C L, H# 00000000 L, 0 L, +H# 02 L, H# FFFFFFFF L, H# 00000003 L, 0 L, +H# 04 L, H# FFFFFFFF L, H# 000381C0 L, 0 L, +H# 05 L, H# FFFFFFFF L, H# 000381F7 L, 0 L, +H# 06 L, H# FFFFFFFF L, H# 000381C0 L, 0 L, +H# 07 L, H# FFFFFFFF L, H# 000381F7 L, 0 L, +H# 02 L, H# FFFFFFFD L, H# 00000000 L, 6 L, +H# 02 L, H# FFFFFFFE L, H# 00000000 L, 5 L, +h# 08 L, H# FFFFFF3C L, H# 00000003 L, 5 L, +H# 0B L, H# FFFFFFFF L, H# 78000800 L, 0 L, +H# 0B L, H# FFFFFFFF L, H# 00004000 L, 0 L, +h# 01 L, h# FFFFFFFF L, H# 00000010 L, 0 L, + +here PLLINIT_ARRAY - /L / CONSTANT PLLINIT_LENGTH + +CREATE MEMINIT_ARRAY +h# 6FFF0000 L, H# 00004000 L, H# 6FFF0000 L, H# 80004000 L, +h# 6FFF0000 L, H# 00000132 L, H# 6FFF0000 L, H# 80000132 L, +h# 6FFF0000 L, H# 00000032 L, H# 6FFF0000 L, H# 80000032 L, +h# 6FFF0000 L, H# 10000032 L, +here MEMINIT_ARRAY - /L / CONSTANT MEMINIT_LENGTH +: L@+ ( addr -- value addr' ) + +dup l@ swap la1+ +; + +0 VALUE _len + +: ENCODE-ARRAY ( array len -- ) + dup to _len 0 do l@+ swap encode-int rot loop + drop _len 1 - 0 ?do encode+ loop +; + +: andorset ( reg and or -- ) + 2 pick dup reg-rl@ + 3 pick AND 2 pick OR swap reg-rl! 3drop +; + +: INIT1 +H# 0F8 ( CONFIG_MEMSIZE ) H# 00000000 H# 01000000 andorset \ Set 16Mb memory size +H# 1C0 ( MPP_TB_CONFIG ) H# 00FFFFFF H# 07000000 andorset +H# 030 ( BUS_CNTL ) H# 00000000 H# 5133A3B0 andorset +H# 0EC ( RBBM_CNTL ) H# 00000000 h# 00004443 andorset +H# 1D0 ( DEBUG_CNTL ) H# FFFFFFFD H# 00000002 andorset +H# 050 ( CRTC_GEN_CNTL ) H# 00000000 H# 04000000 andorset +H# 058 ( DAC_CNTL ) H# 00000000 H# FF604102 andorset +H# 168 ( PAD_CTLR_STRENGTH ) H# FFFEFFFF H# 00001200 andorset +H# 178 ( MEM_REFRESH_CNTL ) H# 00000000 H# 88888888 andorset +H# 17C ( MEM_READ_CNTL ) H# 00000000 H# B7C20000 andorset +H# 188 ( MC_DEBUG ) H# FFFFFFFF H# 00000000 andorset +H# D00 ( DISP_MISC_CNTL) H# 00FFFFFF H# 5B000000 andorset +H# 88C ( TV_DAC_CNTL ) H# F800FCEF H# 00490200 andorset +H# D04 ( DAC_MACRO_CNTL) H# 00000000 H# 00000905 andorset +H# 284 ( FP_GEN_CNTL ) H# FFFFFFFF H# 00000008 andorset +H# 030 ( BUS_CNTL ) H# FFFFFFEF H# 00000000 andorset +; + + +: INIT2 +H# 140 ( MEM_CNTL ) H# 00000000 H# 38001A01 andorset +H# 158 ( MEM_SDRAM_MODE_REG ) H# E0000000 H# 08320032 andorset +H# 144 ( MEM_TIMING_CNTL ) H# 00000000 H# 20123833 andorset +H# 14C ( MC_AGP_LOCATION ) H# 00000000 H# 000FFFF0 andorset +H# 148 ( MC_FB_LOCATION ) H# 00000000 H# FFFF0000 andorset +H# 154 ( MEM_INIT_LAT_TIMER ) H# 00000000 H# 34444444 andorset +H# 18C ( MC_CHP_IO_OE_CNTL ) H# 00000000 H# 0A540002 andorset +H# 910 ( FCP_CNTL ) H# 00000000 H# 00000004 andorset +H# 010 ( BIOS_0_SCRATCH ) H# FFFFFFFB H# 00000004 andorset +H# D64 ( DISP_OUTPUT_CNTL ) H# FFFFFBFF H# 00000000 andorset +H# 2A8 ( TMDS_PLL_CNTL ) H# 00000000 H# 00000A1B andorset +H# 800 ( TV_MASTER_CNTL ) H# BFFFFFFF H# 40000000 andorset +H# D10 ( DISP_TEST_DEBUG_CTL ) H# EFFFFFFF H# 10000000 andorset +H# 4DC ( OV0_FLAG_CNTRL ) H# FFFFFEFF H# 00000100 andorset +H# 034 ( BUS_CNTL1 ) H# 73FFFFFF H# 84000000 andorset +H# 174 ( AGP_CNTL ) H# FFEFFF00 H# 001E0000 andorset +H# 18C ( MC_CHP_IO_OE_CNTL ) H# FFFFFFF9 H# 00000006 andorset h# 000A ms +H# 18C ( MC_CHP_IO_OE_CNTL ) H# FFFFFFFB H# 00000000 andorset H# 000A ms +H# 18C ( MC_CHP_IO_OE_CNTL ) H# FFFFFFFD H# 00000000 andorset +; + +: CLK-CNTL-INDEX! 8 ( CLK_CNTL_INDEX ) reg-rl! ; + +: CLK-CNTL-INDEX@ 8 ( CLK_CNTL_INDEX ) reg-rl@ ; + +: PLLWRITEON clk-cntl-index@ H# 80 ( PLL_WR_ENABLE ) or clk-cntl-index! ; + +: PLLWRITEOFF clk-cntl-index@ H# 80 ( PLL_WR_ENABLE ) not and clk-cntl-index! ; \ Remove PLL_WR_ENABLE + +: CLKDATA! h# 0c ( CLK_CNTL_DATA ) reg-rl! ; + +: CLKDATA@ h# 0c ( CLK_CNTL_DATA ) reg-rl@ ; + +: PLLINDEXSET clk-cntl-index@ h# FFFFFFC0 and or clk-cntl-index! ; + +: PLLSET swap pllindexset clkdata! ; + +: pllandorset ( index and or -- ) + 2 pick pllindexset clkdata@ + 2 pick AND over OR clkdata! 3drop +; + +: PLLINIT +pllwriteon +H# 0D H# FFFF8000 pllset +H# 12 H# 00350000 pllset +H# 08 H# 00000000 pllset +H# 2D H# 00000000 pllset +H# 1F H# 0000000A pllset 5 ms + +H# 03 H# 0000003C pllset +H# 0A H# 00252504 pllset +H# 25 H# 00000005 pllset +H# 0E H# 04756400 pllset +H# 0C H# 04006401 pllset +H# 02 H# 0000A703 pllset +H# 0F H# 0000051C pllset +H# 10 H# 04000400 pllset 5 ms + +H# 0E H# FFFFFFFD 00 pllandorset 5 ms +H# 0E H# FFFFFFFE 00 pllandorset 5 ms +H# 12 H# 00350012 pllset 5 ms +H# 0F H# FFFFFFFE 00 pllandorset 6 ms +H# 10 H# FFFFFFFE 00 pllandorset 5 ms +H# 10 H# FFFEFFFF 00 pllandorset 6 ms +H# 0F H# FFFFFFFD 00 pllandorset 5 ms +H# 10 H# FFFFFFFD 00 pllandorset 5 ms +H# 10 H# FFFDFFFF 00 pllandorset d# 10 ms +H# 0C H# FFFFFFFE 00 pllandorset 6 ms +H# 0C H# FFFFFFFD 00 pllandorset 5 ms +h# 0D h# FFFF8007 pllset 5 ms +H# 08 H# FFFFFF3C 00 pllandorset +H# 02 h# FFFFFFFF 03 pllandorset +H# 04 H# 000381C0 pllset +H# 05 H# 000381F7 pllset +H# 06 H# 000381C0 pllset +H# 07 H# 000381F7 pllset +H# 02 H# FFFFFFFD 00 pllandorset 6 ms +H# 02 h# FFFFFFFE 00 pllandorset 5 ms +h# 08 H# FFFFFF3C 03 pllandorset 5 ms +H# 0B h# 78000800 pllset +H# 0B H# FFFFFFFF h# 4000 pllandorset +h# 01 h# FFFFFFFF h# 0010 pllandorset + +pllwriteoff +; + +: DYNCKE +pllwriteon +H# 14 H# FFFF3FFF H# 30 pllandorset +H# 14 H# FF1FFFFF H# 00 pllandorset +H# 01 h# FFFFFFFF h# 80 pllandorset +H# 0D H# 00000007 pllset 5 ms +h# 2D H# 0000F8C0 pllset +h# 08 H# FFFFFFFF h# C0 pllandorset 5 ms +pllwriteoff +; + +: MEM-MODE@ + h# 158 ( MEM_SDRAM_MODE_REG ) reg-rl@ ; + +: MEM-MODE! + h# 158 ( MEM_SDRAM_MODE_REG ) reg-rl! ; + +: MEM-STATUS@ + H# 150 reg-rl@ ; + +: WAIT-MEM-CMPLT + h# 8000 0 do mem-status@ 3 and 3 = if leave then loop ; + +: INITMEM + + mem-mode@ h# 6FFF0000 and h# 4000 or mem-mode! + mem-mode@ h# 6FFF0000 and h# 80004000 or mem-mode! + wait-mem-cmplt + mem-mode@ h# 6FFF0000 and h# 0132 or mem-mode! + mem-mode@ h# 6FFF0000 and h# 80000132 or mem-mode! + wait-mem-cmplt + mem-mode@ h# 6FFF0000 and h# 0032 or mem-mode! + mem-mode@ h# 6FFF0000 and h# 80000032 or mem-mode! + wait-mem-cmplt + mem-mode@ h# 6FFF0000 and h# 10000032 or mem-mode! +; + + + +: CLR-REG ( reg -- ) + 0 swap reg-rl! + +; +: SET-PALETTE ( -- ) + h# 0 h# b0 pc! \ Reset PALETTE_INDEX + + d# 16 0 do + H# 000000 h# B4 reg-rl! \ Write the PALETTE_DATA ( Auto increments) + H# aa0000 H# B4 reg-rl! + H# 00aa00 H# B4 reg-rl! + H# aa5500 H# B4 reg-rl! + H# 0000aa H# B4 reg-rl! + H# aa00aa H# B4 reg-rl! + H# 00aaaa H# B4 reg-rl! + H# aaaaaa H# B4 reg-rl! + H# 555555 H# B4 reg-rl! + H# ff5555 H# B4 reg-rl! + H# 55ff55 H# B4 reg-rl! + H# ffff55 H# B4 reg-rl! + H# 5555ff H# B4 reg-rl! + H# ff55ff H# B4 reg-rl! + H# 55ffff H# B4 reg-rl! + H# ffffff H# B4 reg-rl! + loop + + ; + +0 VALUE _addr +0 VALUE _color + +: DO-COLOR ( color-addr addr color -- ) + to _color to _addr 0 to _color + 3 0 do _addr i + c@ 2 i - 8 * << _color + to _color loop + _color h# B4 reg-rl! +; + +: SET-COLORS ( addr index #indices -- ) + + swap h# B0 pc! + ( addr #indices ) 0 ?do dup ( index ) i 3 * + DO-COLOR loop + ( addr ) drop ; + +: init-card + + h# FF h# 58 3 + pc! \ + h# 59 pc@ h# FE and h# 59 pc! \ + h# 50 reg-rl@ H# FEFFFFFF AND h# 02000200 or \ Clear 24 set 25 and 8-11 to 2 + h# 50 reg-rl! + h# 4F0063 h# 200 reg-rl! + H# 8C02A2 h# 204 reg-rl! + H# 1Df020C h# 208 reg-rl! + h# 8201EA h# 20C reg-rl! + h# 50 reg-rl@ H# F8FFFFFF AND h# 03000000 or h# 50 reg-rl! + h# 50 h# 22C reg-rl! + set-palette + + \ at this point for some reason mem-addr does not point + \ to the right address and therefore the following command + \ which should probably clean the frame buffer just + \ overwrites everything starting from 0 including the + \ exception vectors + + \ mem-addr h# F0000 0 fill + ; + +: DO-INIT + early-map + enable-card + init1 + pllinit + init2 + initmem + init-card + h# 8020 h# 54 reg-rl! + early-unmap +; + +d# 640 constant /scanline +d# 480 constant #scanlines +/scanline #scanlines * constant /fb + +" okay" encode-string " status" property + +: display-install ( -- ) + is_installed not if + map-csr-base + enable-card + mem-addr to frame-buffer-adr + h# 8020 h# 54 reg-rl! + default-font set-font + /scanline #scanlines d# 100 d# 40 fb8-install + true to is_installed + then +; + +: display-remove ( -- ) ; + +do-init \ Set up the card +\ clear at least 640x480 +10 config-l@ 8 - F0000 0 rfill +init1_array init1_length encode-array " ibm,init1" property +init2_array init2_length encode-array " ibm,init2" property +pllinit_array pllinit_length encode-array " ibm,pllinit" property +meminit_array meminit_length encode-array " ibm,meminit" property +0 0 encode-bytes " iso6429-1983-colors" property +s" display" device-type +/scanline encode-int " width" property + #scanlines encode-int " height" property +8 encode-int " depth" property +/scanline encode-int " linebytes" property + +' display-install is-install +' display-remove is-remove + +: fill-rectangle ( index x y w h -- ) + 2swap -rot /scanline * + frame-buffer-adr + ( index w h fbadr ) + swap 0 ?do ( index w fbadr ) + 3dup swap rot fill ( index w fbadr ) + /scanline + ( index w fbadr' ) + loop + 3drop +; +: draw-rectangle ( addr x y w h -- ) + 2swap -rot /scanline * + frame-buffer-adr + ( addr w h fbadr ) + swap 0 ?do ( addr w fbadr ) + 3dup swap move ( addr w fbadr ) + >r tuck + swap r> ( addr' w fbadr ) + /scanline + ( addr' w fbadr' ) + loop + 3drop + ; + : read-rectangle ( addr x y w h -- ) + 2swap -rot /scanline * + frame-buffer-adr + ( addr w h fbadr ) + swap 0 ?do ( addr w fbadr ) + 3dup -rot move ( addr w fbadr ) + >r tuck + swap r> ( addr' w fbadr ) + /scanline + ( addr' w fbadr' ) + loop + 3drop + ; + +: dimensions ( -- width height ) /scanline #scanlines ; + +." ( rn50 )" cr diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-device_1014_028c.fs b/qemu/roms/SLOF/board-js2x/slof/pci-device_1014_028c.fs new file mode 100644 index 000000000..e83a4e04f --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-device_1014_028c.fs @@ -0,0 +1,25 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space assign-all-device-bars +my-space pci-device-props +my-space pci-set-irq-line + +\ set Memory Write and Invalidate Enable, SERR# Enable (see PCI 3.0 Spec Chapter 6.2.2 device control) + +7 4 config-w! + + +\ Citrine storage controller. +s" citrine" + +include citrine.fs diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-device_1014_02bd.fs b/qemu/roms/SLOF/board-js2x/slof/pci-device_1014_02bd.fs new file mode 100644 index 000000000..1db6bdafc --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-device_1014_02bd.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space assign-all-device-bars +my-space pci-device-props +my-space pci-set-irq-line + +\ set Memory Write and Invalidate Enable, SERR# Enable (see PCI 3.0 Spec Chapter 6.2.2 device control) +7 4 config-w! + +\ Citrine storage controller. +s" obsidian" + +include citrine.fs diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7451.fs b/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7451.fs new file mode 100644 index 000000000..e540cba9c --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7451.fs @@ -0,0 +1,34 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ IO-APIC init + +s" io-apic" 2dup device-name device-type +my-space pci-class-name type s" ( 8131 IO-APIC )" type + +pci-io-enable +pci-mem-enable +pci-master-enable + +my-space b rshift \ Get slot #. +dup c lshift fec00000 or \ Calculate base address. +dup 48 config-l! 0 4c config-l! \ Set base address. +03 44 config-b! \ Enable IO-APIC. + +s" ioapic.fs" included + +2 lshift 14 + \ Calculate first IRQ #. +init-ioapic \ Set IRQs. + +my-space pci-device-props + +cr diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7468.fs b/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7468.fs new file mode 100644 index 000000000..4126ca241 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7468.fs @@ -0,0 +1,50 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space assign-all-device-bars +my-space pci-device-props +my-space pci-set-irq-line + +\ See the "ISA/EISA/ISA-PnP" OF binding document. + +.( isa) + +s" isa" 2dup device-name device-type +\ We have to say it's ISA i.s.o. LPC, as otherwise Linux can't find +\ the serial port for its console. Linux uses the name instead of the +\ device type (and it completely ignores any "compatible" property). + +2 encode-int s" #address-cells" property +1 encode-int s" #size-cells" property + +\ We assume all ISA addresses to refer to I/O space. +: decode-unit 1 hex-decode-unit 1 ; +: encode-unit drop 1 hex-encode-unit ; + +\ 32kB of ISA I/O space. +1 encode-int my-space 01000000 + encode-64+ 0 encode-int+ 0 encode-int+ +8000 encode-int+ s" ranges" property + +: open true ; +: close ; + +\ There's a SIO chip on the LPC bus. +INCLUDE sio.fs + +\ There's also an Atmel TPM chip on JS21 +\ removed on Bimini Pass 2 and therefore disabled on all Biminis +u4? bimini? not and ?INCLUDE tpm.fs + +\ And finally there's the IPMI interface to the BMC. +u4? ?INCLUDE ipmi-kcs.fs + +cr diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7469.fs b/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7469.fs new file mode 100644 index 000000000..fdae920c3 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-device_1022_7469.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space assign-all-device-bars +my-space pci-device-props +my-space pci-set-irq-line + +7 4 config-w! + +s" ide" type cr + +include ide.fs + +cr diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-device_14e4_16a8.fs b/qemu/roms/SLOF/board-js2x/slof/pci-device_14e4_16a8.fs new file mode 100644 index 000000000..ef782c948 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-device_14e4_16a8.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2013 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle bcm57xx device + +s" bcm57xx [ net ]" type cr + +my-space pci-device-generic-setup + +pci-io-enable + +s" bcm57xx.fs" included + +pci-device-disable diff --git a/qemu/roms/SLOF/board-js2x/slof/pci-interrupts.fs b/qemu/roms/SLOF/board-js2x/slof/pci-interrupts.fs new file mode 100644 index 000000000..92851cd58 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/pci-interrupts.fs @@ -0,0 +1,235 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ define function pointer as forward declaration for get-interrupt-line +\ this is board wireing and southbridge dependent +\ returns the wired interrupt line for this config addr +\ ( config-addr -- irq-line ) +DEFER pci-get-irq-line + +\ define function pointer as forward declaration for get-interrupt-sense-type +\ this is board wireing and southbridge dependent +\ returns the wired interrupt sense type for this config addr +\ 0 - Edge rising +\ 1 - Level low +\ 2 - Level high +\ 3 - Edge falling +\ ( config-addr -- irq-sense ) +DEFER pci-get-irq-sense + + +\ ***************************************************************************** +\ Generic IRQ routines +\ ***************************************************************************** + + + +: unknown-slot ( -- 0 ) +\ cr pci-vec ABORT" Unknown slot " + 0 +; +\ 0c s" /ht/@1/@2" PCI-X INTA & INTC Pnpirq0 -> irq12 +\ 0e s" /ht/@1/@2" PCI-X INTB & INTD Pnpirq1 -> irq14 +\ 10 s" /ht/@8,1" ATA +\ 0f s" /ht/@1/@1" Obsidian Pnpirq2 -> irq15 +\ 10 s" /ht/@7/@2" Video / Exar Serial PirqA +\ 11 s" /ht/@2/@4" Ethernet PirqB +\ 12 s" /ht/@2/@4,1" Ethernet PirqC +\ 13 s" /ht/@7/@0" USB PirqD +\ 13 s" /ht/@7/@0,1" USB PirqD +\ 13 s" /ht/@7/@0,2" USB PirqD + +\ 14 s" /ht/@3/@0" PCIe gpio28 +\ 15 s" /ht/@4/@0" PCIe gpio29 +\ 16 s" /ht/@5/@0" PCIe gpio30 +\ 17 s" /ht/@6/@0" PCIe gpio31 + + +\ ----------------------------------------------------------------------------- +\ Get the interrupt pin for a device on ht u4 +: u4-get-irq-line ( config-addr -- irq-line ) +\ cr s" u4-get-irq-line " type + pci-device-vec c@ CASE + 1 OF pci-device-vec-len 1 >= IF + pci-device-vec 1+ c@ CASE + 1 OF f ENDOF + 2 OF dup pci-interrupt@ CASE + 1 OF c ENDOF + 3 OF e ENDOF + 2 OF c ENDOF + 4 OF e ENDOF + ENDCASE + ENDOF + dup OF unknown-slot ENDOF + ENDCASE + ELSE + unknown-slot + THEN + ENDOF + 2 OF pci-device-vec-len 1 >= IF + pci-device-vec 1+ c@ CASE + 4 OF dup pci-addr2fn 1 >= IF 12 ELSE 11 THEN ENDOF + dup OF unknown-slot ENDOF + ENDCASE + ELSE + unknown-slot + THEN + ENDOF + 3 OF 14 ENDOF + 4 OF 15 ENDOF + 5 OF 16 ENDOF + 6 OF 17 ENDOF + 7 OF pci-device-vec-len 1 >= IF + pci-device-vec 1+ c@ CASE + 0 OF 13 ENDOF + 2 OF 10 ENDOF + dup OF unknown-slot ENDOF + ENDCASE + ELSE + unknown-slot + THEN + ENDOF + 8 OF 10 ENDOF + dup OF unknown-slot ENDOF + ENDCASE + swap drop +; + +\ ----------------------------------------------------------------------------- +\ Get the interrupt sense type for a device on ht u4 +: u4-get-irq-sense ( config-addr -- irq-sense ) +\ cr s" u4-get-irq-sense " type + u4-get-irq-line CASE + 0c OF 00 ENDOF + 0e OF 00 ENDOF + dup OF 01 ENDOF + ENDCASE +; + +\ 10 s" /ht/@4,1" set-pci-interrupt \ ATA +\ 13 s" /ht/@3/@0" set-pci-interrupt \ USB +\ 13 s" /ht/@3/@0,1" set-pci-interrupt \ USB +\ 13 s" /ht/@3/@0,2" set-pci-interrupt \ USB +\ 1c s" /ht/@2/@1" set-pci-interrupt \ Ethernet +\ 1d s" /ht/@2/@1,1" set-pci-interrupt \ Ethernet + +\ ----------------------------------------------------------------------------- +\ Get the interrupt pin for a device on ht u3 +: u3-get-irq-line ( config-addr -- irq-line ) +\ cr s" u3-get-irq-line " type + pci-device-vec c@ CASE + 2 OF pci-device-vec-len 1 >= IF + pci-device-vec 1+ c@ CASE + 1 OF dup pci-addr2fn 1 >= IF 1d ELSE 1c THEN ENDOF + dup OF unknown-slot ENDOF + ENDCASE + ELSE + unknown-slot + THEN + ENDOF + 3 OF 13 ENDOF + 4 OF 10 ENDOF + dup OF unknown-slot ENDOF + ENDCASE + swap drop +; + +\ ----------------------------------------------------------------------------- +\ Get the interrupt sense type for a device on ht u3 +: u3-get-irq-sense ( config-addr -- irq-sense ) +\ cr s" u3-get-irq-sense " type + u3-get-irq-line CASE + dup OF 01 ENDOF + ENDCASE +; + + + +\ ----------------------------------------------------------------------------- +\ Get the interrupt pin for a device on attu +: pcie-get-irq-line ( config-addr -- irq-line ) +\ cr s" pcie-get-irq-line " type + drop + 3 +; + + +\ ----------------------------------------------------------------------------- +\ Get the interrupt sense type for a device on attu +: pcie-get-irq-sense ( config-addr -- irq-sense ) +\ cr s" pcie-get-irq-sense " type + drop + 01 +; + +\ ----------------------------------------------------------------------------- +\ Set up the special routines for HT irq handling +: ht-irq-init ( -- ) +\ cr s" ht-irq-init " type + u4? IF + ['] u4-get-irq-line TO pci-get-irq-line + ['] u4-get-irq-sense TO pci-get-irq-sense + ELSE + ['] u3-get-irq-line TO pci-get-irq-line + ['] u3-get-irq-sense TO pci-get-irq-sense + THEN +; + +\ ----------------------------------------------------------------------------- +\ Set up the special routines for PCI-e irq handling +: pcie-irq-init ( -- ) +\ cr s" pcie-irq-init " type + ['] pcie-get-irq-sense TO pci-get-irq-sense + ['] pcie-get-irq-line TO pci-get-irq-line +; + +\ ----------------------------------------------------------------------------- +\ Set up the special routines for irq handling +0 VALUE mpic +: pci-irq-init ( mpic puid -- mpic ) + over TO mpic + 18 rshift FF and + CASE + F1 OF pcie-irq-init ENDOF + F2 OF ht-irq-init ENDOF + dup OF ABORT" Wrong PUID! in pci-irq-init" ENDOF + ENDCASE +; + +\ ----------------------------------------------------------------------------- +\ Set the interrupt pin for a device +: pci-set-irq-line ( config-addr -- ) +\ cr pci-vec + dup pci-get-irq-line +\ ." ->" dup . + swap pci-irq-line! +; + +\ ----------------------------------------------------------------------------- +\ Add an irq entry for the device at config-addr into the irq map +\ each entry consists of 7 integer values +\ Structure of an entry: +\ +----------+---+---+------------+--------------+---------+---------------+ +\ Number# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | +\ +----------+---+---+------------+--------------+---------+---------------+ +\ meaning | config | | | int# | phandle | intr nr | pos edge (0) | +\ | addr | | | (1=a, 2=b, | intr contr | | act ll (1) | +\ +----------+---+---+------------+--------------+---------+---------------+ +\ value | pci slot | 0 | 0 | 1 | mpic | 7 | 0|1 | +\ +----------+---+---+------------+--------------+---------+---------------+ +: pci-gen-irq-entry ( prop-addr prop-len config-addr -- prop-addr prop-len ) + dup >r encode-int+ 0 encode-64+ \ config addr + r@ pci-interrupt@ encode-int+ \ interrupt type + mpic encode-int+ \ phandle to MPIC + r@ pci-irq-line@ encode-int+ \ interrupt number + r> pci-get-irq-sense encode-int+ \ trigger type +; diff --git a/qemu/roms/SLOF/board-js2x/slof/rtas.fs b/qemu/roms/SLOF/board-js2x/slof/rtas.fs new file mode 100644 index 000000000..0a90c2903 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/rtas.fs @@ -0,0 +1,240 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +#include <rtas/rtas-init.fs> +#include <rtas/rtas-cpu.fs> +#include <rtas/rtas-reboot.fs> +#include <rtas/rtas-flash.fs> +#include <rtas/rtas-vpd.fs> + +\ for update-flash +: (get-flashside) ( -- flashside ) rtas-get-flashside ; + +' (get-flashside) to get-flashside + +\ remember the current flashside +get-flashside to flashside? + +\ for update-flash +: (set-flashside) ( flashside -- status ) + dup rtas-set-flashside = IF 0 ELSE -1 THEN +; + +' (set-flashside) to set-flashside + +: rtas-ibm-read-pci-config ( size puid bus devfn off -- x ) + [ s" ibm,read-pci-config" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 4 rtas-cb rtas>nargs l! + 2 rtas-cb rtas>nret l! + swap 8 lshift or swap 10 lshift or rtas-cb rtas>args0 l! + dup 20 rshift rtas-cb rtas>args1 l! + ffffffff and rtas-cb rtas>args2 l! + rtas-cb rtas>args3 l! + enter-rtas + rtas-cb rtas>args5 l@ +; + +: rtas-fetch-cpus ( mask -- status ) + [ s" rtas-fetch-slaves" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 1 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + 0 rtas-cb rtas>args1 l! + enter-rtas + rtas-cb rtas>args1 l@ +; + +: rtas-stop-bootwatchdog ( -- status ) + [ s" rtas-stop-bootwatchdog" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 0 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + enter-rtas + rtas-cb rtas>args0 l@ +; + +: rtas-set-bootwatchdog ( seconds -- ) + [ s" rtas-set-bootwatchdog" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 1 rtas-cb rtas>nargs l! + 0 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + enter-rtas +; + +' rtas-set-bootwatchdog to set-watchdog + +: rtas-dump-flash ( offset cnt -- ) + [ s" rtas-dump-flash" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 2 rtas-cb rtas>nargs l! + 0 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + rtas-cb rtas>args1 l! + enter-rtas +; + +create blist 50 allot +blist 50 erase + +: build-blocklist_old + \ set version + 1 blist c! + \ set length of block list + 50 blist 7 + c! + \ no more block list + 0000000000000000 blist 8 + ! + \ first block + get-load-base 0 + blist 10 + ! + 80000 blist 18 + ! + get-load-base 80000 + blist 20 + ! + 80000 blist 28 + ! + get-load-base 100000 + blist 30 + ! + 80000 blist 38 + ! + get-load-base 180000 + blist 40 + ! + 8006C blist 48 + ! +; + +80000 constant _block_size + +: build-blocklist + \ set length of block list + \ length of flashfs at load-base is at offset 30... get it... + get-load-base 30 + @ + \ calculate the number of blocks we need + _block_size / 1 + + \ total number of blocks is 2 (for header and block_list extension + (number of blocks for flashfs * 2 (1 for address 1 for length)) + 2 * 2 + 8 * blist ! + \ set version ( in first byte only ) + 1 blist c! + \ no more block list + 0000000000000000 blist 8 + ! + \ length of flashfs at load-base is at offset 30... get it... + get-load-base 30 + @ + \ i define one block to be 64K, so calculate the number of blocks we need and loop over them + _block_size / 1 + 0 do + get-load-base _block_size i * + \ which position of load-base to store + blist 10 + \ at what offset of blist ( 0x8 + for header 0x8 + for extension ) + i 10 * + \ for each loop we have done 0x10 + + ! \ store it + get-load-base 30 + @ + _block_size i * - \ remaining length + dup _block_size > + IF \ is the remaining length > block size + drop _block_size \ then store the block size as length + ELSE + \ do nothing (store remaining length) + THEN + blist 10 + \ store the length at + i 10 * + \ correct blist offset + 8 + \ + 8 (we have stored address, now the length) + ! \ store it + loop +; + + + +: build-blocklist-v0_old + \ set version + 0 blist c! + 48 blist 7 + c! + \ first block + get-load-base 0 + blist 8 + ! + 80000 blist 10 + ! + get-load-base 80000 + blist 18 + ! + 80000 blist 20 + ! + get-load-base 100000 + blist 28 + ! + 80000 blist 30 + ! + get-load-base 180000 + blist 38 + ! + 8006C blist 40 + ! +; + +: build-blocklist-v0 + \ set length of block list + \ length of flashfs at load-base is at offset 30... get it... + get-load-base 30 + @ + \ calculate the number of blocks we need + _block_size / 1 + + \ total number of blocks is 1 (for header + (number of blocks for flashfs * 2 (1 for address 1 for length)) + 2 * 1 + 8 * blist ! + \ length of flashfs at load-base is at offset 30... get it... + get-load-base 30 + @ + \ i define one block to be 64K, so calculate the number of blocks we need and loop over them + _block_size / 1 + 0 do + get-load-base _block_size i * + \ which position of load-base to store + blist 8 + \ at what offset of blist ( 0x8 + for header) + i 10 * + \ for each loop we have done 0x10 + + ! \ store it + get-load-base 30 + @ + _block_size i * - \ remaining length + dup _block_size > + IF \ is the remaining length > block size + drop _block_size \ then store the block size as length + ELSE + \ do nothing (store remaining length) + THEN + blist 8 + \ store the length at + i 10 * + \ correct blist offset + 8 + \ + 8 (we have stored address, now the length) + ! \ store it + loop +; + + +: yy + build-blocklist + blist rtas-ibm-update-flash-64-and-reboot +; + +: yy0 + build-blocklist-v0 + blist rtas-ibm-update-flash-64-and-reboot +; + +: rtas-ibm-update-flash-64 ( block-list -- status ) + [ s" ibm,update-flash-64" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 2 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + \ special unofficial parameter: if this is set to 1, the rtas function will not check, wether + \ we are on the perm side... this is needed for "update-flash -c" to work... + 1 rtas-cb rtas>args1 l! + enter-rtas + rtas-cb rtas>args2 l@ +; + +\ for update-flash +: flash-write ( image-address -- status) + load-base-override >r to load-base-override build-blocklist-v0 + blist rtas-ibm-update-flash-64 + r> to load-base-override 0= IF true ELSE false THEN +; + +: commit 1 rtas-ibm-manage-flash-image ; +: reject 0 rtas-ibm-manage-flash-image ; + +: rtas-ibm-validate-flash-image ( image-to-commit -- status ) + [ s" ibm,validate-flash-image" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 2 rtas-cb rtas>nargs l! + 2 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args1 l@ +; + +: rtas-get-blade-descr ( address size -- len status ) + [ s" rtas-get-blade-descr" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 2 rtas-cb rtas>nargs l! + 2 rtas-cb rtas>nret l! + rtas-cb rtas>args1 l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args2 l@ + rtas-cb rtas>args3 l@ +; diff --git a/qemu/roms/SLOF/board-js2x/slof/rtc.fs b/qemu/roms/SLOF/board-js2x/slof/rtc.fs new file mode 100644 index 000000000..861b3f9ff --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/rtc.fs @@ -0,0 +1,59 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ National Semiconductor SIO. +\ See http://www.national.com/pf/PC/PC87417.html for the datasheet. +\ PC87417.pdf +\ moved the RTC initialisation from the device tree to a much earlier point +\ so that the RTC can be accessed before device tree is generated + +\ Enable the RTC, set its address at 1070 +\ see PC87417.pdf page 39 (chapter 3.2.3) +10 7 siocfg! +1 30 siocfg! +1070 wbsplit nip dup 60 siocfg! 62 siocfg! + +: rtc@ ( offset -- value ) + 1070 io-c! 1071 io-c@ +; + +: rtc! ( value offset -- ) + 1070 io-c! 1071 io-c! +; + +\ Set sane configuration; BCD mode is required by Linux. +\ PC87417.pdf page 153 (chapter 8.3.13) - RTC Control Register A +\ 20 - Divider Chain Control = Normal Operation +20 0a rtc! +\ PC87417.pdf page 155 (chapter 8.3.14) - RTC Control Register B +\ 02 - 24-hour format enabled +02 0b rtc! +\ PC87417.pdf page 156 (chapter 8.3.15) - RTC Control Register C +00 0c rtc! + +\ read from the rtc and do the bcd-to-bin conversion +: rtc-bin@ ( offset -- value ) + rtc@ bcd-to-bin +; + +\ to be compatible with the cell boards we provide a .date word +\ .date prints the current date and time on the firmware prompt +: .date ( -- ) + 0 rtc-bin@ ( seconds ) + 2 rtc-bin@ + 4 rtc-bin@ + 7 rtc-bin@ + 8 rtc-bin@ ( seconds minutes hours day month ) + 9 rtc-bin@ d# 1900 + dup d# 1970 < IF d# 100 + THEN + decimal 4 0.r 2d emit 2 0.r 2d emit 2 0.r space + 2 0.r 3a emit 2 0.r 3a emit 2 0.r hex +; diff --git a/qemu/roms/SLOF/board-js2x/slof/serial.fs b/qemu/roms/SLOF/board-js2x/slof/serial.fs new file mode 100644 index 000000000..98b2f2939 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/serial.fs @@ -0,0 +1,48 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Serial console. Enabled very early. +\ remember last console used +CREATE lastser 4 allot 0 lastser l! + +\ On JS21, use serial port 2. Detect Maui by looking at the SIO version. +20 siocfg@ f2 = IF 2f8 ELSE 3f8 THEN + +: >serial LITERAL + ; +: js21? -2f8 >serial 0= ; +: serial! js21? IF 2dup 2f8 + io-c! THEN 3f8 + io-c! ; +: serial1@ 3f8 + io-c@ ; +: serial2@ 2f8 + io-c@ ; + +: serial-init 0 1 serial! 0 2 serial! + 80 3 serial! d# 115200 swap / 0 serial! 0 1 serial! + 3 3 serial! 3 4 serial! ; +: serial-emit BEGIN 5 serial1@ 20 and UNTIL + js21? IF BEGIN 5 serial2@ 20 and UNTIL THEN 0 serial! ; +: serial1-key? 5 serial1@ 1 and 0<> ; +: serial2-key? 5 serial2@ 1 and 0<> ; +: serial1-key serial1-key? dup IF 0 serial1@ swap 0 lastser l! THEN ; +: serial2-key serial2-key? dup IF 0 serial2@ swap 1 lastser l! THEN ; +: serial-key BEGIN serial1-key dup IF ELSE js21? IF drop serial2-key THEN THEN UNTIL ; +: serial-key? serial1-key? js21? IF serial2-key? or THEN ; + +\ : serial-key BEGIN 5 serial2@ 1 and UNTIL 0 serial2@ ; +\ : serial-key? 5 serial2@ 1 and 0<> ; + +d# 19200 serial-init +' serial-emit to emit +' serial-key to key +' serial-key? to key? + +( .( SLOF) +\ .( has started execution, serial console @ ) 0 >serial . diff --git a/qemu/roms/SLOF/board-js2x/slof/sio.fs b/qemu/roms/SLOF/board-js2x/slof/sio.fs new file mode 100644 index 000000000..554cf83e3 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/sio.fs @@ -0,0 +1,85 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ National Semiconductor SIO. +\ See http://www.national.com/pf/PC/PC87417.html for the datasheet. + +\ We use both serial ports, and the RTC. + +\ See 3.7.5. +new-device 3f8 1 set-unit + +s" serial" 2dup device-name device-type + +\ Enable this UART. +3 7 siocfg! 1 30 siocfg! + +\ 8 bytes of ISA I/O space +my-unit encode-int rot encode-int+ 8 encode-int+ s" reg" property +d# 19200 encode-int s" current-speed" property +44 encode-int 0 encode-int+ s" interrupts" property + +: open true ; +: close ; +: write ( adr len -- actual ) tuck type ; +: read ( adr len -- actual ) 0= IF drop 0 EXIT THEN + serial-key? 0= IF 0 swap c! -2 EXIT THEN + serial-key swap c! 1 ; + +finish-device + + +new-device 2f8 1 set-unit + +s" serial" 2dup device-name device-type + +\ Enable this UART. +2 7 siocfg! 1 30 siocfg! + +\ 8 bytes of ISA I/O space +my-unit encode-int rot encode-int+ 8 encode-int+ s" reg" property +d# 19200 encode-int s" current-speed" property +43 encode-int 0 encode-int+ s" interrupts" property + +: open true ; +: close ; +: write ( adr len -- actual ) tuck type ; +: read ( adr len -- actual ) 0= IF drop 0 EXIT THEN + serial-key? 0= IF 0 swap c! -2 EXIT THEN + serial-key swap c! 1 ; + +finish-device + + + +\ See the "Device Support Extensions" OF Recommended Practice document. +new-device 1070 1 set-unit + +s" rtc" 2dup device-name device-type +\ Following is for Linux, to recognize this RTC: +s" pnpPNP,b00" compatible + +: rtc! my-space io-c! my-space 1+ io-c! ; +: rtc@ my-space io-c! my-space 1+ io-c@ ; + +\ 10 bytes of ISA I/O space, at 1070. +my-unit encode-int rot encode-int+ 10 encode-int+ s" reg" property + +: open true ; +: close ; + +\ XXX: dummy methods. +: get-time ( -- sec min hr day mth yr ) 38 22 c 1 1 d# 1973 ; +: set-time ( sec min hr day mth yr -- ) 3drop 3drop ; + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/tpm.fs b/qemu/roms/SLOF/board-js2x/slof/tpm.fs new file mode 100644 index 000000000..69b9bc409 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/tpm.fs @@ -0,0 +1,63 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Atmel TPM. + +new-device 500 1 set-unit + +s" tpm" 2dup device-name device-type + +s" AT97SC3201" compatible + +\ 2 bytes of ISA I/O space +my-unit encode-int rot encode-int+ 2 encode-int+ s" reg" property + +: >tpm 4e io-c! ; +: tpm@ >tpm 4f io-c@ ; +: tpm! >tpm 4f io-c! ; + +: dump-tpm 11 0 DO cr i 2 .r space i tpm@ 2 0.r LOOP ; + +my-address wbsplit 9 tpm! 8 tpm! \ set base address +0 a tpm! \ disable serint + +\ Now we need to execute TPM_Startup. +CREATE startup-cmd +0 c, c1 c, +0 c, 0 c, 0 c, c c, +0 c, 0 c, 0 c, 99 c, \ TPM_ORD_Startup +0 c, 1 c, \ TCPA_ST_CLEAR + +: send ( addr len -- ) bounds ?DO i c@ 500 io-c! LOOP ; +: wait-for-ready ( -- ) BEGIN 501 io-c@ 3 and 2 = UNTIL ; +: recv-verbose ( -- ) + cr ." TPM result: " + 500 io-c@ 2 0.r 500 io-c@ 2 0.r space + 500 io-c@ 500 io-c@ 500 io-c@ 500 io-c@ + bljoin lbflip 6 - dup 8 0.r space 0 + ?DO 500 io-c@ . LOOP +; + +: recv ( -- ) + 500 io-c@ drop 500 io-c@ drop + 500 io-c@ 500 io-c@ 500 io-c@ 500 io-c@ + bljoin lbflip 6 - 0 + ?DO 500 io-c@ drop LOOP +; + +startup-cmd c send wait-for-ready recv + +: open true ; +: close ; + +finish-device diff --git a/qemu/roms/SLOF/board-js2x/slof/tree.fs b/qemu/roms/SLOF/board-js2x/slof/tree.fs new file mode 100644 index 000000000..040d99f09 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/tree.fs @@ -0,0 +1,225 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +400 cp + +0 value puid + +: >conf-rtas ( config-addr -- config-addr ) + puid f2000000 >= IF + ffffff AND \ Mask away highest byte for normal PCI + dup ffff > IF + 1000000 + + THEN + THEN + puid + +; + +: rtas-config-b@ ( config-addr -- value ) >conf-rtas rb@ ; +: rtas-config-b! ( value config-addr -- ) >conf-rtas rb! ; +: rtas-config-w@ ( config-addr -- value ) >conf-rtas rw@-le ; +: rtas-config-w! ( value config-addr -- ) >conf-rtas rw!-le ; +: rtas-config-l@ ( config-addr -- value ) >conf-rtas rl@-le ; +: rtas-config-l! ( value config-addr -- ) >conf-rtas rl!-le ; + +440 cp + +#include "pci-scan.fs" + +480 cp + +\ The root of the device tree and some of its kids. + +s" /" find-device +\ read model string from VPD +vpd-read-model ( straddr strlen ) +\ if it is a bimini, we replace the "IBM," in the model string with "TSS," +bimini? IF + 2dup drop 4 ( straddr strlen str 4 ) \ for string comparison: only first 4 bytes ("IBM,") + \ string comparison + s" IBM," str= IF + \ model starts with "IBM,", we replace it with "TSS," + 2dup drop s" TSS," ( straddr strlen straddr replacestr len ) + rot swap ( straddr strlen replacestr straddr len ) \ correct order for move: src dest len + move ( straddr strlen ) \ now we have TSS, at beginning of str... + THEN +THEN +\ store the model string +encode-string s" model" property + +2 encode-int s" #address-cells" property +2 encode-int s" #size-cells" property + +\ XXX: what requires this? Linux? +0 encode-int f8040000 encode-int+ +0 encode-int+ f8050000 encode-int+ s" platform-open-pic" property + +\ Yaboot is stupid. Without this, it can't/won't find /etc/yaboot.conf. +s" chrp SLOF based 970 blade" device-type + +\ add more information to the compatible property +js21? IF + bimini? IF + s" IBM,Bimini" + ELSE + s" IBM,JS21" + THEN +ELSE + s" IBM,JS20" +THEN encode-string +\ To get linux-2.6.10 and later to work out-of-the-box. +s" Momentum,Maple" encode-string encode+ s" compatible" property + + +\ See 3.6.5, and the PowerPC OF binding document. +new-device +s" mmu" 2dup device-name device-type +0 0 s" translations" property + +: open true ; +: close ; + +finish-device + +new-device flash-addr set-unit-64 + s" flash" 2dup device-name device-type + 0 encode-int flash-addr encode-int+ + 0 encode-int+ get-flash-size encode-int+ s" reg" property + get-flash-size encode-int s" #bytes" property + 0 0 s" used-by-rtas" property + : open true ; + : close ; +finish-device + +4a0 cp + +new-device nvram-base set-unit-64 + s" nvram" 2dup device-name device-type + nvram-size encode-int s" #bytes" property + 0 encode-int nvram-base encode-int+ + 0 encode-int+ nvram-size encode-int+ s" reg" property + get-node node>path s" nvram" 2swap set-alias + : open true ; + : close ; +finish-device + +4c0 cp + +#include "memory.fs" + +500 cp + +#include "mpic.fs" + +580 cp + +#include "dart.fs" + +5a0 cp + +#include "i2c.fs" + +600 cp +get-node device-end +620 cp +\ if it is js21/bimini the fbuffer code is included +u4? ?include fbuffer.fs +640 cp +set-node + +690 cp + +#include "ht.fs" + +6b0 cp + +u4? ?include attu.fs +6c0 cp + +\ See the PowerPC OF binding document. +new-device +s" cpus" device-name + +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +: decode-unit 1 hex-decode-unit ; +: encode-unit 1 hex-encode-unit ; + +cpu-mask @ 40 0 DO dup 1 and IF +i s" cpu.fs" INCLUDED THEN u2/ LOOP drop + +: open true ; +: close ; + +finish-device + +master-cpu s" /cpus/@" rot (u.) $cat open-dev encode-int s" cpu" set-chosen +s" /memory" open-dev encode-int s" memory" set-chosen + +6e0 cp + +new-device + s" rtas" device-name + + rtas-size encode-int s" rtas-size" property + 00000001 encode-int s" ibm,flash-block-version" property + 00000001 encode-int s" rtas-event-scan-rate" property + rtas-create-token-properties + 00000001 encode-int s" rtas-version" property + +: open true ; +: close ; + +: instantiate-rtas instantiate-rtas ; + +finish-device + +700 cp + +device-end + +\ Hack for AIX. +s" /options" find-device + \ s" 33554432" encode-string s" load-base" property + s" 16384" encode-string s" load-base" property +device-end + +\ See 3.5. +s" /openprom" find-device + s" SLOF," slof-build-id here swap rmove here slof-build-id nip $cat encode-string s" model" property + 0 0 s" relative-addressing" property + flashside? 1 = IF s" T" ELSE s" P" THEN + encode-string s" ibm,fw-bank" property + takeover? not IF + 0 set-flashside drop + read-version-and-date s" ibm,fw-perm-bank" property + 1 set-flashside drop + read-version-and-date s" ibm,fw-temp-bank" property + flashside? set-flashside drop + THEN +device-end + +s" /aliases" find-device + : open true ; + : close ; +device-end + +s" /mmu" open-dev encode-int s" mmu" set-chosen + +#include "available.fs" + +#include <term-io.fs> + +u3? IF s" /ht/isa/serial@3f8" io + ELSE s" /ht/isa/serial@2f8" io THEN + diff --git a/qemu/roms/SLOF/board-js2x/slof/u4-mem.fs b/qemu/roms/SLOF/board-js2x/slof/u4-mem.fs new file mode 100644 index 000000000..0f8b1eef6 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/u4-mem.fs @@ -0,0 +1,313 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ U4 DDR2 memory controller. + +cr .( Setting up memory controller...) + + +\ First, I2C access to the SPDs. + +: >i2c f8001000 + ; +: i2c@ >i2c rl@ ; +: i2c! >i2c rl! ; + +: .i2c 80 0 DO i i2c@ . 10 +LOOP ; + +: i2c-addr ( addr -- ) 50 i2c! 2 10 i2c! BEGIN 30 i2c@ 2 and UNTIL ; +: i2c-addr-subaddr ( addr suba -- ) 60 i2c! i2c-addr ; +: i2c-stop ( -- ) BEGIN 30 i2c@ dup 30 i2c! 4 and UNTIL ; +: i2c-nak? ( -- failed? ) 20 i2c@ 2 and 0= dup IF i2c-stop THEN ; +: i2c-short? ( -- failed? ) 30 i2c@ 4 and 0<> dup IF 0 10 i2c! i2c-stop THEN ; +: i2c-aak-if-more ( n -- ) 1 <> 1 and 10 i2c! ; + +: i2c-sub-read ( buf len addr suba -- error? ) + c 0 i2c! >r 1 or r> i2c-addr-subaddr i2c-nak? IF 2drop true EXIT THEN + dup i2c-aak-if-more 2 30 i2c! + BEGIN + 30 i2c@ 1 and IF + 1- >r 70 i2c@ over c! char+ r> + dup 0= IF i2c-stop 2drop false EXIT THEN + dup i2c-aak-if-more 1 30 i2c! THEN + i2c-short? IF 2drop true EXIT THEN + AGAIN ; + + +\ What slots are filled with working memory (bitmask). + +f VALUE dimms-valid +: dimm-invalid 1 swap lshift invert dimms-valid and to dimms-valid ; +: dimm-invalid dup dimm-invalid 2 xor dimm-invalid ; \ DIMMs are paired +: dimm-valid? 1 swap lshift dimms-valid and ; +: dimm( +comp postpone 4 postpone 0 postpone DO + postpone i postpone dimm-valid? postpone IF ; immediate +: )dimm postpone THEN postpone LOOP -comp ; immediate + + +\ The data from the SPDs. + +CREATE spds 100 allot +: spd@ ( dimm# off -- value ) swap 40 * + spds + c@ ; + +CREATE addresses a0 c, a4 c, a2 c, a6 c, +dimm( spds i 40 * + 40 addresses i + c@ 0 i2c-sub-read IF i dimm-invalid THEN )dimm + + +\ Accessors. + +: spd>rows 3 spd@ ; +: spd>cols 4 spd@ ; +: spd>ranks 5 spd@ 7 and 1+ ; +: spd>width d spd@ ; +: spd>banks 11 spd@ ; +: spd>cas 12 spd@ ; \ bit mask of allowable CAS latencies +: spd>trp 1b spd@ ; \ in units of 0.25 ns +: spd>trrd 1c spd@ ; \ in units of 0.25 ns +: spd>trcd 1d spd@ ; \ in units of 0.25 ns +: spd>tras 1e spd@ ; \ in units of 1 ns +: spd>twr 24 spd@ ; \ in units of 0.25 ns +: spd>twtr 25 spd@ ; \ in units of 0.25 ns +: spd>trtp 26 spd@ ; \ in units of 0.25 ns +: spd>trc 29 spd@ ; \ in units of 1 ns XXX: should also look at byte 28 +: spd>trfc 2a spd@ ; \ in units of 1 ns XXX: should also look at byte 28 + +cr .( rows cols ranks width banks trp trrd trcd tras twr twtr trtp trc trfc) +cr .( =====================================================================) +decimal +dimm( cr +i spd>rows 4 .r i spd>cols 5 .r i spd>ranks 6 .r i spd>width 6 .r +i spd>banks 6 .r i spd>trp 4 .r i spd>trrd 5 .r i spd>trcd 5 .r +i spd>tras 5 .r i spd>twr 4 .r i spd>twtr 5 .r i spd>trtp 5 .r +i spd>trc 4 .r i spd>trfc 5 .r +)dimm +hex + +ff dimm( i spd>cas and )dimm CONSTANT cl-supported +: max-cl -1 swap 8 0 DO dup 1 and IF nip i swap THEN u2/ LOOP drop ; +cl-supported max-cl VALUE cl + +: tck>60*ns dup f and swap 4 rshift a * over + 6 * swap CASE + a OF 2d - ENDOF b OF 2e - ENDOF c OF 20 - ENDOF d OF 21 - ENDOF + ENDCASE ; +: cl>tck 0 spd>cas max-cl swap - + CASE 0 OF 9 ENDOF 1 OF 17 ENDOF 2 OF 19 ENDOF + true ABORT" No supported CAS latency for this DIMM" ENDCASE + 0 swap spd@ tck>60*ns ; + +: spd>min-tck dup spd>cas max-cl cl - + CASE 0 OF 9 ENDOF 1 OF 17 ENDOF 2 OF 19 ENDOF + true ABORT" No supported CAS latency for this DIMM" ENDCASE + spd@ tck>60*ns ; +: spd>max-tck 2b spd@ tck>60*ns ; + +: .tck base @ >r decimal dup d# 60 / 0 .r [char] . emit + d# 60 mod d# 1000 * d# 60 / 3 0.r ." ns" r> base ! ; + +cr .( CAS latencies supported: ) +8 0 DO cl-supported 1 i lshift and IF i . THEN LOOP + +\ Find the lowest CL at the highest tCK. +8 0 DO cl-supported 1 i lshift and IF cl cl>tck i cl>tck = IF + i to cl LEAVE THEN THEN LOOP + +.( -- using ) cl . + + +0 dimm( i spd>min-tck max )dimm CONSTANT tck +dimm( i spd>max-tck tck < IF i dimm-invalid THEN )dimm +cr .( tCK is ) tck .tck + + +0 CONSTANT al +cl al + CONSTANT rl +rl 1- CONSTANT wl + +: // dup >r 1- + r> / ; \ round up +0 spd>tras d# 60 * tck // CONSTANT tras +0 spd>trtp d# 15 * tck // CONSTANT trtp +0 spd>twr d# 15 * tck // CONSTANT twr +0 spd>trp d# 15 * tck // CONSTANT trp +0 spd>trrd d# 15 * tck // CONSTANT trrd +0 spd>trrd d# 60 * tck // CONSTANT 4*trrd +0 spd>trcd d# 15 * tck // CONSTANT trcd +0 spd>trc d# 60 * tck // CONSTANT trc +0 spd>twtr d# 15 * tck // CONSTANT twtr + +: spd>memmd + >r r@ spd>rows r@ spd>cols + + r@ spd>banks 2log + 4 * r> spd>width 2log 3 * + 6c - ; +: dimm-group-size ( dimm# -- size ) + >r r@ spd>rows r@ spd>cols + 1 swap lshift + r@ spd>banks * r> spd>ranks * 10 * ; +VARIABLE start-address +VARIABLE was-prev-big +: assign-dimm-group ( dimm# -- config-value ) + dup dimm-valid? 0= IF drop 0 EXIT THEN + \ MemMd, enable, single-sided or not + dup spd>memmd c lshift 1 or over spd>ranks 1 = IF 2 or THEN +cr ." ---> " dup . +>r + dimm-group-size start-address @ 2dup + rot ( start end size ) + 80000000 > IF + dup 1000000000 < IF dup 4 rshift ELSE 08000000 THEN r> or >r \ Add2G + over 0<> IF over c rshift ELSE 00080000 THEN r> or >r \ Sub2G + was-prev-big on + ELSE + was-prev-big @ IF 80000000 + swap 80000000 + swap THEN r> 08080000 or >r + was-prev-big off + THEN + swap 18 rshift r> or >r \ start address + dup 80000000 = IF drop 100000000 THEN start-address ! r> ; + + +\ Now set the frequency in the memory controller +d# 1800 tck / 4 - 12 lshift 33c or f8000800 rl! +f8000860 rl@ 80000000 or f8000860 rl! 10000 0 DO LOOP + +: mc! f8002000 + rl! ; +: mc@ f8002000 + rl@ ; + + +\ memory timing regs (state machine) + +tras 2- +5 lshift al trtp + 2- or +5 lshift wl twr + or +5 lshift trp 2- or +5 lshift trp 2- 0 spd>banks 8 = IF 1+ THEN or +7 lshift 030 mc! + +al trtp + trp + 2- +5 lshift cl al + twr + trp + 1- or +5 lshift trrd 2- or +5 lshift trc 2- or +5 lshift trcd 2- or +5 lshift 4*trrd or +2 lshift 040 mc! + +0 +5 lshift 1 or +5 lshift 1 or +5 lshift cl 1- twtr + or +5 lshift 1 or +5 lshift 1 or +2 lshift 050 mc! + +0 +5 lshift 1 or +5 lshift 1 or +5 lshift 2 or +5 lshift 2 or +5 lshift 2 or +2 lshift 060 mc! \ XXX joerg has different setting + +cl 3 = IF 30801800 ( 30800d00 ) 070 mc! \ XXX memory refresh +ELSE 41002000 070 mc! THEN + +\ memory size regs + +1 dimm-group-size 0 dimm-group-size > 1 0 rot IF swap THEN \ biggest first +assign-dimm-group 200 mc! +assign-dimm-group 210 mc! +0 220 mc! 0 230 mc! + + + + + +\ arbiter tunables +\ 40041040 270 mc! +04041040 270 mc! +50000000 280 mc! +\ a0a00000 290 mc! \ a0000000 might be faster +00000000 290 mc! +\ 20020820 2a0 mc! +04020822 2a0 mc! +00000000 2b0 mc! +\ 30413cc7 2c0 mc! \ have to calculate the low five bits +30413dc5 2c0 mc! +\ cl 3 = IF 76000050 2d0 mc! 70000000 2e0 mc! ELSE +cl 3 = IF 75000050 2d0 mc! 70000000 2e0 mc! ELSE + b8002080 2d0 mc! b0000000 2e0 mc! THEN +\ Should test for something else really + + + +cl 3 = IF 00006000 890 mc! 00006000 8a0 mc! ELSE + 00006500 890 mc! 00006500 8a0 mc! THEN + +cl 3 = IF 1e008a8a ELSE 31000000 THEN +dup 800 mc! dup 810 mc! dup 820 mc! dup 830 mc! +dup 900 mc! dup 910 mc! dup 920 mc! dup 930 mc! dup 980 mc! +dup a00 mc! dup a10 mc! dup a20 mc! dup a30 mc! +dup b00 mc! dup b10 mc! dup b20 mc! dup b30 mc! b80 mc! + +\ 0 8d0 mc! 0 9d0 mc! 0 ad0 mc! 0 bd0 mc! +61630000 8d0 mc! +61630000 9d0 mc! +52510000 ad0 mc! +434e0000 bd0 mc! + +a0200400 100 mc! +80020000 110 mc! +80030000 120 mc! +80010404 130 mc! +cl 3 = IF +8000153a 140 mc! ELSE +8000174a 140 mc! THEN +a0200400 150 mc! +\ 92000000 160 mc! +\ 92000000 170 mc! +\ 91300000 160 mc! +\ 91300000 170 mc! +91800000 160 mc! +91800000 170 mc! +cl 3 = IF +8ff0143a 180 mc! ELSE +8ff0164a 180 mc! THEN +80010784 190 mc! +80010404 1a0 mc! +0 1b0 mc! 0 1c0 mc! 0 1d0 mc! 0 1e0 mc! 0 1f0 mc! + +cl 3 = IF +143a 0c0 mc! ELSE +164a 0c0 mc! THEN +0404 0d0 mc! + +\ after this point, setup is common for all speeds and sizes of dimms (sort of) + +60000000 3a0 mc! + +0 840 mc! 0 850 mc! 0 860 mc! 0 870 mc! +0 940 mc! 0 950 mc! 0 960 mc! 0 970 mc! 0 990 mc! +0 a40 mc! 0 a50 mc! 0 a60 mc! 0 a70 mc! +0 b40 mc! 0 b50 mc! 0 b60 mc! 0 b70 mc! 0 b90 mc! + +0 880 mc! + +001a4000 9a0 mc! + +84800000 500 mc! + +10000 0 DO LOOP + +80000000 b0 mc! BEGIN b0 mc@ 40000000 and UNTIL + +0 300 mc! 0 310 mc! + +80000000 440 mc! +0 410 mc! 27fffffc 420 mc! +fedcba98 430 mc! +c0000000 400 mc! BEGIN 400 mc@ c0000000 and 0= UNTIL + +cr .( mem done) diff --git a/qemu/roms/SLOF/board-js2x/slof/version.c b/qemu/roms/SLOF/board-js2x/slof/version.c new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/version.c diff --git a/qemu/roms/SLOF/board-js2x/slof/vga-display.fs b/qemu/roms/SLOF/board-js2x/slof/vga-display.fs new file mode 100644 index 000000000..96417e2d3 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/slof/vga-display.fs @@ -0,0 +1,157 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ included by pci-class_03.fs + +( str len display_num ) \ name prefix + +false value is-installed? +value display_num ( str len ) + +s" ,Display-" $cat 41 display_num + char-cat \ add ", Display-A" or "-B" to name ( str len ) +encode-string s" name" property \ store as name property + +s" display" device-type + +\ screen-info is set by pci-class_03.fs contains output of get_vbe_info bios-snk call +CASE screen-info c@ \ ( display-type ) + 0 OF s" NONE" ENDOF \ No display + 1 OF s" Analog" ENDOF + 2 OF s" Digital" ENDOF +ENDCASE +encode-string s" display-type" property + +screen-info 8 + l@ value mem-adr +screen-info 1 + w@ value width +screen-info 3 + w@ value height + +screen-info c@ IF + \ if screen-info is not 0, we have some screen attached, add needed properties... + width encode-int s" width" property + height encode-int s" height" property + screen-info 5 + w@ encode-int s" linebytes" property + screen-info 7 + c@ encode-int s" depth" property + mem-adr encode-int s" address" property + \ the EDID property breaks the boot... so i leave it out for now, + \ maybe encode-bytes does s.th. wrong??? + \ screen-info c + 80 encode-bytes s" EDID" property + s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok... +THEN + +\ words for installation/removal, needed by is-install/is-remove, see display.fs +: display-remove ( -- ) +; +: display-install ( -- ) + is-installed? NOT IF + mem-adr to frame-buffer-adr + default-font + set-font + width height width char-width / height char-height / ( width height #lines #cols ) + fb8-install + true to is-installed? + THEN +; + +: color! ( r g b number -- ) + \ 3c8 is RAMDAC write mode select palette entry register + \ 3c9 is RAMDAC write mode write palette entry register ( 3 consecutive writes set new entry ) + vga-device-node? 3c8 translate-address ( r g b number address ) + swap 1 pick ( r g b address number address ) + rb! \ write palette entry number ( r g b address ) + 1 + \ select next register (3c9) + dup 4 pick swap rb! \ write red ( r g b address ) + dup 3 pick swap rb! \ write green ( r g b address ) + dup 2 pick swap rb! \ write blue ( r g b address ) + 4drop +; + +: color@ ( number -- r g b ) + \ 3c7 is RAMDAC read mode select palette entry register + \ 3c9 is RAMDAC read mode read palette entry register ( 3 consecutive reads read entry ) + vga-device-node? 3c7 translate-address ( number address ) + swap 1 pick ( address number address ) + rb! \ write palette entry number ( address ) + 2 + >r \ select next register (3c9) ( R: address ) + r@ rb@ \ read red ( r R: address ) + r@ rb@ \ read green ( r g R: address ) + r@ rb@ \ write blue ( r g b R: address ) + r> drop ( r g b ) +; + +: set-colors ( adr number #numbers -- ) + \ 3c8 is RAMDAC write mode select palette entry register + \ 3c9 is RAMDAC write mode write palette entry register ( 3 consecutive writes set new entry ) + \ since after writing 3 entries, the palette entry is automagically incremented, + \ we can just continue writing... + vga-device-node? 3c8 translate-address ( adr number #numbers ) + dup 3 pick swap ( adr number #numbers address number address ) + rb! \ write palette entry number ( adr number #numbers address ) + 1 + \ select next register (3c9) + -rot swap drop ( adr address #numbers ) + -rot swap rot ( address adr #numbers ) + 0 ?DO + ( address adr ) + dup rb@ \ read red value from adr ( address adr r ) + 2 pick rb! \ write to register ( address adr ) + 1 + \ next adr + dup rb@ \ read green value from adr ( address adr g ) + 2 pick rb! \ write to register ( address adr ) + 1 + \ next adr + dup rb@ \ read blue value from adr ( address adr r ) + 2 pick rb! \ write to register ( address adr ) + 1 + \ next adr + LOOP + 2drop +; + +: get-colors ( adr number #numbers -- ) + \ 3c7 is RAMDAC read mode select palette entry register + \ 3c9 is RAMDAC read mode read palette entry register ( 3 consecutive reads get entry ) + \ since after reading 3 entries, the palette entry is automagically incremented, + \ we can just continue reading... + vga-device-node? 3c7 translate-address ( adr number #numbers ) + dup 3 pick swap ( adr number #numbers address number address ) + rb! \ write palette entry number ( adr number #numbers address ) + 2 + \ select next register (3c9) + -rot swap drop ( adr address #numbers ) + -rot swap rot ( address adr #numbers ) + 0 ?DO + ( address adr ) + 1 pick rb@ \ read red value from register ( address adr r ) + 1 pick rb! \ write to adr ( address adr ) + 1 + \ next adr + 1 pick rb@ \ read green value from register ( address adr g ) + 1 pick rb! \ write to adr ( address adr ) + 1 + \ next adr + 1 pick rb@ \ read blue value from register ( address adr b ) + 1 pick rb! \ write to adr ( address adr ) + 1 + \ next adr + LOOP + 2drop +; + +include graphics.fs + +\ clear screen +mem-adr width height * 0 rfill + +\ call is-install and is-remove +' display-install is-install + +' display-remove is-remove + +s" screen" find-alias 0= IF + \ no previous screen alias defined, define it... + s" screen" get-node node>path set-alias +ELSE + drop +THEN diff --git a/qemu/roms/SLOF/board-qemu/Makefile b/qemu/roms/SLOF/board-qemu/Makefile new file mode 100644 index 000000000..29ee016ad --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/Makefile @@ -0,0 +1,73 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +BOARD_TARGETS = tools_build romfs_build clients_build stage1 subdirs + +SUBDIRS = slof + +COMMON_LIBS = libc libbootmsg libbases libnvram libelf libhvcall libvirtio libusb \ + libveth libe1k + +all: $(BOARD_TARGETS) + $(MAKE) boot_rom.bin + +.PHONY : subdirs $(SUBDIRS) clean distclean + +include config +include Makefile.dirs +include $(TOPCMNDIR)/make.rules +include $(TOPCMNDIR)/Makefile.gen + +subdirs: $(SUBDIRS) + +$(SUBDIRS): common-libs + @echo " ====== Building $@ ======" + $(MAKE) -C $@ $(MAKEARG) RELEASE=-DRELEASE=\"\\\"$(RELEASE)\\\"\" + +stage1: common-libs + @echo " ====== Building llfw ======" + $(MAKE) -C llfw RELEASE=-DRELEASE=\"\\\"$(RELEASE)\\\"\" + +clean_here: + rm -f ../slof/OF.ffs + rm -f ../boot_rom.bin + +clean: clean_here clean_gen + @for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir clean || exit 1; \ + done + rm -f ../boot_rom.bin + @$(MAKE) -C llfw clean + +distclean: clean_here distclean_gen + @for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir distclean || exit 1; \ + done + rm -f ../boot_rom.bin + $(MAKE) -C llfw clean + +.driver_dirs: + @rm -rf ../driver-$(RELEASE) + @mkdir -p ../driver-$(RELEASE) + +.tar_gz: .driver_dirs + @mv ../boot_rom.bin ../driver-$(RELEASE)/$(RELEASE)-slof.bin + @cp ../VERSION ../driver-$(RELEASE) + @cp changes.txt ../driver-$(RELEASE) + @cd ../driver-$(RELEASE) && md5sum * > md5sum.txt + @chmod 644 ../driver-$(RELEASE)/* + @mv ../driver-$(RELEASE) ../driver-$(RELEASE)-`date +%Y-%h%d` + @tar czf ../driver-$(RELEASE)-`date +%Y-%h%d`.tar.gz \ + ../driver-$(RELEASE)-`date +%Y-%h%d` > /dev/null 2>&1 + @rm -rf ../driver-$(RELEASE)-`date +%Y-%h%d` + +driver: driver_prep clean .tar_gz diff --git a/qemu/roms/SLOF/board-qemu/Makefile.dirs b/qemu/roms/SLOF/board-qemu/Makefile.dirs new file mode 100644 index 000000000..1493d3bf1 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/Makefile.dirs @@ -0,0 +1,41 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ +# +# This sub-Makefile contains the directory configuration variables. +# It can be included from all board specific subdirectories. +# + +# The board specific top directory: +export TOPBRDDIR ?= $(shell while ! test -e Makefile.dirs ; do cd .. ; done ; pwd ) + +# The board specific directories: +export INCLBRDDIR ?= $(TOPBRDDIR)/include +export LLFWBRDDIR ?= $(TOPBRDDIR)/llfw +export RTASBRDDIR ?= $(TOPBRDDIR)/rtas +export SLOFBRDDIR ?= $(TOPBRDDIR)/slof +export ROMFSBRDDIR ?= $(TOPBRDDIR)/romfs + +# The common top directory: +export TOPCMNDIR ?= $(shell cd $(TOPBRDDIR)/.. && pwd) + +# The common directories: +export INCLCMNDIR ?= $(TOPCMNDIR)/include +export LLFWCMNDIR ?= $(TOPCMNDIR)/llfw +export RTASCMNDIR ?= $(TOPCMNDIR)/rtas +export SLOFCMNDIR ?= $(TOPCMNDIR)/slof +export ROMFSCMNDIR ?= $(TOPCMNDIR)/romfs + +export LIBCMNDIR ?= $(TOPCMNDIR)/lib + +export TOOLSDIR ?= $(TOPCMNDIR)/tools +export CLIENTSDIR ?= $(TOPCMNDIR)/clients +export OTHERLICENCEDIR ?= $(TOPCMNDIR)/other-licence diff --git a/qemu/roms/SLOF/board-qemu/config b/qemu/roms/SLOF/board-qemu/config new file mode 100644 index 000000000..f1940914f --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/config @@ -0,0 +1,7 @@ +BOARD=qemu +TARG=ppc64 +export FLAG="-DRTAS_NVRAM -DBROKEN_SC1 -DDHCPARCH=0x0C " +export CPUARCH=ppcp7 +export CPUARCHDEF=-DCPU_PPCP7 +#export SNK_BIOSEMU_APPS=1 +FLASH_SIZE=8388608 diff --git a/qemu/roms/SLOF/board-qemu/include/hw.h b/qemu/roms/SLOF/board-qemu/include/hw.h new file mode 100644 index 000000000..27117c3f3 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/include/hw.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +uint16_t bswap16_load(uint64_t addr) ; +uint32_t bswap32_load(uint64_t addr) ; + +void bswap16_store(uint64_t addr, uint16_t val) ; +void bswap32_store(uint64_t addr, uint32_t val) ; + +uint8_t load8_ci(uint64_t addr) ; +uint16_t load16_ci(uint64_t addr) ; +uint32_t load32_ci(uint64_t addr) ; +uint64_t load64_ci(uint64_t addr) ; + +void store8_ci(uint64_t addr, uint8_t val) ; +void store16_ci(uint64_t addr, uint16_t val) ; +void store32_ci(uint64_t addr, uint32_t val) ; +void store64_ci(uint64_t addr, uint64_t val) ; diff --git a/qemu/roms/SLOF/board-qemu/include/nvramlog.h b/qemu/roms/SLOF/board-qemu/include/nvramlog.h new file mode 100644 index 000000000..d13025596 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/include/nvramlog.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef NVRAMLOG_H + #define NVRAMLOG_H + +/* ---------------------------------------------------------------------------- + * NVRAM Log-Partition header design: + * + * Partition Header + * 00h - signature ( 1 byte) + * 01h - checksum ( 1 byte) + * 02h - length ( 2 byte) value = 1st_byte*256 + 2nd_byte + * 04h - name (12 byte) + * space for partiton header = 16 byte + * + * Log Header + * 10h - offset ( 2 byte) from Partition Header to Data Section + * 12h - flags ( 2 byte) control flags + * 14h - pointer ( 4 byte) pointer to first free byte in Data Section + * relative to the beginning of the data section + * 18h - zero ( 32 byte) reserved as stack for four 64 bit register + * 38h - reserved ( 8 byte) reserved for 64 bit CRC (not implemented yet) + * space for header = 64 byte + * Data Section + * 40h - cyclic data + * -------------------------------------------------------------------------------- */ + + // initial values + #define LLFW_LOG_BE0_SIGNATURE 0x51 // signature for general firmware usage + #define LLFW_LOG_BE0_NAME_PREFIX 0x69626D2C // first 4 bytes of name: "ibm," + #define LLFW_LOG_BE0_NAME 0x435055306C6F6700 // remaining 8 bytes : "CPU0log\0" + #define LLFW_LOG_BE0_LENGTH 0x200 // Partition length in block of 16 bytes + #define LLFW_LOG_BE0_DATA_OFFSET 0x40 // offset in bytes between header and data + #define LLFW_LOG_BE0_FLAGS 0 // unused + + #define LLFW_LOG_BE1_SIGNATURE 0x51 // signature for general firmware usage + #define LLFW_LOG_BE1_NAME_PREFIX 0x69626D2C // first 4 bytes of name: "ibm," + #define LLFW_LOG_BE1_NAME 0x435055316C6F6700 // remaining 8 bytes : "CPU1log\0\0" + #define LLFW_LOG_BE1_LENGTH 0x80 // Partition length in block of 16 bytes + #define LLFW_LOG_BE1_DATA_OFFSET 0x40 // offset in bytes between header and data + #define LLFW_LOG_BE1_FLAGS 0x0 // unused + + // positions of the initial values + #define LLFW_LOG_POS_CHECKSUM 0x01 // 1 + #define LLFW_LOG_POS_LENGTH 0x02 // 2 + #define LLFW_LOG_POS_NAME 0x04 // 4 + #define LLFW_LOG_POS_DATA_OFFSET 0x10 // 16 + #define LLFW_LOG_POS_FLAGS 0x12 // 18 + #define LLFW_LOG_POS_POINTER 0x14 // 20 + + // NVRAM info + #define NVRAM_EMPTY_PATTERN 0x0000000000000000 // Pattern (64-bit) used to overwrite NVRAM + +#endif diff --git a/qemu/roms/SLOF/board-qemu/include/product.h b/qemu/roms/SLOF/board-qemu/include/product.h new file mode 100644 index 000000000..819d6eda1 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/include/product.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _PRODUCT_H +#define _PRODUCT_H + +/* This is also the name which is also put in the flash and should + * therefore not excedd the length of 32 bytes */ +#define PRODUCT_NAME "QEMU" + +/* Generic identifier used in the flash */ +#define FLASHFS_MAGIC "magic123" + +/* Magic identifying the platform */ +#define FLASHFS_PLATFORM_MAGIC "qemu0" + +/* also used in the flash */ +#define FLASHFS_PLATFORM_REVISION "1" + +#define BOOT_MESSAGE "Press \"s\" to enter Open Firmware.\r\n\r\n\0" + +#endif diff --git a/qemu/roms/SLOF/board-qemu/include/southbridge.h b/qemu/roms/SLOF/board-qemu/include/southbridge.h new file mode 100644 index 000000000..1cdb422c0 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/include/southbridge.h @@ -0,0 +1,19 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* Not used */ +#define SB_NVRAM_adr 0 +#define SB_FLASH_adr 0 +#define FLASH_LENGTH 0 +#define SB_MAILBOX_adr 0 + +#define SECONDARY_CPUS_STOPPED diff --git a/qemu/roms/SLOF/board-qemu/llfw/Cboot.S b/qemu/roms/SLOF/board-qemu/llfw/Cboot.S new file mode 100644 index 000000000..d22f3c934 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/Cboot.S @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + .org 0 + + /* Boot Information, hardcoded to ColdReset */ + .quad 1 + /* start address */ + .quad 0x100 diff --git a/qemu/roms/SLOF/board-qemu/llfw/Makefile b/qemu/roms/SLOF/board-qemu/llfw/Makefile new file mode 100644 index 000000000..c83f21e3a --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/Makefile @@ -0,0 +1,59 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include ../../make.rules + +CPPFLAGS = -I$(INCLBRDDIR) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) \ + -I$(LIBCMNDIR)/libc/include +CFLAGS += -fno-builtin $(FLAG) $(CPPFLAGS) -O2 -msoft-float $(MAMBO) +CFLAGS += $(BOOT) $(IOCONF) -Wa,-mregnames $(RELEASE) $(CPUARCHDEF) -Wall +ASFLAGS = $(BOOT) $(IOCONF) $(RELEASE)$(CPUARCHDEF) -Wa,-mregnames +LDFLAGS1 = -nostdlib -e__start -Tstage2.lds -N -Ttext=0x100 + + +STG1OBJ = startup.o version.o boot_abort.o romfs.o io_generic.o board_io.o +STG1OBJ += stage2_head.o stage2.o comlib.o romfs_wrap.o nvramlog.o + +.PHONY: version.S + +all: stage1.bin Cboot.o + +stage1.bin: $(STG1OBJ) $(LIBCMNDIR)/libelf.a $(LIBCMNDIR)/libc.a \ + $(LIBCMNDIR)/libhvcall.a + $(LD) $(LDFLAGS1) -o stage1.elf $^ + $(OBJCOPY) -O binary stage1.elf $@ + +romfs.o: ../../llfw/romfs.S + $(CC) $(CFLAGS) -c ../../llfw/romfs.S + +boot_abort.o: ../../llfw/boot_abort.S + $(CC) $(CFLAGS) -c ../../llfw/boot_abort.S + +nvramlog.o: ../../llfw/nvramlog.S + $(CC) $(CFLAGS) -c ../../llfw/nvramlog.S + +include $(LLFWCMNDIR)/clib/Makefile.inc + +include $(LLFWCMNDIR)/io_generic/Makefile.inc + +romfs_wrap.o: ../../llfw/romfs_wrap.c + $(CC) $(CFLAGS) -c ../../llfw/romfs_wrap.c + +Cboot.o: Cboot.S + $(CC) $(CFLAGS) -c $^ + $(OBJCOPY) -O binary Cboot.o Cboot.bin + +%.o: %.S + $(CC) $(CFLAGS) -c $^ + +clean: + rm -f *.o *.bin *.elf diff --git a/qemu/roms/SLOF/board-qemu/llfw/board_io.S b/qemu/roms/SLOF/board-qemu/llfw/board_io.S new file mode 100644 index 000000000..7d572ab18 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/board_io.S @@ -0,0 +1,46 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <macros.h> +#include <cpu.h> + + .text + +/**************************************************************************** + * prints one character to serial console + * + * Input: + * R3 - character + * + * Returns: - + * + * Modifies Registers: + * R3, R4, R5, R6, R7 + ****************************************************************************/ +ENTRY(io_putchar) + sldi r6,r3,(24+32) + li r3,0x58 + li r4,0 + li r5,1 + .long 0x44000022 + blr + +ENTRY(io_getchar) + mr r10,r3 + li r3,0x54 + li r4,0 + .long 0x44000022 + mr. r3,r4 + beq 1f + srdi r3,r5,(24+32) + stb r3,0(r10) +1: blr diff --git a/qemu/roms/SLOF/board-qemu/llfw/stage2.c b/qemu/roms/SLOF/board-qemu/llfw/stage2.c new file mode 100644 index 000000000..ef6ea355a --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/stage2.c @@ -0,0 +1,205 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <xvect.h> +#include <hw.h> +#include <stdio.h> +#include <romfs.h> +#include "memmap.h" +#include "stage2.h" +#include <termctrl.h> +#include "product.h" +#include "calculatecrc.h" +#include <cpu.h> +#include <libelf.h> +#include <string.h> +#include "../lib/libhvcall/libhvcall.h" + +#define DEBUG(fmt...) +//#define DEBUG(fmt...) printf(fmt) + +uint64_t gVecNum; + +uint64_t exception_stack_frame; + +typedef void (*pInterruptFunc_t) (void); + +pInterruptFunc_t vectorTable[0x2E << 1]; + +extern void proceedInterrupt(void); + +/* Prototypes for functions of this file */ +void c_interrupt(uint64_t vecNum); +void set_exceptionVector(int num, void *func); +void early_c_entry(uint64_t start_addr, uint64_t fdt_addr); + + +static void exception_forward(void) +{ + uint64_t val; + + if (*(uint64_t *) XVECT_M_HANDLER) { + proceedInterrupt(); + } + + printf("\r\n exception %llx ", gVecNum); + asm volatile ("mfsrr0 %0":"=r" (val):); + printf("\r\nSRR0 = %08llx%08llx ", val >> 32, val); + asm volatile ("mfsrr1 %0":"=r" (val):); + printf(" SRR1 = %08llx%08llx ", val >> 32, val); + + asm volatile ("mfsprg %0,2":"=r" (val):); + printf("\r\nSPRG2 = %08llx%08llx ", val >> 32, val); + asm volatile ("mfsprg %0,3":"=r" (val):); + printf(" SPRG3 = %08llx%08llx \r\n", val >> 32, val); + while (1); +} + +void c_interrupt(uint64_t vecNum) +{ + gVecNum = vecNum; + if (vectorTable[vecNum >> 7]) { + vectorTable[vecNum >> 7] (); + } else { + exception_forward(); + } +} + +void set_exceptionVector(int num, void *func) +{ + vectorTable[num >> 7] = (pInterruptFunc_t) func; +} + +static void load_file(uint64_t destAddr, char *name, uint64_t maxSize, + uint64_t romfs_base) +{ + uint64_t cnt; + struct romfs_lookup_t fileInfo; + int rc; + + rc = c_romfs_lookup(name, romfs_base, &fileInfo); + if (rc) { + printf("Cannot find romfs file %s\n", name); + return; + } + DEBUG("Found romfs file %s\n", name); + if (maxSize) { + cnt = maxSize; + } else { + cnt = fileInfo.size_data; + } + memcpy((void *)destAddr, (void *)fileInfo.addr_data, cnt); + flush_cache((void *) destAddr, fileInfo.size_data); +} + +extern void print_version(void); + +/*************************************************************************** + * Function: early_c_entry + * Input : start_addr + * + * Description: + **************************************************************************/ +void early_c_entry(uint64_t start_addr, uint64_t fdt_addr) +{ + struct romfs_lookup_t fileInfo; + void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); + uint64_t *boot_info; + uint64_t romfs_base, paflof_base; + // romfs header values + // struct stH *header = (struct stH *) (start_addr + 0x28); + // uint64_t flashlen = header->flashlen; + unsigned long ofw_addr[2]; + int rc; + extern char __executable_start; + extern char __etext; + + /* + * If we run on a broken environment, we need to patch our own sc 1 + * calls to be able to trap hypercalls. This does not cover RTAS or + * any payload we will load yet. + */ + if (patch_broken_sc1(&__executable_start, &__etext, NULL)) { + /* We are running in PR KVM on top of pHyp. Print all output + we missed to print so far again to fake identical behavior */ + printf("\n\r\nSLOF"); + print_version(); + } + + if (fdt_addr == 0) { + puts("ERROR: Flatten device tree not available!"); + } + + /* Hack: Determine base for "ROM filesystem" in memory... + * QEMU loads the FDT at the top of the available RAM, so we place + * the ROMFS just underneath. */ + romfs_base = (fdt_addr - 0x410000) & ~0xffffLL; + memcpy((char *)romfs_base, 0, 0x400000); + + exception_stack_frame = 0; + + printf(" Press \"s\" to enter Open Firmware.\r\n\r\n"); + + DEBUG(" [c_romfs_lookup at %p]\n", c_romfs_lookup); + rc = c_romfs_lookup("bootinfo", romfs_base, &fileInfo); + if (rc) + printf(" !!! roomfs lookup(bootinfo) = %d\n", rc); + boot_info = (uint64_t *) fileInfo.addr_data; + boot_info[1] = start_addr; + load_file(0x100, "xvect", 0, romfs_base); + rc = c_romfs_lookup("ofw_main", romfs_base, &fileInfo); + if (rc) + printf(" !!! roomfs lookup(bootinfo) = %d\n", rc); + + DEBUG(" [ofw_main addr hdr 0x%lx]\n", fileInfo.addr_header); + DEBUG(" [ofw_main addr data 0x%lx]\n", fileInfo.addr_data); + DEBUG(" [ofw_main size data 0x%lx]\n", fileInfo.size_data); + DEBUG(" [ofw_main flags 0x%lx]\n", fileInfo.flags); + DEBUG(" [hdr: 0x%08lx 0x%08lx]\n [ 0x%08lx 0x%08lx]\n", + ((uint64_t *)fileInfo.addr_header)[0], + ((uint64_t *)fileInfo.addr_header)[1], + ((uint64_t *)fileInfo.addr_header)[2], + ((uint64_t *)fileInfo.addr_header)[3]); + + /* Assume that paflof and SNK need ca. 31 MiB RAM right now. + * TODO: Use value from ELF file instead */ + paflof_base = romfs_base - 0x1F00000 + 0x100; + if ((int64_t)paflof_base <= 0LL) { + puts("ERROR: Not enough memory for Open Firmware"); + } + rc = elf_load_file_to_addr((void *)fileInfo.addr_data, (void*)paflof_base, + ofw_addr, NULL, flush_cache); + DEBUG(" [load_elf_file returned %d]\n", rc); + + ofw_start = + (void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t)) + &ofw_addr; + // re-enable the cursor + printf("%s%s", TERM_CTRL_RESET, TERM_CTRL_CRSON); + DEBUG(" [ofw_start=%p ofw_addr=0x%lx]\n", ofw_start, ofw_addr[0]); + ofw_addr[1] = ofw_addr[0]; + /* Call the Open Firmware layer with ePAPR-style calling conventions: + * r3 = R3 Effective address of the device tree image. Note: this + * address must be 8-byte aligned in memory. + * r4 = implementation dependent, we use it for ROMFS base address + * r5 = 0 + * r6 = 0x65504150 -- ePAPR magic value-to distinguish from + * non-ePAPR-compliant firmware + * r7 = size of Initially Mapped Area + * (right now we assume everything from 0 to the FDT is the IMA) + */ + asm volatile("isync; sync;" : : : "memory"); + ofw_start(fdt_addr, romfs_base, 0, 0x65504150, fdt_addr); + asm volatile("isync; sync;" : : : "memory"); + // never return +} diff --git a/qemu/roms/SLOF/board-qemu/llfw/stage2.h b/qemu/roms/SLOF/board-qemu/llfw/stage2.h new file mode 100644 index 000000000..9ce3c8203 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/stage2.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __STAGE2_H +#define __STAGE2_H + +#ifndef __ASSEMBLER__ + +#include <stddef.h> + +void u4memInit(void); + +#endif /* __ASSEMBLER__ */ +#endif /* __STAGE2_H */ diff --git a/qemu/roms/SLOF/board-qemu/llfw/stage2.lds b/qemu/roms/SLOF/board-qemu/llfw/stage2.lds new file mode 100644 index 000000000..e060dd189 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/stage2.lds @@ -0,0 +1,59 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) + +/* set the entry point */ +ENTRY ( __start ) + +SECTIONS { + __executable_start = .; + + .text : { + *(.text) + } + + __etext = .; + + . = ALIGN(8); + + .data : { + *(.data) + *(.rodata .rodata.*) + *(.got1) + *(.sdata) + *(.opd) + } + + /* FIXME bss at end ??? */ + + . = ALIGN(8); + __bss_start = .; + .bss : { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + } + + . = ALIGN(8); + __bss_end = .; + __bss_size = (__bss_end - __bss_start); + + __toc_start = .; + .got : + { + *(.toc .got) + } + . = ALIGN(8); + __toc_end = .; +} diff --git a/qemu/roms/SLOF/board-qemu/llfw/stage2_head.S b/qemu/roms/SLOF/board-qemu/llfw/stage2_head.S new file mode 100644 index 000000000..c56b117ce --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/stage2_head.S @@ -0,0 +1,95 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "macros.h" +#include "../../llfw/boot_abort.h" + +/*#################### defines #####################*/ +#define STACK_SIZE 0x4000 + +/*#################### code ########################*/ + .text + .globl .gluon_c_entry + .globl __toc_start + .globl __toc_end + .globl __bss_start + .globl __bss_size + .globl __start + +ASM_ENTRY(__startC) + /* clear out bss section */ + LOAD64(r3, (__bss_start - 8)) + LOAD64(r4, __bss_size) + + /* divide __bss_size by 8 to get number */ + /* of dwords to clear */ + srwi. r4, r4, 3 + beq bsscdone + li r5, 0 + mtctr r4 +bssc: stdu r5, 8(r3) + bdnz bssc +bsscdone: + /* setup stack */ + LOAD64(r1, __stack_end + STACK_SIZE) + + /* save return address beside stack */ + addi r3, r1, 128 + mflr r0 + std r0, 0(r3) + + /* setup toc */ + bl toc_init + + /* ------------------------------------ */ + /* jump to c-code */ + /* r31 = fdt - r5 */ + /* ------------------------------------ */ + li r3, r0 + mr r4, r31 + bl .early_c_entry + + /* return to caller... */ + LOAD64(r1, __stack_end + STACK_SIZE) + addi r1, r1, 128 + ld r3, 0(r1) + mtlr r3 + blr + + /* #################################### */ + /* Basic Additional Functions */ + /* for extended lib functions see */ + /* external library */ + /* #################################### */ + .align 2 + + /* ------------------------------------ */ + /* updates toc in r2 */ + /* ------------------------------------ */ +ASM_ENTRY(toc_init) + LOAD64(r2, __toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + blr + + /* ------------------------------------ */ + /* stores arg#1 in r27 and stops */ + /* ------------------------------------ */ +ENTRY(do_panic) +ENTRY(halt_sys) + BOOT_ABORT_R3HINT(ABORT_CANIO, ALTBOOT, msg_e_ierror); + + .section ".bss" + .balign STACK_SIZE +__stack_end: + .space STACK_SIZE + .text diff --git a/qemu/roms/SLOF/board-qemu/llfw/startup.S b/qemu/roms/SLOF/board-qemu/llfw/startup.S new file mode 100644 index 000000000..bbd3ce3ac --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/startup.S @@ -0,0 +1,240 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* SLOF for QEMU -- boot code. + * Initial entry point + */ + +#include <xvect.h> +#include <cpu.h> +#include <macros.h> + + /* qemu entry: + * + * __start loaded at 0x100 + * + * CPU 0 starts at 0 with GPR3 pointing to the flat devtree + * + * All other CPUs are held in stopped state by qemu and are + * started via RTAS + */ + .text + .globl __start +__start: + b _start + .long 0xDEADBEE0 + .long 0x0 /* size */ + .long 0x0 /* crc */ + .long relTag - __start + + /* Some exception vectors + * + * FIXME: Also need 0280, 0380, 0f20, etc. + */ + + .irp i, 0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,0x0400,0x0500, \ + 0x0600,0x0700,0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00, \ + 0x0e00,0x0f00,0x1000,0x1100,0x1200,0x1300,0x1400,0x1500, \ + 0x1600,0x1700, \ + 0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \ + 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \ + 0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00 + . = \i + + /* enable this if you get exceptions before the console works */ + /* this will allow using the hardware debugger to see where */ + /* it traps, and with what register values etc. */ + // b $ + + mtsprg 0,r0 + mfctr r0 + mtsprg 2,r0 + mflr r0 +// 10 + mtsprg 3,r0 + ld r0, (\i + 0x60)(0) + mtctr r0 + li r0, \i + 0x100 +// 20 + bctr + + . = \i + 0x60 + .quad intHandler2C + .endr + + . = XVECT_M_HANDLER - 0x100 + .quad 0x00 + .text + + /* Here's the startup code for the master CPU */ + .org 0x4000 - 0x100 +_start: + /* Save device-tree pointer */ + mr r31,r3 + + /* Switch to 64-bit mode with 64-bit exceptions */ +#define MSR_SF_LG 63 /* Enable 64 bit mode */ +#define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */ +#define __MASK(X) (1<<(X)) +#define MSR_SF __MASK(MSR_SF_LG) /* Enable 64 bit mode */ +#define MSR_ISF __MASK(MSR_ISF_LG) /* Interrupt 64b mode */ + mfmsr r11 /* grab the current MSR */ + li r12,(MSR_SF | MSR_ISF)@highest + sldi r12,r12,48 + or r11,r11,r12 + mtmsrd r11 + isync + + /* Early greet */ + li r3,10 + bl putc + li r3,13 + bl putc + li r3,10 + bl putc + li r3,'S' + bl putc + + li r3,'L' + bl putc + li r3,'O' + bl putc + li r3,'F' + bl putc + + bl print_version + + /* go! */ + li r3,__startC@l + mtctr r3 + bctrl + + /* write a character to the HV console */ +putc: sldi r6,r3,(24+32) + li r3,0x58 + li r4,0 + li r5,1 + .long 0x44000022 + blr + +relTag: + .ascii RELEASE + .ascii "\0" + .align 2 + +C_ENTRY(proceedInterrupt) + + ld r3,exception_stack_frame@got(r2) + ld r1,0(r3) + + .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \ + 27, 28, 29, 30, 31 + ld r\i, 0x30+\i*8 (r1) + .endr + + ld r14,0x138(r1); + mtsrr0 r14 + + ld r14,0x140(r1); + mtsrr1 r14 + + ld r14,0x148(r1); + mtcr r14 + + ld 0,XVECT_M_HANDLER(0) + mtctr 0 + + ld r0,0x30(r1); # restore vector number + ld r1,0x38(r1); + + bctr + +intHandler2C: + mtctr r1 # save old stack pointer + lis r1,0x4 + stdu r1, -0x160(r1) + .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \ + 27, 28, 29, 30, 31 + std r\i, 0x30+\i*8 (r1) + .endr + + std r0,0x30(r1); # save vector number + + mfctr r14 + std r14,0x38(r1); # save old r1 + + mfsrr0 r14 + std r14,0x138(r1); + + mfsrr1 r14 + std r14,0x140(r1); + + mfcr r14 + std r14,0x148(r1); + + mfxer r14 + std r14,0x150(r1); + + bl toc_init + + ld r3,exception_stack_frame@got(r2) + std r1,0(r3) + + + mr r3,r0 + bl .c_interrupt + + ld r14,0x138(r1); + mtsrr0 r14 + + ld r14,0x140(r1); + mtsrr1 r14 + + ld r14,0x148(r1); + mtcr r14 + + ld r14,0x150(r1); + mtxer r14 + + + .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \ + 27, 28, 29, 30, 31 + ld r\i, 0x30+\i*8 (r1) + .endr + + ld r1,0x38(r1); + + mfsprg r0,2 + mtctr r0 + mfsprg r0,3 + mtlr r0 + mfsprg r0,0 + rfid + +/* Set exception handler for given exception vector. + r3: exception vector offset + r4: exception handler +*/ + .globl .set_exception +.set_exception: + .globl set_exception +set_exception: + ld r4,0x0(r4) + .globl .set_exception_asm +.set_exception_asm: + .globl set_exception_asm +set_exception_asm: + std r4, 0x60(r3) # fixme diff 1f - 0b + blr diff --git a/qemu/roms/SLOF/board-qemu/llfw/version.S b/qemu/roms/SLOF/board-qemu/llfw/version.S new file mode 100644 index 000000000..f0a778abe --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/llfw/version.S @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) 2010, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * Print version information + * This code is in a separate file so that it can be easily compiled during + * each new build (for refreshing the build date). + */ + +#include "termctrl.h" +#include <product.h> + +.global print_version +print_version: + mflr r4 + bl 0f + .ascii TERM_CTRL_RESET + .ascii TERM_CTRL_CRSOFF + .ascii " **********************************************************************" + .ascii "\r\n" + .ascii TERM_CTRL_BRIGHT + .ascii PRODUCT_NAME + .ascii " Starting\r\n" + .ascii TERM_CTRL_RESET + .ascii " Build Date = ", __DATE__, " ", __TIME__ + .ascii "\r\n" + .ascii " FW Version = " , RELEASE + .ascii "\r\n\0" + .align 2 +0: + mflr r3 + mtlr r4 + b io_print diff --git a/qemu/roms/SLOF/board-qemu/romfs/boot_rom.ffs b/qemu/roms/SLOF/board-qemu/romfs/boot_rom.ffs new file mode 100644 index 000000000..3cdb7d348 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/romfs/boot_rom.ffs @@ -0,0 +1,20 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +# FFile-Name Real Filename Flags ROM-Offset i/a +#--------------|-------------------------------|-----------------------|-------------- +header romfs/header.img 0 0 +stage1 board-qemu/llfw/stage1.bin 1 0x100 +xvect slof/xvect.bin 0 0 +ofw_main board-qemu/slof/paflof 0 0 +bootinfo board-qemu/llfw/Cboot.bin 0 0 +snk clients/net-snk.client 0 0 diff --git a/qemu/roms/SLOF/board-qemu/slof/.gitignore b/qemu/roms/SLOF/board-qemu/slof/.gitignore new file mode 100644 index 000000000..55268aa6a --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/.gitignore @@ -0,0 +1 @@ +OF.ffs diff --git a/qemu/roms/SLOF/board-qemu/slof/Makefile b/qemu/roms/SLOF/board-qemu/slof/Makefile new file mode 100644 index 000000000..283f77d32 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/Makefile @@ -0,0 +1,126 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +include ../Makefile.dirs + +include $(TOPBRDDIR)/config +include $(TOPCMNDIR)/make.rules + +all: version.o Makefile.dep OF.ffs paflof $(SLOFCMNDIR)/xvect.bin + +CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libhvcall \ + -I$(LIBCMNDIR)/libvirtio -I$(LIBCMNDIR)/libnvram \ + -I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libveth \ + -I$(LIBCMNDIR)/libe1k +SLOF_LIBS = \ + $(LIBCMNDIR)/libbootmsg.a \ + $(LIBCMNDIR)/libelf.a \ + $(LIBCMNDIR)/libhvcall.a \ + $(LIBCMNDIR)/libvirtio.a \ + $(LIBCMNDIR)/libusb.a \ + $(LIBCMNDIR)/libnvram.a \ + $(LIBCMNDIR)/libveth.a \ + $(LIBCMNDIR)/libe1k.a +BOARD_SLOF_IN = \ + $(LIBCMNDIR)/libhvcall/hvcall.in \ + $(LIBCMNDIR)/libvirtio/virtio.in \ + $(LIBCMNDIR)/libusb/usb.in \ + $(LIBCMNDIR)/libbootmsg/bootmsg.in \ + $(LIBCMNDIR)/libelf/libelf.in \ + $(LIBCMNDIR)/libnvram/libnvram.in \ + $(LIBCMNDIR)/libbases/libbases.in \ + $(LIBCMNDIR)/libveth/veth.in \ + $(LIBCMNDIR)/libe1k/e1k.in +BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code) + +include $(SLOFCMNDIR)/Makefile.inc + +AS1FLAGS = $(CPPFLAGS) $(RELEASE) $(FLAG) $(CPUARCHDEF) -Wa,-mregnames + +%.o: %.S + $(CC) $(AS1FLAGS) -o $@ -c $^ + +FPPINCLUDES = -I. -I$(SLOFCMNDIR)/fs -I$(SLOFCMNDIR) + +USB_FFS_FILES = \ + $(SLOFCMNDIR)/fs/devices/pci-class_02.fs \ + $(SLOFCMNDIR)/fs/devices/pci-class_0c.fs \ + $(SLOFCMNDIR)/fs/usb/dev-hci.fs \ + $(SLOFCMNDIR)/fs/usb/slofdev.fs \ + $(SLOFCMNDIR)/fs/usb/dev-parent-calls.fs \ + $(SLOFCMNDIR)/fs/usb/dev-keyb.fs \ + $(SLOFCMNDIR)/fs/usb/dev-mouse.fs \ + $(SLOFCMNDIR)/fs/usb/dev-storage.fs \ + $(SLOFCMNDIR)/fs/usb/dev-hub.fs + + +VIO_FFS_FILES = \ + $(SLOFBRDDIR)/pci-device_1af4_1000.fs \ + $(SLOFBRDDIR)/pci-device_1af4_1001.fs \ + $(SLOFBRDDIR)/pci-device_1af4_1004.fs \ + $(SLOFBRDDIR)/pci-device_1af4_1009.fs \ + $(SLOFBRDDIR)/vio-hvterm.fs \ + $(SLOFBRDDIR)/vio-vscsi.fs \ + $(SLOFBRDDIR)/vio-veth.fs \ + $(SLOFBRDDIR)/rtas-nvram.fs \ + $(SLOFBRDDIR)/virtio-net.fs \ + $(SLOFBRDDIR)/virtio-block.fs \ + $(SLOFBRDDIR)/virtio-fs.fs \ + $(SLOFBRDDIR)/dev-null.fs \ + $(SLOFBRDDIR)/virtio-scsi.fs + +# Files that should go into the ROM fs (and so have to be listed in OF.ffs): +OF_FFS_FILES = \ + $(SLOFCMNDIR)/fs/ide.fs \ + $(SLOFCMNDIR)/fs/fbuffer.fs \ + $(SLOFCMNDIR)/fs/graphics.fs \ + $(SLOFCMNDIR)/fs/generic-disk.fs \ + $(SLOFCMNDIR)/fs/dma-function.fs \ + $(SLOFCMNDIR)/fs/pci-device.fs \ + $(SLOFCMNDIR)/fs/pci-bridge.fs \ + $(SLOFCMNDIR)/fs/pci-properties.fs \ + $(SLOFCMNDIR)/fs/pci-config-bridge.fs \ + $(SLOFCMNDIR)/fs/update_flash.fs \ + $(SLOFCMNDIR)/fs/xmodem.fs \ + $(SLOFCMNDIR)/fs/scsi-disk.fs \ + $(SLOFCMNDIR)/fs/scsi-host-helpers.fs \ + $(SLOFCMNDIR)/fs/scsi-probe-helpers.fs \ + $(SLOFCMNDIR)/fs/scsi-support.fs \ + $(SLOFBRDDIR)/default-font.bin \ + $(SLOFBRDDIR)/pci-phb.fs \ + $(SLOFBRDDIR)/rtas.fs \ + $(SLOFBRDDIR)/pci-device_1234_1111.fs \ + $(SLOFBRDDIR)/pci-device_1013_00b8.fs \ + $(SLOFBRDDIR)/pci-device_8086_100e.fs \ + $(SLOFBRDDIR)/e1k.fs \ + $(FCODE_FFS_FILES) + +# Uncomment the following line to enable the USB code: +OF_FFS_FILES += $(USB_FFS_FILES) + +OF_FFS_FILES += $(VIO_FFS_FILES) + +OF_FFS_FILES := $(OF_FFS_FILES:%.fs=%.fsi) + +OF.ffs: Makefile $(SLOFCMNDIR)/Makefile.inc $(OF_FFS_FILES) + $(MAKE) create_OF_ffs + +# Rules for cleaning up: +.PHONY: clean_here clean distclean + +clean_here: + rm -f *.o OF.fsi OF.ffs + +clean: clean_here clean_slof + +distclean: clean_here distclean_slof diff --git a/qemu/roms/SLOF/board-qemu/slof/OF.fs b/qemu/roms/SLOF/board-qemu/slof/OF.fs new file mode 100644 index 000000000..561d89225 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/OF.fs @@ -0,0 +1,306 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ The master file. Everything else is included into here. + +hex + +' ll-cr to cr + +#include "header.fs" + +#include "hvterm.fs" + +#include "base.fs" + +\ Set default load-base to 0x4000 +4000 to default-load-base + +\ Little-endian accesses. Also known as `wrong-endian'. +#include <little-endian.fs> + +: #join ( lo hi #bits -- x ) lshift or ; +: #split ( x #bits -- lo hi ) 2dup rshift dup >r swap lshift xor r> ; + +: blink ; +: reset-dual-emit ; +: console-clean-fifo ; +: bootmsg-nvupdate ; +: asm-cout 2drop drop ; + +#include "logging.fs" + +: log-string 2drop ; + +#include "bootmsg.fs" + +000 cp + +#include "exception.fs" + +: mm-log-warning 2drop ; + +: write-mm-log ( data length type -- status ) + 3drop 0 +; + +100 cp + +\ Input line editing. +#include "accept.fs" + +120 cp + +#include "dump.fs" + +cistack ciregs >r1 ! \ kernel wants a stack :-) + +140 cp + +#include "romfs.fs" + +200 cp + +#include <slof-logo.fs> + +201 cp + +#include <banner.fs> + +: .banner .slof-logo .banner ; + +220 cp + +DEFER find-boot-sector ( -- ) + +240 cp +\ Timebase frequency, in Hz. Start with a good default +\ Use device-tree later to fix it up +d# 512000000 VALUE tb-frequency \ default value - needed for "ms" to work +-1 VALUE cpu-frequency + +#include "helper.fs" +260 cp + +#include <timebase.fs> + +270 cp + +#include <fcode/evaluator.fs> + +2e0 cp + +#include <quiesce.fs> + +300 cp + +#include <usb/usb-static.fs> + +320 cp + +#include <scsi-loader.fs> + +340 cp + +#include "fdt.fs" + +360 cp + +#include <root.fs> + +370 cp + +: check-boot-menu + s" qemu,boot-menu" get-chosen IF + decode-int 1 = IF + ." Press F12 for boot menu." cr cr + THEN + 2drop + THEN +; +check-boot-menu + +380 cp + +\ Grab rtas from qemu +#include "rtas.fs" + +390 cp + +#include "virtio.fs" + +3f0 cp + +#include "tree.fs" + +800 cp + +#include "nvram.fs" + +880 cp + +#include "envvar.fs" +check-for-nvramrc + +890 cp + +#include "qemu-bootlist.fs" + +8a0 cp + +\ The client interface. +#include "client.fs" +\ ELF binary file format. +#include "elf.fs" +#include <loaders.fs> + +8a8 cp +CREATE version-str 10 ALLOT +0 value temp-ptr + +: dump-display-buffer + disp-ptr to temp-ptr + " SLOF **********************************************************************" terminal-write drop + cr + version-str get-print-version + version-str @ \ start + version-str 8 + @ \ end + over - terminal-write drop + " Press 's' to enter Open Firmware." terminal-write drop + cr cr + temp-ptr disp-size > IF + temp-ptr disp-size MOD + dup + prevga-disp-buf + swap disp-size swap - terminal-write drop + temp-ptr disp-size MOD + prevga-disp-buf swap 1 - terminal-write drop + ELSE + prevga-disp-buf temp-ptr terminal-write drop + THEN +; + +: enable-framebuffer-output ( -- ) +\ enable output on framebuffer + s" screen" find-alias ?dup IF + \ we need to open/close the screen device once + \ before "ticking" display-emit to emit + open-dev close-node + false to store-prevga? + s" display-emit" $find IF + to emit + dump-display-buffer + ELSE + 2drop + THEN + THEN +; + +enable-framebuffer-output + +8b0 cp + +\ Scan USB devices +usb-scan + +8c0 cp + +\ Claim remaining memory that is used by firmware: +romfs-base 400000 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop + +8d0 cp + +: set-default-console + s" linux,stdout-path" get-chosen IF + decode-string + ." Using default console: " 2dup type cr + io + 2drop + ELSE + ." No console specified " + " screen" find-alias dup IF nip THEN + " keyboard" find-alias dup IF nip THEN + AND IF + ." using screen & keyboard" cr + " screen" output + " keyboard" input + ELSE + " hvterm" find-alias IF + drop + ." using hvterm" cr + " hvterm" io + ELSE + " /openprom" find-node ?dup IF + set-node + ." and no default found, creating dev-null" cr + " dev-null.fs" included + " devnull-console" io + 0 set-node + THEN + THEN + THEN + THEN +; +set-default-console + +8e0 cp + +\ Check if we are booting a kernel passed by qemu, in which case +\ we skip initializing some devices + +0 VALUE direct-ram-boot-base +0 VALUE direct-ram-boot-size + +: (boot-ram) + direct-ram-boot-size 0<> IF + ." Booting from memory..." cr + s" go-args 2@ " evaluate + direct-ram-boot-base 0 + s" true state-valid ! " evaluate + s" disable-watchdog go-64" evaluate + THEN +; + +8e8 cp + +: check-boot-from-ram + s" qemu,boot-kernel" get-chosen IF + decode-int -rot decode-int -rot ( n1 n2 p s ) + decode-int -rot decode-int -rot ( n1 n2 n3 n4 p s ) + 2drop + swap 20 << or to direct-ram-boot-size + swap 20 << or to direct-ram-boot-base + ." Detected RAM kernel at " direct-ram-boot-base . + ." (" direct-ram-boot-size . ." bytes) " + \ Override the boot-command word without touching the + \ nvram environment + s" boot-command" $create " (boot-ram)" env-string + THEN +; +check-boot-from-ram + +8ff cp + +#include <start-up.fs> + +." " \ Clear last checkpoint + +#include <boot.fs> + +cr .( Welcome to Open Firmware) +cr +#include "copyright-oss.fs" +cr cr + +\ this CATCH is to ensure the code bellow always executes: boot may ABORT! +' start-it CATCH drop + +cr ." Ready!" diff --git a/qemu/roms/SLOF/board-qemu/slof/copyright-oss.fs b/qemu/roms/SLOF/board-qemu/slof/copyright-oss.fs new file mode 100644 index 000000000..e45b19403 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/copyright-oss.fs @@ -0,0 +1,16 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +cr .( Copyright (c) char ) emit .( 2004, 2011 IBM Corporation All rights reserved.) +cr .( This program and the accompanying materials are made available) +cr .( under the terms of the BSD License available at) +cr .( http://www.opensource.org/licenses/bsd-license.php) diff --git a/qemu/roms/SLOF/board-qemu/slof/dev-null.fs b/qemu/roms/SLOF/board-qemu/slof/dev-null.fs new file mode 100644 index 000000000..d0ffad6b9 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/dev-null.fs @@ -0,0 +1,35 @@ +\ Introduce a dummy console that will eat away all chars and make all +\ the components dependent on stdout happy. + +new-device +" devnull-console" device-name + +: open true ; +: close ; + +: write ( adr len -- actual ) + nip +; + +: read ( adr len -- actual ) + nip +; + +: setup-alias + " devnull-console" find-alias 0= IF + " devnull-console" get-node node>path set-alias + ELSE + drop + THEN +; + +: dummy-term-emit drop ; +: dummy-term-key 0 ; +: dummy-term-key? FALSE ; + +' dummy-term-emit to emit +' dummy-term-key to key +' dummy-term-key? to key? + +setup-alias +finish-device diff --git a/qemu/roms/SLOF/board-qemu/slof/e1k.fs b/qemu/roms/SLOF/board-qemu/slof/e1k.fs new file mode 100644 index 000000000..51855be82 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/e1k.fs @@ -0,0 +1,98 @@ +\ ***************************************************************************** +\ * Copyright (c) 2013 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle e1000 device + +s" network" device-type + +INSTANCE VARIABLE obp-tftp-package +get-node CONSTANT my-phandle +10 config-l@ translate-my-address 3 not AND CONSTANT baseaddr + +0 VALUE e1k-priv +0 VALUE open-count + +: open ( -- okay? ) + open-count 0= IF + open IF + baseaddr + e1k-open dup not IF ." e1k-open failed" EXIT THEN + drop TO e1k-priv + true + ELSE + false + THEN + ELSE + true + THEN + my-args s" obp-tftp" $open-package obp-tftp-package ! + open-count 1 + to open-count +; + + +: close ( -- ) + my-phandle set-node + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + e1k-priv e1k-close + close + THEN + THEN + s" close" obp-tftp-package @ $call-method +; + +: read ( buf len -- actual ) + dup IF + e1k-read + ELSE + nip + THEN +; + +: write ( buf len -- actual ) + dup IF + e1k-write + ELSE + nip + THEN +; + +: load ( addr -- len ) + s" load" obp-tftp-package @ $call-method +; + +: ping ( -- ) + s" ping" obp-tftp-package @ $call-method +; + +6 BUFFER: local-mac +: setup-mac ( -- ) + pci-mem-enable + " vendor-id" get-node get-property IF EXIT THEN + decode-int nip nip + " device-id" get-node get-property IF EXIT THEN + decode-int nip nip + baseaddr + local-mac e1k-mac-setup IF + encode-bytes " local-mac-address" property + THEN +; + +setup-mac + +: setup-alias ( -- ) + " net" get-next-alias ?dup IF + get-node node>path set-alias + THEN +; +setup-alias diff --git a/qemu/roms/SLOF/board-qemu/slof/fdt.fs b/qemu/roms/SLOF/board-qemu/slof/fdt.fs new file mode 100644 index 000000000..8d4635f30 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/fdt.fs @@ -0,0 +1,435 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +0 VALUE fdt-debug +TRUE VALUE fdt-cas-fix? + +\ Bail out if no fdt +fdt-start 0 = IF -1 throw THEN + +struct + 4 field >fdth_magic + 4 field >fdth_tsize + 4 field >fdth_struct_off + 4 field >fdth_string_off + 4 field >fdth_rsvmap_off + 4 field >fdth_version + 4 field >fdth_compat_vers + 4 field >fdth_boot_cpu + 4 field >fdth_string_size + 4 field >fdth_struct_size +drop + +h# d00dfeed constant OF_DT_HEADER +h# 1 constant OF_DT_BEGIN_NODE +h# 2 constant OF_DT_END_NODE +h# 3 constant OF_DT_PROP +h# 4 constant OF_DT_NOP +h# 9 constant OF_DT_END + +\ Create some variables early +0 value fdt-start-addr +0 value fdt-struct +0 value fdt-strings + +: fdt-init ( fdt-start -- ) + dup to fdt-start-addr + dup dup >fdth_struct_off l@ + to fdt-struct + dup dup >fdth_string_off l@ + to fdt-strings + drop +; +fdt-start fdt-init + +\ Dump fdt header for all to see and check FDT validity +: fdt-check-header ( -- ) + fdt-start-addr dup 0 = IF + ." No flat device tree !" cr drop -1 throw EXIT THEN + hex + fdt-debug IF + ." Flat device tree header at 0x" dup . s" :" type cr + ." magic : 0x" dup >fdth_magic l@ . cr + ." total size : 0x" dup >fdth_tsize l@ . cr + ." offset to struct : 0x" dup >fdth_struct_off l@ . cr + ." offset to strings: 0x" dup >fdth_string_off l@ . cr + ." offset to rsvmap : 0x" dup >fdth_rsvmap_off l@ . cr + ." version : " dup >fdth_version l@ decimal . hex cr + ." last compat vers : " dup >fdth_compat_vers l@ decimal . hex cr + dup >fdth_version l@ 2 >= IF + ." boot CPU : 0x" dup >fdth_boot_cpu l@ . cr + THEN + dup >fdth_version l@ 3 >= IF + ." strings size : 0x" dup >fdth_string_size l@ . cr + THEN + dup >fdth_version l@ 17 >= IF + ." struct size : 0x" dup >fdth_struct_size l@ . cr + THEN + THEN + dup >fdth_magic l@ OF_DT_HEADER <> IF + ." Flat device tree has incorrect magic value !" cr + drop -1 throw EXIT + THEN + dup >fdth_version l@ 10 < IF + ." Flat device tree has usupported version !" cr + drop -1 throw EXIT + THEN + + drop +; +fdt-check-header + +\ Fetch next tag, skip nops and increment address +: fdt-next-tag ( addr -- nextaddr tag ) + 0 ( dummy tag on stack for loop ) + BEGIN + drop ( drop previous tag ) + dup l@ ( read new tag ) + swap 4 + swap ( increment addr ) + dup OF_DT_NOP <> UNTIL ( loop until not nop ) +; + +\ Parse unit name and advance addr +: fdt-fetch-unit ( addr -- addr $name ) + dup from-cstring \ get string size + 2dup + 1 + 3 + fffffffc and -rot +; + +\ Update unit with information from the reg property... +\ ... this is required for the PCI nodes for example. +: fdt-reg-unit ( prop-addr prop-len -- ) + decode-phys ( prop-addr' prop-len' phys.lo ... phys.hi ) + set-unit ( prop-addr' prop-len' ) + 2drop +; + +\ Lookup a string by index +: fdt-fetch-string ( index -- str-addr str-len ) + fdt-strings + dup from-cstring +; + +: fdt-create-dec s" decode-unit" $CREATE , DOES> @ hex64-decode-unit ; +: fdt-create-enc s" encode-unit" $CREATE , DOES> @ hex64-encode-unit ; + +\ Check whether array contains an zero-terminated ASCII string: +: fdt-prop-is-string? ( addr len -- string? ) + dup 1 < IF 2drop FALSE EXIT THEN \ Check for valid length + 1- + 2dup + c@ 0<> IF 2drop FALSE EXIT THEN \ Check zero-termination + test-string +; + +\ Encode fdt property to OF property +: fdt-encode-prop ( addr len -- ) + 2dup fdt-prop-is-string? IF + 1- encode-string + ELSE + encode-bytes + THEN +; + +\ Method to unflatten a node +: fdt-unflatten-node ( start -- end ) + \ this can and will recurse + recursive + + \ Get & check first tag of node ( addr -- addr) + fdt-next-tag dup OF_DT_BEGIN_NODE <> IF + s" Weird tag 0x" type . " at start of node" type cr + -1 throw + THEN drop + + new-device + + \ Parse name, split unit address + fdt-fetch-unit + dup 0 = IF drop drop " /" THEN + 40 left-parse-string + \ Set name + device-name + + \ Set preliminary unit address - might get overwritten by reg property + dup IF + " #address-cells" get-parent get-package-property IF + 2drop + ELSE + decode-int nip nip + hex-decode-unit + set-unit + THEN + ELSE 2drop THEN + + \ Iterate sub tags + BEGIN + fdt-next-tag dup OF_DT_END_NODE <> + WHILE + dup OF_DT_PROP = IF + \ Found property + drop dup ( drop tag, dup addr : a1 a1 ) + dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2) + dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 ) + rot ( we now have: a1 s i a3 s ) + fdt-encode-prop rot ( a1 s pa ps i) + fdt-fetch-string ( a1 s pa ps na ns ) + 2dup s" reg" str= IF + 2swap 2dup fdt-reg-unit 2swap + THEN + property + + 8 + 3 + fffffffc and + ELSE dup OF_DT_BEGIN_NODE = IF + drop ( drop tag ) + 4 - + fdt-unflatten-node + ELSE + drop -1 throw + THEN THEN + REPEAT drop \ drop tag + + \ Create encode/decode unit + " #address-cells" get-node get-package-property IF ELSE + decode-int dup fdt-create-dec fdt-create-enc 2drop + THEN + + finish-device +; + +\ Start unflattening +: fdt-unflatten-tree + fdt-debug IF + ." Unflattening device tree..." cr THEN + fdt-struct fdt-unflatten-node drop + fdt-debug IF + ." Done !" cr THEN +; +fdt-unflatten-tree + +\ Find memory size +: fdt-parse-memory + \ XXX FIXME Handle more than one memory node, and deal + \ with RMA vs. full access + " /memory@0" find-device + " reg" get-node get-package-property IF throw -1 THEN + + \ XXX FIXME Assume one entry only in "reg" property for now + decode-phys 2drop decode-phys + my-#address-cells 1 > IF 20 << or THEN + + fdt-debug IF + dup ." Memory size: " . cr + THEN + \ claim.fs already released the memory between 0 and MIN-RAM-SIZE, + \ so we've got only to release the remaining memory now: + MIN-RAM-SIZE swap MIN-RAM-SIZE - release + 2drop device-end +; +fdt-parse-memory + + +\ Claim fdt memory and reserve map +: fdt-claim-reserve + fdt-start-addr + dup dup >fdth_tsize l@ 0 claim drop + dup >fdth_rsvmap_off l@ + + BEGIN + dup dup x@ swap 8 + x@ + dup 0 <> + WHILE + fdt-debug IF + 2dup swap ." Reserve map entry: " . ." : " . cr + THEN + 0 claim drop + 10 + + REPEAT drop drop drop +; +fdt-claim-reserve + + +\ The following functions are use to replace the FDT phandle and +\ linux,phandle properties with our own OF1275 phandles... + +\ This is used to check whether we successfully replaced a phandle value +0 VALUE (fdt-phandle-replaced) + +\ Replace phandle value in "interrupt-map" property +: fdt-replace-interrupt-map ( old new prop-addr prop-len -- old new ) + BEGIN + dup ( old new prop-addr prop-len prop-len ) + WHILE + \ This is a little bit ugly ... we're accessing the property at + \ hard-coded offsets instead of analyzing it completely... + swap dup 10 + ( old new prop-len prop-addr prop-addr+10 ) + dup l@ 5 pick = IF + \ it matches the old phandle value! + 3 pick swap l! + TRUE TO (fdt-phandle-replaced) + ELSE + drop + THEN + ( old new prop-len prop-addr ) + 1c + swap 1c - + ( old new new-prop-addr new-prop-len ) + REPEAT + 2drop +; + +\ Replace one FDT phandle "old" with a OF1275 phandle "new" in the +\ whole tree: +: fdt-replace-all-phandles ( old new node -- ) + \ ." Replacing in " dup node>path type cr + >r + s" interrupt-map" r@ get-property 0= IF + ( old new prop-addr prop-len R: node ) + fdt-replace-interrupt-map + THEN + s" interrupt-parent" r@ get-property 0= IF + ( old new prop-addr prop-len R: node ) + decode-int -rot 2drop ( old new val R: node ) + 2 pick = IF ( old new R: node ) + dup encode-int s" interrupt-parent" r@ set-property + TRUE TO (fdt-phandle-replaced) + THEN + THEN + \ ... add more properties that have to be fixed here ... + r> + \ Now recurse over all child nodes: ( old new node ) + child BEGIN + dup + WHILE + 3dup RECURSE + PEER + REPEAT + 3drop +; + +\ Check whether a node has "phandle" or "linux,phandle" properties +\ and replace them: +: fdt-fix-node-phandle ( node -- ) + >r + FALSE TO (fdt-phandle-replaced) + s" phandle" r@ get-property 0= IF + decode-int ( p-addr2 p-len2 val ) + \ ." found phandle: " dup . cr + r@ s" /" find-node ( p-addr2 p-len2 val node root ) + fdt-replace-all-phandles ( p-addr2 p-len2 ) + 2drop + (fdt-phandle-replaced) IF + r@ set-node + s" phandle" delete-property + s" linux,phandle" delete-property + ELSE + diagnostic-mode? IF + cr ." Warning: Did not replace phandle in " r@ node>path type cr + THEN + THEN + THEN + r> drop +; + +\ Recursively walk through all nodes to fix their phandles: +: fdt-fix-phandles ( node -- ) + \ ." fixing phandles of " dup node>path type cr + dup fdt-fix-node-phandle + child BEGIN + dup + WHILE + dup RECURSE + PEER + REPEAT + drop + device-end +; + +: fdt-create-cas-node ( name -- ) + 2dup + 2dup " memory@" find-substr 0 = IF + fdt-debug IF ." Creating memory@ " cr THEN + new-device + 2dup " @" find-substr nip device-name \ Parse the node name + 2dup + 2dup " @" find-substr rot over + 1 + -rot - 1 - \ Jump to addr afte "@" + parse-2int nip xlsplit set-unit \ Parse and set unit + finish-device + ELSE + 2dup " ibm,dynamic-reconfiguration-memory" find-substr 0 = IF + fdt-debug IF ." Creating ibm,dynamic-reconfiguration-memory " cr THEN + new-device + device-name + finish-device + ELSE + 2drop 2drop + false to fdt-cas-fix? + ." Node not supported " cr + EXIT + THEN + THEN + + find-node ?dup 0 <> IF set-node THEN +; + +: fdt-fix-cas-node ( start -- end ) + recursive + fdt-next-tag dup OF_DT_BEGIN_NODE <> IF + ." Error " cr + false to fdt-cas-fix? + EXIT + THEN drop + fdt-fetch-unit + dup 0 = IF drop drop " /" THEN + 40 left-parse-string + 2swap ?dup 0 <> IF + nip + 1 + + \ Add the string len +@ + ELSE + drop + THEN + fdt-debug IF ." Setting node: " 2dup type cr THEN + 2dup find-node ?dup 0 <> IF + set-node 2drop + ELSE + fdt-debug IF ." Node not found, creating " 2dup type cr THEN + fdt-create-cas-node + THEN + fdt-debug IF ." Current now: " pwd cr THEN + BEGIN + fdt-next-tag dup OF_DT_END_NODE <> + WHILE + dup OF_DT_PROP = IF + fdt-debug IF ." Found property " cr THEN + drop dup ( drop tag, dup addr : a1 a1 ) + dup l@ dup rot 4 + ( fetch size, stack is : a1 s s a2) + dup l@ swap 4 + ( fetch nameid, stack is : a1 s s i a3 ) + rot ( we now have: a1 s i a3 s ) + fdt-encode-prop rot ( a1 s pa ps i) + fdt-fetch-string ( a1 s pa ps na ns ) + property + fdt-debug IF ." Setting property done " cr THEN + + 8 + 3 + fffffffc and + ELSE dup OF_DT_BEGIN_NODE = IF + drop ( drop tag ) + 4 - + fdt-fix-cas-node + get-parent set-node + fdt-debug IF ." Returning back " pwd cr THEN + ELSE + ." Error " cr + drop + false to fdt-cas-fix? + EXIT + THEN + THEN + REPEAT + drop \ drop tag +; + +: fdt-fix-cas-success + fdt-cas-fix? +; + +s" /" find-node fdt-fix-phandles diff --git a/qemu/roms/SLOF/board-qemu/slof/header.fs b/qemu/roms/SLOF/board-qemu/slof/header.fs new file mode 100644 index 000000000..8bc17a189 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/header.fs @@ -0,0 +1,18 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ XXXFIXME: Old Bimini/JX2x crap to remove + +get-flash-base VALUE flash-addr + +get-nvram-base CONSTANT nvram-base +get-nvram-size CONSTANT nvram-size diff --git a/qemu/roms/SLOF/board-qemu/slof/helper.fs b/qemu/roms/SLOF/board-qemu/slof/helper.fs new file mode 100644 index 000000000..96da49894 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/helper.fs @@ -0,0 +1,35 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: slof-build-id ( -- str len ) + flash-header 10 + a +; + +: slof-revision s" 001" ; + +: read-version-and-date + flash-header 0= IF + s" " encode-string + ELSE + flash-header 10 + 10 + here swap rmove + here 10 + s" , " $cat + bdate2human $cat encode-string THEN +; + +\ Fetch C string +: from-cstring ( addr - len ) + dup dup BEGIN c@ 0 <> WHILE 1 + dup REPEAT + swap - +; + diff --git a/qemu/roms/SLOF/board-qemu/slof/hvterm.fs b/qemu/roms/SLOF/board-qemu/slof/hvterm.fs new file mode 100644 index 000000000..98c144582 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/hvterm.fs @@ -0,0 +1,43 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ PAPR hvterm console. Enabled very early. + +0 CONSTANT default-hvtermno +\ Buffer for pre-display +4096 CONSTANT disp-size +CREATE prevga-disp-buf 4096 allot +0 value disp-ptr +true value store-prevga? + +: store-to-disp-buffer ( ch -- ) + prevga-disp-buf disp-ptr disp-size MOD + c! + disp-ptr 1 + to disp-ptr +; + +: hvterm-emit + store-prevga? IF + dup store-to-disp-buffer + THEN + default-hvtermno SWAP hv-putchar +; +: hvterm-key? default-hvtermno hv-haschar ; +: hvterm-key BEGIN hvterm-key? UNTIL default-hvtermno hv-getchar ; + +' hvterm-emit to emit +' hvterm-key to key +' hvterm-key? to key? + +\ Override serial methods to make term-io.fs happy +: serial-emit hvterm-emit ; +: serial-key? hvterm-key? ; +: serial-key hvterm-key ; diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-aliases.fs b/qemu/roms/SLOF/board-qemu/slof/pci-aliases.fs new file mode 100644 index 000000000..9ce519da1 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-aliases.fs @@ -0,0 +1,58 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Starting alias number for net devices after the onboard devices. +0 VALUE pci-net-num +\ Starting alias number for disks after the onboard devices. +0 VALUE pci-disk-num +\ Starting alias number for cdroms after the onboard devices. +0 VALUE pci-cdrom-num + +\ define a new alias for this device +: pci-set-alias ( str-addr str-len num -- ) + $cathex strdup \ create alias name + get-node node>path \ get path string + set-alias \ and set the alias +; + +\ define a new net alias +: unknown-enet ( -- pci-net-num ) + pci-net-num dup 1+ TO pci-net-num +; +: pci-alias-net ( config-addr -- ) + drop \ forget the config address + pci-net-num dup 1+ TO pci-net-num \ increase the pci-net-num + s" net" rot pci-set-alias \ create the alias +; + +\ define a new disk alias +: pci-alias-disk ( config-addr -- ) + drop \ forget the config address + pci-disk-num dup 1+ TO pci-disk-num \ increase the pci-disk-num + s" disk" rot pci-set-alias \ create the alias +; +\ define a new cdrom alias +: pci-alias-cdrom ( config-addr -- ) + drop \ forget the config address + pci-cdrom-num dup 1+ TO pci-cdrom-num \ increase the pci-cdrom-num + s" cdrom" rot pci-set-alias \ create the alias +; + +\ define the alias for the calling device +: pci-alias ( config-addr -- ) + dup pci-class@ + 10 rshift CASE + 01 OF pci-alias-disk ENDOF + 02 OF pci-alias-net ENDOF + dup OF drop ENDOF + ENDCASE +; diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-capabilities.fs b/qemu/roms/SLOF/board-qemu/slof/pci-capabilities.fs new file mode 100644 index 000000000..ef8c7b0d4 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-capabilities.fs @@ -0,0 +1,34 @@ +\ Set up all known capabilities for this board to the plugged devices + +: pci-msi-prop ( addr -- ) + 5 pci-cap-find ( capaddr ) + ?dup IF + 2+ rtas-config-w@ ( msi-control ) + 1 rshift 7 and ( msi-control:3:1 ) + + dup 6 < IF + 1 swap lshift ( vectors# ) + encode-int " ibm,req#msi" property + ELSE + ." Invalid MSI vectors number " . cr + THEN + THEN +; + +: pci-msix-prop ( addr -- ) + 11 pci-cap-find ( capaddr ) + ?dup IF + 2+ rtas-config-w@ ( msix-control ) + 7ff and ( msix-control:10:0 ) + 1+ ( vectors# ) + ?dup IF + encode-int " ibm,req#msi-x" property + THEN + THEN +; + +: pci-set-capabilities ( config-addr -- ) + dup pci-msi-prop + dup pci-msix-prop + drop +; diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1013_00b8.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1013_00b8.fs new file mode 100644 index 000000000..c3ac2ec41 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1013_00b8.fs @@ -0,0 +1,265 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space pci-device-generic-setup + +\ Defaults, overriden from qemu +d# 800 VALUE disp-width +d# 600 VALUE disp-height +d# 8 VALUE disp-depth + +\ Determine base address +10 config-l@ translate-my-address f not AND VALUE fb-base + +\ Fixed up later +-1 VALUE io-base + +\ We support only one instance +false VALUE is-installed? + +: vga-io-xlate ( port -- addr ) + io-base -1 = IF + dup translate-my-address fff not and to io-base + THEN + io-base + +; + +: vga-w! ( value port -- ) + vga-io-xlate rw!-le +; + +: vga-w@ ( port -- value ) + vga-io-xlate rw@-le +; + +: vga-b! ( value port -- ) + vga-io-xlate rb! +; + +: vga-b@ ( port -- value ) + vga-io-xlate rb@ +; + +: vga-crt@ ( index -- value ) + 3d4 vga-b! + 3d5 vga-b@ +; + +: vga-crt! ( value index -- ) + 3d4 vga-b! + 3d5 vga-b! +; + +: vga-seq@ ( index -- value ) + 3c4 vga-b! + 3c5 vga-b@ +; + +: vga-seq! ( value index -- ) + 3c4 vga-b! + 3c5 vga-b! +; + +: vga-att@ ( index -- value ) + 3c0 vga-b! + 3c1 vga-b@ +; + +: vga-att! ( value index -- ) + 3c0 vga-b! + 3c0 vga-b! +; + +: vga-gfx@ ( index -- value ) + 3ce vga-b! + 3cf vga-b@ +; + +: vga-gfx! ( value index -- ) + 3ce vga-b! + 3cf vga-b! +; + +: color! ( r g b number -- ) + 3c8 vga-b! + rot 2 >> 3c9 vga-b! + swap 2 >> 3c9 vga-b! + 2 >> 3c9 vga-b! +; + +: color@ ( number -- r g b ) + 3c8 vga-b! + 3c9 vga-b@ 2 << + 3c9 vga-b@ 2 << + 3c9 vga-b@ 2 << +; + +: set-colors ( adr number #numbers -- ) + over 3c8 vga-b! + swap DO + rb@ 2 >> 3c9 vga-b! + rb@ 2 >> 3c9 vga-b! + rb@ 2 >> 3c9 vga-b! + LOOP + 3drop +; + +: get-colors ( adr number #numbers -- ) + 3drop +; + +include graphics.fs + +: init-mode + 3da vga-b@ drop \ reset flip flop + 0f 3c2 vga-b! \ color mode, ram enable, ... + 12 06 vga-seq! \ unlock extensions + 05 06 vga-gfx! \ graphic mode + \ set bit depth. Note: we should set the hidden + \ dac register to differenciate 15 and 16bpp, but + \ it's annoying and in practice we don't care as + \ we are only displaying in black & white atm + disp-depth CASE \ set depth + 8 OF 01 07 vga-seq! ENDOF + f OF 07 07 vga-seq! ENDOF + 10 OF 07 07 vga-seq! ENDOF + 20 OF 09 07 vga-seq! ENDOF + ENDCASE + ff 02 vga-seq! \ enable plane write + 0a 04 vga-seq! \ memory mode + 03 17 vga-crt! \ disable display + \ calculate line offset & split + disp-width disp-depth 7 + 8 / * 3 >> + dup ff and 13 vga-crt! \ bottom bits + 4 >> 10 and 1b vga-crt! \ top bit + disp-width 3 >> 1 - 01 vga-crt! \ H_DISP + disp-height 1 - ff and 12 vga-crt! \ V_DISP + disp-height 1 - 7 >> 2 and + disp-height 1 - 3 >> 40 and + or 10 or 07 vga-crt! \ OFLOW + ff 18 vga-crt! \ LINE_COMPARE + 40 09 vga-crt! \ MAX_SCAN + 08 04 vga-crt! \ SYNC_START + 0f 02 vga-crt! \ BLANK_START + 00 0c vga-crt! + 00 0d vga-crt! + 40 05 vga-gfx! \ gfx mode + 83 17 vga-crt! \ enable display + 33 3c0 vga-b! \ gfx in ar index + 00 3c0 vga-b! + 01 01 vga-seq! \ enable seq +; + +: clear-screen + fb-base disp-width disp-height disp-depth 7 + 8 / * * 0 rfill +; + +: read-settings + s" qemu,graphic-width" get-chosen IF + decode-int to disp-width 2drop + THEN + s" qemu,graphic-height" get-chosen IF + decode-int to disp-height 2drop + THEN + s" qemu,graphic-depth" get-chosen IF + decode-int nip nip + dup 8 = + over f = or + over 10 = or + over 20 = or IF + to disp-depth + ELSE + ." Unsupported bit depth, using 8bpp " drop cr + THEN + THEN +; + +: add-legacy-reg + \ add legacy I/O Ports / Memory regions to assigned-addresses + \ see PCI Bus Binding Revision 2.1 Section 7. + s" reg" get-node get-property IF + \ "reg" does not exist, create new + encode-start + ELSE + \ "reg" does exist, copy it + encode-bytes + THEN + \ I/O Range 0x1ce-0x1d2 + my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space + 1ce encode-64+ 4 encode-64+ \ addr size + \ I/O Range 0x3B0-0x3BB + my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space + 3b0 encode-64+ c encode-64+ \ addr size + \ I/O Range 0x3C0-0x3DF + my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space + 3c0 encode-64+ 20 encode-64+ \ addr size + \ Memory Range 0xA0000-0xBFFFF + my-space a2000000 or encode-int+ \ non-relocatable, <1MB Memory space + a0000 encode-64+ 20000 encode-64+ \ addr size + s" reg" property \ store "reg" property +; + +: setup-properties + \ Shouldn't this be done from open ? + disp-width encode-int s" width" property + disp-height encode-int s" height" property + disp-width disp-depth 7 + 8 / * encode-int s" linebytes" property + disp-depth encode-int s" depth" property + s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok... + \ add "device_type" property + s" display" device-type + \ XXX We don't create an "address" property because Linux doesn't know what + \ to do with it for >32-bit +; + +\ words for installation/removal, needed by is-install/is-remove, see display.fs +: display-remove ( -- ) +; + +: display-install ( -- ) + is-installed? NOT IF + ." Installing QEMU fb" cr + fb-base to frame-buffer-adr + default-font + set-font + disp-width disp-height + disp-width char-width / disp-height char-height / + disp-depth 7 + 8 / ( width height #lines #cols depth ) + fb-install + true to is-installed? + THEN +; + +: set-alias + s" screen" find-alias 0= IF + \ no previous screen alias defined, define it... + s" screen" get-node node>path set-alias + ELSE + drop + THEN +; + + +." cirrus vga" cr + +pci-master-enable +pci-mem-enable +pci-io-enable +add-legacy-reg +read-settings +init-mode +clear-screen +init-default-palette +setup-properties +' display-install is-install +' display-remove is-remove +set-alias diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs new file mode 100644 index 000000000..a5c3584f9 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1234_1111.fs @@ -0,0 +1,242 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space pci-device-generic-setup + +\ Defaults, overriden from qemu +d# 800 VALUE disp-width +d# 600 VALUE disp-height +d# 8 VALUE disp-depth + +\ Determine base address +10 config-l@ translate-my-address f not AND VALUE fb-base + +\ Fixed up later +-1 VALUE io-base + +\ We support only one instance +false VALUE is-installed? + +: vga-io-xlate ( port -- addr ) + io-base -1 = IF + dup translate-my-address fff not and to io-base + THEN + io-base + +; + +: vga-w! ( value port -- ) + vga-io-xlate rw!-le +; + +: vga-w@ ( port -- value ) + vga-io-xlate rw@-le +; + +: vga-b! ( value port -- ) + vga-io-xlate rb! +; + +: vga-b@ ( port -- value ) + vga-io-xlate rb@ +; + +: vbe! ( value index -- ) + 1ce vga-w! 1d0 vga-w! +; + +: vbe@ ( index -- value ) + 1ce vga-w! 1d0 vga-w@ +; + +: color! ( r g b number -- ) + 3c8 vga-b! + rot 3c9 vga-b! + swap 3c9 vga-b! + 3c9 vga-b! +; + +: color@ ( number -- r g b ) + 3c8 vga-b! + 3c9 vga-b@ + 3c9 vga-b@ + 3c9 vga-b@ +; + +: set-colors ( adr number #numbers -- ) + over 3c8 vga-b! + swap DO + rb@ 3c9 vga-b! + rb@ 3c9 vga-b! + rb@ 3c9 vga-b! + LOOP + 3drop +; + +: get-colors ( adr number #numbers -- ) + 3drop +; + +include graphics.fs + +\ qemu fake VBE IO registers +0 CONSTANT VBE_DISPI_INDEX_ID +1 CONSTANT VBE_DISPI_INDEX_XRES +2 CONSTANT VBE_DISPI_INDEX_YRES +3 CONSTANT VBE_DISPI_INDEX_BPP +4 CONSTANT VBE_DISPI_INDEX_ENABLE +5 CONSTANT VBE_DISPI_INDEX_BANK +6 CONSTANT VBE_DISPI_INDEX_VIRT_WIDTH +7 CONSTANT VBE_DISPI_INDEX_VIRT_HEIGHT +8 CONSTANT VBE_DISPI_INDEX_X_OFFSET +9 CONSTANT VBE_DISPI_INDEX_Y_OFFSET +a CONSTANT VBE_DISPI_INDEX_NB + +\ ENABLE register +00 CONSTANT VBE_DISPI_DISABLED +01 CONSTANT VBE_DISPI_ENABLED +02 CONSTANT VBE_DISPI_GETCAPS +20 CONSTANT VBE_DISPI_8BIT_DAC +40 CONSTANT VBE_DISPI_LFB_ENABLED +80 CONSTANT VBE_DISPI_NOCLEARMEM + +: init-mode + 0 3c0 vga-b! + VBE_DISPI_DISABLED VBE_DISPI_INDEX_ENABLE vbe! + 0 VBE_DISPI_INDEX_X_OFFSET vbe! + 0 VBE_DISPI_INDEX_Y_OFFSET vbe! + disp-width VBE_DISPI_INDEX_XRES vbe! + disp-height VBE_DISPI_INDEX_YRES vbe! + disp-depth VBE_DISPI_INDEX_BPP vbe! + VBE_DISPI_ENABLED VBE_DISPI_8BIT_DAC or VBE_DISPI_INDEX_ENABLE vbe! + 0 3c0 vga-b! + 20 3c0 vga-b! +; + +: clear-screen + fb-base disp-width disp-height disp-depth 7 + 8 / * * 0 rfill +; + +: read-settings + s" qemu,graphic-width" get-chosen IF + decode-int to disp-width 2drop + THEN + s" qemu,graphic-height" get-chosen IF + decode-int to disp-height 2drop + THEN + s" qemu,graphic-depth" get-chosen IF + decode-int nip nip + dup 8 = + over f = or + over 10 = or + over 20 = or IF + to disp-depth + ELSE + ." Unsupported bit depth, using 8bpp " drop cr + THEN + THEN +; + +: add-legacy-reg + \ add legacy I/O Ports / Memory regions to assigned-addresses + \ see PCI Bus Binding Revision 2.1 Section 7. + s" reg" get-node get-property IF + \ "reg" does not exist, create new + encode-start + ELSE + \ "reg" does exist, copy it + encode-bytes + THEN + \ I/O Range 0x1ce-0x1d2 + my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space + 1ce encode-64+ 4 encode-64+ \ addr size + \ I/O Range 0x3B0-0x3BB + my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space + 3b0 encode-64+ c encode-64+ \ addr size + \ I/O Range 0x3C0-0x3DF + my-space a1000000 or encode-int+ \ non-relocatable, aliased I/O space + 3c0 encode-64+ 20 encode-64+ \ addr size + \ Memory Range 0xA0000-0xBFFFF + my-space a2000000 or encode-int+ \ non-relocatable, <1MB Memory space + a0000 encode-64+ 20000 encode-64+ \ addr size + s" reg" property \ store "reg" property +; + +: setup-properties + \ Shouldn't this be done from open ? + disp-width encode-int s" width" property + disp-height encode-int s" height" property + disp-width disp-depth 7 + 8 / * encode-int s" linebytes" property + disp-depth encode-int s" depth" property + s" ISO8859-1" encode-string s" character-set" property \ i hope this is ok... + \ add "device_type" property + s" display" device-type + s" qemu,std-vga" encode-string s" compatible" property + \ XXX We don't create an "address" property because Linux doesn't know what + \ to do with it for >32-bit +; + +\ words for installation/removal, needed by is-install/is-remove, see display.fs +: display-remove ( -- ) +; + +: hcall-invert-screen ( -- ) + frame-buffer-adr frame-buffer-adr 3 + screen-height screen-width * screen-depth * /x / + 1 hv-logical-memop + drop +; + +: hcall-blink-screen ( -- ) + \ 32 msec delay for visually noticing the blink + hcall-invert-screen 20 ms hcall-invert-screen +; + +: display-install ( -- ) + is-installed? NOT IF + ." Installing QEMU fb" cr + fb-base to frame-buffer-adr + clear-screen + default-font + set-font + disp-width disp-height + disp-width char-width / disp-height char-height / + disp-depth 7 + 8 / ( width height #lines #cols depth ) + fb-install + ['] hcall-invert-screen to invert-screen + ['] hcall-blink-screen to blink-screen + true to is-installed? + THEN +; + +: set-alias + s" screen" find-alias 0= IF + \ no previous screen alias defined, define it... + s" screen" get-node node>path set-alias + ELSE + drop + THEN +; + + +." qemu vga" cr + +pci-master-enable +pci-mem-enable +pci-io-enable +add-legacy-reg +read-settings +init-mode +init-default-palette +setup-properties +' display-install is-install +' display-remove is-remove +set-alias diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1000.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1000.fs new file mode 100644 index 000000000..ac18e0efb --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1000.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle virtio-net device + +s" virtio [ net ]" type cr + +my-space pci-device-generic-setup + +pci-io-enable + +s" virtio-net.fs" included + +pci-device-disable diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs new file mode 100644 index 000000000..fb2463467 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs @@ -0,0 +1,34 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle virtio-blk device + +s" virtio [ block ]" type cr + +my-space pci-device-generic-setup + +pci-master-enable +pci-mem-enable +pci-io-enable + +s" virtio-block.fs" included + +\ Allocate memory for virtio queue: +virtiodev 0 virtio-get-qsize virtio-vring-size +1000 CLAIM VALUE queue-addr + +\ Write queue address into device: +queue-addr c rshift +virtiodev vd>base @ 8 + +rl!-le + +pci-device-disable diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1004.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1004.fs new file mode 100644 index 000000000..9c1089ac8 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1004.fs @@ -0,0 +1,24 @@ +\ ***************************************************************************** +\ * Copyright (c) 2012 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle virtio-net device + +s" virtio [ scsi ]" type cr + +my-space pci-device-generic-setup +pci-master-enable +pci-mem-enable +pci-io-enable + +s" virtio-scsi.fs" included + +pci-device-disable diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs new file mode 100644 index 000000000..03964a6db --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs @@ -0,0 +1,34 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle virtio-fs device + +s" virtio [ network ]" type cr + +my-space pci-device-generic-setup + +pci-master-enable +pci-mem-enable +pci-io-enable + +s" virtio-fs.fs" included + +\ Allocate memory for virtio queue: +virtiodev 0 virtio-get-qsize virtio-vring-size +1000 CLAIM VALUE queue-addr + +\ Write queue address into device: +queue-addr c rshift +virtiodev vd>base @ 8 + +rl!-le + +pci-device-disable diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-device_8086_100e.fs b/qemu/roms/SLOF/board-qemu/slof/pci-device_8086_100e.fs new file mode 100644 index 000000000..8f279a254 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-device_8086_100e.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2013 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Handle e1000 device + +s" e1000 [ net ]" type cr + +my-space pci-device-generic-setup + +pci-io-enable + +s" e1k.fs" included + +pci-device-disable diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-interrupts.fs b/qemu/roms/SLOF/board-qemu/slof/pci-interrupts.fs new file mode 100644 index 000000000..e11b77932 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-interrupts.fs @@ -0,0 +1,38 @@ + +: pci-gen-irq-map-one ( prop-addr prop-len slot pin -- prop-addr prop-len ) + 2dup + 4 mod ( prop-addr prop-len slot pin parentpin ) + >r >r ( prop-addr prop-len slot R: swizzledpin pin ) + + \ Child slot# + B lshift encode-int+ ( prop-addr prop-len R: swizzledpin pin ) + \ Child 64bit BAR (not really used) + 0 encode-64+ + \ Chile pin# + r> encode-int+ ( prop-addr prop-len R: swizzledpin ) + + \ Parent phandle + get-parent encode-int+ + + \ Parent slot# + get-node >space + pci-addr2dev B lshift ( prop-addr prop-len parent-slot R: swizzledpin ) + encode-int+ + \ Parent 64bit BAR (not really used) + 0 encode-64+ + \ Parent pin + r> encode-int+ ( prop-addr prop-len R: ) +; + +: pci-gen-irq-entry ( prop-addr prop-len config-addr -- prop-addr prop-len ) + pci-addr2dev 4 mod ( prop-addr prop-len slot ) + -rot ( slot prop-addr prop-len ) + 5 1 DO + 2 pick i ( slot prop-addr prop-len slot pin ) + pci-gen-irq-map-one + LOOP + rot drop +; + +: pci-set-irq-line ( config-addr -- ) + drop +; diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-phb.fs b/qemu/roms/SLOF/board-qemu/slof/pci-phb.fs new file mode 100644 index 000000000..a8fb7ca5e --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/pci-phb.fs @@ -0,0 +1,337 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ PAPR PCI host bridge. + +0 VALUE phb-debug? + + +." Populating " pwd cr + +\ needed to find the right path in the device tree +: decode-unit ( addr len -- phys.lo ... phys.hi ) + 2 hex-decode-unit \ decode string + b lshift swap \ shift the devicenumber to the right spot + 8 lshift or \ add the functionnumber + \ my-bus 10 lshift or \ add the busnumber (assume always bus 0) + 0 0 rot \ make phys.lo = 0 = phys.mid +; + +\ needed to have the right unit address in the device tree listing +\ phys.lo=phys.mid=0 , phys.hi=config-address +: encode-unit ( phys.lo phys-mid phys.hi -- unit-str unit-len ) + nip nip \ forget the phys.lo and phys.mid + dup 8 rshift 7 and swap \ calculate function number + B rshift 1F and \ calculate device number + over IF 2 ELSE nip 1 THEN \ create string with dev#,fn# or dev# only? + hex-encode-unit +; + + +0 VALUE my-puid + +: setup-puid + s" reg" get-node get-property 0= IF + decode-64 to my-puid 2drop + THEN +; + +setup-puid + +: config-b@ puid >r my-puid TO puid rtas-config-b@ r> TO puid ; +: config-w@ puid >r my-puid TO puid rtas-config-w@ r> TO puid ; +: config-l@ puid >r my-puid TO puid rtas-config-l@ r> TO puid ; + +\ define the config writes +: config-b! puid >r my-puid TO puid rtas-config-b! r> TO puid ; +: config-w! puid >r my-puid TO puid rtas-config-w! r> TO puid ; +: config-l! puid >r my-puid TO puid rtas-config-l! r> TO puid ; + + +: map-in ( phys.lo phys.mid phys.hi size -- virt ) + phb-debug? IF cr ." map-in called: " .s cr THEN + \ Ignore the size, phys.lo and phys.mid, get BAR from config space + drop nip nip ( phys.hi ) + \ Sanity check whether config address is in expected range: + dup FF AND dup 10 28 WITHIN NOT swap 30 <> AND IF + cr ." phys.hi = " . cr + ABORT" map-in with illegal config space address" + THEN + 00FFFFFF AND \ Need only bus-dev-fn+register bits + dup config-l@ ( phys.hi' bar.lo ) + dup 7 AND 4 = IF \ Is it a 64-bit BAR? + swap 4 + config-l@ lxjoin \ Add upper part of 64-bit BAR + ELSE + nip + THEN + F NOT AND \ Clear indicator bits + translate-my-address + phb-debug? IF ." map-in done: " .s cr THEN +; + +: map-out ( virt size -- ) + phb-debug? IF ." map-out called: " .s cr THEN + 2drop +; + + +: dma-alloc ( size -- virt ) + phb-debug? IF cr ." dma-alloc called: " .s cr THEN + fff + fff not and \ Align size to next 4k boundary + alloc-mem + \ alloc-mem always returns aligned memory - double check just to be sure + dup fff and IF + ." Warning: dma-alloc got unaligned memory!" cr + THEN +; + +: dma-free ( virt size -- ) + phb-debug? IF cr ." dma-free called: " .s cr THEN + fff + fff not and \ Align size to next 4k boundary + free-mem +; + + +\ Helper variables for dma-map-in and dma-map-out +0 VALUE dma-window-liobn \ Logical I/O bus number +0 VALUE dma-window-base \ Start address of window +0 VALUE dma-window-size \ Size of the window + +0 VALUE bm-handle \ Bitmap allocator handle +0 VALUE my-virt +0 VALUE my-size +0 VALUE dev-addr +0 VALUE tmp-dev-addr + +\ Read helper variables (LIOBN, DMA window base and size) from the +\ "ibm,dma-window" property. This property can be either located +\ in the PCI device node or in the bus node, so we've got to use the +\ "calling-child" variable here to get to the node that initiated the call. +\ XXX We should search all the way up the tree to the PHB ... +: (init-dma-window-vars) ( -- ) +\ ." Foo called in " pwd cr +\ ." calling child is " calling-child .node cr +\ ." parent is " calling-child parent .node cr + s" ibm,dma-window" calling-child get-property IF + s" ibm,dma-window" calling-child parent get-property + ABORT" no dma-window property available" + THEN + decode-int TO dma-window-liobn + decode-64 TO dma-window-base + decode-64 TO dma-window-size + 2drop + bm-handle 0= IF + dma-window-base dma-window-size 1000 bm-allocator-init to bm-handle + \ Sometimes the window-base appears as zero, that does not + \ go well with NULL pointers. So block this address + dma-window-base 0= IF + bm-handle 1000 bm-alloc drop + THEN + THEN +; + +: (clear-dma-window-vars) ( -- ) + 0 TO dma-window-liobn + 0 TO dma-window-base + 0 TO dma-window-size +; + +\ We assume that firmware never maps more than the whole dma-window-size +\ so we cheat by calculating the remainder of addr/windowsize instead +\ of taking care to maintain a list of assigned device addresses +: dma-virt2dev ( virt -- devaddr ) + dma-window-size mod dma-window-base + +; + +: dma-map-in ( virt size cachable? -- devaddr ) + phb-debug? IF cr ." dma-map-in called: " .s cr THEN + (init-dma-window-vars) + drop ( virt size ) + + to my-size + to my-virt + bm-handle my-size bm-alloc + to dev-addr + dev-addr 0 < IF + ." Bitmap allocation Failed " dev-addr . + FALSE EXIT + THEN + dev-addr to tmp-dev-addr + + my-virt my-size + bounds dup >r ( v+s virt R: virt ) + swap fff + fff not and \ Align end to next 4k boundary + swap fff not and ( v+s' virt' R: virt ) + ?DO + \ ." mapping " i . cr + dma-window-liobn \ liobn + tmp-dev-addr \ ioba + i 3 OR \ Make a read- & writeable TCE + ( liobn ioba tce R: virt ) + hv-put-tce ABORT" H_PUT_TCE failed" + tmp-dev-addr 1000 + to tmp-dev-addr + 1000 +LOOP + r> drop + my-virt FFF and dev-addr or + (clear-dma-window-vars) +; + +: dma-map-out ( virt devaddr size -- ) + phb-debug? IF cr ." dma-map-out called: " .s cr THEN + (init-dma-window-vars) + to my-size + to dev-addr + to my-virt + dev-addr fff not and to dev-addr + dev-addr to tmp-dev-addr + + my-virt my-size ( virt size ) + bounds ( v+s virt ) + swap fff + fff not and \ Align end to next 4k boundary + swap fff not and ( v+s' virt' ) + ?DO + \ ." unmapping " i . cr + dma-window-liobn \ liobn + tmp-dev-addr \ ioba + i \ Lowest bits not set => invalid TCE + ( liobn ioba tce ) + hv-put-tce ABORT" H_PUT_TCE failed" + tmp-dev-addr 1000 + to tmp-dev-addr + 1000 +LOOP + bm-handle dev-addr my-size bm-free + (clear-dma-window-vars) +; + +: dma-sync ( virt devaddr size -- ) + phb-debug? IF cr ." dma-sync called: " .s cr THEN + \ TODO: Call flush-cache or sync here? + 3drop +; + + +: open true ; +: close ; + +\ Parse the "ranges" property of the root pci node to decode the available +\ memory ranges. See "PCI Bus Binding to IEEE Std 1275-1994" for details. +\ The memory ranges are then used for setting up the device bars (if necessary) +: phb-parse-ranges ( -- ) + \ First clear everything, in case there is something missing in the ranges + 0 pci-next-io ! + 0 pci-max-io ! + 0 pci-next-mem ! + 0 pci-max-mem ! + 0 pci-next-mmio ! + 0 pci-max-mmio ! + 0 pci-next-mem64 ! + 0 pci-max-mem64 ! + + \ Now get the "ranges" property + s" ranges" get-node get-property 0<> ABORT" ranges property not found" + ( prop-addr prop-len ) + BEGIN + dup + WHILE + decode-int \ Decode phys.hi + 3000000 AND \ Filter out address space in phys.hi + CASE + 1000000 OF \ I/O space? + decode-64 dup >r pci-next-io ! \ Decode PCI base address + decode-64 drop \ Forget the parent address + decode-64 r> + pci-max-io ! \ Decode size & calc max address + pci-next-io @ 0= IF + pci-next-io @ 10 + pci-next-io ! \ BARs must not be set to zero + THEN + ENDOF + 2000000 OF \ 32-bit memory space? + decode-64 pci-next-mem ! \ Decode mem base address + decode-64 drop \ Forget the parent address + decode-64 2 / dup >r \ Decode and calc size/2 + pci-next-mem @ + dup pci-max-mem ! \ and calc max mem address + dup pci-next-mmio ! \ which is the same as MMIO base + r> + pci-max-mmio ! \ calc max MMIO address + ENDOF + 3000000 OF \ 64-bit memory space? + decode-64 pci-next-mem64 ! + decode-64 drop \ Forget the parent address + decode-64 pci-max-mem64 ! + ENDOF + ENDCASE + REPEAT + ( prop-addr prop-len ) + 2drop + + phb-debug? IF + ." pci-next-io = " pci-next-io @ . cr + ." pci-max-io = " pci-max-io @ . cr + ." pci-next-mem = " pci-next-mem @ . cr + ." pci-max-mem = " pci-max-mem @ . cr + ." pci-next-mmio = " pci-next-mmio @ . cr + ." pci-max-mmio = " pci-max-mmio @ . cr + ." pci-next-mem64 = " pci-next-mem64 @ . cr + ." pci-max-mem64 = " pci-max-mem64 @ . cr + THEN +; + +: phb-pci-walk-bridge ( -- ) + phb-debug? IF ." Calling pci-walk-bridge " pwd cr THEN + + get-node child ?dup 0= IF EXIT THEN \ get and check if we have children + 0 to pci-device-slots \ reset slot array to unpoppulated + BEGIN + dup \ Continue as long as there are children + WHILE + dup set-node \ Set child node as current node + my-space pci-set-slot \ set the slot bit + my-space pci-htype@ \ read HEADER-Type + 7f and \ Mask bit 7 - multifunction device + CASE + 0 OF my-space pci-device-setup ENDOF \ | set up the device + 1 OF my-space pci-bridge-setup ENDOF \ | set up the bridge + dup OF my-space pci-htype@ pci-out ENDOF + ENDCASE + peer + REPEAT drop + get-parent set-node +; + +\ Landing routing to probe the popuated device tree +: phb-pci-probe-bus ( busnr -- ) + drop phb-pci-walk-bridge +; + +\ Stub routine, as qemu has enumerated, we already have the device +\ properties set. +: phb-pci-device-props ( addr -- ) + dup pci-class-name device-name + dup pci-device-assigned-addresses-prop + drop +; + +\ Scan the child nodes of the pci root node to assign bars, fixup +\ properties etc. +: phb-setup-children + puid >r \ Save old value of puid + my-puid TO puid \ Set current puid + phb-parse-ranges + 1 TO pci-hotplug-enabled + s" qemu,phb-enumerated" get-node get-property 0<> IF + 1 0 (probe-pci-host-bridge) + ELSE + 2drop + ['] phb-pci-probe-bus TO func-pci-probe-bus + ['] phb-pci-device-props TO func-pci-device-props + phb-pci-walk-bridge \ PHB device tree is already populated. + THEN + r> TO puid \ Restore previous puid +; +phb-setup-children diff --git a/qemu/roms/SLOF/board-qemu/slof/qemu-bootlist.fs b/qemu/roms/SLOF/board-qemu/slof/qemu-bootlist.fs new file mode 100644 index 000000000..4778e1629 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/qemu-bootlist.fs @@ -0,0 +1,61 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +defer set-boot-device +defer add-boot-device + +8 CONSTANT MAX-ALIAS +: add-boot-aliases ( str -- ) + 2dup add-boot-device ( $str ) + MAX-ALIAS 1 DO + 2dup i $cathex 2dup ( $str $strN $strN ) + find-alias 0 > IF ( $str $strN false | $result ) + drop strdup add-boot-device ( $str ) + ELSE 2drop THEN + LOOP + 2drop +; + +: qemu-read-bootlist ( -- ) + \ See if QEMU has set exact boot device list + " qemu,boot-list" get-chosen IF + s" boot-device" $setenv + EXIT + THEN + + 0 0 set-boot-device + + " qemu,boot-device" get-chosen not IF + \ No boot list set from qemu, so check nvram + " boot-device" evaluate swap drop 0= IF + \ Not set in nvram too, set default disk/cdrom alias + " disk" add-boot-aliases + " cdrom" add-boot-aliases + " net" add-boot-aliases + THEN + EXIT + THEN + + 0 ?DO + dup i + c@ CASE + 0 OF ENDOF + [char] a OF ENDOF + [char] b OF ENDOF + [char] c OF " disk" add-boot-aliases ENDOF + [char] d OF " cdrom" add-boot-aliases ENDOF + [char] n OF " net" add-boot-aliases ENDOF + ENDCASE cr + LOOP + drop +; + +' qemu-read-bootlist to read-bootlist diff --git a/qemu/roms/SLOF/board-qemu/slof/rtas-nvram.fs b/qemu/roms/SLOF/board-qemu/slof/rtas-nvram.fs new file mode 100644 index 000000000..fdebfb239 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/rtas-nvram.fs @@ -0,0 +1,48 @@ +\ ***************************************************************************** +\ * Copyright (c) 2012 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +." Populating " pwd cr + +0 VALUE my-nvram-fetch +0 VALUE my-nvram-store +0 VALUE my-nvram-size +0 VALUE nvram-addr + +: open true ; +: close ; + +: write ( adr len -- actual ) + nip +; + +: read ( adr len -- actual ) + nip +; + +: setup-alias + " nvram" find-alias 0= IF + " nvram" get-node node>path set-alias + ELSE + drop + THEN +; + +" #bytes" get-node get-package-property 0= IF + decode-int to my-nvram-size 2drop + " nvram-fetch" rtas-get-token to my-nvram-fetch + " nvram-store" rtas-get-token to my-nvram-store + my-nvram-size to nvram-size + nvram-size alloc-mem to nvram-addr + my-nvram-fetch my-nvram-store nvram-size nvram-addr internal-nvram-init +THEN + +setup-alias diff --git a/qemu/roms/SLOF/board-qemu/slof/rtas.fs b/qemu/roms/SLOF/board-qemu/slof/rtas.fs new file mode 100644 index 000000000..2e10b0a50 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/rtas.fs @@ -0,0 +1,189 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ KVM/qemu RTAS + +\ rtas control block + +371 cp + +STRUCT + /l field rtas>token + /l field rtas>nargs + /l field rtas>nret + /l field rtas>args0 + /l field rtas>args1 + /l field rtas>args2 + /l field rtas>args3 + /l field rtas>args4 + /l field rtas>args5 + /l field rtas>args6 + /l field rtas>args7 + /l C * field rtas>args + /l field rtas>bla +CONSTANT /rtas-control-block + +CREATE rtas-cb /rtas-control-block allot +rtas-cb /rtas-control-block erase + +0 VALUE rtas-base +0 VALUE rtas-size +0 VALUE rtas-entry +0 VALUE rtas-node + +\ Locate qemu RTAS, remove the linux,... properties we really don't +\ want them to stick around + +372 cp + +: find-qemu-rtas ( -- ) + " /rtas" find-device get-node to rtas-node + + " linux,rtas-base" rtas-node get-package-property IF + device-end EXIT THEN + drop l@ to rtas-base + " linux,rtas-base" delete-property + + " rtas-size" rtas-node get-package-property IF + device-end EXIT THEN + drop l@ to rtas-size + + " linux,rtas-entry" rtas-node get-package-property IF + rtas-base to rtas-entry + ELSE + drop l@ to rtas-entry + " linux,rtas-entry" delete-property + THEN + +\ ." RTAS found, base=" rtas-base . ." size=" rtas-size . cr + + \ Patch the RTAS blob with our sc1 patcher if necessary + 0 + rtas-base + dup rtas-size + + check-and-patch-sc1 + + device-end +; +find-qemu-rtas +373 cp + +: enter-rtas ( -- ) + rtas-cb rtas-base 0 rtas-entry call-c drop +; + +: rtas-get-token ( str len -- token | 0 ) + rtas-node get-package-property IF 0 ELSE drop l@ THEN +; + +#include <rtas/rtas-reboot.fs> +#include <rtas/rtas-cpu.fs> + +: rtas-set-tce-bypass ( unit enable -- ) + " ibm,set-tce-bypass" rtas-get-token rtas-cb rtas>token l! + 2 rtas-cb rtas>nargs l! + 0 rtas-cb rtas>nret l! + rtas-cb rtas>args1 l! + rtas-cb rtas>args0 l! + enter-rtas +; + +: rtas-quiesce ( -- ) + " quiesce" rtas-get-token rtas-cb rtas>token l! + 0 rtas-cb rtas>nargs l! + 0 rtas-cb rtas>nret l! + enter-rtas +; + + +0 value puid + +: rtas-do-config-@ ( config-addr size -- value) + \ We really want to cache this ! + " ibm,read-pci-config" rtas-get-token rtas-cb rtas>token l! + 4 rtas-cb rtas>nargs l! + 2 rtas-cb rtas>nret l! + ( addr size ) rtas-cb rtas>args3 l! + puid ffffffff and rtas-cb rtas>args2 l! + puid 20 rshift rtas-cb rtas>args1 l! + ( addr ) rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args4 l@ dup IF + \ Do not warn on error as this is part of the + \ normal PCI probing pass + drop ffffffff + ELSE + drop rtas-cb rtas>args5 l@ + THEN +; + +: rtas-do-config-! ( value config-addr size ) + \ We really want to cache this ! + " ibm,write-pci-config" rtas-get-token rtas-cb rtas>token l! + 5 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + ( value addr size ) rtas-cb rtas>args3 l! + puid ffffffff and rtas-cb rtas>args2 l! + puid 20 rshift rtas-cb rtas>args1 l! + ( value addr ) rtas-cb rtas>args0 l! + ( value ) rtas-cb rtas>args4 l! + enter-rtas + rtas-cb rtas>args5 l@ dup IF + ." RTAS write config err " . cr + ELSE drop THEN +; + +: rtas-config-b@ ( config-addr -- value ) + 1 rtas-do-config-@ ff and +; +: rtas-config-b! ( value config-addr -- ) + 1 rtas-do-config-! +; +: rtas-config-w@ ( config-addr -- value ) + 2 rtas-do-config-@ ffff and +; +: rtas-config-w! ( value config-addr -- ) + 2 rtas-do-config-! +; +: rtas-config-l@ ( config-addr -- value ) + 4 rtas-do-config-@ ffffffff and +; +: rtas-config-l! ( value config-addr -- ) + 4 rtas-do-config-! +; + +: of-start-cpu rtas-start-cpu ; + +' power-off to halt +' rtas-system-reboot to reboot + +\ Methods of the rtas node proper +rtas-node set-node + +: open true ; +: close ; + +: instantiate-rtas ( adr -- entry ) + dup rtas-base swap rtas-size move + dup rtas-entry rtas-base - + + 2dup hv-rtas-update dup 0 <> IF + \ Ignore hcall not implemented error, print error otherwise + dup -2 <> IF ." HV-RTAS-UPDATE error: " . cr ELSE drop THEN + ELSE + drop + THEN + nip +; + +device-end + +374 cp diff --git a/qemu/roms/SLOF/board-qemu/slof/tree.fs b/qemu/roms/SLOF/board-qemu/slof/tree.fs new file mode 100644 index 000000000..4aba4c53f --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/tree.fs @@ -0,0 +1,193 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: strequal ( str1 len1 str2 len2 -- flag ) + rot dup rot = IF comp 0= ELSE 2drop drop 0 THEN ; + +400 cp + +\ The root of the device tree and some of its kids. +" /" find-device + +\ The following properties have been provided by the FDT from QEMU already, +\ so we do not have to create them on our own: + +\ " QEMU" encode-string s" model" property +\ 2 encode-int s" #address-cells" property +\ 2 encode-int s" #size-cells" property +\ s" chrp" device-type + +480 cp + +\ See 3.6.5, and the PowerPC OF binding document. +new-device +s" mmu" 2dup device-name device-type +0 0 s" translations" property + +: open true ; +: close ; + +finish-device +device-end + +4c0 cp + +\ Fixup timebase frequency from device-tree +: fixup-tbfreq + " /cpus/@0" find-device + " timebase-frequency" get-node get-package-property IF + 2drop + ELSE + decode-int to tb-frequency 2drop + THEN + device-end +; +fixup-tbfreq + +4d0 cp + +include fbuffer.fs + +500 cp + +: populate-vios ( -- ) + \ Populate the /vdevice children with their methods + \ WARNING: Quite a few SLOFisms here like get-node, set-node, ... + + ." Populating /vdevice methods" cr + " /vdevice" find-device get-node child + BEGIN + dup 0 <> + WHILE + dup set-node + dup " compatible" rot get-package-property 0 = IF + drop dup from-cstring + 2dup " hvterm1" strequal IF + " vio-hvterm.fs" included + THEN + 2dup " IBM,v-scsi" strequal IF + " vio-vscsi.fs" included + THEN + 2dup " IBM,l-lan" strequal IF + " vio-veth.fs" included + THEN + 2dup " qemu,spapr-nvram" strequal IF + " rtas-nvram.fs" included + THEN + 2drop + THEN + peer + REPEAT drop + + device-end +; + +\ Now do it +populate-vios + +580 cp + +5a0 cp + +#include "pci-scan.fs" + +: populate-pci-busses ( -- ) + \ Populate the /pci* children with their methods + " /" find-device get-node child + BEGIN + dup 0 <> + WHILE + dup set-node + dup " name" rot get-package-property 0 = IF + drop dup from-cstring + 2dup s" pci" strequal IF + s" pci-phb.fs" included + THEN + 2drop + THEN + peer + REPEAT drop + + device-end +; + +populate-pci-busses + +600 cp + +: check-patch-kernel-sc1 ( -- ) + \ At this point we can try our best to patch the kernel. This function + \ gets called from the "quiesce" call that kernels execute before they + \ take over the system. + \ + \ Here we know that ciregs->r4 contains the return address that gets us + \ back into enter_prom inside the guest kernel. + \ We assume that within a range of +- 16MB of that pointer all sc 1 + \ instructions inside of that kernel reside. + + \ test_ins (instruction that tells us the kernel's endianness; we use the + \ return address back into the kernel here.) + ciregs >r4 @ + \ test_ins + 16MB (end of search range) + dup 1000000 + + \ MAX(test_ins - 16MB, 0) (start of search range) + dup 2000000 < IF 0 ELSE dup 2000000 - THEN + swap + check-and-patch-sc1 +; + +\ Add sc 1 patching +' check-patch-kernel-sc1 add-quiesce-xt + +\ Add rtas cleanup last +' rtas-quiesce add-quiesce-xt + +640 cp + +690 cp + +6a0 cp + +6a8 cp + +6b0 cp + +6b8 cp + +6c0 cp + +s" /cpus/@0" open-dev encode-int s" cpu" set-chosen +s" /memory@0" open-dev encode-int s" memory" set-chosen + +6e0 cp + +700 cp + +\ See 3.5. +s" /openprom" find-device + s" SLOF," slof-build-id here swap rmove here slof-build-id nip $cat encode-string s" model" property + 0 0 s" relative-addressing" property +device-end + +s" /aliases" find-device + : open true ; + : close ; +device-end + +s" /mmu" open-dev encode-int s" mmu" set-chosen + +#include "available.fs" + +\ Setup terminal IO + +#include <term-io.fs> + diff --git a/qemu/roms/SLOF/board-qemu/slof/version.S b/qemu/roms/SLOF/board-qemu/slof/version.S new file mode 100644 index 000000000..9aa2a94fc --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/version.S @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2010, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * Print version information - in SLOF + * This code is in a separate file so that it can be easily compiled during + * each new build (for refreshing the build date). + */ + +#include "termctrl.h" +#include <product.h> + +.global print_version +print_version: + .ascii TERM_CTRL_RESET + .ascii TERM_CTRL_CRSOFF + .ascii TERM_CTRL_BRIGHT + .ascii PRODUCT_NAME + .ascii " Starting\r\n" + .ascii TERM_CTRL_RESET + .ascii " Build Date = ", __DATE__, " ", __TIME__ + .ascii "\r\n" + .ascii " FW Version = " , RELEASE + .ascii "\r\n\0" + .align 2 +.global print_version_end +print_version_end: diff --git a/qemu/roms/SLOF/board-qemu/slof/vio-hvterm.fs b/qemu/roms/SLOF/board-qemu/slof/vio-hvterm.fs new file mode 100644 index 000000000..3519751e6 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/vio-hvterm.fs @@ -0,0 +1,41 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +." Populating " pwd cr + +: open true ; +: close ; + +: write ( adr len -- actual ) + tuck + 0 ?DO + dup c@ my-unit SWAP hv-putchar + 1 + + LOOP + drop +; + +: read ( adr len -- actual ) + 0= IF drop 0 EXIT THEN + my-unit hv-haschar 0= IF 0 swap c! -2 EXIT THEN + my-unit hv-getchar swap c! 1 +; + +: setup-alias + " hvterm" find-alias 0= IF + " hvterm" get-node node>path set-alias + ELSE + drop + THEN +; + +setup-alias diff --git a/qemu/roms/SLOF/board-qemu/slof/vio-veth.fs b/qemu/roms/SLOF/board-qemu/slof/vio-veth.fs new file mode 100644 index 000000000..3c8f489fe --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/vio-veth.fs @@ -0,0 +1,76 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +." Populating " pwd cr + +" network" device-type + +INSTANCE VARIABLE obp-tftp-package +0 VALUE veth-priv +0 VALUE open-count + +: open ( -- okay? ) + open-count 0= IF + my-unit 1 rtas-set-tce-bypass + s" local-mac-address" get-node get-property not + s" reg" get-node get-property not 3 pick and IF + >r nip r> + libveth-open dup not IF ." libveth-open failed" EXIT THEN + drop TO veth-priv + THEN + THEN + my-args s" obp-tftp" $open-package obp-tftp-package ! + open-count 1 + to open-count + true +; + +: close ( -- ) + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + veth-priv libveth-close + my-unit 0 rtas-set-tce-bypass + THEN + THEN + s" close" obp-tftp-package @ $call-method +; + +: read ( buf len -- actual ) + dup IF + veth-priv libveth-read + ELSE + nip + THEN +; + +: write ( buf len -- actual ) + dup IF + veth-priv libveth-write + ELSE + nip + THEN +; + +: load ( addr -- len ) + s" load" obp-tftp-package @ $call-method +; + +: ping ( -- ) + s" ping" obp-tftp-package @ $call-method +; + +: setup-alias + " net" get-next-alias ?dup IF + get-node node>path set-alias + THEN +; +setup-alias diff --git a/qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs b/qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs new file mode 100644 index 000000000..f2d4c6fcc --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/vio-vscsi.fs @@ -0,0 +1,546 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +." Populating " pwd + +false VALUE vscsi-debug? +0 VALUE vscsi-unit + +\ ----------------------------------------------------------- +\ Direct DMA conversion hack +\ ----------------------------------------------------------- +: l2dma ( laddr - dma_addr) +; + +\ ----------------------------------------------------------- +\ CRQ related functions +\ ----------------------------------------------------------- + +0 VALUE crq-real-base +0 VALUE crq-base +0 VALUE crq-dma +0 VALUE crq-offset +1000 CONSTANT CRQ-SIZE + +CREATE crq 10 allot + +: crq-alloc ( -- ) + \ Allocate enough to align to a page + CRQ-SIZE fff + alloc-mem to crq-real-base + \ align the result + crq-real-base fff + fffff000 AND to crq-base 0 to crq-offset + crq-base l2dma to crq-dma +; + +: crq-free ( -- ) + vscsi-unit hv-free-crq + crq-real-base CRQ-SIZE fff + free-mem 0 to crq-base 0 to crq-real-base +; + +: crq-init ( -- res ) + \ Allocate CRQ. XXX deal with fail + crq-alloc + + vscsi-debug? IF + ." VSCSI: allocated crq at " crq-base . cr + THEN + + \ Clear buffer + crq-base CRQ-SIZE erase + + \ Register with HV + vscsi-unit crq-dma CRQ-SIZE hv-reg-crq + + \ Fail case + dup 0 <> IF + ." VSCSI: Error " . ." registering CRQ !" cr + crq-free + THEN +; + +: crq-cleanup ( -- ) + crq-base 0 = IF EXIT THEN + + vscsi-debug? IF + ." VSCSI: freeing crq at " crq-base . cr + THEN + crq-free +; + +: crq-send ( msgaddr -- true | false ) + vscsi-unit swap hv-send-crq 0 = +; + +: crq-poll ( -- true | false) + crq-offset crq-base + dup + vscsi-debug? IF + ." VSCSI: crq poll " dup . + THEN + c@ + vscsi-debug? IF + ." value=" dup . cr + THEN + 80 and 0 <> IF + dup crq 10 move + 0 swap c! + crq-offset 10 + dup CRQ-SIZE >= IF drop 0 THEN to crq-offset + true + ELSE drop false THEN +; + +: crq-wait ( -- true | false) + \ FIXME: Add timeout + 0 BEGIN drop crq-poll dup not WHILE d# 1 ms REPEAT + dup not IF + ." VSCSI: Timeout waiting response !" cr EXIT + ELSE + vscsi-debug? IF + ." VSCSI: got crq: " crq dup l@ . ." " 4 + dup l@ . ." " + 4 + dup l@ . ." " 4 + l@ . cr + THEN + THEN +; + +\ ----------------------------------------------------------- +\ CRQ encapsulated SRP definitions +\ ----------------------------------------------------------- + +01 CONSTANT VIOSRP_SRP_FORMAT +02 CONSTANT VIOSRP_MAD_FORMAT +03 CONSTANT VIOSRP_OS400_FORMAT +04 CONSTANT VIOSRP_AIX_FORMAT +06 CONSTANT VIOSRP_LINUX_FORMAT +07 CONSTANT VIOSRP_INLINE_FORMAT + +struct + 1 field >crq-valid + 1 field >crq-format + 1 field >crq-reserved + 1 field >crq-status + 2 field >crq-timeout + 2 field >crq-iu-len + 8 field >crq-iu-data-ptr +constant /crq + +: srp-send-crq ( addr len -- ) + 80 crq >crq-valid c! + VIOSRP_SRP_FORMAT crq >crq-format c! + 0 crq >crq-reserved c! + 0 crq >crq-status c! + 0 crq >crq-timeout w! + ( len ) crq >crq-iu-len w! + ( addr ) l2dma crq >crq-iu-data-ptr x! + crq crq-send + not IF + ." VSCSI: Error sending CRQ !" cr + THEN +; + +: srp-wait-crq ( -- [tag true] | false ) + crq-wait not IF false EXIT THEN + + crq >crq-format c@ VIOSRP_SRP_FORMAT <> IF + ." VSCSI: Unsupported SRP response: " + crq >crq-format c@ . cr + false EXIT + THEN + + crq >crq-iu-data-ptr x@ true +; + +\ Add scsi functions to dictionary +scsi-open + + +\ ----------------------------------------------------------- +\ SRP definitions +\ ----------------------------------------------------------- + +0 VALUE >srp_opcode + +00 CONSTANT SRP_LOGIN_REQ +01 CONSTANT SRP_TSK_MGMT +02 CONSTANT SRP_CMD +03 CONSTANT SRP_I_LOGOUT +c0 CONSTANT SRP_LOGIN_RSP +c1 CONSTANT SRP_RSP +c2 CONSTANT SRP_LOGIN_REJ +80 CONSTANT SRP_T_LOGOUT +81 CONSTANT SRP_CRED_REQ +82 CONSTANT SRP_AER_REQ +41 CONSTANT SRP_CRED_RSP +42 CONSTANT SRP_AER_RSP + +02 CONSTANT SRP_BUF_FORMAT_DIRECT +04 CONSTANT SRP_BUF_FORMAT_INDIRECT + +struct + 1 field >srp-login-opcode + 3 + + 8 field >srp-login-tag + 4 field >srp-login-req-it-iu-len + 4 + + 2 field >srp-login-req-buf-fmt + 1 field >srp-login-req-flags + 5 + + 10 field >srp-login-init-port-ids + 10 field >srp-login-trgt-port-ids +constant /srp-login + +struct + 1 field >srp-lresp-opcode + 3 + + 4 field >srp-lresp-req-lim-delta + 8 field >srp-lresp-tag + 4 field >srp-lresp-max-it-iu-len + 4 field >srp-lresp-max-ti-iu-len + 2 field >srp-lresp-buf-fmt + 1 field >srp-lresp-flags +constant /srp-login-resp + +struct + 1 field >srp-lrej-opcode + 3 + + 4 field >srp-lrej-reason + 8 field >srp-lrej-tag + 8 + + 2 field >srp-lrej-buf-fmt +constant /srp-login-rej + +00 CONSTANT SRP_NO_DATA_DESC +01 CONSTANT SRP_DATA_DESC_DIRECT +02 CONSTANT SRP_DATA_DESC_INDIRECT + +struct + 1 field >srp-cmd-opcode + 1 field >srp-cmd-sol-not + 3 + + 1 field >srp-cmd-buf-fmt + 1 field >srp-cmd-dout-desc-cnt + 1 field >srp-cmd-din-desc-cnt + 8 field >srp-cmd-tag + 4 + + 8 field >srp-cmd-lun + 1 + + 1 field >srp-cmd-task-attr + 1 + + 1 field >srp-cmd-add-cdb-len + 10 field >srp-cmd-cdb + 0 field >srp-cmd-cdb-add +constant /srp-cmd + +struct + 1 field >srp-rsp-opcode + 1 field >srp-rsp-sol-not + 2 + + 4 field >srp-rsp-req-lim-delta + 8 field >srp-rsp-tag + 2 + + 1 field >srp-rsp-flags + 1 field >srp-rsp-status + 4 field >srp-rsp-dout-res-cnt + 4 field >srp-rsp-din-res-cnt + 4 field >srp-rsp-sense-len + 4 field >srp-rsp-resp-len + 0 field >srp-rsp-data +constant /srp-rsp + +\ Constants for srp-rsp-flags +01 CONSTANT SRP_RSP_FLAG_RSPVALID +02 CONSTANT SRP_RSP_FLAG_SNSVALID +04 CONSTANT SRP_RSP_FLAG_DOOVER +05 CONSTANT SRP_RSP_FLAG_DOUNDER +06 CONSTANT SRP_RSP_FLAG_DIOVER +07 CONSTANT SRP_RSP_FLAG_DIUNDER + +\ Storage for up to 256 bytes SRP request */ +CREATE srp 100 allot +0 VALUE srp-len + +: srp-prep-cmd-nodata ( srplun -- ) + srp /srp-cmd erase + SRP_CMD srp >srp-cmd-opcode c! + 1 srp >srp-cmd-tag x! + srp >srp-cmd-lun x! \ 8 bytes lun + /srp-cmd to srp-len +; + +: srp-prep-cmd-io ( addr len srplun -- ) + srp-prep-cmd-nodata ( addr len ) + swap l2dma ( len dmaaddr ) + srp srp-len + ( len dmaaddr descaddr ) + dup >r x! r> 8 + ( len descaddr+8 ) + dup 0 swap l! 4 + ( len descaddr+c ) + l! + srp-len 10 + to srp-len +; + +: srp-prep-cmd-read ( addr len srplun -- ) + srp-prep-cmd-io + 01 srp >srp-cmd-buf-fmt c! \ in direct buffer + 1 srp >srp-cmd-din-desc-cnt c! +; + +: srp-prep-cmd-write ( addr len srplun -- ) + srp-prep-cmd-io + 10 srp >srp-cmd-buf-fmt c! \ out direct buffer + 1 srp >srp-cmd-dout-desc-cnt c! +; + +: srp-send-cmd ( -- ) + vscsi-debug? IF + ." VSCSI: Sending SCSI cmd " srp >srp-cmd-cdb c@ . cr + THEN + srp srp-len srp-send-crq +; + +: srp-rsp-find-sense ( -- addr len true | false ) + srp >srp-rsp-flags c@ SRP_RSP_FLAG_SNSVALID and 0= IF + false EXIT + THEN + \ XXX FIXME: We assume the sense data is right at response + \ data. A different server might actually have both + \ some response data we need to skip *and* some sense + \ data. + srp >srp-rsp-data srp >srp-rsp-sense-len l@ true +; + +\ Wait for a response to the last sent SRP command +\ returns a SCSI status code or -1 (HW error). +\ +: srp-wait-rsp ( -- stat ) + srp-wait-crq not IF false EXIT THEN + dup 1 <> IF + ." VSCSI: Invalid CRQ response tag, want 1 got " . cr + -1 EXIT + THEN drop + + srp >srp-rsp-tag x@ dup 1 <> IF + ." VSCSI: Invalid SRP response tag, want 1 got " . cr + -1 EXIT + THEN drop + + srp >srp-rsp-status c@ + vscsi-debug? IF + ." VSCSI: Got response status: " + dup .status-text cr + THEN +; + +\ ----------------------------------------------------------- +\ Perform SCSI commands +\ ----------------------------------------------------------- + +8000000000000000 INSTANCE VALUE current-target + +\ SCSI command. We do *NOT* implement the "standard" execute-command +\ because that doesn't have a way to return the sense buffer back, and +\ we do have auto-sense with some hosts. Instead we implement a made-up +\ do-scsi-command. +\ +\ Note: stat is -1 for "hw error" (ie, error queuing the command or +\ getting the response). +\ +\ A sense buffer is returned whenever the status is non-0 however +\ if sense-len is 0 then no sense data is actually present +\ + +: execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) + ( ... [ sense-buf sense-len ] stat ) + \ Stash command addr & len + >r >r ( buf-addr buf-len dir ) + \ Command has no data ? + over 0= IF + 3drop current-target srp-prep-cmd-nodata + ELSE + \ Command is a read ? + current-target swap IF srp-prep-cmd-read ELSE srp-prep-cmd-write THEN + THEN + \ Recover command and copy it to our srp buffer + r> r> + srp >srp-cmd-cdb swap move + srp-send-cmd + srp-wait-rsp + + \ Check for HW error + dup -1 = IF + 0 0 rot EXIT + THEN + + \ Other error status + dup 0<> IF + srp-rsp-find-sense IF + vscsi-debug? IF + over scsi-get-sense-data + ." VSCSI: Sense key [ " dup . ." ] " .sense-text + ." ASC,ASCQ: " . . cr + THEN + ELSE 0 0 + \ This relies on auto-sense from qemu... if that isn't always the + \ case we should request sense here + ." VSCSI: No sense data" cr + THEN + rot + THEN +; + +\ -------------------------------- +\ Include the generic host helpers +\ -------------------------------- + +" scsi-host-helpers.fs" included + +TRUE VALUE first-time-init? +0 VALUE open-count + +\ Cleanup behind us +: vscsi-cleanup + vscsi-debug? IF ." VSCSI: Cleaning up" cr THEN + crq-cleanup + + \ Disable TCE bypass: + vscsi-unit 0 rtas-set-tce-bypass +; + +\ Initialize our vscsi instance +: vscsi-init ( -- true | false ) + vscsi-debug? IF ." VSCSI: Initializing" cr THEN + + my-unit to vscsi-unit + + \ Enable TCE bypass special qemu feature + vscsi-unit 1 rtas-set-tce-bypass + + \ Initialize CRQ + crq-init 0 <> IF false EXIT THEN + + \ Send init command + " "(C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00)" drop + crq-send not IF + ." VSCSI: Error sending init command" + crq-cleanup false EXIT + THEN + + \ Wait reply + crq-wait not IF + crq-cleanup false EXIT + THEN + + \ Check init reply + crq c@ c0 <> crq 1 + c@ 02 <> or IF + ." VSCSI: Initial handshake failed" + crq-cleanup false EXIT + THEN + + \ We should now login etc.. but we really don't need to + \ with our qemu model + + \ Ensure we cleanup after booting + first-time-init? IF + ['] vscsi-cleanup add-quiesce-xt + false to first-time-init? + THEN + + true +; + +: open + vscsi-debug? IF ." VSCSI: Opening (count is " open-count . ." )" cr THEN + + open-count 0= IF + vscsi-init IF + 1 to open-count true + ELSE ." VSCSI initialization failed !" cr false THEN + ELSE + open-count 1 + to open-count + true + THEN +; + +: close + vscsi-debug? IF ." VSCSI: Closing (count is " open-count . ." )" cr THEN + + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + vscsi-cleanup + THEN + THEN +; + +\ ----------------------------------------------------------- +\ SCSI scan at boot and child device support +\ ----------------------------------------------------------- + +\ We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun +\ in the top 16 bits of the 64-bit LUN +: (set-target) + to current-target +; + +: dev-generate-srplun ( target lun -- ) + swap 8 << 8000 or or 30 << +; + +\ We obtain here a unit address on the stack, since our #address-cells +\ is 2, the 64-bit srplun is split in two cells that we need to join +\ +\ Note: This diverges a bit from the original OF scsi spec as the two +\ cells are the 2 words of a 64-bit SRP LUN +: set-address ( srplun.lo srplun.hi -- ) + lxjoin (set-target) +; + +\ We set max-transfer to a fixed value for now to avoid problems +\ with some CD-ROM drives. +\ FIXME: Check max transfer coming from VSCSI +: max-transfer ( -- n ) + 10000 \ Larger value seem to have problems with some CDROMs +; + +8 CONSTANT #dev +: dev-max-target ( -- #max-target ) + #dev +; + +" scsi-probe-helpers.fs" included + +\ Remove scsi functions from word list +scsi-close + +: setup-alias + " scsi" find-alias 0= IF + " scsi" get-node node>path set-alias + ELSE + drop + THEN +; + +: vscsi-init-and-scan ( -- ) + \ Create instance for scanning: + 0 0 get-node open-node ?dup 0= IF EXIT THEN + my-self >r + dup to my-self + \ Scan the VSCSI bus: + scsi-find-disks + setup-alias + \ Close the temporary instance: + close-node + r> to my-self +; + +: vscsi-add-disk + " scsi-disk.fs" included +; + +vscsi-add-disk +vscsi-init-and-scan diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-block.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-block.fs new file mode 100644 index 000000000..ea388fb00 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/virtio-block.fs @@ -0,0 +1,89 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ." Populating " pwd cr + +s" block" device-type + +FALSE VALUE initialized? + +\ Required interface for deblocker + +200 VALUE block-size +8000 CONSTANT max-transfer + +INSTANCE VARIABLE deblocker + +/vd-len BUFFER: virtiodev +virtiodev virtio-setup-vd + +\ Quiesce the virtqueue of this device so that no more background +\ transactions can be pending. +: shutdown ( -- ) + initialized? IF + my-phandle node>path open-dev ?dup IF + virtiodev virtio-blk-shutdown + close-dev + THEN + FALSE to initialized? + THEN +; + +\ Basic device initialization - which has only to be done once +: init ( -- ) + virtiodev virtio-blk-init to block-size + TRUE to initialized? + ['] shutdown add-quiesce-xt +; + +\ Read multiple blocks - called by deblocker package +: read-blocks ( addr block# #blocks -- #read ) + virtiodev virtio-blk-read +; + +\ Standard node "open" function +: open ( -- okay? ) + open 0= IF false EXIT THEN + dup initialized? 0= AND IF + init + THEN + 0 0 s" deblocker" $open-package dup deblocker ! dup IF + s" disk-label" find-package IF + my-args rot interpose + THEN + THEN + 0<> +; + +\ Standard node "close" function +: close ( -- ) + deblocker @ close-package + close +; + +\ Standard node "seek" function +: seek ( pos.lo pos.hi -- status ) + s" seek" deblocker @ $call-method +; + +\ Standard node "read" function +: read ( addr len -- actual ) + s" read" deblocker @ $call-method +; + +\ Set disk alias if none is set yet +: (set-alias) + s" disk" get-next-alias ?dup IF + get-node node>path set-alias + THEN +; +(set-alias) diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs new file mode 100644 index 000000000..8632b465f --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/virtio-fs.fs @@ -0,0 +1,96 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +." Populating " pwd cr + +s" network" device-type + +0 VALUE virtfs-rx-buffer +0 VALUE virtfs-tx-buffer +FALSE VALUE initialized? + +2000 CONSTANT VIRTFS-BUF-SIZE \ 8k + +/vd-len BUFFER: virtiodev +virtiodev virtio-setup-vd + +\ +\ Support methods. + +: shutdown ( -- ) + initialized? 0= IF EXIT THEN + virtiodev virtio-fs-shutdown + virtfs-rx-buffer VIRTFS-BUF-SIZE free-mem + virtfs-tx-buffer VIRTFS-BUF-SIZE free-mem + FALSE to initialized? +; + +: init ( -- success ) + VIRTFS-BUF-SIZE alloc-mem to virtfs-rx-buffer + VIRTFS-BUF-SIZE alloc-mem to virtfs-tx-buffer + + virtiodev ( dev ) + virtfs-tx-buffer ( dev tx ) + virtfs-rx-buffer ( reg tx rx ) + VIRTFS-BUF-SIZE ( reg tx rx size ) + virtio-fs-init ( success ) + + dup IF + TRUE to initialized? + ['] shutdown add-quiesce-xt + THEN +; + +\ +\ Standard network interface. + +: open ( -- okay? ) + open 0= IF false EXIT THEN + initialized? 0= IF + init 0= IF false EXIT THEN + THEN + true +; + +: load ( addr -- len ) + virtiodev swap ( dev addr ) + my-args ( dev addr str strlen ) + 1 + \ hack to make the following allocate 1 more byte + \-to-/ \ convert path elements + 1 - 2dup + 0 swap c! drop + virtio-fs-load ( length ) +; + +: close ( -- ) + initialized? IF + shutdown + THEN + close +; + +: ping ( -- ) + cr s" ping not supported for this device" type cr cr +; + + +: (set-alias) + " virtfs" find-alias 0= IF + " virtfs" get-node node>path set-alias + ELSE + drop + THEN +; + +\ +\ Init the module. + +(set-alias) diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-net.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-net.fs new file mode 100644 index 000000000..412b34fa6 --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/virtio-net.fs @@ -0,0 +1,96 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ." Populating " pwd cr + +s" network" device-type + +INSTANCE VARIABLE obp-tftp-package + +/vd-len BUFFER: virtiodev +virtiodev virtio-setup-vd +0 VALUE virtio-net-priv +0 VALUE open-count + +: open ( -- okay? ) + open-count 0= IF + open IF + \ my-unit 1 rtas-set-tce-bypass + s" local-mac-address" get-node get-property not IF + virtiodev virtio-net-open dup not IF ." virtio-net-open failed" EXIT THEN + drop TO virtio-net-priv + THEN + true + ELSE + false + THEN + ELSE + true + THEN + my-args s" obp-tftp" $open-package obp-tftp-package ! + open-count 1 + to open-count +; + + +: close ( -- ) + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + virtio-net-priv virtio-net-close + \ my-unit 0 rtas-set-tce-bypass + close + THEN + THEN + s" close" obp-tftp-package @ $call-method +; + +: read ( buf len -- actual ) + dup IF + virtio-net-read + ELSE + nip + THEN +; + +: write ( buf len -- actual ) + dup IF + virtio-net-write + ELSE + nip + THEN +; + +: load ( addr -- len ) + s" load" obp-tftp-package @ $call-method +; + +: ping ( -- ) + s" ping" obp-tftp-package @ $call-method +; + +\ Set up MAC address from config virtqueue +6 BUFFER: local-mac +: setup-mac ( -- ) + 6 0 DO + virtiodev i 1 virtio-get-config + local-mac i + c! + LOOP + local-mac 6 encode-bytes s" local-mac-address" property +; +setup-mac + +: setup-alias ( -- ) + " net" get-next-alias ?dup IF + get-node node>path set-alias + THEN +; +setup-alias diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs b/qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs new file mode 100644 index 000000000..ca5fb13aa --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/virtio-scsi.fs @@ -0,0 +1,232 @@ +\ ***************************************************************************** +\ * Copyright (c) 2012 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +." Populating " pwd cr + +FALSE CONSTANT virtio-scsi-debug + +2 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +: decode-unit 2 hex64-decode-unit ; +: encode-unit 2 hex64-encode-unit ; + +FALSE VALUE initialized? + +/vd-len BUFFER: virtiodev +virtiodev virtio-setup-vd + +STRUCT \ virtio-scsi-config + /l FIELD vs-cfg>num-queues + /l FIELD vs-cfg>seg-max + /l FIELD vs-cfg>max-sectors + /l FIELD vs-cfg>cmd-per-lun + /l FIELD vs-cfg>event-info-size + /l FIELD vs-cfg>sense_size + /l FIELD vs-cfg>cdb-size + /w FIELD vs-cfg>max-channel + /w FIELD vs-cfg>max-target + /l FIELD vs-cfg>max-lun +CONSTANT vs-cfg-length + +STRUCT \ virtio-scsi-req + 8 FIELD vs-req>lun + 8 FIELD vs-req>tag + /c FIELD vs-req>task-attr + /c FIELD vs-req>prio + /c FIELD vs-req>crn + 20 FIELD vs-req>cdb +CONSTANT vs-req-length + +STRUCT \ virtio-scsi-resp + /l FIELD vs-rsp>sense-len + /l FIELD vs-rsp>residual + /w FIELD vs-rsp>status-qualifier + /c FIELD vs-rsp>status + /c FIELD vs-rsp>response + 60 FIELD vs-rsp>sense +CONSTANT vs-rsp-length + +CREATE vs-req vs-req-length allot +CREATE vs-rsp vs-rsp-length allot + +scsi-open + +\ ----------------------------------------------------------- +\ Perform SCSI commands +\ ----------------------------------------------------------- + +0 INSTANCE VALUE current-target + +\ SCSI command. We do *NOT* implement the "standard" execute-command +\ because that doesn't have a way to return the sense buffer back, and +\ we do have auto-sense with some hosts. Instead we implement a made-up +\ do-scsi-command. +\ +\ Note: stat is -1 for "hw error" (ie, error queuing the command or +\ getting the response). +\ +\ A sense buffer is returned whenever the status is non-0 however +\ if sense-len is 0 then no sense data is actually present +\ + +: execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) + ( ... [ sense-buf sense-len ] stat ) + \ Cleanup virtio request and response + vs-req vs-req-length erase + vs-rsp vs-rsp-length erase + + \ Populate the request + current-target vs-req vs-req>lun x! + vs-req vs-req>cdb swap move + + \ Send it + vs-req vs-rsp virtiodev + virtio-scsi-send + + 0 <> IF + ." VIRTIO-SCSI: Queuing failure !" cr + 0 0 -1 EXIT + THEN + + \ Check virtio response + vs-rsp vs-rsp>response c@ CASE + 0 OF ENDOF \ Good + 5 OF drop 0 0 8 EXIT ENDOF \ Busy + dup OF 0 0 -1 EXIT ENDOF \ Anything else -> HW error + ENDCASE + + \ Other error status + vs-rsp vs-rsp>status c@ dup 0<> IF + vs-rsp vs-rsp>sense-len l@ dup 0= IF + \ This relies on auto-sense from qemu... if that isn't always the + \ case we should request sense here + ." VIRTIO-SCSI: No sense data" cr + 0 EXIT + THEN + vs-rsp vs-rsp>sense swap + virtio-scsi-debug IF + over scsi-get-sense-data + ." VIRTIO-SCSI: Sense key [ " dup . ." ] " .sense-text + ." ASC,ASCQ: " . . cr + THEN + rot + THEN +; + +\ -------------------------------- +\ Include the generic host helpers +\ -------------------------------- + +" scsi-host-helpers.fs" included + +\ FIXME: Check max transfer coming from virtio config +: max-transfer ( -- n ) + 10000 \ Larger value seem to have problems with some CDROMs +; + +\ ----------------------------------------------------------- +\ SCSI scan at boot and child device support +\ ----------------------------------------------------------- + +\ We use SRP luns of the form 01000000 | (target << 16) | lun +\ in the top 32 bits of the 64-bit LUN +: (set-target) + to current-target +; + +: dev-generate-srplun ( target lun-id -- srplun ) + swap 0100 or 10 << or 20 << +; + +\ We obtain here a unit address on the stack, since our #address-cells +\ is 2, the 64-bit srplun is split in two cells that we need to join +\ +\ Note: This diverges a bit from the original OF scsi spec as the two +\ cells are the 2 words of a 64-bit SRP LUN +: set-address ( srplun.lo srplun.hi -- ) + lxjoin (set-target) +; + +100 CONSTANT #target +: dev-max-target ( -- #target ) + #target +; + +" scsi-probe-helpers.fs" included + +scsi-close \ no further scsi words required + +0 VALUE queue-control-addr +0 VALUE queue-event-addr +0 VALUE queue-cmd-addr + +: setup-virt-queues + \ add 3 queues 0-controlq, 1-eventq, 2-cmdq + \ fixme: do we need to find more than the above 3 queues if exists + virtiodev 0 virtio-get-qsize virtio-vring-size + alloc-mem to queue-control-addr + virtiodev 0 queue-control-addr virtio-set-qaddr + + virtiodev 1 virtio-get-qsize virtio-vring-size + alloc-mem to queue-event-addr + virtiodev 1 queue-event-addr virtio-set-qaddr + + virtiodev 2 virtio-get-qsize virtio-vring-size + alloc-mem to queue-cmd-addr + virtiodev 2 queue-cmd-addr virtio-set-qaddr +; + +\ Set scsi alias if none is set yet +: setup-alias + s" scsi" find-alias 0= IF + s" scsi" get-node node>path set-alias + ELSE + drop + THEN +; + +: shutdown ( -- ) + initialized? IF + my-phandle node>path open-dev ?dup IF + virtiodev virtio-scsi-shutdown + close-dev + THEN + FALSE to initialized? + THEN +; + +: virtio-scsi-init-and-scan ( -- ) + \ Create instance for scanning: + 0 0 get-node open-node ?dup 0= IF ." exiting " cr EXIT THEN + my-self >r + dup to my-self + \ Scan the VSCSI bus: + virtiodev virtio-scsi-init + 0= IF + setup-virt-queues + scsi-find-disks + setup-alias + TRUE to initialized? + ['] shutdown add-quiesce-xt + THEN + \ Close the temporary instance: + close-node + r> to my-self +; + +: virtio-scsi-add-disk + " scsi-disk.fs" included +; + +virtio-scsi-add-disk +virtio-scsi-init-and-scan diff --git a/qemu/roms/SLOF/board-qemu/slof/virtio.fs b/qemu/roms/SLOF/board-qemu/slof/virtio.fs new file mode 100644 index 000000000..818c1320e --- /dev/null +++ b/qemu/roms/SLOF/board-qemu/slof/virtio.fs @@ -0,0 +1,35 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ This struct must match "struct virtio_device" in virtio.h! +STRUCT + /n FIELD vd>base + /l FIELD vd>type +CONSTANT /vd-len + + +\ Initialize virtiodev structure for the current node +: virtio-setup-vd ( vdstruct -- ) + >r + \ Does it have a "class-code" property? If yes, assume we're a PCI device + s" class-code" get-node get-property 0= IF + \ Set up for PCI device interface + 2drop + s" 10 config-l@ translate-my-address 3 not AND" evaluate + ( io-base ) r@ vd>base ! + 0 r@ vd>type l! + ELSE + ." unsupported virtio interface!" cr + 1 r@ vd>type l! + THEN + r> drop +; diff --git a/qemu/roms/SLOF/clients/.gitignore b/qemu/roms/SLOF/clients/.gitignore new file mode 100644 index 000000000..c5c20bfab --- /dev/null +++ b/qemu/roms/SLOF/clients/.gitignore @@ -0,0 +1,3 @@ +*.client +*/client +*/client.unstripped diff --git a/qemu/roms/SLOF/clients/Makefile b/qemu/roms/SLOF/clients/Makefile new file mode 100644 index 000000000..d656f08ce --- /dev/null +++ b/qemu/roms/SLOF/clients/Makefile @@ -0,0 +1,29 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include clients.mk + +all: + for dir in $(CLIENTS); do \ + if [ -r $$dir/Makefile ]; then \ + $(MAKE) -C $$dir "FLAG=$(FLAG)" || exit 1; \ + cp $$dir/client $$dir.client; \ + fi; \ + done + +clean distclean: + @for dir in $(CLIENTS); do \ + if [ -r $$dir/Makefile ]; then \ + $(MAKE) -C $$dir $@ || exit 1; \ + rm -f $$dir.client; \ + fi; \ + done diff --git a/qemu/roms/SLOF/clients/clients.mk b/qemu/roms/SLOF/clients/clients.mk new file mode 100644 index 000000000..ca741e420 --- /dev/null +++ b/qemu/roms/SLOF/clients/clients.mk @@ -0,0 +1,13 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +CLIENTS = net-snk diff --git a/qemu/roms/SLOF/clients/net-snk/Makefile b/qemu/roms/SLOF/clients/net-snk/Makefile new file mode 100644 index 000000000..c0bb73a52 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/Makefile @@ -0,0 +1,66 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOP=$(shell pwd) +export TOP +include $(TOP)/make.rules + +OBJS = kernel/kernel.o oflib/oflib.o libc/libc-glue.o app/app.o +.PHONY : subdirs clean depend mrproper + +CLIENTLIBS = $(LIBCMNDIR)/libelf.a $(LIBCMNDIR)/libc.a + +all: .depend subdirs + $(MAKE) client + +client : $(OBJS) $(CLIENTLIBS) + $(LD) $(LDFLAGS) -o $@ -Tclient.lds $(OBJS) $(CLIENTLIBS) + cp $@ $@.unstripped + $(STRIP) --strip-unneeded $@ + +client.dis: client + $(OBJDUMP) -DSsx client.unstripped > $@ + +sec-client : subdirs $(OBJS) $(LIBCMNDIR)/libc.a + $(LD) $(LDFLAGS) -o $@ -Tsec-client.lds $(OBJS) $(LIBCMNDIR)/libc.a + +subdirs : + @for dir in $(dir $(OBJS)); do \ + $(MAKE) -C $$dir || exit 1; \ + done + +$(LIBCMNDIR)/%.a: + $(MAKE) -C $(LIBCMNDIR) $(@:$(LIBCMNDIR)/%.a=%) + +clean: + @for dir in $(dir $(OBJS)); do \ + $(MAKE) -C $$dir clean; \ + done + rm -f $(OBJS) client diag netboot sec-client net-diag \ + *.dis client.unstripped fpga-client + +mrproper : clean + $(MAKE) -C app mrproper + $(MAKE) -C libc mrproper + $(MAKE) -C kernel mrproper + $(MAKE) -C oflib mrproper + find -name .*.bak | xargs rm -rf + $(RM) .depend + +distclean: mrproper + +depend .depend: + $(MAKE) -C app depend + $(MAKE) -C libc depend + $(MAKE) -C kernel depend + $(MAKE) -C oflib depend + touch .depend diff --git a/qemu/roms/SLOF/clients/net-snk/app/Makefile b/qemu/roms/SLOF/clients/net-snk/app/Makefile new file mode 100644 index 000000000..8b0c08f19 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/Makefile @@ -0,0 +1,51 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP +TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) +export TOP +endif +include $(TOP)/make.rules + +CFLAGS +=$(ADDCFLAGS) + +OBJS = main.o +OBJDIRS = netlib/netlib.o netapps/netboot.o +OBJDIRS += netapps/ping.o +OBJDIRS += netapps/args.o + +ifeq ($(SNK_BIOSEMU_APPS), 1) +OBJDIRS += biosemu/biosemu_app.o +CFLAGS += -DSNK_BIOSEMU_APPS +endif + +SUBDIRS = $(dir $(OBJDIRS)) + +all: subdirs + $(MAKE) app.o + +subdirs: + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \ + done + +app.o: $(OBJS) $(OBJDIRS) + $(LD) $(LDFLAGS) $(OBJDIRS) $(OBJS) -o $@ -r + +clean : + $(RM) -f *.o *.a *.i + for dir in $(SUBDIRS); do \ + $(CLEAN) ; \ + $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \ + done + +include $(TOP)/make.depend diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/Makefile b/qemu/roms/SLOF/clients/net-snk/app/biosemu/Makefile new file mode 100644 index 000000000..3a07ada31 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/Makefile @@ -0,0 +1,38 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +CFLAGS += -I$(ROOTDIR)/other-licence/x86emu -I$(ROOTDIR)/other-licence/x86emu/include + +OBJS = biosemu.o debug.o device.o mem.o io.o interrupt.o vbe.o +LIBX86EMU = $(ROOTDIR)/other-licence/x86emu/libx86emu.a + +.PHONY: $(LIBX86EMU) + +all: biosemu_app.o + +# special rule for libx86emu.a +$(LIBX86EMU): + $(MAKE) -C $(dir $@) + +biosemu_app.o: $(OBJS) $(LIBX86EMU) + $(LD) $(LDFLAGS) $^ -o $@ -r + +clean: + $(RM) -f *.o *.a *.i *.s + +include $(TOP)/make.depend diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/biosemu.c b/qemu/roms/SLOF/clients/net-snk/app/biosemu/biosemu.c new file mode 100644 index 000000000..82a763acf --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/biosemu.c @@ -0,0 +1,345 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <stdint.h> +#include <cpu.h> + +#include "debug.h" + +#include <x86emu/x86emu.h> +#include <x86emu/regs.h> +#include <x86emu/prim_ops.h> // for push_word + +#include "biosemu.h" +#include "io.h" +#include "mem.h" +#include "interrupt.h" +#include "device.h" + +#include <rtas.h> + + +static X86EMU_memFuncs my_mem_funcs = { + my_rdb, my_rdw, my_rdl, + my_wrb, my_wrw, my_wrl +}; + +static X86EMU_pioFuncs my_pio_funcs = { + my_inb, my_inw, my_inl, + my_outb, my_outw, my_outl +}; + +void dump(uint8_t * addr, uint32_t len); + +uint32_t +biosemu(char argc, char **argv) +{ + uint8_t *rom_image; + int i = 0; + uint8_t *biosmem; + uint32_t biosmem_size; +#ifdef DEBUG + //debug_flags = DEBUG_PRINT_INT10 | DEBUG_PNP;// | DEBUG_PMM;// | DEBUG_INTR | DEBUG_CHECK_VMEM_ACCESS | DEBUG_MEM | DEBUG_IO;// | DEBUG_TRACE_X86EMU | DEBUG_JMP; +#endif + if (argc < 4) { + printf("Usage %s <vmem_base> <vmem_size> <device_path> [<debug_flags>]\n", argv[0]); + for (i = 0; i < argc; i++) { + printf("argv[%d]: %s\n", i, argv[i]); + } + return -1; + } + // argv[1] is address of virtual BIOS mem... + // argv[2] is the size + biosmem = (uint8_t *) strtoul(argv[1], 0, 16); + biosmem_size = strtoul(argv[2], 0, 16); + if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) { + printf("Error: Not enough virtual memory: %x, required: %x!\n", + biosmem_size, MIN_REQUIRED_VMEM_SIZE); + return -1; + } + // argv[3] is the device to open and use... + if (dev_init(argv[3]) != 0) { + printf("Error initializing device!\n"); + return -1; + } + if (dev_check_exprom() != 0) { + printf("Error: Device Expansion ROM invalid!\n"); + return -1; + } + // argv[4] if set, is additional debug_flags + if (argc >= 5) { + debug_flags |= strtoul(argv[4], 0, 16); + printf("debug_flags: %x\n", debug_flags); + } + rom_image = (uint8_t *) bios_device.img_addr; + DEBUG_PRINTF("executing rom_image from %p\n", rom_image); + DEBUG_PRINTF("biosmem at %p\n", biosmem); + + DEBUG_PRINTF("Image Size: %d\n", bios_device.img_size); + + // in case we jump somewhere unexpected, or execution is finished, + // fill the biosmem with hlt instructions (0xf4) + memset(biosmem, 0xf4, biosmem_size); + + M.mem_base = (long) biosmem; + M.mem_size = biosmem_size; + DEBUG_PRINTF("membase set: %08x, size: %08x\n", (int) M.mem_base, + (int) M.mem_size); + + // copy expansion ROM image to segment OPTION_ROM_CODE_SEGMENT + // NOTE: this sometimes fails, some bytes are 0x00... so we compare + // after copying and do some retries... + uint8_t *mem_img = biosmem + (OPTION_ROM_CODE_SEGMENT << 4); + uint8_t copy_count = 0; + uint8_t cmp_result = 0; + do { +#if 0 + set_ci(); + memcpy(mem_img, rom_image, len); + clr_ci(); +#else + // memcpy fails... try copy byte-by-byte with set/clr_ci + uint8_t c; + for (i = 0; i < bios_device.img_size; i++) { + set_ci(); + c = *(rom_image + i); + if (c != *(rom_image + i)) { + clr_ci(); + printf("Copy failed at: %x/%x\n", i, + bios_device.img_size); + printf("rom_image(%x): %x, mem_img(%x): %x\n", + i, *(rom_image + i), i, *(mem_img + i)); + break; + } + clr_ci(); + *(mem_img + i) = c; + } +#endif + copy_count++; + set_ci(); + cmp_result = memcmp(mem_img, rom_image, bios_device.img_size); + clr_ci(); + } + while ((copy_count < 5) && (cmp_result != 0)); + if (cmp_result != 0) { + printf + ("\nCopying Expansion ROM Image to Memory failed after %d retries! (%x)\n", + copy_count, cmp_result); + dump(rom_image, 0x20); + dump(mem_img, 0x20); + return 0; + } + // setup default Interrupt Vectors + // some expansion ROMs seem to check for these addresses.. + // each handler is only an IRET (0xCF) instruction + // ROM BIOS Int 10 Handler F000:F065 + my_wrl(0x10 * 4, 0xf000f065); + my_wrb(0x000ff065, 0xcf); + // ROM BIOS Int 11 Handler F000:F84D + my_wrl(0x11 * 4, 0xf000f84d); + my_wrb(0x000ff84d, 0xcf); + // ROM BIOS Int 12 Handler F000:F841 + my_wrl(0x12 * 4, 0xf000f841); + my_wrb(0x000ff841, 0xcf); + // ROM BIOS Int 13 Handler F000:EC59 + my_wrl(0x13 * 4, 0xf000ec59); + my_wrb(0x000fec59, 0xcf); + // ROM BIOS Int 14 Handler F000:E739 + my_wrl(0x14 * 4, 0xf000e739); + my_wrb(0x000fe739, 0xcf); + // ROM BIOS Int 15 Handler F000:F859 + my_wrl(0x15 * 4, 0xf000f859); + my_wrb(0x000ff859, 0xcf); + // ROM BIOS Int 16 Handler F000:E82E + my_wrl(0x16 * 4, 0xf000e82e); + my_wrb(0x000fe82e, 0xcf); + // ROM BIOS Int 17 Handler F000:EFD2 + my_wrl(0x17 * 4, 0xf000efd2); + my_wrb(0x000fefd2, 0xcf); + // ROM BIOS Int 1A Handler F000:FE6E + my_wrl(0x1a * 4, 0xf000fe6e); + my_wrb(0x000ffe6e, 0xcf); + + // setup BIOS Data Area (0000:04xx, or 0040:00xx) + // we currently 0 this area, meaning "we dont have + // any hardware" :-) no serial/parallel ports, floppys, ... + memset(biosmem + 0x400, 0x0, 0x100); + + // at offset 13h in BDA is the memory size in kbytes + my_wrw(0x413, biosmem_size / 1024); + // at offset 0eh in BDA is the segment of the Extended BIOS Data Area + // see setup further down + my_wrw(0x40e, INITIAL_EBDA_SEGMENT); + // TODO: setup BDA Video Data ( offset 49h-66h) + // e.g. to store video mode, cursor position, ... + // in int10 (done) handler and VBE Functions + + // TODO: setup BDA Fixed Disk Data + // 74h: Fixed Disk Last Operation Status + // 75h: Fixed Disk Number of Disk Drives + + // TODO: check BDA for further needed data... + + //setup Extended BIOS Data Area + //we currently 0 this area + memset(biosmem + (INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE); + // at offset 0h in EBDA is the size of the EBDA in KB + my_wrw((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024); + //TODO: check for further needed EBDA data... + + // setup original ROM BIOS Area (F000:xxxx) + char *date = "06/11/99"; + for (i = 0; date[i]; i++) + my_wrb(0xffff5 + i, date[i]); + // set up eisa ident string + char *ident = "PCI_ISA"; + for (i = 0; ident[i]; i++) + my_wrb(0xfffd9 + i, ident[i]); + + // write system model id for IBM-AT + // according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515, + // model FC is the original AT and also used in all DOSEMU Versions. + my_wrb(0xFFFFE, 0xfc); + + //setup interrupt handler + X86EMU_intrFuncs intrFuncs[256]; + for (i = 0; i < 256; i++) + intrFuncs[i] = handleInterrupt; + X86EMU_setupIntrFuncs(intrFuncs); + X86EMU_setupPioFuncs(&my_pio_funcs); + X86EMU_setupMemFuncs(&my_mem_funcs); + + // setup the CPU + M.x86.R_AH = bios_device.bus; + M.x86.R_AL = bios_device.devfn; + M.x86.R_DX = 0x80; + M.x86.R_EIP = 3; + M.x86.R_CS = OPTION_ROM_CODE_SEGMENT; + + // Initialize stack and data segment + M.x86.R_SS = STACK_SEGMENT; + M.x86.R_SP = STACK_START_OFFSET; + M.x86.R_DS = DATA_SEGMENT; + + // push a HLT instruction and a pointer to it onto the stack + // any return will pop the pointer and jump to the HLT, thus + // exiting (more or less) cleanly + push_word(0xf4f4); //F4=HLT + push_word(M.x86.R_SS); + push_word(M.x86.R_SP + 2); + + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } else { +#ifdef DEBUG + M.x86.debug |= DEBUG_SAVE_IP_CS_F; + M.x86.debug |= DEBUG_DECODE_F; + M.x86.debug |= DEBUG_DECODE_NOPRINT_F; +#endif + } + CHECK_DBG(DEBUG_JMP) { + M.x86.debug |= DEBUG_TRACEJMP_F; + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACECALL_F; + M.x86.debug |= DEBUG_TRACECALL_REGS_F; + } + + DEBUG_PRINTF("Executing Initialization Vector...\n"); + X86EMU_exec(); + DEBUG_PRINTF("done\n"); + + // according to PNP BIOS Spec, Option ROMs should upon exit, return some boot device status in + // AX (see PNP BIOS Spec Section 3.3 + DEBUG_PRINTF_CS_IP("Option ROM Exit Status: %04x\n", M.x86.R_AX); +#ifdef DEBUG + DEBUG_PRINTF("Exit Status Decode:\n"); + if (M.x86.R_AX & 0x100) { // bit 8 + DEBUG_PRINTF + (" IPL Device supporting INT 13h Block Device Format:\n"); + switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 + case 0: + DEBUG_PRINTF(" No IPL Device attached\n"); + break; + case 1: + DEBUG_PRINTF(" IPL Device status unknown\n"); + break; + case 2: + DEBUG_PRINTF(" IPL Device attached\n"); + break; + case 3: + DEBUG_PRINTF(" IPL Device status RESERVED!!\n"); + break; + } + } + if (M.x86.R_AX & 0x80) { // bit 7 + DEBUG_PRINTF + (" Output Device supporting INT 10h Character Output:\n"); + switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 + case 0: + DEBUG_PRINTF(" No Display Device attached\n"); + break; + case 1: + DEBUG_PRINTF(" Display Device status unknown\n"); + break; + case 2: + DEBUG_PRINTF(" Display Device attached\n"); + break; + case 3: + DEBUG_PRINTF(" Display Device status RESERVED!!\n"); + break; + } + } + if (M.x86.R_AX & 0x40) { // bit 6 + DEBUG_PRINTF + (" Input Device supporting INT 9h Character Input:\n"); + switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 + case 0: + DEBUG_PRINTF(" No Input Device attached\n"); + break; + case 1: + DEBUG_PRINTF(" Input Device status unknown\n"); + break; + case 2: + DEBUG_PRINTF(" Input Device attached\n"); + break; + case 3: + DEBUG_PRINTF(" Input Device status RESERVED!!\n"); + break; + } + } +#endif + // check wether the stack is "clean" i.e. containing the HLT instruction + // we pushed before executing, and pointing to the original stack address... + // indicating that the initialization probably was successful + if ((pop_word() == 0xf4f4) && (M.x86.R_SS == STACK_SEGMENT) + && (M.x86.R_SP == STACK_START_OFFSET)) { + DEBUG_PRINTF("Stack is clean, initialization successful!\n"); + } else { + DEBUG_PRINTF + ("Stack unclean, initialization probably NOT COMPLETE!!!\n"); + DEBUG_PRINTF("SS:SP = %04x:%04x, expected: %04x:%04x\n", + M.x86.R_SS, M.x86.R_SP, STACK_SEGMENT, + STACK_START_OFFSET); + } + + + // TODO: according to the BIOS Boot Spec initializations may be ended using INT18h and setting + // the status. + // We need to implement INT18 accordingly, pseudo code is in specsbbs101.pdf page 30 + // (also for Int19) + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/biosemu.h b/qemu/roms/SLOF/clients/net-snk/app/biosemu/biosemu.h new file mode 100644 index 000000000..28b7ab881 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/biosemu.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _BIOSEMU_BIOSEMU_H_ +#define _BIOSEMU_BIOSEMU_H_ + +#define MIN_REQUIRED_VMEM_SIZE 0x100000 // 1MB + +//define default segments for different components +#define STACK_SEGMENT 0x1000 //1000:xxxx +#define STACK_START_OFFSET 0xfffe + +#define DATA_SEGMENT 0x2000 +#define VBE_SEGMENT 0x3000 + +#define PMM_CONV_SEGMENT 0x4000 // 4000:xxxx is PMM conventional memory area, extended memory area + // will be anything beyound MIN_REQUIRED_MEMORY_SIZE +#define PNP_DATA_SEGMENT 0x5000 + +#define OPTION_ROM_CODE_SEGMENT 0xc000 + +#define BIOS_DATA_SEGMENT 0xF000 +// both EBDA values are _initial_ values, they may (and will be) changed at runtime by option ROMs!! +#define INITIAL_EBDA_SEGMENT 0xF600 // segment of the Extended BIOS Data Area +#define INITIAL_EBDA_SIZE 0x400 // size of the EBDA (at least 1KB!! since size is stored in KB!) + +#define PMM_INT_NUM 0xFC // we misuse INT FC for PMM functionality, at the PMM Entry Point + // Address, there will only be a call to this INT and a RETF +#define PNP_INT_NUM 0xFD + +uint32_t biosemu(char argc, char **argv); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/debug.c b/qemu/roms/SLOF/clients/net-snk/app/biosemu/debug.c new file mode 100644 index 000000000..2fce24497 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/debug.c @@ -0,0 +1,55 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> + +#include "debug.h" + +uint32_t debug_flags = 0; + +void +dump(uint8_t * addr, uint32_t len) +{ + printf("\n\r%s(%p, %x):\n", __FUNCTION__, addr, len); + while (len) { + unsigned int tmpCnt = len; + unsigned char x; + if (tmpCnt > 8) + tmpCnt = 8; + printf("\n\r%p: ", addr); + // print hex + while (tmpCnt--) { + set_ci(); + x = *addr++; + clr_ci(); + printf("%02x ", x); + } + tmpCnt = len; + if (tmpCnt > 8) + tmpCnt = 8; + len -= tmpCnt; + //reset addr ptr to print ascii + addr = addr - tmpCnt; + // print ascii + while (tmpCnt--) { + set_ci(); + x = *addr++; + clr_ci(); + if ((x < 32) || (x >= 127)) { + //non-printable char + x = '.'; + } + printf("%c", x); + } + } + printf("\n"); +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/debug.h b/qemu/roms/SLOF/clients/net-snk/app/biosemu/debug.h new file mode 100644 index 000000000..46a026ae6 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/debug.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef _BIOSEMU_DEBUG_H_ +#define _BIOSEMU_DEBUG_H_ + +#include <stdio.h> +#include <stdint.h> + +extern uint32_t debug_flags; +// from x86emu...needed for debugging +extern void x86emu_dump_xregs(void); + +#define DEBUG_IO 0x1 +#define DEBUG_MEM 0x2 +// set this to print messages for certain virtual memory accesses (Interrupt Vectors, ...) +#define DEBUG_CHECK_VMEM_ACCESS 0x4 +#define DEBUG_INTR 0x8 +#define DEBUG_PRINT_INT10 0x10 // set to have the INT10 routine print characters +#define DEBUG_VBE 0x20 +#define DEBUG_PMM 0x40 +#define DEBUG_DISK 0x80 +#define DEBUG_PNP 0x100 + +#define DEBUG_TRACE_X86EMU 0x1000 +// set to enable tracing of JMPs in x86emu +#define DEBUG_JMP 0x2000 + +//#define DEBUG +#ifdef DEBUG + +#define CHECK_DBG(_flag) if (debug_flags & _flag) + +#define DEBUG_PRINTF(_x...) printf(_x); +// prints the CS:IP before the printout, NOTE: actually its CS:IP of the _next_ instruction +// to be executed, since the x86emu advances CS:IP _before_ actually executing an instruction +#define DEBUG_PRINTF_CS_IP(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x); + +#define DEBUG_PRINTF_IO(_x...) CHECK_DBG(DEBUG_IO) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_MEM(_x...) CHECK_DBG(DEBUG_MEM) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_INTR(_x...) CHECK_DBG(DEBUG_INTR) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_VBE(_x...) CHECK_DBG(DEBUG_VBE) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_PMM(_x...) CHECK_DBG(DEBUG_PMM) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_DISK(_x...) CHECK_DBG(DEBUG_DISK) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_PNP(_x...) CHECK_DBG(DEBUG_PNP) { DEBUG_PRINTF_CS_IP(_x) } + +#else + +#define CHECK_DBG(_flag) if (0) + +#define DEBUG_PRINTF(_x...) +#define DEBUG_PRINTF_CS_IP(_x...) + +#define DEBUG_PRINTF_IO(_x...) +#define DEBUG_PRINTF_MEM(_x...) +#define DEBUG_PRINTF_INTR(_x...) +#define DEBUG_PRINTF_VBE(_x...) +#define DEBUG_PRINTF_PMM(_x...) +#define DEBUG_PRINTF_DISK(_x...) +#define DEBUG_PRINTF_PNP(_x...) + +#endif //DEBUG + +void dump(uint8_t * addr, uint32_t len); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/device.c b/qemu/roms/SLOF/clients/net-snk/app/biosemu/device.c new file mode 100644 index 000000000..514b87e62 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/device.c @@ -0,0 +1,324 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "device.h" +#include "rtas.h" +#include <stdio.h> +#include <string.h> +#include <of.h> // use translate_address_dev and get_puid from net-snk +#include "debug.h" + +typedef struct { + uint8_t info; + uint8_t bus; + uint8_t devfn; + uint8_t cfg_space_offset; + uint64_t address; + uint64_t size; +} __attribute__ ((__packed__)) assigned_address_t; + + +// scan all adresses assigned to the device ("assigned-addresses" and "reg") +// store in translate_address_array for faster translation using dev_translate_address +static void +dev_get_addr_info(void) +{ + // get bus/dev/fn from assigned-addresses + int32_t len; + //max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges + assigned_address_t buf[11]; + len = + of_getprop(bios_device.phandle, "assigned-addresses", buf, + sizeof(buf)); + bios_device.bus = buf[0].bus; + bios_device.devfn = buf[0].devfn; + DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus, + bios_device.devfn); + //store address translations for all assigned-addresses and regs in + //translate_address_array for faster translation later on... + int i = 0; + // index to insert data into translate_address_array + int taa_index = 0; + uint64_t address_offset; + for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) { + //copy all info stored in assigned-addresses + translate_address_array[taa_index].info = buf[i].info; + translate_address_array[taa_index].bus = buf[i].bus; + translate_address_array[taa_index].devfn = buf[i].devfn; + translate_address_array[taa_index].cfg_space_offset = + buf[i].cfg_space_offset; + translate_address_array[taa_index].address = buf[i].address; + translate_address_array[taa_index].size = buf[i].size; + // translate first address and store it as address_offset + address_offset = buf[i].address; + translate_address_dev(&address_offset, bios_device.phandle); + translate_address_array[taa_index].address_offset = + address_offset - buf[i].address; + } + //get "reg" property + len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf)); + for (i = 0; i < (len / sizeof(assigned_address_t)); i++) { + if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) { + // we dont care for ranges with size 0 and + // BARs and Expansion ROM must be in assigned-addresses... so in reg + // we only look for those without config space offset set... + // i.e. the legacy ranges + continue; + } + //copy all info stored in assigned-addresses + translate_address_array[taa_index].info = buf[i].info; + translate_address_array[taa_index].bus = buf[i].bus; + translate_address_array[taa_index].devfn = buf[i].devfn; + translate_address_array[taa_index].cfg_space_offset = + buf[i].cfg_space_offset; + translate_address_array[taa_index].address = buf[i].address; + translate_address_array[taa_index].size = buf[i].size; + // translate first address and store it as address_offset + address_offset = buf[i].address; + translate_address_dev(&address_offset, bios_device.phandle); + translate_address_array[taa_index].address_offset = + address_offset - buf[i].address; + taa_index++; + } + // store last entry index of translate_address_array + taa_last_entry = taa_index - 1; +#ifdef DEBUG + //dump translate_address_array + printf("translate_address_array: \n"); + translate_address_t ta; + for (i = 0; i <= taa_last_entry; i++) { + ta = translate_address_array[i]; + printf + ("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n", + i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset, + ta.address, ta.address_offset, ta.size); + } +#endif +} + +// to simulate accesses to legacy VGA Memory (0xA0000-0xBFFFF) +// we look for the first prefetchable memory BAR, if no prefetchable BAR found, +// we use the first memory BAR +// dev_translate_addr will translate accesses to the legacy VGA Memory into the found vmem BAR +static void +dev_find_vmem_addr(void) +{ + int i = 0; + translate_address_t ta; + int8_t tai_np = -1, tai_p = -1; // translate_address_array index for non-prefetchable and prefetchable memory + //search backwards to find first entry + for (i = taa_last_entry; i >= 0; i--) { + ta = translate_address_array[i]; + if ((ta.cfg_space_offset >= 0x10) + && (ta.cfg_space_offset <= 0x24)) { + //only BARs + if ((ta.info & 0x03) >= 0x02) { + //32/64bit memory + tai_np = i; + if ((ta.info & 0x40) != 0) { + // prefetchable + tai_p = i; + } + } + } + } + if (tai_p != -1) { + ta = translate_address_array[tai_p]; + bios_device.vmem_addr = ta.address; + bios_device.vmem_size = ta.size; + DEBUG_PRINTF + ("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n", + __FUNCTION__, bios_device.vmem_addr, + bios_device.vmem_size); + } else if (tai_np != -1) { + ta = translate_address_array[tai_np]; + bios_device.vmem_addr = ta.address; + bios_device.vmem_size = ta.size; + DEBUG_PRINTF + ("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx", + __FUNCTION__, bios_device.vmem_addr, + bios_device.vmem_size); + } + // disable vmem + //bios_device.vmem_size = 0; +} + +static void +dev_get_puid(void) +{ + // get puid + bios_device.puid = get_puid(bios_device.phandle); + DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid); +} + +static void +dev_get_device_vendor_id(void) +{ + uint32_t pci_config_0 = + rtas_pci_config_read(bios_device.puid, 4, bios_device.bus, + bios_device.devfn, 0x0); + bios_device.pci_device_id = + (uint16_t) ((pci_config_0 & 0xFFFF0000) >> 16); + bios_device.pci_vendor_id = (uint16_t) (pci_config_0 & 0x0000FFFF); + DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n", + bios_device.pci_device_id, bios_device.pci_vendor_id); +} + +/* check, wether the device has a valid Expansion ROM, also search the PCI Data Structure and + * any Expansion ROM Header (using dev_scan_exp_header()) for needed information */ +uint8_t +dev_check_exprom(void) +{ + int i = 0; + translate_address_t ta; + uint64_t rom_base_addr = 0; + uint16_t pci_ds_offset; + pci_data_struct_t pci_ds; + // check for ExpROM Address (Offset 30) in taa + for (i = 0; i <= taa_last_entry; i++) { + ta = translate_address_array[i]; + if (ta.cfg_space_offset == 0x30) { + rom_base_addr = ta.address + ta.address_offset; //translated address + break; + } + } + // in the ROM there could be multiple Expansion ROM Images... start searching + // them for a x86 image + do { + if (rom_base_addr == 0) { + printf("Error: no Expansion ROM address found!\n"); + return -1; + } + set_ci(); + uint16_t rom_signature = *((uint16_t *) rom_base_addr); + clr_ci(); + if (rom_signature != 0x55aa) { + printf + ("Error: invalid Expansion ROM signature: %02x!\n", + *((uint16_t *) rom_base_addr)); + return -1; + } + set_ci(); + // at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure + pci_ds_offset = in16le((void *) (rom_base_addr + 0x18)); + //copy the PCI Data Structure + memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset), + sizeof(pci_ds)); + clr_ci(); +#ifdef DEBUG + DEBUG_PRINTF("PCI Data Structure @%llx:\n", + rom_base_addr + pci_ds_offset); + dump((void *) &pci_ds, sizeof(pci_ds)); +#endif + if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) { + printf("Invalid PCI Data Structure found!\n"); + break; + } + //little-endian conversion + pci_ds.vendor_id = in16le(&pci_ds.vendor_id); + pci_ds.device_id = in16le(&pci_ds.device_id); + pci_ds.img_length = in16le(&pci_ds.img_length); + pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length); + if (pci_ds.vendor_id != bios_device.pci_vendor_id) { + printf + ("Image has invalid Vendor ID: %04x, expected: %04x\n", + pci_ds.vendor_id, bios_device.pci_vendor_id); + break; + } + if (pci_ds.device_id != bios_device.pci_device_id) { + printf + ("Image has invalid Device ID: %04x, expected: %04x\n", + pci_ds.device_id, bios_device.pci_device_id); + break; + } + //DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512); + //DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type); + if (pci_ds.code_type == 0) { + //x86 image + //store image address and image length in bios_device struct + bios_device.img_addr = rom_base_addr; + bios_device.img_size = pci_ds.img_length * 512; + // we found the image, exit the loop + break; + } else { + // no x86 image, check next image (if any) + rom_base_addr += pci_ds.img_length * 512; + } + if ((pci_ds.indicator & 0x80) == 0x80) { + //last image found, exit the loop + DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n"); + break; + } + } + while (bios_device.img_addr == 0); + // in case we did not find a valid x86 Expansion ROM Image + if (bios_device.img_addr == 0) { + printf("Error: no valid x86 Expansion ROM Image found!\n"); + return -1; + } + return 0; +} + +uint8_t +dev_init(char *device_name) +{ + uint8_t rval = 0; + //init bios_device struct + DEBUG_PRINTF("%s(%s)\n", __FUNCTION__, device_name); + memset(&bios_device, 0, sizeof(bios_device)); + bios_device.ihandle = of_open(device_name); + if (bios_device.ihandle == 0) { + DEBUG_PRINTF("%s is no valid device!\n", device_name); + return -1; + } + bios_device.phandle = of_finddevice(device_name); + dev_get_addr_info(); + dev_find_vmem_addr(); + dev_get_puid(); + dev_get_device_vendor_id(); + return rval; +} + +// translate address function using translate_address_array assembled +// by dev_get_addr_info... MUCH faster than calling translate_address_dev +// and accessing client interface for every translation... +// returns: 0 if addr not found in translate_address_array, 1 if found. +uint8_t +dev_translate_address(uint64_t * addr) +{ + int i = 0; + translate_address_t ta; + //check if it is an access to legacy VGA Mem... if it is, map the address + //to the vmem BAR and then translate it... + // (translation info provided by Ben Herrenschmidt) + // NOTE: the translation seems to only work for NVIDIA cards... but it is needed + // to make some NVIDIA cards work at all... + if ((bios_device.vmem_size > 0) + && ((*addr >= 0xA0000) && (*addr < 0xB8000))) { + *addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr; + } + if ((bios_device.vmem_size > 0) + && ((*addr >= 0xB8000) && (*addr < 0xC0000))) { + uint8_t shift = *addr & 1; + *addr &= 0xfffffffe; + *addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr; + } + for (i = 0; i <= taa_last_entry; i++) { + ta = translate_address_array[i]; + if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size))) { + *addr += ta.address_offset; + return 1; + } + } + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/device.h b/qemu/roms/SLOF/clients/net-snk/app/biosemu/device.h new file mode 100644 index 000000000..425dd3caf --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/device.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef DEVICE_LIB_H +#define DEVICE_LIB_H + +#include <stdint.h> +#include <cpu.h> +#include "of.h" +#include <stdio.h> + +// a Expansion Header Struct as defined in Plug and Play BIOS Spec 1.0a Chapter 3.2 +typedef struct { + char signature[4]; // signature + uint8_t structure_revision; + uint8_t length; // in 16 byte blocks + uint16_t next_header_offset; // offset to next Expansion Header as 16bit little-endian value, as offset from the start of the Expansion ROM + uint8_t reserved; + uint8_t checksum; // the sum of all bytes of the Expansion Header must be 0 + uint32_t device_id; // PnP Device ID as 32bit little-endian value + uint16_t p_manufacturer_string; //16bit little-endian offset from start of Expansion ROM + uint16_t p_product_string; //16bit little-endian offset from start of Expansion ROM + uint8_t device_base_type; + uint8_t device_sub_type; + uint8_t device_if_type; + uint8_t device_indicators; + // the following vectors are all 16bit little-endian offsets from start of Expansion ROM + uint16_t bcv; // Boot Connection Vector + uint16_t dv; // Disconnect Vector + uint16_t bev; // Bootstrap Entry Vector + uint16_t reserved_2; + uint16_t sriv; // Static Resource Information Vector +} __attribute__ ((__packed__)) exp_header_struct_t; + +// a PCI Data Struct as defined in PCI 2.3 Spec Chapter 6.3.1.2 +typedef struct { + uint8_t signature[4]; // signature, the String "PCIR" + uint16_t vendor_id; + uint16_t device_id; + uint16_t reserved; + uint16_t pci_ds_length; // PCI Data Structure Length, 16bit little-endian value + uint8_t pci_ds_revision; + uint8_t class_code[3]; + uint16_t img_length; // length of the Exp.ROM Image, 16bit little-endian value in 512 bytes + uint16_t img_revision; + uint8_t code_type; + uint8_t indicator; + uint16_t reserved_2; +} __attribute__ ((__packed__)) pci_data_struct_t; + +typedef struct { + uint8_t bus; + uint8_t devfn; + uint64_t puid; + phandle_t phandle; + ihandle_t ihandle; + // store the address of the BAR that is used to simulate + // legacy VGA memory accesses + uint64_t vmem_addr; + uint64_t vmem_size; + // used to buffer I/O Accesses, that do not access the I/O Range of the device... + // 64k might be overkill, but we can buffer all I/O accesses... + uint8_t io_buffer[64 * 1024]; + uint16_t pci_vendor_id; + uint16_t pci_device_id; + // translated address of the "PC-Compatible" Expansion ROM Image for this device + uint64_t img_addr; + uint32_t img_size; // size of the Expansion ROM Image (read from the PCI Data Structure) +} device_t; + +typedef struct { + uint8_t info; + uint8_t bus; + uint8_t devfn; + uint8_t cfg_space_offset; + uint64_t address; + uint64_t address_offset; + uint64_t size; +} __attribute__ ((__packed__)) translate_address_t; + +// array to store address translations for this +// device. Needed for faster address translation, so +// not every I/O or Memory Access needs to call translate_address_dev +// and access the device tree +// 6 BARs, 1 Exp. ROM, 1 Cfg.Space, and 3 Legacy +// translations are supported... this should be enough for +// most devices... for VGA it is enough anyways... +translate_address_t translate_address_array[11]; + +// index of last translate_address_array entry +// set by get_dev_addr_info function +uint8_t taa_last_entry; + +device_t bios_device; + +uint8_t dev_init(char *device_name); +// NOTE: for dev_check_exprom to work, dev_init MUST be called first! +uint8_t dev_check_exprom(void); + +uint8_t dev_translate_address(uint64_t * addr); + +/* endianness swap functions for 16 and 32 bit words + * copied from axon_pciconfig.c + */ +static inline void +out32le(void *addr, uint32_t val) +{ + asm volatile ("stwbrx %0, 0, %1"::"r" (val), "r"(addr)); +} + +static inline uint32_t +in32le(void *addr) +{ + uint32_t val; + const uint32_t *zaddr = addr; + asm volatile ("lwbrx %0, %y1" : "=r"(val) : "Z"(*zaddr)); + return val; +} + +static inline void +out16le(void *addr, uint16_t val) +{ + asm volatile ("sthbrx %0, 0, %1"::"r" (val), "r"(addr)); +} + +static inline uint16_t +in16le(void *addr) +{ + uint16_t val; + const uint16_t *zaddr = addr; + asm volatile ("lhbrx %0, %y1" : "=r"(val) : "Z"(*zaddr)); + return val; +} + +/* debug function, dumps HID1 and HID4 to detect wether caches are on/off */ +static inline void +dumpHID(void) +{ + uint64_t hid; + //HID1 = 1009 + __asm__ __volatile__("mfspr %0, 1009":"=r"(hid)); + printf("HID1: %016llx\n", hid); + //HID4 = 1012 + __asm__ __volatile__("mfspr %0, 1012":"=r"(hid)); + printf("HID4: %016llx\n", hid); +} + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/interrupt.c b/qemu/roms/SLOF/clients/net-snk/app/biosemu/interrupt.c new file mode 100644 index 000000000..ac3f5b430 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/interrupt.c @@ -0,0 +1,606 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> + +#include <rtas.h> + +#include "biosemu.h" +#include "mem.h" +#include "device.h" +#include "debug.h" +#include "interrupt.h" + +#include <x86emu/x86emu.h> +#include <x86emu/prim_ops.h> + + + +//setup to run the code at the address, that the Interrupt Vector points to... +static void +setupInt(int intNum) +{ + DEBUG_PRINTF_INTR("%s(%x): executing interrupt handler @%08x\n", + __FUNCTION__, intNum, my_rdl(intNum * 4)); + // push current R_FLG... will be popped by IRET + push_word((u16) M.x86.R_FLG); + CLEAR_FLAG(F_IF); + CLEAR_FLAG(F_TF); + // push current CS:IP to the stack, will be popped by IRET + push_word(M.x86.R_CS); + push_word(M.x86.R_IP); + // set CS:IP to the interrupt handler address... so the next executed instruction will + // be the interrupt handler + M.x86.R_CS = my_rdw(intNum * 4 + 2); + M.x86.R_IP = my_rdw(intNum * 4); +} + +// handle int10 (VGA BIOS Interrupt) +static void +handleInt10(void) +{ + // the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h + // function number in AH + //DEBUG_PRINTF_CS_IP("%s:\n", __FUNCTION__); + //x86emu_dump_xregs(); + //if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){ + //X86EMU_trace_on(); + //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + //} + switch (M.x86.R_AH) { + case 0x00: + // set video mode + // BDA offset 49h is current video mode + my_wrb(0x449, M.x86.R_AL); + if (M.x86.R_AL > 7) + M.x86.R_AL = 0x20; + else if (M.x86.R_AL == 6) + M.x86.R_AL = 0x3f; + else + M.x86.R_AL = 0x30; + break; + case 0x01: + // set cursor shape + // ignore + break; + case 0x02: + // set cursor position + // BH: pagenumber, DX: cursor_pos (DH:row, DL:col) + // BDA offset 50h-60h are 8 cursor position words for + // eight possible video pages + my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX); + break; + case 0x03: + //get cursor position + // BH: pagenumber + // BDA offset 50h-60h are 8 cursor position words for + // eight possible video pages + M.x86.R_AX = 0; + M.x86.R_CH = 0; // start scan line ??? + M.x86.R_CL = 0; // end scan line ??? + M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2)); + break; + case 0x05: + // set active page + // BDA offset 62h is current page number + my_wrb(0x462, M.x86.R_AL); + break; + case 0x06: + //scroll up windows + break; + case 0x07: + //scroll down windows + break; + case 0x08: + //read character and attribute at position + M.x86.R_AH = 0x07; // white-on-black + M.x86.R_AL = 0x20; // a space... + break; + case 0x09: + // write character and attribute + //AL: char, BH: page number, BL: attribute, CX: number of times to write + //BDA offset 62h is current page number + CHECK_DBG(DEBUG_PRINT_INT10) { + uint32_t i = 0; + if (M.x86.R_BH == my_rdb(0x462)) { + for (i = 0; i < M.x86.R_CX; i++) + printf("%c", M.x86.R_AL); + } + } + break; + case 0x0a: + // write character + //AL: char, BH: page number, BL: attribute, CX: number of times to write + //BDA offset 62h is current page number + CHECK_DBG(DEBUG_PRINT_INT10) { + uint32_t i = 0; + if (M.x86.R_BH == my_rdb(0x462)) { + for (i = 0; i < M.x86.R_CX; i++) + printf("%c", M.x86.R_AL); + } + } + break; + case 0x0e: + // teletype output: write character and advance cursor... + //AL: char, BH: page number, BL: attribute + //BDA offset 62h is current page number + CHECK_DBG(DEBUG_PRINT_INT10) { + // we ignore the pagenumber on this call... + //if (M.x86.R_BH == my_rdb(0x462)) + { + printf("%c", M.x86.R_AL); + // for debugging, to read all lines + //if (M.x86.R_AL == 0xd) // carriage return + // printf("\n"); + } + } + break; + case 0x0f: + // get video mode + // BDA offset 49h is current video mode + // BDA offset 62h is current page number + // BDA offset 4ah is columns on screen + M.x86.R_AH = 80; //number of character columns... we hardcode it to 80 + M.x86.R_AL = my_rdb(0x449); + M.x86.R_BH = my_rdb(0x462); + break; + default: + printf("%s(): unknown function (%x) for int10 handler.\n", + __FUNCTION__, M.x86.R_AH); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); + HALT_SYS(); + break; + } +} + +// this table translates ASCII chars into their XT scan codes: +static uint8_t keycode_table[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 - 7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8 - 15 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 23 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 - 31 + 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, // 32 - 39 + 0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35, // 40 - 47 + 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 48 - 55 + 0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35, // 56 - 63 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64 - 71 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72 - 79 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 87 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 95 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 103 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 104 - 111 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112 - 119 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 - 127 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static void +translate_keycode(uint64_t * keycode) +{ + uint8_t scan_code = 0; + uint8_t char_code = 0; + if (*keycode < 256) { + scan_code = keycode_table[*keycode]; + char_code = (uint8_t) * keycode & 0xff; + } else { + switch (*keycode) { + case 0x1b50: + // F1 + scan_code = 0x3b; + char_code = 0x0; + break; + default: + printf("%s(): unknown multibyte keycode: %llx\n", + __FUNCTION__, *keycode); + break; + } + } + //assemble scan/char code in keycode + *keycode = (uint64_t) ((((uint16_t) scan_code) << 8) | char_code); +} + +// handle int16 (Keyboard BIOS Interrupt) +static void +handleInt16(void) +{ + // keyboard buffer is in BIOS Memory Area: + // offset 0x1a (WORD) pointer to next char in keybuffer + // offset 0x1c (WORD) pointer to next insert slot in keybuffer + // offset 0x1e-0x3e: 16 WORD Ring Buffer + // since we currently always read the char from the FW buffer, + // we misuse the ring buffer, we use it as pointer to a uint64_t that stores + // multi-byte keys (e.g. special keys in VT100 terminal) + // and as long as a key is available (not 0) we dont read further keys + uint64_t *keycode = (uint64_t *) (M.mem_base + 0x41e); + int8_t c; + // function number in AH + DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n", + __FUNCTION__, M.x86.R_AH); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX, + M.x86.R_BX, M.x86.R_CX, M.x86.R_DX); + switch (M.x86.R_AH) { + case 0x00: + // get keystroke + if (*keycode) { + M.x86.R_AX = (uint16_t) * keycode; + // clear keycode + *keycode = 0; + } else { + M.x86.R_AH = 0x61; // scancode for space key + M.x86.R_AL = 0x20; // a space + } + break; + case 0x01: + // check keystroke + // ZF set = no keystroke + // read first byte of key code + if (*keycode) { + // already read, but not yet taken + CLEAR_FLAG(F_ZF); + M.x86.R_AX = (uint16_t) * keycode; + } else { + c = getchar(); + if (c == -1) { + // no key available + SET_FLAG(F_ZF); + } else { + *keycode = c; + + // since after an ESC it may take a while to receive the next char, + // we send something that is not shown on the screen, and then try to get + // the next char + // TODO: only after ESC?? what about other multibyte keys + printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace + + while ((c = getchar()) != -1) { + *keycode = (*keycode << 8) | c; + DEBUG_PRINTF(" key read: %0llx\n", + *keycode); + } + translate_keycode(keycode); + DEBUG_PRINTF(" translated key: %0llx\n", + *keycode); + if (*keycode == 0) { + //not found + SET_FLAG(F_ZF); + } else { + CLEAR_FLAG(F_ZF); + M.x86.R_AX = (uint16_t) * keycode; + //X86EMU_trace_on(); + //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + } + } + } + break; + default: + printf("%s(): unknown function (%x) for int16 handler.\n", + __FUNCTION__, M.x86.R_AH); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); + HALT_SYS(); + break; + } +} + +// handle int1a (PCI BIOS Interrupt) +static void +handleInt1a(void) +{ + // function number in AX + uint8_t bus, devfn, offs; + switch (M.x86.R_AX) { + case 0xb101: + // Installation check + CLEAR_FLAG(F_CF); // clear CF + M.x86.R_EDX = 0x20494350; // " ICP" endian swapped "PCI " + M.x86.R_AL = 0x1; // Config Space Mechanism 1 supported + M.x86.R_BX = 0x0210; // PCI Interface Level Version 2.10 + M.x86.R_CL = 0xff; // number of last PCI Bus in system TODO: check! + break; + case 0xb102: + // Find PCI Device + // NOTE: we currently only allow the device to find itself... + // it SHOULD be all we ever need... + // device_id in CX, vendor_id in DX + // device index in SI (i.e. if multiple devices with same vendor/device id + // are connected). We currently only support device index 0 + DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n", + __FUNCTION__, M.x86.R_AX); + if ((M.x86.R_CX == bios_device.pci_device_id) + && (M.x86.R_DX == bios_device.pci_vendor_id) + // device index must be 0 + && (M.x86.R_SI == 0)) { + CLEAR_FLAG(F_CF); + M.x86.R_AH = 0x00; // return code: success + M.x86.R_BH = bios_device.bus; + M.x86.R_BL = bios_device.devfn; + DEBUG_PRINTF_INTR + ("%s(): function %x: PCI Find Device --> 0x%04x\n", + __FUNCTION__, M.x86.R_AX, M.x86.R_BX); + } else { + DEBUG_PRINTF_INTR + ("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/0) \n", + __FUNCTION__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX, + M.x86.R_SI, bios_device.pci_device_id, + bios_device.pci_vendor_id); + SET_FLAG(F_CF); + M.x86.R_AH = 0x86; // return code: device not found + } + break; + case 0xb108: //read configuration byte + case 0xb109: //read configuration word + case 0xb10a: //read configuration dword + bus = M.x86.R_BH; + devfn = M.x86.R_BL; + offs = M.x86.R_DI; + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... + printf + ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n", + __FUNCTION__, bus, bios_device.bus, devfn, + bios_device.devfn, offs); + SET_FLAG(F_CF); + M.x86.R_AH = 0x87; //return code: bad pci register + HALT_SYS(); + return; + } else { + switch (M.x86.R_AX) { + case 0xb108: + M.x86.R_CL = + (uint8_t) rtas_pci_config_read(bios_device. + puid, 1, + bus, devfn, + offs); + DEBUG_PRINTF_INTR + ("%s(): function %x: PCI Config Read @%02x --> 0x%02x\n", + __FUNCTION__, M.x86.R_AX, offs, + M.x86.R_CL); + break; + case 0xb109: + M.x86.R_CX = + (uint16_t) rtas_pci_config_read(bios_device. + puid, 2, + bus, devfn, + offs); + DEBUG_PRINTF_INTR + ("%s(): function %x: PCI Config Read @%02x --> 0x%04x\n", + __FUNCTION__, M.x86.R_AX, offs, + M.x86.R_CX); + break; + case 0xb10a: + M.x86.R_ECX = + (uint32_t) rtas_pci_config_read(bios_device. + puid, 4, + bus, devfn, + offs); + DEBUG_PRINTF_INTR + ("%s(): function %x: PCI Config Read @%02x --> 0x%08x\n", + __FUNCTION__, M.x86.R_AX, offs, + M.x86.R_ECX); + break; + } + CLEAR_FLAG(F_CF); + M.x86.R_AH = 0x0; // return code: success + } + break; + case 0xb10b: //write configuration byte + case 0xb10c: //write configuration word + case 0xb10d: //write configuration dword + bus = M.x86.R_BH; + devfn = M.x86.R_BL; + offs = M.x86.R_DI; + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... + printf + ("%s(): Config read access invalid! bus: %x (%x), devfn: %x (%x), offs: %x\n", + __FUNCTION__, bus, bios_device.bus, devfn, + bios_device.devfn, offs); + SET_FLAG(F_CF); + M.x86.R_AH = 0x87; //return code: bad pci register + HALT_SYS(); + return; + } else { + switch (M.x86.R_AX) { + case 0xb10b: + rtas_pci_config_write(bios_device.puid, 1, bus, + devfn, offs, M.x86.R_CL); + DEBUG_PRINTF_INTR + ("%s(): function %x: PCI Config Write @%02x <-- 0x%02x\n", + __FUNCTION__, M.x86.R_AX, offs, + M.x86.R_CL); + break; + case 0xb10c: + rtas_pci_config_write(bios_device.puid, 2, bus, + devfn, offs, M.x86.R_CX); + DEBUG_PRINTF_INTR + ("%s(): function %x: PCI Config Write @%02x <-- 0x%04x\n", + __FUNCTION__, M.x86.R_AX, offs, + M.x86.R_CX); + break; + case 0xb10d: + rtas_pci_config_write(bios_device.puid, 4, bus, + devfn, offs, M.x86.R_ECX); + DEBUG_PRINTF_INTR + ("%s(): function %x: PCI Config Write @%02x <-- 0x%08x\n", + __FUNCTION__, M.x86.R_AX, offs, + M.x86.R_ECX); + break; + } + CLEAR_FLAG(F_CF); + M.x86.R_AH = 0x0; // return code: success + } + break; + default: + printf("%s(): unknown function (%x) for int1a handler.\n", + __FUNCTION__, M.x86.R_AX); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); + HALT_SYS(); + break; + } +} + +// main Interrupt Handler routine, should be registered as x86emu interrupt handler +void +handleInterrupt(int intNum) +{ + uint8_t int_handled = 0; +#ifndef DEBUG_PRINT_INT10 + // this printf makes output by int 10 unreadable... + // so we only enable it, if int10 print is disabled + DEBUG_PRINTF_INTR("%s(%x)\n", __FUNCTION__, intNum); +#endif + switch (intNum) { + case 0x10: //BIOS video interrupt + case 0x42: // INT 10h relocated by EGA/VGA BIOS + case 0x6d: // INT 10h relocated by VGA BIOS + // get interrupt vector from IDT (4 bytes per Interrupt starting at address 0 + if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address + (my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid + { +#if 0 + // ignore interrupt... + DEBUG_PRINTF_INTR + ("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n", + __FUNCTION__, intNum, my_rdl(intNum * 4)); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); + //HALT_SYS(); +#endif + handleInt10(); + int_handled = 1; + } + break; + case 0x16: + // Keyboard BIOS Interrupt + handleInt16(); + int_handled = 1; + break; + case 0x1a: + // PCI BIOS Interrupt + handleInt1a(); + int_handled = 1; + break; + default: + printf("Interrupt %#x (Vector: %x) not implemented\n", intNum, + my_rdl(intNum * 4)); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); + int_handled = 1; + HALT_SYS(); + break; + } + // if we did not handle the interrupt, jump to the interrupt vector... + if (!int_handled) { + setupInt(intNum); + } +} + +// prepare and execute Interrupt 10 (VGA Interrupt) +void +runInt10() +{ + // Initialize stack and data segment + M.x86.R_SS = STACK_SEGMENT; + M.x86.R_DS = DATA_SEGMENT; + M.x86.R_SP = STACK_START_OFFSET; + + // push a HLT instruction and a pointer to it onto the stack + // any return will pop the pointer and jump to the HLT, thus + // exiting (more or less) cleanly + push_word(0xf4f4); //F4=HLT + //push_word(M.x86.R_SS); + //push_word(M.x86.R_SP + 2); + + // setupInt will push the current CS and IP to the stack to return to it, + // but we want to halt, so set CS:IP to the HLT instruction we just pushed + // to the stack + M.x86.R_CS = M.x86.R_SS; + M.x86.R_IP = M.x86.R_SP; // + 4; + + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + CHECK_DBG(DEBUG_JMP) { + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACECALL_F; + M.x86.debug |= DEBUG_TRACECALL_REGS_F; + } + setupInt(0x10); + DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n", + __FUNCTION__); + X86EMU_exec(); + DEBUG_PRINTF_INTR("%s(): execution finished\n", __FUNCTION__); +} + +// prepare and execute Interrupt 13 (Disk Interrupt) +void +runInt13(void) +{ + // Initialize stack and data segment + M.x86.R_SS = STACK_SEGMENT; + M.x86.R_DS = DATA_SEGMENT; + M.x86.R_SP = STACK_START_OFFSET; + + // push a HLT instruction and a pointer to it onto the stack + // any return will pop the pointer and jump to the HLT, thus + // exiting (more or less) cleanly + push_word(0xf4f4); //F4=HLT + //push_word(M.x86.R_SS); + //push_word(M.x86.R_SP + 2); + + // setupInt will push the current CS and IP to the stack to return to it, + // but we want to halt, so set CS:IP to the HLT instruction we just pushed + // to the stack + M.x86.R_CS = M.x86.R_SS; + M.x86.R_IP = M.x86.R_SP; + + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + CHECK_DBG(DEBUG_JMP) { + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACECALL_F; + M.x86.debug |= DEBUG_TRACECALL_REGS_F; + } + + setupInt(0x13); + DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n", + __FUNCTION__); + X86EMU_exec(); + DEBUG_PRINTF_INTR("%s(): execution finished\n", __FUNCTION__); +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/interrupt.h b/qemu/roms/SLOF/clients/net-snk/app/biosemu/interrupt.h new file mode 100644 index 000000000..11755e102 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/interrupt.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef _BIOSEMU_INTERRUPT_H_ +#define _BIOSEMU_INTERRUPT_H_ + +void handleInterrupt(int intNum); + +void runInt10(void); + +void runInt13(void); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/io.c b/qemu/roms/SLOF/clients/net-snk/app/biosemu/io.c new file mode 100644 index 000000000..e9c08932a --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/io.c @@ -0,0 +1,382 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <cpu.h> +#include <pci.h> +#include "device.h" +#include "rtas.h" +#include "debug.h" +#include "device.h" +#include <stdint.h> +#include <x86emu/x86emu.h> +#include <time.h> +#include "io.h" + +//defined in net-snk/kernel/timer.c +extern uint64_t get_time(void); + +uint32_t pci_cfg_read(X86EMU_pioAddr addr, uint8_t size); +void pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size); +uint8_t handle_port_61h(void); + +uint8_t +my_inb(X86EMU_pioAddr addr) +{ + uint8_t rval = 0xFF; + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__, + addr); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + rval = read_io((void *)translated_addr, 1); + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __FUNCTION__, + addr, rval); + return rval; + } else { + switch (addr) { + case 0x61: + //8254 KB Controller / Timer Port + rval = handle_port_61h(); + //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __FUNCTION__, addr, rval); + return rval; + break; + case 0xCFC: + case 0xCFD: + case 0xCFE: + case 0xCFF: + // PCI Config Mechanism 1 Ports + return (uint8_t) pci_cfg_read(addr, 1); + break; + case 0x0a: + CHECK_DBG(DEBUG_INTR) { + X86EMU_trace_on(); + } + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + //HALT_SYS(); + // no break, intentional fall-through to default!! + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __FUNCTION__, addr); + rval = *((uint8_t *) (bios_device.io_buffer + addr)); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n", + __FUNCTION__, addr, rval); + return rval; + break; + } + } +} + +uint16_t +my_inw(X86EMU_pioAddr addr) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__, + addr); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + uint16_t rval; + if ((translated_addr & (uint64_t) 0x1) == 0) { + // 16 bit aligned access... + uint16_t tempval = read_io((void *)translated_addr, 2); + //little endian conversion + rval = in16le((void *) &tempval); + } else { + // unaligned access, read single bytes, little-endian + rval = (read_io((void *)translated_addr, 1) << 8) + | (read_io((void *)(translated_addr + 1), 1)); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __FUNCTION__, + addr, rval); + return rval; + } else { + switch (addr) { + case 0xCFC: + case 0xCFE: + //PCI Config Mechanism 1 + return (uint16_t) pci_cfg_read(addr, 2); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __FUNCTION__, addr); + uint16_t rval = + in16le((void *) bios_device.io_buffer + addr); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n", + __FUNCTION__, addr, rval); + return rval; + break; + } + } +} + +uint32_t +my_inl(X86EMU_pioAddr addr) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__, + addr); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + uint32_t rval; + if ((translated_addr & (uint64_t) 0x3) == 0) { + // 32 bit aligned access... + uint32_t tempval = read_io((void *) translated_addr, 4); + //little endian conversion + rval = in32le((void *) &tempval); + } else { + // unaligned access, read single bytes, little-endian + rval = (read_io((void *)(translated_addr), 1) << 24) + | (read_io((void *)(translated_addr + 1), 1) << 16) + | (read_io((void *)(translated_addr + 2), 1) << 8) + | (read_io((void *)(translated_addr + 3), 1)); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __FUNCTION__, + addr, rval); + return rval; + } else { + switch (addr) { + case 0xCFC: + //PCI Config Mechanism 1 + return pci_cfg_read(addr, 4); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __FUNCTION__, addr); + uint32_t rval = + in32le((void *) bios_device.io_buffer + addr); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n", + __FUNCTION__, addr, rval); + return rval; + break; + } + } +} + +void +my_outb(X86EMU_pioAddr addr, uint8_t val) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __FUNCTION__, addr, val); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + write_io((void *) translated_addr, val, 1); + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __FUNCTION__, + addr, val); + } else { + switch (addr) { + case 0xCFC: + case 0xCFD: + case 0xCFE: + case 0xCFF: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 1); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%02x) writing to bios_device.io_buffer\n", + __FUNCTION__, addr, val); + *((uint8_t *) (bios_device.io_buffer + addr)) = val; + break; + } + } +} + +void +my_outw(X86EMU_pioAddr addr, uint16_t val) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __FUNCTION__, addr, val); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + if ((translated_addr & (uint64_t) 0x1) == 0) { + // little-endian conversion + uint16_t tempval = in16le((void *) &val); + // 16 bit aligned access... + write_io((void *) translated_addr, tempval, 2); + } else { + // unaligned access, write single bytes, little-endian + write_io(((void *) (translated_addr + 1)), + (uint8_t) ((val & 0xFF00) >> 8), 1); + write_io(((void *) translated_addr), + (uint8_t) (val & 0x00FF), 1); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __FUNCTION__, + addr, val); + } else { + switch (addr) { + case 0xCFC: + case 0xCFE: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 2); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%04x) writing to bios_device.io_buffer\n", + __FUNCTION__, addr, val); + out16le((void *) bios_device.io_buffer + addr, val); + break; + } + } +} + +void +my_outl(X86EMU_pioAddr addr, uint32_t val) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __FUNCTION__, addr, val); + //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + if ((translated_addr & (uint64_t) 0x3) == 0) { + // little-endian conversion + uint32_t tempval = in32le((void *) &val); + // 32 bit aligned access... + write_io((void *) translated_addr, tempval, 4); + } else { + // unaligned access, write single bytes, little-endian + write_io(((void *) translated_addr + 3), + (uint8_t) ((val & 0xFF000000) >> 24), 1); + write_io(((void *) translated_addr + 2), + (uint8_t) ((val & 0x00FF0000) >> 16), 1); + write_io(((void *) translated_addr + 1), + (uint8_t) ((val & 0x0000FF00) >> 8), 1); + write_io(((void *) translated_addr), + (uint8_t) (val & 0x000000FF), 1); + } + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __FUNCTION__, + addr, val); + } else { + switch (addr) { + case 0xCFC: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 4); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%08x) writing to bios_device.io_buffer\n", + __FUNCTION__, addr, val); + out32le((void *) bios_device.io_buffer + addr, val); + break; + } + } +} + +uint32_t +pci_cfg_read(X86EMU_pioAddr addr, uint8_t size) +{ + uint32_t rval = 0xFFFFFFFF; + if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) { + // PCI Configuration Mechanism 1 step 1 + // write to 0xCF8, sets bus, device, function and Config Space offset + // later read from 0xCFC-0xCFF returns the value... + uint8_t bus, devfn, offs; + uint32_t port_cf8_val = my_inl(0xCF8); + if ((port_cf8_val & 0x80000000) != 0) { + //highest bit enables config space mapping + bus = (port_cf8_val & 0x00FF0000) >> 16; + devfn = (port_cf8_val & 0x0000FF00) >> 8; + offs = (port_cf8_val & 0x000000FF); + offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... + printf + ("Config access invalid! bus: %x, devfn: %x, offs: %x\n", + bus, devfn, offs); + HALT_SYS(); + } else { + rval = + (uint32_t) rtas_pci_config_read(bios_device. + puid, size, + bus, devfn, + offs); + DEBUG_PRINTF_IO + ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n", + __FUNCTION__, addr, offs, size, rval); + } + } + } + return rval; +} + +void +pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size) +{ + if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) { + // PCI Configuration Mechanism 1 step 1 + // write to 0xCF8, sets bus, device, function and Config Space offset + // later write to 0xCFC-0xCFF sets the value... + uint8_t bus, devfn, offs; + uint32_t port_cf8_val = my_inl(0xCF8); + if ((port_cf8_val & 0x80000000) != 0) { + //highest bit enables config space mapping + bus = (port_cf8_val & 0x00FF0000) >> 16; + devfn = (port_cf8_val & 0x0000FF00) >> 8; + offs = (port_cf8_val & 0x000000FF); + offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... + printf + ("Config access invalid! bus: %x, devfn: %x, offs: %x\n", + bus, devfn, offs); + HALT_SYS(); + } else { + rtas_pci_config_write(bios_device.puid, + size, bus, devfn, offs, + val); + DEBUG_PRINTF_IO + ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n", + __FUNCTION__, addr, offs, size, val); + } + } + } +} + +uint8_t +handle_port_61h(void) +{ + static uint64_t last_time = 0; + uint64_t curr_time = get_time(); + uint64_t time_diff; // time since last call + uint32_t period_ticks; // length of a period in ticks + uint32_t nr_periods; //number of periods passed since last call + // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??) + time_diff = curr_time - last_time; + // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second) + // TODO: as long as the frequency does not change, we should not calculate this every time + period_ticks = (15 * tb_freq) / 1000000; + nr_periods = time_diff / period_ticks; + // if the number if ticks passed since last call is odd, we toggle bit 4 + if ((nr_periods % 2) != 0) { + *((uint8_t *) (bios_device.io_buffer + 0x61)) ^= 0x10; + } + //finally read the value from the io_buffer + return *((uint8_t *) (bios_device.io_buffer + 0x61)); +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/io.h b/qemu/roms/SLOF/clients/net-snk/app/biosemu/io.h new file mode 100644 index 000000000..5a0bb4b4b --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/io.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _BIOSEMU_IO_H_ +#define _BIOSEMU_IO_H_ +#include <x86emu/x86emu.h> +#include <stdint.h> + +uint8_t my_inb(X86EMU_pioAddr addr); + +uint16_t my_inw(X86EMU_pioAddr addr); + +uint32_t my_inl(X86EMU_pioAddr addr); + +void my_outb(X86EMU_pioAddr addr, uint8_t val); + +void my_outw(X86EMU_pioAddr addr, uint16_t val); + +void my_outl(X86EMU_pioAddr addr, uint32_t val); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/mem.c b/qemu/roms/SLOF/clients/net-snk/app/biosemu/mem.c new file mode 100644 index 000000000..1a6207554 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/mem.c @@ -0,0 +1,464 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <stdint.h> +#include <cpu.h> +#include "debug.h" +#include "device.h" +#include "x86emu/x86emu.h" +#include "biosemu.h" +#include <time.h> +#include "mem.h" + +// define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...) +#ifdef DEBUG +static uint8_t in_check = 0; // to avoid recursion... +uint16_t ebda_segment; +uint32_t ebda_size; + +//TODO: these macros have grown so large, that they should be changed to an inline function, +//just for the sake of readability... + +//declare prototypes of the functions to follow, for use in DEBUG_CHECK_VMEM_ACCESS +uint8_t my_rdb(uint32_t); +uint16_t my_rdw(uint32_t); +uint32_t my_rdl(uint32_t); + +#define DEBUG_CHECK_VMEM_READ(_addr, _rval) \ + if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \ + in_check = 1; \ + /* determine ebda_segment and size \ + * since we are using my_rdx calls, make sure, this is after setting in_check! */ \ + /* offset 03 in BDA is EBDA segment */ \ + ebda_segment = my_rdw(0x40e); \ + /* first value in ebda is size in KB */ \ + ebda_size = my_rdb(ebda_segment << 4) * 1024; \ + /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \ + if (_addr < 0x400) { \ + DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n", \ + __FUNCTION__, _addr / 4, _rval); \ + } \ + /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \ + else if ((_addr >= 0x400) && (addr < 0x500)) { \ + DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n", \ + __FUNCTION__, _addr, _rval); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* access to first 64k of memory... */ \ + else if (_addr < 0x10000) { \ + DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n", \ + __FUNCTION__, _addr, _rval); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* read from PMM_CONV_SEGMENT */ \ + else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n", \ + __FUNCTION__, PMM_CONV_SEGMENT, _addr, _rval); \ + /* HALT_SYS(); */ \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* read from PNP_DATA_SEGMENT */ \ + else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n", \ + __FUNCTION__, PNP_DATA_SEGMENT, _addr, _rval); \ + /* HALT_SYS(); */ \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* read from EBDA Segment */ \ + else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n", \ + __FUNCTION__, ebda_segment, ebda_size, _addr, _rval); \ + } \ + /* read from BIOS_DATA_SEGMENT */ \ + else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n", \ + __FUNCTION__, BIOS_DATA_SEGMENT, _addr, _rval); \ + /* for PMM debugging */ \ + /*if (_addr == BIOS_DATA_SEGMENT << 4) { \ + X86EMU_trace_on(); \ + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; \ + }*/ \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + in_check = 0; \ + } +#define DEBUG_CHECK_VMEM_WRITE(_addr, _val) \ + if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \ + in_check = 1; \ + /* determine ebda_segment and size \ + * since we are using my_rdx calls, make sure, this is after setting in_check! */ \ + /* offset 03 in BDA is EBDA segment */ \ + ebda_segment = my_rdw(0x40e); \ + /* first value in ebda is size in KB */ \ + ebda_size = my_rdb(ebda_segment << 4) * 1024; \ + /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \ + if (_addr < 0x400) { \ + DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n", \ + __FUNCTION__, _addr / 4, _val); \ + } \ + /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \ + else if ((_addr >= 0x400) && (addr < 0x500)) { \ + DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n", \ + __FUNCTION__, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* access to first 64k of memory...*/ \ + else if (_addr < 0x10000) { \ + DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n", \ + __FUNCTION__, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to PMM_CONV_SEGMENT... */ \ + else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, PMM_CONV_SEGMENT, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to PNP_DATA_SEGMENT... */ \ + else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, PNP_DATA_SEGMENT, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to EBDA Segment... */ \ + else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n", \ + __FUNCTION__, ebda_segment, ebda_size, _addr, _val); \ + } \ + /* write to BIOS_DATA_SEGMENT... */ \ + else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, BIOS_DATA_SEGMENT, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to current CS segment... */ \ + else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, M.x86.R_CS, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + in_check = 0; \ + } +#else +#define DEBUG_CHECK_VMEM_READ(_addr, _rval) +#define DEBUG_CHECK_VMEM_WRITE(_addr, _val) +#endif + +//defined in net-snk/kernel/timer.c +extern uint64_t get_time(void); + +void update_time(uint32_t); + +// read byte from memory +uint8_t +my_rdb(uint32_t addr) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + uint8_t rval; + if (translated != 0) { + //translation successful, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n", + __FUNCTION__, addr); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + set_ci(); + rval = *((uint8_t *) translated_addr); + clr_ci(); + DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __FUNCTION__, addr, + rval); + return rval; + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __FUNCTION__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* read from virtual memory */ + rval = *((uint8_t *) (M.mem_base + addr)); + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; + } + return -1; +} + +//read word from memory +uint16_t +my_rdw(uint32_t addr) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + uint16_t rval; + if (translated != 0) { + //translation successful, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n", + __FUNCTION__, addr); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //words may not be contiguous in memory, so we need to translate + //every address... + rval = ((uint8_t) my_rdb(addr)) | + (((uint8_t) my_rdb(addr + 1)) << 8); + } else { + if ((translated_addr & (uint64_t) 0x1) == 0) { + // 16 bit aligned access... + set_ci(); + rval = in16le((void *) translated_addr); + clr_ci(); + } else { + // unaligned access, read single bytes + set_ci(); + rval = (*((uint8_t *) translated_addr)) | + (*((uint8_t *) translated_addr + 1) << 8); + clr_ci(); + } + } + DEBUG_PRINTF_MEM("%s(%08x) VGA --> %04x\n", __FUNCTION__, addr, + rval); + return rval; + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __FUNCTION__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* read from virtual memory */ + rval = in16le((void *) (M.mem_base + addr)); + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; + } + return -1; +} + +//read long from memory +uint32_t +my_rdl(uint32_t addr) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + uint32_t rval; + if (translated != 0) { + //translation successful, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n", + __FUNCTION__, addr); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //dwords may not be contiguous in memory, so we need to translate + //every address... + rval = ((uint8_t) my_rdb(addr)) | + (((uint8_t) my_rdb(addr + 1)) << 8) | + (((uint8_t) my_rdb(addr + 2)) << 16) | + (((uint8_t) my_rdb(addr + 3)) << 24); + } else { + if ((translated_addr & (uint64_t) 0x3) == 0) { + // 32 bit aligned access... + set_ci(); + rval = in32le((void *) translated_addr); + clr_ci(); + } else { + // unaligned access, read single bytes + set_ci(); + rval = (*((uint8_t *) translated_addr)) | + (*((uint8_t *) translated_addr + 1) << 8) | + (*((uint8_t *) translated_addr + 2) << 16) | + (*((uint8_t *) translated_addr + 3) << 24); + clr_ci(); + } + } + DEBUG_PRINTF_MEM("%s(%08x) VGA --> %08x\n", __FUNCTION__, addr, + rval); + //HALT_SYS(); + return rval; + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __FUNCTION__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* read from virtual memory */ + rval = in32le((void *) (M.mem_base + addr)); + switch (addr) { + case 0x46c: + //BDA Time Data, update it, before reading + update_time(rval); + rval = in32le((void *) (M.mem_base + addr)); + break; + } + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; + } + return -1; +} + +//write byte to memory +void +my_wrb(uint32_t addr, uint8_t val) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n", + __FUNCTION__, addr, val); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + set_ci(); + *((uint8_t *) translated_addr) = val; + clr_ci(); + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __FUNCTION__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); + *((uint8_t *) (M.mem_base + addr)) = val; + } +} + +void +my_wrw(uint32_t addr, uint16_t val) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n", + __FUNCTION__, addr, val); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //words may not be contiguous in memory, so we need to translate + //every address... + my_wrb(addr, (uint8_t) (val & 0x00FF)); + my_wrb(addr + 1, (uint8_t) ((val & 0xFF00) >> 8)); + } else { + if ((translated_addr & (uint64_t) 0x1) == 0) { + // 16 bit aligned access... + set_ci(); + out16le((void *) translated_addr, val); + clr_ci(); + } else { + // unaligned access, write single bytes + set_ci(); + *((uint8_t *) translated_addr) = + (uint8_t) (val & 0x00FF); + *((uint8_t *) translated_addr + 1) = + (uint8_t) ((val & 0xFF00) >> 8); + clr_ci(); + } + } + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __FUNCTION__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); + out16le((void *) (M.mem_base + addr), val); + } +} +void +my_wrl(uint32_t addr, uint32_t val) +{ + uint64_t translated_addr = addr; + uint8_t translated = dev_translate_address(&translated_addr); + if (translated != 0) { + //translation successful, access VGA Memory (BAR or Legacy...) + DEBUG_PRINTF_MEM("%s(%x, %x): access to VGA Memory\n", + __FUNCTION__, addr, val); + //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); + // check for legacy memory, because of the remapping to BARs, the reads must + // be byte reads... + if ((addr >= 0xa0000) && (addr < 0xc0000)) { + //read bytes a using my_rdb, because of the remapping to BARs + //words may not be contiguous in memory, so we need to translate + //every address... + my_wrb(addr, (uint8_t) (val & 0x000000FF)); + my_wrb(addr + 1, (uint8_t) ((val & 0x0000FF00) >> 8)); + my_wrb(addr + 2, (uint8_t) ((val & 0x00FF0000) >> 16)); + my_wrb(addr + 3, (uint8_t) ((val & 0xFF000000) >> 24)); + } else { + if ((translated_addr & (uint64_t) 0x3) == 0) { + // 32 bit aligned access... + set_ci(); + out32le((void *) translated_addr, val); + clr_ci(); + } else { + // unaligned access, write single bytes + set_ci(); + *((uint8_t *) translated_addr) = + (uint8_t) (val & 0x000000FF); + *((uint8_t *) translated_addr + 1) = + (uint8_t) ((val & 0x0000FF00) >> 8); + *((uint8_t *) translated_addr + 2) = + (uint8_t) ((val & 0x00FF0000) >> 16); + *((uint8_t *) translated_addr + 3) = + (uint8_t) ((val & 0xFF000000) >> 24); + clr_ci(); + } + } + } else if (addr > M.mem_size) { + DEBUG_PRINTF("%s(%08x): Memory Access out of range!\n", + __FUNCTION__, addr); + //disassemble_forward(M.x86.saved_cs, M.x86.saved_ip, 1); + HALT_SYS(); + } else { + /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); + out32le((void *) (M.mem_base + addr), val); + } +} + +//update time in BIOS Data Area +//DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz +//byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00 +//cur_val is the current value, of offset 6c... +void +update_time(uint32_t cur_val) +{ + //for convenience, we let the start of timebase be at midnight, we currently dont support + //real daytime anyway... + uint64_t ticks_per_day = tb_freq * 60 * 24; + // at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second) + uint32_t period_ticks = (55 * tb_freq) / 1000; + uint64_t curr_time = get_time(); + uint64_t ticks_since_midnight = curr_time % ticks_per_day; + uint32_t periods_since_midnight = ticks_since_midnight / period_ticks; + // if periods since midnight is smaller than last value, set overflow + // at BDA Offset 0x70 + if (periods_since_midnight < cur_val) { + my_wrb(0x470, 1); + } + // store periods since midnight at BDA offset 0x6c + my_wrl(0x46c, periods_since_midnight); +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/mem.h b/qemu/roms/SLOF/clients/net-snk/app/biosemu/mem.h new file mode 100644 index 000000000..f0fbad96c --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/mem.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _BIOSEMU_MEM_H_ +#define _BIOSEMU_MEM_H_ +#include <x86emu/x86emu.h> +#include <stdint.h> + +// read byte from memory +uint8_t my_rdb(uint32_t addr); + +//read word from memory +uint16_t my_rdw(uint32_t addr); + +//read long from memory +uint32_t my_rdl(uint32_t addr); + +//write byte to memory +void my_wrb(uint32_t addr, uint8_t val); + +//write word to memory +void my_wrw(uint32_t addr, uint16_t val); + +//write long to memory +void my_wrl(uint32_t addr, uint32_t val); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/vbe.c b/qemu/roms/SLOF/clients/net-snk/app/biosemu/vbe.c new file mode 100644 index 000000000..957a1f2a0 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/vbe.c @@ -0,0 +1,780 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <stdint.h> +#include <cpu.h> + +#include "debug.h" + +#include <x86emu/x86emu.h> +#include <x86emu/regs.h> +#include <x86emu/prim_ops.h> // for push_word + +#include "biosemu.h" +#include "io.h" +#include "mem.h" +#include "interrupt.h" +#include "device.h" +#include "vbe.h" + +static X86EMU_memFuncs my_mem_funcs = { + my_rdb, my_rdw, my_rdl, + my_wrb, my_wrw, my_wrl +}; + +static X86EMU_pioFuncs my_pio_funcs = { + my_inb, my_inw, my_inl, + my_outb, my_outw, my_outl +}; + +// pointer to VBEInfoBuffer, set by vbe_prepare +uint8_t *vbe_info_buffer = 0; +// virtual BIOS Memory +uint8_t *biosmem; +uint32_t biosmem_size; + +// these structs are for input from and output to OF +typedef struct { + uint8_t display_type; // 0=NONE, 1= analog, 2=digital + uint16_t screen_width; + uint16_t screen_height; + uint16_t screen_linebytes; // bytes per line in framebuffer, may be more than screen_width + uint8_t color_depth; // color depth in bpp + uint32_t framebuffer_address; + uint8_t edid_block_zero[128]; +} __attribute__ ((__packed__)) screen_info_t; + +typedef struct { + uint8_t signature[4]; + uint16_t size_reserved; + uint8_t monitor_number; + uint16_t max_screen_width; + uint8_t color_depth; +} __attribute__ ((__packed__)) screen_info_input_t; + +// these structs only store a subset of the VBE defined fields +// only those needed. +typedef struct { + char signature[4]; + uint16_t version; + uint8_t *oem_string_ptr; + uint32_t capabilities; + uint16_t video_mode_list[256]; // lets hope we never have more than 256 video modes... + uint16_t total_memory; +} vbe_info_t; + +typedef struct { + uint16_t video_mode; + uint8_t mode_info_block[256]; + uint16_t attributes; + uint16_t linebytes; + uint16_t x_resolution; + uint16_t y_resolution; + uint8_t x_charsize; + uint8_t y_charsize; + uint8_t bits_per_pixel; + uint8_t memory_model; + uint32_t framebuffer_address; +} vbe_mode_info_t; + +typedef struct { + uint8_t port_number; // i.e. monitor number + uint8_t edid_transfer_time; + uint8_t ddc_level; + uint8_t edid_block_zero[128]; +} vbe_ddc_info_t; + +static inline uint8_t +vbe_prepare(void) +{ + vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area + //clear buffer + memset(vbe_info_buffer, 0, 512); + //set VbeSignature to "VBE2" to indicate VBE 2.0+ request + vbe_info_buffer[0] = 'V'; + vbe_info_buffer[0] = 'B'; + vbe_info_buffer[0] = 'E'; + vbe_info_buffer[0] = '2'; + // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above... + M.x86.R_EDI = 0x0; + M.x86.R_ES = VBE_SEGMENT; + + return 0; // successful init +} + +// VBE Function 00h +static uint8_t +vbe_info(vbe_info_t * info) +{ + vbe_prepare(); + // call VBE function 00h (Info Function) + M.x86.R_EAX = 0x4f00; + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: VBE Info Function Return Code NOT OK! AH=%x\n", + __FUNCTION__, M.x86.R_AH); + return M.x86.R_AH; + } + //printf("VBE Info Dump:"); + //dump(vbe_info_buffer, 64); + + //offset 0: signature + info->signature[0] = vbe_info_buffer[0]; + info->signature[1] = vbe_info_buffer[1]; + info->signature[2] = vbe_info_buffer[2]; + info->signature[3] = vbe_info_buffer[3]; + + // offset 4: 16bit le containing VbeVersion + info->version = in16le(vbe_info_buffer + 4); + + // offset 6: 32bit le containg segment:offset of OEM String in virtual Mem. + info->oem_string_ptr = + biosmem + ((in16le(vbe_info_buffer + 8) << 4) + + in16le(vbe_info_buffer + 6)); + + // offset 10: 32bit le capabilities + info->capabilities = in32le(vbe_info_buffer + 10); + + // offset 14: 32 bit le containing segment:offset of supported video mode table + uint16_t *video_mode_ptr; + video_mode_ptr = + (uint16_t *) (biosmem + + ((in16le(vbe_info_buffer + 16) << 4) + + in16le(vbe_info_buffer + 14))); + uint32_t i = 0; + do { + info->video_mode_list[i] = in16le(video_mode_ptr + i); + i++; + } + while ((i < + (sizeof(info->video_mode_list) / + sizeof(info->video_mode_list[0]))) + && (info->video_mode_list[i - 1] != 0xFFFF)); + + //offset 18: 16bit le total memory in 64KB blocks + info->total_memory = in16le(vbe_info_buffer + 18); + + return 0; +} + +// VBE Function 01h +static uint8_t +vbe_get_mode_info(vbe_mode_info_t * mode_info) +{ + vbe_prepare(); + // call VBE function 01h (Return VBE Mode Info Function) + M.x86.R_EAX = 0x4f01; + M.x86.R_CX = mode_info->video_mode; + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE + ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n", + __FUNCTION__, mode_info->video_mode, M.x86.R_AH); + return M.x86.R_AH; + } + //pointer to mode_info_block is in ES:DI + memcpy(mode_info->mode_info_block, + biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI), + sizeof(mode_info->mode_info_block)); + + //printf("Mode Info Dump:"); + //dump(mode_info_block, 64); + + // offset 0: 16bit le mode attributes + mode_info->attributes = in16le(mode_info->mode_info_block); + + // offset 16: 16bit le bytes per scan line + mode_info->linebytes = in16le(mode_info->mode_info_block + 16); + + // offset 18: 16bit le x resolution + mode_info->x_resolution = in16le(mode_info->mode_info_block + 18); + + // offset 20: 16bit le y resolution + mode_info->y_resolution = in16le(mode_info->mode_info_block + 20); + + // offset 22: 8bit le x charsize + mode_info->x_charsize = *(mode_info->mode_info_block + 22); + + // offset 23: 8bit le y charsize + mode_info->y_charsize = *(mode_info->mode_info_block + 23); + + // offset 25: 8bit le bits per pixel + mode_info->bits_per_pixel = *(mode_info->mode_info_block + 25); + + // offset 27: 8bit le memory model + mode_info->memory_model = *(mode_info->mode_info_block + 27); + + // offset 40: 32bit le containg offset of frame buffer memory ptr + mode_info->framebuffer_address = + in32le(mode_info->mode_info_block + 40); + + return 0; +} + +// VBE Function 02h +static uint8_t +vbe_set_mode(vbe_mode_info_t * mode_info) +{ + vbe_prepare(); + // call VBE function 02h (Set VBE Mode Function) + M.x86.R_EAX = 0x4f02; + M.x86.R_BX = mode_info->video_mode; + M.x86.R_BX |= 0x4000; // set bit 14 to request linear framebuffer mode + M.x86.R_BX &= 0x7FFF; // clear bit 15 to request clearing of framebuffer + + DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __FUNCTION__, + M.x86.R_BX); + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE + ("%s: VBE Set Mode Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n", + __FUNCTION__, mode_info->video_mode, M.x86.R_AH); + return M.x86.R_AH; + } + return 0; +} + +//VBE Function 08h +static uint8_t +vbe_set_palette_format(uint8_t format) +{ + vbe_prepare(); + // call VBE function 09h (Set/Get Palette Data Function) + M.x86.R_EAX = 0x4f08; + M.x86.R_BL = 0x00; // set format + M.x86.R_BH = format; + + DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __FUNCTION__, + format); + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE + ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n", + __FUNCTION__, M.x86.R_AH); + return M.x86.R_AH; + } + return 0; +} + +// VBE Function 09h +static uint8_t +vbe_set_color(uint16_t color_number, uint32_t color_value) +{ + vbe_prepare(); + // call VBE function 09h (Set/Get Palette Data Function) + M.x86.R_EAX = 0x4f09; + M.x86.R_BL = 0x00; // set color + M.x86.R_CX = 0x01; // set only one entry + M.x86.R_DX = color_number; + // ES:DI is address where color_value is stored, we store it at 2000:0000 + M.x86.R_ES = 0x2000; + M.x86.R_DI = 0x0; + + // store color value at ES:DI + out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value); + + DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __FUNCTION__, + color_number, color_value); + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE + ("%s: VBE Set Palette Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n", + __FUNCTION__, M.x86.R_AH); + return M.x86.R_AH; + } + return 0; +} + +#if 0 +static uint8_t +vbe_get_color(uint16_t color_number, uint32_t * color_value) +{ + vbe_prepare(); + // call VBE function 09h (Set/Get Palette Data Function) + M.x86.R_EAX = 0x4f09; + M.x86.R_BL = 0x00; // get color + M.x86.R_CX = 0x01; // get only one entry + M.x86.R_DX = color_number; + // ES:DI is address where color_value is stored, we store it at 2000:0000 + M.x86.R_ES = 0x2000; + M.x86.R_DI = 0x0; + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE + ("%s: VBE Set Palette Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n", + __FUNCTION__, M.x86.R_AH); + return M.x86.R_AH; + } + // read color value from ES:DI + *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI); + + DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __FUNCTION__, + color_number, *color_value); + + return 0; +} +#endif + +// VBE Function 15h +static uint8_t +vbe_get_ddc_info(vbe_ddc_info_t * ddc_info) +{ + vbe_prepare(); + // call VBE function 15h (DDC Info Function) + M.x86.R_EAX = 0x4f15; + M.x86.R_BL = 0x00; // get DDC Info + M.x86.R_CX = ddc_info->port_number; + M.x86.R_ES = 0x0; + M.x86.R_DI = 0x0; + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE + ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n", + __FUNCTION__, ddc_info->port_number, M.x86.R_AH); + return M.x86.R_AH; + } + // BH = approx. time in seconds to transfer one EDID block + ddc_info->edid_transfer_time = M.x86.R_BH; + // BL = DDC Level + ddc_info->ddc_level = M.x86.R_BL; + + vbe_prepare(); + // call VBE function 15h (DDC Info Function) + M.x86.R_EAX = 0x4f15; + M.x86.R_BL = 0x01; // read EDID + M.x86.R_CX = ddc_info->port_number; + M.x86.R_DX = 0x0; // block number + // ES:DI is address where EDID is stored, we store it at 2000:0000 + M.x86.R_ES = 0x2000; + M.x86.R_DI = 0x0; + + // enable trace + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + // run VESA Interrupt + runInt10(); + + if (M.x86.R_AL != 0x4f) { + DEBUG_PRINTF_VBE + ("%s: VBE Read EDID Function NOT supported! AL=%x\n", + __FUNCTION__, M.x86.R_AL); + return -1; + } + + if (M.x86.R_AH != 0x0) { + DEBUG_PRINTF_VBE + ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n", + __FUNCTION__, ddc_info->port_number, M.x86.R_AH); + return M.x86.R_AH; + } + + memcpy(ddc_info->edid_block_zero, + biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, + sizeof(ddc_info->edid_block_zero)); + + return 0; +} + +uint32_t +vbe_get_info(uint8_t argc, char ** argv) +{ + uint8_t rval; + static const uint8_t valid_edid_sig[] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 + }; + uint32_t i; + + if (argc < 4) { + printf + ("Usage %s <vmem_base> <device_path> <address of screen_info_t>\n", + argv[0]); + int i = 0; + for (i = 0; i < argc; i++) { + printf("argv[%d]: %s\n", i, argv[i]); + } + return -1; + } + // get a copy of input struct... + screen_info_input_t input = + *((screen_info_input_t *) strtoul((char *) argv[4], 0, 16)); + // output is pointer to the address passed as argv[4] + screen_info_t *output = + (screen_info_t *) strtoul((char *) argv[4], 0, 16); + // zero output + memset(output, 0, sizeof(screen_info_t)); + + // argv[1] is address of virtual BIOS mem... + // argv[2] is the size + biosmem = (uint8_t *) strtoul(argv[1], 0, 16); + biosmem_size = strtoul(argv[2], 0, 16);; + if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) { + printf("Error: Not enough virtual memory: %x, required: %x!\n", + biosmem_size, MIN_REQUIRED_VMEM_SIZE); + return -1; + } + // argv[3] is the device to open and use... + if (dev_init((char *) argv[3]) != 0) { + printf("Error initializing device!\n"); + return -1; + } + //setup interrupt handler + X86EMU_intrFuncs intrFuncs[256]; + for (i = 0; i < 256; i++) + intrFuncs[i] = handleInterrupt; + X86EMU_setupIntrFuncs(intrFuncs); + X86EMU_setupPioFuncs(&my_pio_funcs); + X86EMU_setupMemFuncs(&my_mem_funcs); + + // set mem_base + M.mem_base = (long) biosmem; + M.mem_size = biosmem_size; + DEBUG_PRINTF_VBE("membase set: %08x, size: %08x\n", (int) M.mem_base, + (int) M.mem_size); + + vbe_info_t info; + rval = vbe_info(&info); + if (rval != 0) + return rval; + + DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature); + DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version); + DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr); + DEBUG_PRINTF_VBE("Capabilities:\n"); + DEBUG_PRINTF_VBE("\tDAC: %s\n", + (info.capabilities & 0x1) == + 0 ? "fixed 6bit" : "switchable 6/8bit"); + DEBUG_PRINTF_VBE("\tVGA: %s\n", + (info.capabilities & 0x2) == + 0 ? "compatible" : "not compatible"); + DEBUG_PRINTF_VBE("\tRAMDAC: %s\n", + (info.capabilities & 0x4) == + 0 ? "normal" : "use blank bit in Function 09h"); + + // argv[4] may be a pointer with enough space to return screen_info_t + // as input, it must contain a screen_info_input_t with the following content: + // byte[0:3] = "DDC\0" (zero-terminated signature header) + // byte[4:5] = reserved space for the return struct... just in case we ever change + // the struct and dont have reserved enough memory (and let's hope the struct + // never gets larger than 64KB) + // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors... + // byte[7:8] = max. screen width (OF may want to limit this) + // byte[9] = required color depth in bpp + if (strncmp((char *) input.signature, "DDC", 4) != 0) { + printf + ("%s: Invalid input signature! expected: %s, is: %s\n", + __FUNCTION__, "DDC", input.signature); + return -1; + } + if (input.size_reserved != sizeof(screen_info_t)) { + printf + ("%s: Size of return struct is wrong, required: %d, available: %d\n", + __FUNCTION__, (int) sizeof(screen_info_t), + input.size_reserved); + return -1; + } + + vbe_ddc_info_t ddc_info; + ddc_info.port_number = input.monitor_number; + vbe_get_ddc_info(&ddc_info); + +#if 0 + DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n", + ddc_info.edid_transfer_time); + DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level); + DEBUG_PRINTF_VBE("DDC: EDID: \n"); + CHECK_DBG(DEBUG_VBE) { + dump(ddc_info.edid_block_zero, + sizeof(ddc_info.edid_block_zero)); + } +#endif + if (memcmp(ddc_info.edid_block_zero, valid_edid_sig, 8) != 0) { + // invalid EDID signature... probably no monitor + output->display_type = 0x0; + return 0; + } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) { + // digital display + output->display_type = 2; + } else { + // analog + output->display_type = 1; + } + DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type); + memcpy(output->edid_block_zero, ddc_info.edid_block_zero, + sizeof(ddc_info.edid_block_zero)); + i = 0; + vbe_mode_info_t mode_info; + vbe_mode_info_t best_mode_info; + // initialize best_mode to 0 + memset(&best_mode_info, 0, sizeof(best_mode_info)); + while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) { + //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode); + vbe_get_mode_info(&mode_info); +#if 0 + DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n", + mode_info.video_mode, + (mode_info.attributes & 0x1) == + 0 ? "not supported" : "supported"); + DEBUG_PRINTF_VBE("\tTTY: %s\n", + (mode_info.attributes & 0x4) == + 0 ? "no" : "yes"); + DEBUG_PRINTF_VBE("\tMode: %s %s\n", + (mode_info.attributes & 0x8) == + 0 ? "monochrome" : "color", + (mode_info.attributes & 0x10) == + 0 ? "text" : "graphics"); + DEBUG_PRINTF_VBE("\tVGA: %s\n", + (mode_info.attributes & 0x20) == + 0 ? "compatible" : "not compatible"); + DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n", + (mode_info.attributes & 0x40) == + 0 ? "yes" : "no"); + DEBUG_PRINTF_VBE("\tFramebuffer: %s\n", + (mode_info.attributes & 0x80) == + 0 ? "no" : "yes"); + DEBUG_PRINTF_VBE("\tResolution: %dx%d\n", + mode_info.x_resolution, + mode_info.y_resolution); + DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n", + mode_info.x_charsize, mode_info.y_charsize); + DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n", + mode_info.bits_per_pixel); + DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n", + mode_info.memory_model); + DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n", + mode_info.framebuffer_address); +#endif + if ((mode_info.bits_per_pixel == input.color_depth) + && (mode_info.x_resolution <= input.max_screen_width) + && ((mode_info.attributes & 0x80) != 0) // framebuffer mode + && ((mode_info.attributes & 0x10) != 0) // graphics + && ((mode_info.attributes & 0x8) != 0) // color + && (mode_info.x_resolution > best_mode_info.x_resolution)) // better than previous best_mode + { + // yiiiihaah... we found a new best mode + memcpy(&best_mode_info, &mode_info, sizeof(mode_info)); + } + i++; + } + + if (best_mode_info.video_mode != 0) { + DEBUG_PRINTF_VBE + ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n", + best_mode_info.video_mode, + best_mode_info.x_resolution, + best_mode_info.y_resolution, + best_mode_info.bits_per_pixel, + best_mode_info.framebuffer_address); + + //printf("Mode Info Dump:"); + //dump(best_mode_info.mode_info_block, 64); + + // set the video mode + vbe_set_mode(&best_mode_info); + + if ((info.capabilities & 0x1) != 0) { + // switch to 8 bit palette format + vbe_set_palette_format(8); + } + // setup a palette: + // - first 216 colors are mixed colors for each component in 6 steps + // (6*6*6=216) + // - then 10 shades of the three primary colors + // - then 10 shades of grey + // ------- + // = 256 colors + // + // - finally black is color 0 and white color FF (because SLOF expects it + // this way...) + // this resembles the palette that the kernel/X Server seems to expect... + + uint8_t mixed_color_values[6] = + { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 }; + uint8_t primary_color_values[10] = + { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F, + 0x27 + }; + uint8_t mc_size = sizeof(mixed_color_values); + uint8_t prim_size = sizeof(primary_color_values); + + uint8_t curr_color_index; + uint32_t curr_color; + + uint8_t r, g, b; + // 216 mixed colors + for (r = 0; r < mc_size; r++) { + for (g = 0; g < mc_size; g++) { + for (b = 0; b < mc_size; b++) { + curr_color_index = + (r * mc_size * mc_size) + + (g * mc_size) + b; + curr_color = 0; + curr_color |= ((uint32_t) mixed_color_values[r]) << 16; //red value + curr_color |= ((uint32_t) mixed_color_values[g]) << 8; //green value + curr_color |= (uint32_t) mixed_color_values[b]; //blue value + vbe_set_color(curr_color_index, + curr_color); + } + } + } + + // 10 shades of each primary color + // red + for (r = 0; r < prim_size; r++) { + curr_color_index = mc_size * mc_size * mc_size + r; + curr_color = ((uint32_t) primary_color_values[r]) << 16; + vbe_set_color(curr_color_index, curr_color); + } + //green + for (g = 0; g < prim_size; g++) { + curr_color_index = + mc_size * mc_size * mc_size + prim_size + g; + curr_color = ((uint32_t) primary_color_values[g]) << 8; + vbe_set_color(curr_color_index, curr_color); + } + //blue + for (b = 0; b < prim_size; b++) { + curr_color_index = + mc_size * mc_size * mc_size + prim_size * 2 + b; + curr_color = (uint32_t) primary_color_values[b]; + vbe_set_color(curr_color_index, curr_color); + } + // 10 shades of grey + for (i = 0; i < prim_size; i++) { + curr_color_index = + mc_size * mc_size * mc_size + prim_size * 3 + i; + curr_color = 0; + curr_color |= ((uint32_t) primary_color_values[i]) << 16; //red + curr_color |= ((uint32_t) primary_color_values[i]) << 8; //green + curr_color |= ((uint32_t) primary_color_values[i]); //blue + vbe_set_color(curr_color_index, curr_color); + } + + // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen... + vbe_set_color(0x00, 0x00000000); + vbe_set_color(0xFF, 0x00FFFFFF); + + output->screen_width = best_mode_info.x_resolution; + output->screen_height = best_mode_info.y_resolution; + output->screen_linebytes = best_mode_info.linebytes; + output->color_depth = best_mode_info.bits_per_pixel; + output->framebuffer_address = + best_mode_info.framebuffer_address; + } else { + printf("%s: No suitable video mode found!\n", __FUNCTION__); + //unset display_type... + output->display_type = 0; + } + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/biosemu/vbe.h b/qemu/roms/SLOF/clients/net-snk/app/biosemu/vbe.h new file mode 100644 index 000000000..17e982632 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/biosemu/vbe.h @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _BIOSEMU_VBE_H_ +#define _BIOSEMU_VBE_H_ + +uint32_t vbe_get_info(uint8_t argc, char ** argv); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/main.c b/qemu/roms/SLOF/clients/net-snk/app/main.c new file mode 100644 index 000000000..90e14b370 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/main.c @@ -0,0 +1,77 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include <of.h> +#include <netapps/netapps.h> +#include <libbootmsg.h> + +#ifdef SNK_BIOSEMU_APPS +#include "biosemu/biosemu.h" +#include "biosemu/vbe.h" +#endif + +extern void _callback_entry(void); +int callback(int argc, char *argv[]); + + +int +main(int argc, char *argv[]) +{ + int i; + of_set_callback((void *) &_callback_entry); + + if (strcmp(argv[0], "netboot") == 0 && argc >= 5) + return netboot(argc, argv); + if (strcmp(argv[0], "ping") == 0) + return ping(argc, argv); +#ifdef SNK_BIOSEMU_APPS + // BIOS Emulator applications + if (strcmp(argv[0], "biosemu") == 0) + return biosemu(argc, argv); + if (strcmp(argv[0], "get_vbe_info") == 0) + return vbe_get_info(argc, argv); +#endif + + printf("Unknown client application called\n"); + for (i = 0; i < argc; i++) + printf("argv[%d] %s\n", i, argv[i]); + + return -1; +} + +int +callback(int argc, char *argv[]) +{ + int i; + + printf("\n"); + + /* + * Register your application's callback handler here, similar to + * the way you would register an application. + * Please note that callback functions can be called safely only after + * your application has called of_yield(). If you return or exit() from + * your client application, the callback can no longer be used. + */ +#if 0 + if (strcmp(argv[0], "example") == 0) + return example(argc, argv); +#endif + + printf("No such callback function\n"); + for (i = 0; i < argc; i++) + printf("argv[%d] %s\n", i, argv[i]); + + return (-1); +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netapps/Makefile b/qemu/roms/SLOF/clients/net-snk/app/netapps/Makefile new file mode 100644 index 000000000..70b990a77 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netapps/Makefile @@ -0,0 +1,28 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +CFLAGS += -I../ -I../../../../lib/ -Wall -W + +OBJS = netboot.o ping.o args.o + +all: $(OBJS) + +clean: + $(RM) -f *.o *.a *.i + +include $(TOP)/make.depend diff --git a/qemu/roms/SLOF/clients/net-snk/app/netapps/args.c b/qemu/roms/SLOF/clients/net-snk/app/netapps/args.c new file mode 100644 index 000000000..52215e6a7 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netapps/args.c @@ -0,0 +1,143 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include "args.h" + +/** + * Returns pointer of the n'th argument within a string. + * + * @param arg_str string with arguments, separated with ',' + * @param index index of the requested arguments within arg_str + * @return pointer of argument[index] on success + * NULL if index is out of range + */ +const char * +get_arg_ptr(const char *arg_str, unsigned int index) +{ + unsigned int i; + + for (i = 0; i < index; ++i) { + for (; *arg_str != ',' && *arg_str != 0; ++arg_str); + if (*arg_str == 0) + return 0; + ++arg_str; + } + return arg_str; +} + +/** + * Returns number of arguments within a string. + * + * @param arg_str string with arguments, separated with ',' + * @return number of arguments + */ +unsigned int +get_args_count(const char *arg_str) +{ + unsigned int count = 1; + + while ((arg_str = get_arg_ptr(arg_str, 1)) != 0) + ++count; + return count; +} + +/** + * Returns the length of the first argument. + * + * @param arg_str string with arguments, separated with ',' + * @return length of first argument + */ +unsigned int +get_arg_length(const char *arg_str) +{ + unsigned int i; + + for (i = 0; *arg_str != ',' && *arg_str != 0; ++i) + ++arg_str; + return i; +} + +/** + * Copy the n'th argument within a string into a buffer in respect + * to a limited buffer size + * + * @param arg_str string with arguments, separated with ',' + * @param index index of the requested arguments within arg_str + * @param buffer pointer to the buffer + * @param length size of the buffer + * @return pointer of buffer on success + * NULL if index is out of range. + */ +char * +argncpy(const char *arg_str, unsigned int index, char *buffer, + unsigned int length) +{ + const char *ptr = get_arg_ptr(arg_str, index); + unsigned int len; + + if (!ptr) + return 0; + len = get_arg_length(ptr); + if (!strncpy(buffer, ptr, length)) + return 0; + buffer[len] = 0; + return buffer; +} + +/** + * Converts "255.255.255.255" -> char[4] = { 0xff, 0xff, 0xff, 0xff } + * + * @param str string to be converted + * @param ip in case of SUCCESS - 32-bit long IP + in case of FAULT - zero + * @return TRUE - IP converted successfully; + * FALSE - error condition occurs (e.g. bad format) + */ +int +strtoip(const char *str, char ip[4]) +{ + char octet[10]; + int res; + unsigned int i = 0, len; + + while (*str != 0) { + if (i > 3 || !isdigit(*str)) + return 0; + if (strstr(str, ".") != NULL) { + len = (int16_t) (strstr(str, ".") - str); + if (len >= 10) + return 0; + strncpy(octet, str, len); + octet[len] = 0; + str += len; + } else { + strncpy(octet, str, 9); + octet[9] = 0; + str += strlen(octet); + } + res = strtol(octet, NULL, 10); + if ((res > 255) || (res < 0)) + return 0; + ip[i] = (char) res; + i++; + if (*str == '.') + str++; + } + + if (i != 4) + return 0; + return -1; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netapps/args.h b/qemu/roms/SLOF/clients/net-snk/app/netapps/args.h new file mode 100644 index 000000000..b80982a39 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netapps/args.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _ARGS_H +#define _ARGS_H + +const char *get_arg_ptr(const char *, unsigned int); +unsigned int get_args_count(const char *); +unsigned int get_arg_length(const char *); +char *argncpy(const char *, unsigned int, char *, unsigned int); +int strtoip(const char *, char[4]); + +#endif /* _ARGS_H */ diff --git a/qemu/roms/SLOF/clients/net-snk/app/netapps/netapps.h b/qemu/roms/SLOF/clients/net-snk/app/netapps/netapps.h new file mode 100644 index 000000000..18e607f53 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netapps/netapps.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _NETAPPS_H_ +#define _NETAPPS_H_ + +#include <netlib/tftp.h> + +#define F_IPV4 4 +#define F_IPV6 6 + +int netboot(int argc, char *argv[]); +int netsave(int argc, char *argv[]); +int netflash(int argc, char *argv[]); +int bcmflash(int argc, char *argv[]); +int mac_sync(int argc, char *argv[]); +int net_eeprom_version( void ); +int ping(int argc, char *argv[]); +int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flags); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c b/qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c new file mode 100644 index 000000000..cf20b5915 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netapps/netboot.c @@ -0,0 +1,832 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <netlib/tftp.h> +#include <netlib/ethernet.h> +#include <netlib/dhcp.h> +#include <netlib/dhcpv6.h> +#include <netlib/ipv4.h> +#include <netlib/ipv6.h> +#include <netlib/dns.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <netapps/args.h> +#include <libbootmsg/libbootmsg.h> +#include <of.h> +#include "netapps.h" + +#define IP_INIT_DEFAULT 5 +#define IP_INIT_NONE 0 +#define IP_INIT_BOOTP 1 +#define IP_INIT_DHCP 2 +#define IP_INIT_DHCPV6_STATELESS 3 +#define IP_INIT_IPV6_MANUAL 4 + +#define DEFAULT_BOOT_RETRIES 10 +#define DEFAULT_TFTP_RETRIES 20 +static int ip_version = 4; + +typedef struct { + char filename[100]; + int ip_init; + char siaddr[4]; + ip6_addr_t si6addr; + char ciaddr[4]; + ip6_addr_t ci6addr; + char giaddr[4]; + ip6_addr_t gi6addr; + int bootp_retries; + int tftp_retries; +} obp_tftp_args_t; + + +/** + * Parses a argument string for IPv6 booting, extracts all + * parameters and fills a structure accordingly + * + * @param arg_str string with arguments, separated with ',' + * @param argc number of arguments + * @param obp_tftp_args structure which contains the result + * @return updated arg_str + */ +static const char * +parse_ipv6args (const char *arg_str, unsigned int argc, + obp_tftp_args_t *obp_tftp_args) +{ + char *ptr = NULL; + char arg_buf[100]; + + // find out siaddr + if (argc == 0) + memset(&obp_tftp_args->si6addr.addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if(str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(&obp_tftp_args->si6addr.addr, 0, 16); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->si6addr.addr, 0, 16); + } + + // find out filename + if (argc == 0) + obp_tftp_args->filename[0] = 0; + else { + argncpy(arg_str, 0, obp_tftp_args->filename, 100); + for(ptr = obp_tftp_args->filename; *ptr != 0; ++ptr) + if(*ptr == '\\') { + *ptr = '/'; + } + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + + // find out ciaddr + if (argc == 0) + memset(&obp_tftp_args->ci6addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr[0]))) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(&obp_tftp_args->ci6addr.addr, 0, 16); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->ci6addr.addr, 0, 16); + } + + // find out giaddr + if (argc == 0) + memset(&obp_tftp_args->gi6addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(&obp_tftp_args->gi6addr, 0, 16); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->gi6addr.addr, 0, 16); + } + + return arg_str; +} + + +/** + * Parses a argument string for IPv4 booting, extracts all + * parameters and fills a structure accordingly + * + * @param arg_str string with arguments, separated with ',' + * @param argc number of arguments + * @param obp_tftp_args structure which contains the result + * @return updated arg_str + */ +static const char * +parse_ipv4args (const char *arg_str, unsigned int argc, + obp_tftp_args_t *obp_tftp_args) +{ + char *ptr = NULL; + char arg_buf[100]; + + // find out siaddr + if(argc==0) { + memset(obp_tftp_args->siaddr, 0, 4); + } else { + argncpy(arg_str, 0, arg_buf, 100); + if(strtoip(arg_buf, obp_tftp_args->siaddr)) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(obp_tftp_args->siaddr, 0, 4); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(obp_tftp_args->siaddr, 0, 4); + } + + // find out filename + if(argc==0) + obp_tftp_args->filename[0] = 0; + else { + argncpy(arg_str, 0, obp_tftp_args->filename, 100); + for(ptr = obp_tftp_args->filename; *ptr != 0; ++ptr) + if(*ptr == '\\') + *ptr = '/'; + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + + // find out ciaddr + if(argc==0) + memset(obp_tftp_args->ciaddr, 0, 4); + else { + argncpy(arg_str, 0, arg_buf, 100); + if(strtoip(arg_buf, obp_tftp_args->ciaddr)) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(obp_tftp_args->ciaddr, 0, 4); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(obp_tftp_args->ciaddr, 0, 4); + } + + // find out giaddr + if(argc==0) + memset(obp_tftp_args->giaddr, 0, 4); + else { + argncpy(arg_str, 0, arg_buf, 100); + if(strtoip(arg_buf, obp_tftp_args->giaddr)) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(obp_tftp_args->giaddr, 0, 4); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(obp_tftp_args->giaddr, 0, 4); + } + + return arg_str; +} + +/** + * Parses a argument string which is given by netload, extracts all + * parameters and fills a structure according to this + * + * Netload-Parameters: + * [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries + * + * @param arg_str string with arguments, separated with ',' + * @param obp_tftp_args structure which contains the result + * @return none + */ +static void +parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args) +{ + unsigned int argc; + char arg_buf[100]; + + memset(obp_tftp_args, 0, sizeof(*obp_tftp_args)); + + argc = get_args_count(arg_str); + + // find out if we should use BOOTP or DHCP + if(argc==0) + obp_tftp_args->ip_init = IP_INIT_DEFAULT; + else { + argncpy(arg_str, 0, arg_buf, 100); + if (strcasecmp(arg_buf, "bootp") == 0) { + obp_tftp_args->ip_init = IP_INIT_BOOTP; + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(strcasecmp(arg_buf, "dhcp") == 0) { + obp_tftp_args->ip_init = IP_INIT_DHCP; + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(strcasecmp(arg_buf, "ipv6") == 0) { + obp_tftp_args->ip_init = IP_INIT_DHCPV6_STATELESS; + arg_str = get_arg_ptr(arg_str, 1); + --argc; + ip_version = 6; + } + else + obp_tftp_args->ip_init = IP_INIT_DEFAULT; + } + + if (ip_version == 4) { + arg_str = parse_ipv4args (arg_str, argc, obp_tftp_args); + } + else if (ip_version == 6) { + arg_str = parse_ipv6args (arg_str, argc, obp_tftp_args); + } + + // find out bootp-retries + if (argc == 0) + obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES; + else { + argncpy(arg_str, 0, arg_buf, 100); + if(arg_buf[0] == 0) + obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES; + else { + obp_tftp_args->bootp_retries = strtol(arg_buf, 0, 10); + if(obp_tftp_args->bootp_retries < 0) + obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES; + } + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + + // find out tftp-retries + if (argc == 0) + obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES; + else { + argncpy(arg_str, 0, arg_buf, 100); + if(arg_buf[0] == 0) + obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES; + else { + obp_tftp_args->tftp_retries = strtol(arg_buf, 0, 10); + if(obp_tftp_args->tftp_retries < 0) + obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES; + } + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } +} + +/** + * DHCP: Wrapper for obtaining IP and configuration info from DHCP server + * for both IPv4 and IPv6. + * (makes several attempts). + * + * @param ret_buffer buffer for returning BOOTP-REPLY packet data + * @param fn_ip contains the following configuration information: + * client MAC, client IP, TFTP-server MAC, + * TFTP-server IP, Boot file name + * @param retries No. of DHCP attempts + * @param flags flags for specifying type of dhcp attempt (IPv4/IPv6) + * ZERO - attempt DHCPv4 followed by DHCPv6 + * F_IPV4 - attempt only DHCPv4 + * F_IPV6 - attempt only DHCPv6 + * @return ZERO - IP and configuration info obtained; + * NON ZERO - error condition occurs. + */ +int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flags) +{ + int i = (int) retries+1; + int rc = -1; + + printf(" "); + + do { + printf("\b\b\b%03d", i-1); + if (getchar() == 27) { + printf("\nAborted\n"); + return -1; + } + if (!--i) { + printf("\nGiving up after %d DHCP requests\n", retries); + return -1; + } + if (!flags || (flags == F_IPV4)) { + ip_version = 4; + rc = dhcpv4(ret_buffer, fn_ip); + } + if ((!flags && (rc == -1)) || (flags == F_IPV6)) { + ip_version = 6; + set_ipv6_address(fn_ip->fd, 0); + rc = dhcpv6(ret_buffer, fn_ip); + if (rc == 0) { + printf("\n"); + memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16); + break; + } + + } + if (rc != -1) /* either success or non-dhcp failure */ + break; + } while (1); + printf("\b\b\b\b"); + + return rc; +} + +int +netboot(int argc, char *argv[]) +{ + char buf[256]; + int rc; + int len = strtol(argv[2], 0, 16); + char *buffer = (char *) strtol(argv[1], 0, 16); + char *ret_buffer = (char *) strtol(argv[3], 0, 16); + filename_ip_t fn_ip; + int fd_device; + tftp_err_t tftp_err; + obp_tftp_args_t obp_tftp_args; + char null_ip[4] = { 0x00, 0x00, 0x00, 0x00 }; + char null_ip6[16] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + int huge_load = strtol(argv[4], 0, 10); + int32_t block_size = strtol(argv[5], 0, 10); + uint8_t own_mac[6]; + + printf("\n"); + printf(" Bootloader 1.6 \n"); + memset(&fn_ip, 0, sizeof(filename_ip_t)); + + /*********************************************************** + * + * Initialize network stuff and retrieve boot informations + * + ***********************************************************/ + + /* Wait for link up and get mac_addr from device */ + for(rc=0; rc<DEFAULT_BOOT_RETRIES; ++rc) { + if(rc > 0) { + set_timer(TICKS_SEC); + while (get_timer() > 0); + } + fd_device = socket(0, 0, 0, (char*) own_mac); + if(fd_device != -2) + break; + if(getchar() == 27) { + fd_device = -2; + break; + } + } + + if (fd_device == -1) { + strcpy(buf,"E3000: (net) Could not read MAC address"); + bootmsg_error(0x3000, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -100; + } + else if (fd_device == -2) { + strcpy(buf,"E3006: (net) Could not initialize network device"); + bootmsg_error(0x3006, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -101; + } + + fn_ip.fd = fd_device; + + printf(" Reading MAC address from device: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + own_mac[0], own_mac[1], own_mac[2], + own_mac[3], own_mac[4], own_mac[5]); + + // init ethernet layer + set_mac_address(own_mac); + + if (argc > 6) { + parse_args(argv[6], &obp_tftp_args); + if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES) + obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES; + else + obp_tftp_args.bootp_retries -= rc; + } + else { + memset(&obp_tftp_args, 0, sizeof(obp_tftp_args_t)); + obp_tftp_args.ip_init = IP_INIT_DEFAULT; + obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES; + obp_tftp_args.tftp_retries = DEFAULT_TFTP_RETRIES; + } + memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4); + + // reset of error code + rc = 0; + + /* if we still have got all necessary parameters, then we don't + need to perform an BOOTP/DHCP-Request */ + if (ip_version == 4) { + if (memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0 + && memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0 + && obp_tftp_args.filename[0] != 0) { + + memcpy(&fn_ip.server_ip, &obp_tftp_args.siaddr, 4); + obp_tftp_args.ip_init = IP_INIT_NONE; + } + } + else if (ip_version == 6) { + if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16) != 0 + && memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0 + && obp_tftp_args.filename[0] != 0) { + + memcpy(&fn_ip.server_ip6.addr[0], + &obp_tftp_args.si6addr.addr, 16); + obp_tftp_args.ip_init = IP_INIT_IPV6_MANUAL; + } + else { + obp_tftp_args.ip_init = IP_INIT_DHCPV6_STATELESS; + } + } + + // construction of fn_ip from parameter + switch(obp_tftp_args.ip_init) { + case IP_INIT_BOOTP: + printf(" Requesting IP address via BOOTP: "); + // if giaddr in not specified, then we have to identify + // the BOOTP server via broadcasts + if(memcmp(obp_tftp_args.giaddr, null_ip, 4) == 0) { + // don't do this, when using DHCP !!! + fn_ip.server_ip = 0xFFFFFFFF; + } + // if giaddr is specified, then we have to use this + // IP address as proxy to identify the BOOTP server + else { + memcpy(&fn_ip.server_ip, obp_tftp_args.giaddr, 4); + } + rc = bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); + break; + case IP_INIT_DHCP: + printf(" Requesting IP address via DHCPv4: "); + rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, F_IPV4); + break; + case IP_INIT_DHCPV6_STATELESS: + printf(" Requesting information via DHCPv6: "); + rc = dhcp(ret_buffer, &fn_ip, + obp_tftp_args.bootp_retries, F_IPV6); + break; + case IP_INIT_IPV6_MANUAL: + set_ipv6_address(fn_ip.fd, &obp_tftp_args.ci6addr); + break; + case IP_INIT_DEFAULT: + printf(" Requesting IP address via DHCP: "); + rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, 0); + break; + case IP_INIT_NONE: + default: + break; + } + + if(rc >= 0 && ip_version == 4) { + if(memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0 + && memcmp(obp_tftp_args.ciaddr, &fn_ip.own_ip, 4) != 0) + memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4); + + if(memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0 + && memcmp(obp_tftp_args.siaddr, &fn_ip.server_ip, 4) != 0) + memcpy(&fn_ip.server_ip, obp_tftp_args.siaddr, 4); + + // init IPv4 layer + set_ipv4_address(fn_ip.own_ip); + } + else if (rc >= 0 && ip_version == 6) { + if(memcmp(&obp_tftp_args.ci6addr.addr, null_ip6, 16) != 0 + && memcmp(&obp_tftp_args.ci6addr.addr, &fn_ip.own_ip6, 16) != 0) + memcpy(&fn_ip.own_ip6, &obp_tftp_args.ci6addr.addr, 16); + + if(memcmp(&obp_tftp_args.si6addr.addr, null_ip6, 16) != 0 + && memcmp(&obp_tftp_args.si6addr.addr, &fn_ip.server_ip6.addr, 16) != 0) + memcpy(&fn_ip.server_ip6.addr, &obp_tftp_args.si6addr.addr, 16); + } + if (rc == -1) { + strcpy(buf,"E3001: (net) Could not get IP address"); + bootmsg_error(0x3001, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -101; + } + + if(ip_version == 4) + printf("%d.%d.%d.%d\n", + ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF), + ((fn_ip.own_ip >> 8) & 0xFF), ( fn_ip.own_ip & 0xFF)); + + if (rc == -2) { + sprintf(buf, + "E3002: (net) ARP request to TFTP server " + "(%d.%d.%d.%d) failed", + ((fn_ip.server_ip >> 24) & 0xFF), + ((fn_ip.server_ip >> 16) & 0xFF), + ((fn_ip.server_ip >> 8) & 0xFF), + ( fn_ip.server_ip & 0xFF)); + bootmsg_error(0x3002, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -102; + } + if (rc == -4 || rc == -3) { + strcpy(buf,"E3008: (net) Can't obtain TFTP server IP address"); + bootmsg_error(0x3008, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -107; + } + + + /*********************************************************** + * + * Load file via TFTP into buffer provided by OpenFirmware + * + ***********************************************************/ + + if (obp_tftp_args.filename[0] != 0) { + strncpy((char *) fn_ip.filename, obp_tftp_args.filename, sizeof(fn_ip.filename)-1); + fn_ip.filename[sizeof(fn_ip.filename)-1] = 0; + } + + if (ip_version == 4) { + printf(" Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n", + fn_ip.filename, + ((fn_ip.server_ip >> 24) & 0xFF), + ((fn_ip.server_ip >> 16) & 0xFF), + ((fn_ip.server_ip >> 8) & 0xFF), + ( fn_ip.server_ip & 0xFF)); + } else if (ip_version == 6) { + char ip6_str[40]; + printf(" Requesting file \"%s\" via TFTP from ", fn_ip.filename); + ipv6_to_str(fn_ip.server_ip6.addr, ip6_str); + printf("%s\n", ip6_str); + } + + // accept at most 20 bad packets + // wait at most for 40 packets + rc = tftp(&fn_ip, (unsigned char *) buffer, + len, obp_tftp_args.tftp_retries, + &tftp_err, huge_load, block_size, ip_version); + + if(obp_tftp_args.ip_init == IP_INIT_DHCP) + dhcp_send_release(fn_ip.fd); + + if (rc > 0) { + printf(" TFTP: Received %s (%d KBytes)\n", fn_ip.filename, + rc / 1024); + } else if (rc == -1) { + bootmsg_error(0x3003, "(net) unknown TFTP error"); + return -103; + } else if (rc == -2) { + sprintf(buf, + "E3004: (net) TFTP buffer of %d bytes " + "is too small for %s", + len, fn_ip.filename); + bootmsg_error(0x3004, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -104; + } else if (rc == -3) { + sprintf(buf,"E3009: (net) file not found: %s", + fn_ip.filename); + bootmsg_error(0x3009, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -108; + } else if (rc == -4) { + strcpy(buf,"E3010: (net) TFTP access violation"); + bootmsg_error(0x3010, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -109; + } else if (rc == -5) { + strcpy(buf,"E3011: (net) illegal TFTP operation"); + bootmsg_error(0x3011, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -110; + } else if (rc == -6) { + strcpy(buf, "E3012: (net) unknown TFTP transfer ID"); + bootmsg_error(0x3012, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -111; + } else if (rc == -7) { + strcpy(buf, "E3013: (net) no such TFTP user"); + bootmsg_error(0x3013, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -112; + } else if (rc == -8) { + strcpy(buf, "E3017: (net) TFTP blocksize negotiation failed"); + bootmsg_error(0x3017, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -116; + } else if (rc == -9) { + strcpy(buf,"E3018: (net) file exceeds maximum TFTP transfer size"); + bootmsg_error(0x3018, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -117; + } else if (rc <= -10 && rc >= -15) { + sprintf(buf,"E3005: (net) ICMP ERROR \""); + switch (rc) { + case -ICMP_NET_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"net unreachable"); + break; + case -ICMP_HOST_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"host unreachable"); + break; + case -ICMP_PROTOCOL_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"protocol unreachable"); + break; + case -ICMP_PORT_UNREACHABLE - 10: + sprintf(buf+strlen(buf),"port unreachable"); + break; + case -ICMP_FRAGMENTATION_NEEDED - 10: + sprintf(buf+strlen(buf),"fragmentation needed and DF set"); + break; + case -ICMP_SOURCE_ROUTE_FAILED - 10: + sprintf(buf+strlen(buf),"source route failed"); + break; + default: + sprintf(buf+strlen(buf)," UNKNOWN"); + break; + } + sprintf(buf+strlen(buf),"\""); + bootmsg_error(0x3005, &buf[7]); + + write_mm_log(buf, strlen(buf), 0x91); + return -105; + } else if (rc == -40) { + sprintf(buf, + "E3014: (net) TFTP error occurred after " + "%d bad packets received", + tftp_err.bad_tftp_packets); + bootmsg_error(0x3014, &buf[7]); + write_mm_log(buf, strlen(buf), 0x91); + return -113; + } else if (rc == -41) { + sprintf(buf, + "E3015: (net) TFTP error occurred after " + "missing %d responses", + tftp_err.no_packets); + bootmsg_error(0x3015, &buf[7]); + write_mm_log(buf, strlen(buf), 0x91); + return -114; + } else if (rc == -42) { + sprintf(buf, + "E3016: (net) TFTP error missing block %d, " + "expected block was %d", + tftp_err.blocks_missed, + tftp_err.blocks_received); + bootmsg_error(0x3016, &buf[7]); + write_mm_log(buf, strlen(buf), 0x91); + return -115; + } + return rc; +} + +/** + * Parses a tftp arguments, extracts all + * parameters and fills server ip according to this + * + * Parameters: + * @param buffer string with arguments, + * @param server_ip server ip as result + * @param filename default filename + * @param fd Socket descriptor + * @param len len of the buffer, + * @return 0 on SUCCESS and -1 on failure + */ +int parse_tftp_args(char buffer[], char *server_ip, char filename[], int fd, + int len) +{ + char *raw; + char *tmp, *tmp1; + int i, j = 0; + char domainname[256]; + uint8_t server_ip6[16]; + + raw = malloc(len); + if (raw == NULL) { + printf("\n unable to allocate memory, parsing failed\n"); + return -1; + } + strncpy(raw,(const char *)buffer,len); + /*tftp url contains tftp://[fd00:4f53:4444:90:214:5eff:fed9:b200]/testfile*/ + if(strncmp(raw,"tftp://",7)){ + printf("\n tftp missing in %s\n",raw); + free(raw); + return -1; + } + tmp = strchr(raw,'['); + if(tmp != NULL && *tmp == '[') { + /*check for valid ipv6 address*/ + tmp1 = strchr(tmp,']'); + if (tmp1 == NULL) { + printf("\n missing ] in %s\n",raw); + free(raw); + return -1; + } + i = tmp1 - tmp; + /*look for file name*/ + tmp1 = strchr(tmp,'/'); + if (tmp1 == NULL) { + printf("\n missing filename in %s\n",raw); + free(raw); + return -1; + } + tmp[i] = '\0'; + /*check for 16 byte ipv6 address */ + if (!str_to_ipv6((tmp+1), (uint8_t *)(server_ip))) { + printf("\n wrong format IPV6 address in %s\n",raw); + free(raw); + return -1;; + } + else { + /*found filename */ + strcpy(filename,(tmp1+1)); + free(raw); + return 0; + } + } + else { + /*here tftp://hostname/testfile from option request of dhcp*/ + /*look for dns server name */ + tmp1 = strchr(raw,'.'); + if(tmp1 == NULL) { + printf("\n missing . seperator in %s\n",raw); + free(raw); + return -1; + } + /*look for domain name beyond dns server name + * so ignore the current . and look for one more + */ + tmp = strchr((tmp1+1),'.'); + if(tmp == NULL) { + printf("\n missing domain in %s\n",raw); + free(raw); + return -1; + } + tmp1 = strchr(tmp1,'/'); + if (tmp1 == NULL) { + printf("\n missing filename in %s\n",raw); + free(raw); + return -1; + } + j = tmp1 - (raw + 7); + tmp = raw + 7; + tmp[j] = '\0'; + strcpy(domainname, tmp); + if (dns_get_ip(fd, (int8_t *)domainname, server_ip6, 6) == 0) { + printf("\n DNS failed for IPV6\n"); + return -1; + } + ipv6_to_str(server_ip6, server_ip); + + strcpy(filename,(tmp1+1)); + free(raw); + return 0; + } + +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netapps/ping.c b/qemu/roms/SLOF/clients/net-snk/app/netapps/ping.c new file mode 100644 index 000000000..2c7dadbde --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netapps/ping.c @@ -0,0 +1,196 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <netlib/ipv4.h> +#include <netlib/dhcp.h> +#include <netlib/ethernet.h> +#include <sys/socket.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <netapps/args.h> +#include "netapps.h" + +struct ping_args { + union { + char string[4]; + unsigned int integer; + } server_ip; + union { + char string[4]; + unsigned int integer; + } client_ip; + union { + char string[4]; + unsigned int integer; + } gateway_ip; + unsigned int timeout; +}; + +static void +usage(void) +{ + printf + ("\nping device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]\n"); + +} + +static int +parse_args(const char *args, struct ping_args *ping_args) +{ + unsigned int argc = get_args_count(args); + char buf[64]; + ping_args->timeout = 10; + if (argc == 0) + /* at least server-ip has to be specified */ + return -1; + if (argc == 1) { + /* probably only server ip is specified */ + argncpy(args, 0, buf, 64); + if (!strtoip(buf, ping_args->server_ip.string)) + return -1; + return 0; + } + /* get first option from list */ + argncpy(args, 0, buf, 64); + if (!strtoip(buf, ping_args->server_ip.string)) { + /* it is not an IP address + * therefore it has to be device-args + * device-args are not supported and just ignored */ + args = get_arg_ptr(args, 1); + argc--; + } + + argncpy(args, 0, buf, 64); + if (!strtoip(buf, ping_args->server_ip.string)) { + /* this should have been the server IP address */ + return -1; + } else { + args = get_arg_ptr(args, 1); + if (!--argc) + return 0; + } + + argncpy(args, 0, buf, 64); + if (!strtoip(buf, ping_args->client_ip.string)) { + /* this should have been the client (our) IP address */ + return -1; + } else { + args = get_arg_ptr(args, 1); + if (!--argc) + return 0; + } + argncpy(args, 0, buf, 64); + if (!strtoip(buf, ping_args->gateway_ip.string)) { + /* this should have been the gateway IP address */ + return -1; + } else { + args = get_arg_ptr(args, 1); + if (!--argc) + return 0; + } + argncpy(args, 0, buf, 64); + ping_args->timeout = strtol(args, 0, 10); + return 0; +} + +int +ping(int argc, char *argv[]) +{ + short arp_failed = 0; + filename_ip_t fn_ip; + int fd_device; + struct ping_args ping_args; + uint8_t own_mac[6]; + + memset(&ping_args, 0, sizeof(struct ping_args)); + + if (argc == 2) { + if (parse_args(argv[1], &ping_args)) { + usage(); + return -1; + } + } else { + usage(); + return -1; + } + + memset(&fn_ip, 0, sizeof(filename_ip_t)); + + /* Get mac_addr from device */ + printf("\n Reading MAC address from device: "); + fd_device = socket(0, 0, 0, (char *) own_mac); + if (fd_device == -1) { + printf("\nE3000: Could not read MAC address\n"); + return -100; + } else if (fd_device == -2) { + printf("\nE3006: Could not initialize network device\n"); + return -101; + } + + fn_ip.fd = fd_device; + + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + own_mac[0], own_mac[1], own_mac[2], + own_mac[3], own_mac[4], own_mac[5]); + + // init ethernet layer + set_mac_address(own_mac); + // identify the BOOTP/DHCP server via broadcasts + // don't do this, when using DHCP !!! + // fn_ip.server_ip = 0xFFFFFFFF; + // memset(fn_ip.server_mac, 0xff, 6); + + if (!ping_args.client_ip.integer) { + /* Get ip address for our mac address */ + printf(" Requesting IP address via DHCP: "); + arp_failed = dhcp(0, &fn_ip, 30, F_IPV4); + + if (arp_failed == -1) { + printf("\n DHCP: Could not get ip address\n"); + return -1; + } + + } else { + memcpy(&fn_ip.own_ip, &ping_args.client_ip.integer, 4); + arp_failed = 1; + printf(" Own IP address: "); + } + + // reinit network stack + set_ipv4_address(fn_ip.own_ip); + + printf("%d.%d.%d.%d\n", + ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF), + ((fn_ip.own_ip >> 8) & 0xFF), (fn_ip.own_ip & 0xFF)); + + memcpy(&fn_ip.server_ip, &ping_args.server_ip.integer, 4); + printf(" Ping to %d.%d.%d.%d ", ((fn_ip.server_ip >> 24) & 0xFF), + ((fn_ip.server_ip >> 16) & 0xFF), + ((fn_ip.server_ip >> 8) & 0xFF), (fn_ip.server_ip & 0xFF)); + + + ping_ipv4(fd_device, fn_ip.server_ip); + + set_timer(TICKS_SEC / 10 * ping_args.timeout); + while(get_timer() > 0) { + receive_ether(fd_device); + if(pong_ipv4() == 0) { + printf("success\n"); + return 0; + } + } + + printf("failed\n"); + return -1; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/Makefile b/qemu/roms/SLOF/clients/net-snk/app/netlib/Makefile new file mode 100644 index 000000000..df09bf82e --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/Makefile @@ -0,0 +1,42 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +CFLAGS += -I../ + +ifeq ($(SNK_USE_MTFTP), 1) +CFLAGS += -DUSE_MTFTP +endif + +OBJS = ethernet.o ipv4.o udp.o tcp.o dns.o bootp.o \ + dhcp.o ipv6.o dhcpv6.o icmpv6.o ndp.o + +ifeq ($(SNK_USE_MTFTP), 1) +OBJS += mtftp.o +else +OBJS += tftp.o +endif + +all: netlib.o + +netlib.o: $(OBJS) + $(LD) $(LDFLAGS) $^ -o $@ -r + +clean: + $(RM) -f *.o *.a *.i + +include $(TOP)/make.depend diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c new file mode 100644 index 000000000..1bc6efe5b --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/bootp.c @@ -0,0 +1,254 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <time.h> + +#include <ethernet.h> +#include <ipv4.h> +#include <udp.h> +#include <dhcp.h> + +#define DEBUG 0 + +static char * response_buffer; + +#if DEBUG +static void +print_ip(char *ip) +{ + printf("%d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); +} +#endif + +/* IP header checksum calculation */ +static unsigned short +checksum(unsigned short *packet, int words) +{ + unsigned long checksum; + for (checksum = 0; words > 0; words--) + checksum += *packet++; + checksum = (checksum >> 16) + (checksum & 0xffff); + checksum += (checksum >> 16); + return ~checksum; +} + + +static int +send_bootp(filename_ip_t * fn_ip) +{ +#if DEBUG + int i; +#endif + unsigned int packetsize = + sizeof(struct iphdr) + sizeof(struct ethhdr) + + sizeof(struct udphdr) + sizeof(struct btphdr); + unsigned char packet[packetsize]; + struct iphdr *iph; + struct udphdr *udph; + struct btphdr *btph; + + iph = (struct iphdr *) packet; + udph = (struct udphdr *) (iph + 1); + btph = (struct btphdr *) (udph + 1); + + memset(packet, 0, packetsize); + + fill_iphdr((uint8_t *) iph, htons(packetsize - sizeof(struct ethhdr)), + IPTYPE_UDP, 0, fn_ip->server_ip); + fill_udphdr((uint8_t *) udph, + htons(sizeof(struct udphdr) + sizeof(struct btphdr)), + htons(UDPPORT_BOOTPC), htons(UDPPORT_BOOTPS)); + btph->op = 1; + btph->htype = 1; + btph->hlen = 6; + strcpy((char *) btph->file, "bla"); + memcpy(btph->chaddr, get_mac_address(), 6); + +#if DEBUG + printf("Sending packet\n"); + printf("Packet is "); + for (i = 0; i < packetsize; i++) + printf(" %02x", packet[i]); + printf(".\n"); +#endif + + send_ipv4(fn_ip->fd, packet, iph->ip_len); +#if DEBUG + printf("%d bytes transmitted over socket.\n", i); +#endif + + return 0; +} + + +static int +receive_bootp(filename_ip_t * fn_ip) +{ + int len, old_sum; + unsigned int packetsize = 2000; + unsigned char packet[packetsize]; + struct iphdr *iph; + struct udphdr *udph; + struct btphdr *btph; + +#if DEBUG + struct ethhdr *ethh; + ethh = (struct ethhdr *) packet; +#endif + + iph = (struct iphdr *) (packet + sizeof(struct ethhdr)); + udph = (struct udphdr *) (iph + 1); + btph = (struct btphdr *) (udph + 1); + + memset(packet, 0, packetsize); + + /* setting up a timer with a timeout of one second */ + set_timer(TICKS_SEC); + + do { + + /* let's receive a packet */ + len = recv(fn_ip->fd, packet, packetsize, 0); + +#if DEBUG + int j; + printf("%d bytes received, %d expected \n", len, packetsize); + if (len == 346) { + printf("Rec packet\n"); + printf("Packet is "); + for (j = 0; j < len; j++) { + if (j % 16 == 0) + printf("\n"); + printf(" %02x", packet[j]); + } + printf(".\n"); + } +#endif + if (len == 0) + continue; + + /* check if the ip checksum is correct */ + old_sum = iph->ip_sum; + iph->ip_sum = 0x00; + if (old_sum != + checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1)) + /* checksum failed */ + continue; + /* is it a udp packet */ + if (iph->ip_p != IPTYPE_UDP) + continue; + /* check if the source port and destination port and the packet + * say that it is a bootp answer */ + if (udph->uh_dport != htons(UDPPORT_BOOTPC) || udph->uh_sport != htons(UDPPORT_BOOTPS)) + continue; + /* check if it is a Boot Reply */ + if (btph->op != 2) + continue; + /* Comparing our mac address with the one in the bootp reply */ + if (memcmp(get_mac_address(), btph->chaddr, ETH_ALEN)) + continue; + + if(response_buffer) + memcpy(response_buffer, btph, 1720); + + fn_ip->own_ip = btph->yiaddr; + fn_ip->server_ip = btph->siaddr; + strcpy((char *) fn_ip->filename, (char *) btph->file); + +#if DEBUG + printf("\nThese are the details of the bootp reply:\n"); + printf("Our IP address: "); + print_ip((char*) &fn_ip->own_ip); + printf("Next server IP address: "); + print_ip((char*) &fn_ip->server_ip); + printf("Boot file name: %s\n", btph->file); + printf("Packet is: %s\n", btph->file); + for (j = 0; j < len; j++) { + if (j % 16 == 0) + printf("\n"); + printf(" %02x", packet[j]); + } + printf(".\n"); + printf("fn_ip->own_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", + get_mac_address()[0], get_mac_address()[1], + get_mac_address()[2], get_mac_address()[3], + get_mac_address()[4], get_mac_address()[5]); + printf("Header ethh->dest_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", + ethh->dest_mac[0], ethh->dest_mac[1], ethh->dest_mac[2], + ethh->dest_mac[3], ethh->dest_mac[4], ethh->dest_mac[5]); + printf("Header ethh->src_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", + ethh->src_mac[0], ethh->src_mac[1], ethh->src_mac[2], + ethh->src_mac[3], ethh->src_mac[4], ethh->src_mac[5]); + printf("Header ethh->typ: %x\n",ethh->type); + printf("Header iph->ip_hlv: %x\n",iph->ip_hlv); + printf("Header iph->ip_len: %x\n",iph->ip_len); + printf("Header iph->ip_id: %x\n",iph->ip_id); + printf("Header iph->ip_off: %x\n",iph->ip_off); + printf("Header iph->ip_ttl: %x\n",iph->ip_ttl); + printf("Header iph->ip_p: %x\n",iph->ip_p); + printf("Header iph->ip_sum: %x\n",iph->ip_sum); + printf("Header iph->ip_src: %x\n",iph->ip_src); + printf("Header iph->ip_dst: %x\n",iph->ip_dst); + + printf("Header btph->op: %x\n",btph->op); + printf("Header btph->htype: %x\n",btph->htype); + printf("Header btph->hlen: %x\n",btph->hlen); + printf("Header btph->hops: %x\n",btph->hops); + printf("Header btph->xid: %x\n",btph->xid); + printf("Header btph->secs: %x\n",btph->secs); + printf("Header btph->ciaddr: %x\n",btph->ciaddr); + printf("Header btph->yiaddr: %x\n",btph->yiaddr); + printf("Header btph->siaddr: %x\n",btph->siaddr); + printf("Header btph->giaddr: %x\n",btph->giaddr); + + printf("Header btph->chaddr: %02x:%02x:%02x:%02x:%02x:%02x:\n", + btph->chaddr[0], btph->chaddr[1], btph->chaddr[2], + btph->chaddr[3], btph->chaddr[4], btph->chaddr[5]); +#endif + return 0; + + /* only do this for the time specified during set_timer() */ + } while (get_timer() > 0); + return -1; +} + + +int +bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) +{ + int i = (int) retries+1; + fn_ip->own_ip = 0; + + printf(" "); + + response_buffer = ret_buffer; + + do { + printf("\b\b%02d", i); + if (!i--) { + printf("\nGiving up after %d bootp requests\n", + retries+1); + return -1; + } + send_bootp(fn_ip); + /* if the timer in receive_bootp expired it will return + * -1 and we will just send another bootp request just + * in case the previous one was lost. And because we don't + * trust the network cable we keep on doing this 30 times */ + } while (receive_bootp(fn_ip) != 0); + printf("\b\b\b"); + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c new file mode 100644 index 000000000..5f26f3afb --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.c @@ -0,0 +1,998 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/** \file dhcp.c <pre> + * **************** State-transition diagram for DHCP client ************* + * + * +---------+ Note: DHCP-server msg / DHCP-client msg + * | INIT | + * +---------+ + * | + * | - / Discover + * V + * +---------+ + * | SELECT | Timeout + * +---------+ | + * | | + * | Offer / Request | + * | | + * V V + * +---------+ NACK / - *********** + * | REQUEST | ----------------> * FAULT * + * +---------+ *********** + * | + * | ACK / - *********** + * +----------------------> * SUCCESS * + * *********** + * + * ************************************************************************ + * </pre> */ + + +/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/ + +#include <dhcp.h> +#include <ethernet.h> +#include <ipv4.h> +#include <udp.h> +#include <dns.h> + +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <sys/socket.h> +#include <ctype.h> +#include <stdlib.h> + +/* DHCP Message Types */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNACK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +/* DHCP Option Codes */ +#define DHCP_MASK 1 +#define DHCP_ROUTER 3 +#define DHCP_DNS 6 +#define DHCP_REQUESTED_IP 50 +#define DHCP_OVERLOAD 52 +#define DHCP_MSG_TYPE 53 +#define DHCP_SERVER_ID 54 +#define DHCP_REQUEST_LIST 55 +#define DHCP_TFTP_SERVER 66 +#define DHCP_BOOTFILE 67 +#define DHCP_CLIENT_ARCH 93 +#define DHCP_ENDOPT 0xFF +#define DHCP_PADOPT 0x00 + +/* "file/sname" overload option values */ +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME 2 +#define DHCP_OVERLOAD_BOTH 3 + +/* DHCP states codes */ +#define DHCP_STATE_SELECT 1 +#define DHCP_STATE_REQUEST 2 +#define DHCP_STATE_SUCCESS 3 +#define DHCP_STATE_FAULT 4 + +/* DHCP Client Architecture */ +#ifndef DHCPARCH +#define USE_DHCPARCH 0 +#define DHCPARCH 0 +#else +#define USE_DHCPARCH 1 +#endif + +static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63}; +/**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */ + +/** \struct dhcp_options_t + * This structure is used to fill options in DHCP-msg during transmitting + * or to retrieve options from DHCP-msg during receiving. + * <p> + * If flag[i] == TRUE then field for i-th option retains valid value and + * information from this field may retrived (in case of receiving) or will + * be transmitted (in case of transmitting). + * + */ +typedef struct { + uint8_t flag[256]; /**< Show if corresponding opt. is valid */ + uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th + option will be requested from server */ + uint32_t server_ID; /**< o.54 Identifies DHCP-server */ + uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */ + uint32_t dns_IP; /**< o. 6 DNS IP */ + uint32_t router_IP; /**< o. 3 Router IP */ + uint32_t subnet_mask; /**< o. 1 Subnet mask */ + uint8_t msg_type; /**< o.53 DHCP-message type */ + uint8_t overload; /**< o.52 Overload sname/file fields */ + int8_t tftp_server[256]; /**< o.66 TFTP server name */ + int8_t bootfile[256]; /**< o.67 Boot file name */ + uint16_t client_arch; /**< o.93 Client architecture type */ +} dhcp_options_t; + +/** Stores state of DHCP-client (refer to State-transition diagram) */ +static uint8_t dhcp_state; + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +static int32_t +dhcp_attempt(int fd); + +static int32_t +dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct); + +static int32_t +dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, + dhcp_options_t * opt_struct); + +static int8_t +dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, + uint8_t src_options[], uint32_t src_len); + +static int8_t +dhcp_find_option(uint8_t options[], uint32_t len, + uint8_t op_code, uint32_t * op_offset); + +static void +dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, + uint8_t * new_option); + +static void +dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, + uint32_t dst_offset, uint8_t * new_option); + +static void +dhcp_send_discover(int fd); + +static void +dhcp_send_request(int fd); + +static uint8_t +strtoip(int8_t * str, uint32_t * ip); + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static uint32_t dhcp_own_ip = 0; +static uint32_t dhcp_server_ip = 0; +static uint32_t dhcp_siaddr_ip = 0; +static int8_t dhcp_filename[256]; +static int8_t dhcp_tftp_name[256]; + +static char * response_buffer; + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +int32_t +dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) { + + uint32_t dhcp_tftp_ip = 0; + int fd = fn_ip->fd; + + strcpy((char *) dhcp_filename, ""); + strcpy((char *) dhcp_tftp_name, ""); + + response_buffer = ret_buffer; + + if (dhcp_attempt(fd) == 0) + return -1; + + if (fn_ip->own_ip) { + dhcp_own_ip = fn_ip->own_ip; + } + if (fn_ip->server_ip) { + dhcp_siaddr_ip = fn_ip->server_ip; + } + if(fn_ip->filename[0] != 0) { + strcpy((char *) dhcp_filename, (char *) fn_ip->filename); + } + + // TFTP SERVER + if (!strlen((char *) dhcp_tftp_name)) { + if (!dhcp_siaddr_ip) { + // ERROR: TFTP name is not presented + return -3; + } + + // take TFTP-ip from siaddr field + dhcp_tftp_ip = dhcp_siaddr_ip; + } + else { + // TFTP server defined by its name + if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) { + if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&(dhcp_tftp_ip), 4)) { + // DNS error - can't obtain TFTP-server name + // Use TFTP-ip from siaddr field, if presented + if (dhcp_siaddr_ip) { + dhcp_tftp_ip = dhcp_siaddr_ip; + } + else { + // ERROR: Can't obtain TFTP server IP + return -4; + } + } + } + } + + // Store configuration info into filename_ip strucutre + fn_ip -> own_ip = dhcp_own_ip; + fn_ip -> server_ip = dhcp_tftp_ip; + strcpy((char *) fn_ip -> filename, (char *) dhcp_filename); + + return 0; +} + +/** + * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram + */ +static int32_t +dhcp_attempt(int fd) { + int sec; + + // Send DISCOVER message and switch DHCP-client to SELECT state + dhcp_send_discover(fd); + + dhcp_state = DHCP_STATE_SELECT; + + // setting up a timer with a timeout of two seconds + for (sec = 0; sec < 2; sec++) { + set_timer(TICKS_SEC); + do { + receive_ether(fd); + + // Wait until client will switch to Final state or Timeout occurs + switch (dhcp_state) { + case DHCP_STATE_SUCCESS : + return 1; + case DHCP_STATE_FAULT : + return 0; + } + } while (get_timer() > 0); + } + + // timeout + return 0; +} + +/** + * DHCP: Supplements DHCP-message with options stored in structure. + * For more information about option coding see dhcp_options_t. + * + * @param opt_field Points to the "vend" field of DHCP-message + * (destination) + * @param opt_struct this structure stores info about the options which + * will be added to DHCP-message (source) + * @return TRUE - options packed; + * FALSE - error condition occurs. + * @see dhcp_options_t + */ +static int32_t +dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) { + uint8_t * options = opt_field; + uint16_t i, sum; // used to define is any options set + + // magic + memcpy(options, dhcp_magic, 4); + options += 4; + + // fill message type + switch (opt_struct -> msg_type) { + case DHCPDISCOVER : + case DHCPREQUEST : + case DHCPDECLINE : + case DHCPINFORM : + case DHCPRELEASE : + options[0] = DHCP_MSG_TYPE; + options[1] = 1; + options[2] = opt_struct -> msg_type; + options += 3; + break; + default : + return 0; // Unsupported DHCP-message + } + + if (opt_struct -> overload) { + options[0] = DHCP_OVERLOAD; + options[1] = 0x01; + options[2] = opt_struct -> overload; + options +=3; + } + + if (opt_struct -> flag[DHCP_REQUESTED_IP]) { + options[0] = DHCP_REQUESTED_IP; + options[1] = 0x04; + * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP); + options +=6; + } + + if (opt_struct -> flag[DHCP_SERVER_ID]) { + options[0] = DHCP_SERVER_ID; + options[1] = 0x04; + * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID); + options +=6; + } + + sum = 0; + for (i = 0; i < 256; i++) + sum += opt_struct -> request_list[i]; + + if (sum) { + options[0] = DHCP_REQUEST_LIST; + options[1] = sum; + options += 2; + for (i = 0; i < 256; i++) { + if (opt_struct -> request_list[i]) { + options[0] = i; options++; + } + } + } + + if (opt_struct -> flag[DHCP_TFTP_SERVER]) { + options[0] = DHCP_TFTP_SERVER; + options[1] = strlen((char *) opt_struct -> tftp_server) + 1; + memcpy(options + 2, opt_struct -> tftp_server, options[1]); + options += options[1] + 2; + } + + if (opt_struct -> flag[DHCP_BOOTFILE]) { + options[0] = DHCP_BOOTFILE; + options[1] = strlen((char *) opt_struct -> bootfile) + 1; + memcpy(options + 2, opt_struct -> bootfile, options[1]); + options += options[1] + 2; + } + + if (opt_struct -> flag[DHCP_CLIENT_ARCH]) { + options[0] = DHCP_CLIENT_ARCH; + options[1] = 2; + options[2] = (DHCPARCH >> 8); + options[3] = DHCPARCH & 0xff; + options += 4; + } + + // end options + options[0] = 0xFF; + options++; + + return 1; +} + +/** + * DHCP: Extracts encoded options from DHCP-message into the structure. + * For more information about option coding see dhcp_options_t. + * + * @param opt_field Points to the "options" field of DHCP-message + * (source). + * @param opt_len Length of "options" field. + * @param opt_struct this structure stores info about the options which + * was extracted from DHCP-message (destination). + * @return TRUE - options extracted; + * FALSE - error condition occurs. + * @see dhcp_options_t + */ +static int32_t +dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, + dhcp_options_t * opt_struct) { + int32_t offset = 0; + + memset(opt_struct, 0, sizeof(dhcp_options_t)); + + // magic + if (memcmp(opt_field, dhcp_magic, 4)) { + return 0; + } + + offset += 4; + while (offset < opt_len) { + opt_struct -> flag[opt_field[offset]] = 1; + switch(opt_field[offset]) { + case DHCP_OVERLOAD : + opt_struct -> overload = opt_field[offset + 2]; + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_REQUESTED_IP : + opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_MASK : + opt_struct -> flag[DHCP_MASK] = 1; + opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2)); + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_DNS : + opt_struct -> flag[DHCP_DNS] = 1; + opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_ROUTER : + opt_struct -> flag[DHCP_ROUTER] = 1; + opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_MSG_TYPE : + if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9)) + opt_struct -> msg_type = opt_field[offset + 2]; + else + return 0; + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_SERVER_ID : + opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2)); + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_TFTP_SERVER : + memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]); + (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0; + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_BOOTFILE : + memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offset + 1]); + (opt_struct -> bootfile)[opt_field[offset + 1]] = 0; + offset += 2 + opt_field[offset + 1]; + break; + + case DHCP_CLIENT_ARCH : + opt_struct -> client_arch = ((opt_field[offset + 2] << 8) & 0xFF00) | (opt_field[offset + 3] & 0xFF); + offset += 4; + break; + + case DHCP_PADOPT : + offset++; + break; + + case DHCP_ENDOPT : // End of options + return 1; + + default : + offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing + } + } + if (offset == opt_len) + return 1; // options finished without 0xFF + + return 0; +} + +/** + * DHCP: Appends information from source "options" into dest "options". + * This function is used to support "file/sname" overloading. + * + * @param dst_options destanation "options" field + * @param dst_len size of dst_options (modified by this function) + * @param src_options source "options" field + * @param src_len size of src_options + * @return TRUE - options merged; + * FALSE - error condition occurs. + */ +static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, + uint8_t src_options[], uint32_t src_len) { + int32_t dst_offset, src_offset = 0; + + // remove ENDOPT if presented + if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset)) + * dst_len = dst_offset; + + while (src_offset < src_len) { + switch(src_options[src_offset]) { + case DHCP_PADOPT: + src_offset++; + break; + case DHCP_ENDOPT: + return 1; + default: + if (dhcp_find_option(dst_options, * dst_len, + src_options[src_offset], + (uint32_t *) &dst_offset)) { + dhcp_combine_option(dst_options, dst_len, + dst_offset, + (uint8_t *) src_options + + src_offset); + } + else { + dhcp_append_option(dst_options, dst_len, src_options + src_offset); + } + src_offset += 2 + src_options[src_offset + 1]; + } + } + + if (src_offset == src_len) + return 1; + return 0; +} + +/** + * DHCP: Finds given occurrence of the option with the given code (op_code) + * in "options" field of DHCP-message. + * + * @param options "options" field of DHCP-message + * @param len length of the "options" field + * @param op_code code of the option to find + * @param op_offset SUCCESS - offset to an option occurrence; + * FAULT - offset is set to zero. + * @return TRUE - option was find; + * FALSE - option wasn't find. + */ +static int8_t dhcp_find_option(uint8_t options[], uint32_t len, + uint8_t op_code, uint32_t * op_offset) { + uint32_t srch_offset = 0; + * op_offset = 0; + + while (srch_offset < len) { + if (options[srch_offset] == op_code) { + * op_offset = srch_offset; + return 1; + } + if (options[srch_offset] == DHCP_ENDOPT) + return 0; + + if (options[srch_offset] == DHCP_PADOPT) + srch_offset++; + else + srch_offset += 2 + options[srch_offset + 1]; + } + return 0; +} + +/** + * DHCP: Appends new option from one list (src) into the tail + * of another option list (dst) + * + * @param dst_options "options" field of DHCP-message + * @param dst_len length of the "options" field (modified) + * @param new_option points to an option in another list (src) + */ +static void +dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, + uint8_t * new_option) { + memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1))); + * dst_len += 2 + *(new_option + 1); +} + +/** + * DHCP: This function is used when options with the same code are + * presented in both merged lists. In this case information + * about the option from one list (src) is combined (complemented) + * with information about the option in another list (dst). + * + * @param dst_options "options" field of DHCP-message + * @param dst_len length of the "options" field (modified) + * @param dst_offset offset of the option from beginning of the list + * @param new_option points to an option in another list (src) + */ +static void +dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, + uint32_t dst_offset, uint8_t * new_option) { + + uint8_t tmp_buffer[1024]; // use to provide safe memcpy + uint32_t tail_len; + + // move all subsequent options (allocate size for additional info) + tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1]; + + memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len); + memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)), + tmp_buffer, tail_len); + + // add new_content to option + memcpy(dst_options + (* dst_len) - tail_len, new_option + 2, + * (new_option + 1)); + dst_options[dst_offset + 1] += * (new_option + 1); + + // correct dst_len + * dst_len += * (new_option + 1); +} + +/** + * DHCP: Sends DHCP-Discover message. Looks for DHCP servers. + */ +static void +dhcp_send_discover(int fd) { + uint32_t packetsize = sizeof(struct iphdr) + + sizeof(struct udphdr) + sizeof(struct btphdr); + struct btphdr *btph; + dhcp_options_t opt; + + memset(ether_packet, 0, packetsize); + + btph = (struct btphdr *) (ðer_packet[ + sizeof(struct iphdr) + sizeof(struct udphdr)]); + + btph -> op = 1; + btph -> htype = 1; + btph -> hlen = 6; + memcpy(btph -> chaddr, get_mac_address(), 6); + + memset(&opt, 0, sizeof(dhcp_options_t)); + + opt.msg_type = DHCPDISCOVER; + + opt.request_list[DHCP_MASK] = 1; + opt.request_list[DHCP_DNS] = 1; + opt.request_list[DHCP_ROUTER] = 1; + opt.request_list[DHCP_TFTP_SERVER] = 1; + opt.request_list[DHCP_BOOTFILE] = 1; + opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH; + + dhcp_encode_options(btph -> vend, &opt); + + fill_udphdr(ðer_packet[sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ether_packet, sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), + IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF); + + send_ipv4(fd, ether_packet, packetsize); +} + +/** + * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP. + */ +static void +dhcp_send_request(int fd) { + uint32_t packetsize = sizeof(struct iphdr) + + sizeof(struct udphdr) + sizeof(struct btphdr); + struct btphdr *btph; + dhcp_options_t opt; + + memset(ether_packet, 0, packetsize); + + btph = (struct btphdr *) (ðer_packet[ + sizeof(struct iphdr) + sizeof(struct udphdr)]); + + btph -> op = 1; + btph -> htype = 1; + btph -> hlen = 6; + memcpy(btph -> chaddr, get_mac_address(), 6); + + memset(&opt, 0, sizeof(dhcp_options_t)); + + opt.msg_type = DHCPREQUEST; + memcpy(&(opt.requested_IP), &dhcp_own_ip, 4); + opt.flag[DHCP_REQUESTED_IP] = 1; + memcpy(&(opt.server_ID), &dhcp_server_ip, 4); + opt.flag[DHCP_SERVER_ID] = 1; + + opt.request_list[DHCP_MASK] = 1; + opt.request_list[DHCP_DNS] = 1; + opt.request_list[DHCP_ROUTER] = 1; + opt.request_list[DHCP_TFTP_SERVER] = 1; + opt.request_list[DHCP_BOOTFILE] = 1; + opt.request_list[DHCP_CLIENT_ARCH] = USE_DHCPARCH; + opt.flag[DHCP_CLIENT_ARCH] = USE_DHCPARCH; + + dhcp_encode_options(btph -> vend, &opt); + + fill_udphdr(ðer_packet[sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ether_packet, sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), + IPTYPE_UDP, 0, 0xFFFFFFFF); + + send_ipv4(fd, ether_packet, packetsize); +} + + +/** + * DHCP: Sends DHCP-Release message. Releases occupied IP. + */ +void dhcp_send_release(int fd) { + uint32_t packetsize = sizeof(struct iphdr) + + sizeof(struct udphdr) + sizeof(struct btphdr); + struct btphdr *btph; + dhcp_options_t opt; + + btph = (struct btphdr *) (ðer_packet[ + sizeof(struct iphdr) + sizeof(struct udphdr)]); + + memset(ether_packet, 0, packetsize); + + btph -> op = 1; + btph -> htype = 1; + btph -> hlen = 6; + strcpy((char *) btph -> file, ""); + memcpy(btph -> chaddr, get_mac_address(), 6); + btph -> ciaddr = htonl(dhcp_own_ip); + + memset(&opt, 0, sizeof(dhcp_options_t)); + + opt.msg_type = DHCPRELEASE; + opt.server_ID = dhcp_server_ip; + opt.flag[DHCP_SERVER_ID] = 1; + + dhcp_encode_options(btph -> vend, &opt); + + fill_udphdr(ðer_packet[sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ether_packet, sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP, + dhcp_own_ip, dhcp_server_ip); + + send_ipv4(fd, ether_packet, packetsize); +} + +/** + * DHCP: Handles DHCP-messages according to Receive-handle diagram. + * Changes the state of DHCP-client. + * + * @param fd socket descriptor + * @param packet BootP/DHCP-packet to be handled + * @param packetsize length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see btphdr + */ + +int8_t +handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) { + struct btphdr * btph; + struct iphdr * iph; + dhcp_options_t opt; + + memset(&opt, 0, sizeof(dhcp_options_t)); + btph = (struct btphdr *) packet; + iph = (struct iphdr *) packet - sizeof(struct udphdr) - + sizeof(struct iphdr); + if (btph -> op != 2) + return -1; // it is not Boot Reply + + if (memcmp(btph -> vend, dhcp_magic, 4)) { + // It is BootP - RFC 951 + dhcp_own_ip = htonl(btph -> yiaddr); + dhcp_siaddr_ip = htonl(btph -> siaddr); + dhcp_server_ip = htonl(iph -> ip_src); + + if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { + strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, + sizeof(btph -> sname)); + dhcp_tftp_name[sizeof(btph -> sname)] = 0; + } + + if (strlen((char *) btph -> file)) { + strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file)); + dhcp_filename[sizeof(btph -> file)] = 0; + } + + dhcp_state = DHCP_STATE_SUCCESS; + return 0; + } + + + // decode options + if (!dhcp_decode_options(btph -> vend, packetsize - + sizeof(struct btphdr) + sizeof(btph -> vend), + &opt)) { + return -1; // can't decode options + } + + if (opt.overload) { + int16_t decode_res = 0; + uint8_t options[1024]; // buffer for merged options + uint32_t opt_len; + + // move 1-st part of options from vend field into buffer + opt_len = packetsize - sizeof(struct btphdr) + + sizeof(btph -> vend) - 4; + memcpy(options, btph -> vend, opt_len + 4); + + // add other parts + switch (opt.overload) { + case DHCP_OVERLOAD_FILE: + decode_res = dhcp_merge_options(options + 4, &opt_len, + btph -> file, + sizeof(btph -> file)); + break; + case DHCP_OVERLOAD_SNAME: + decode_res = dhcp_merge_options(options + 4, &opt_len, + btph -> sname, + sizeof(btph -> sname)); + break; + case DHCP_OVERLOAD_BOTH: + decode_res = dhcp_merge_options(options + 4, &opt_len, + btph -> file, + sizeof(btph -> file)); + if (!decode_res) + break; + decode_res = dhcp_merge_options(options + 4, &opt_len, + btph -> sname, + sizeof(btph -> sname)); + break; + } + + if (!decode_res) + return -1; // bad options in sname/file fields + + // decode merged options + if (!dhcp_decode_options(options, opt_len + 4, &opt)) { + return -1; // can't decode options + } + } + + if (!opt.msg_type) { + // It is BootP with Extensions - RFC 1497 + // retrieve conf. settings from BootP - reply + dhcp_own_ip = htonl(btph -> yiaddr); + dhcp_siaddr_ip = htonl(btph -> siaddr); + if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { + strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname)); + dhcp_tftp_name[sizeof(btph -> sname)] = 0; + } + + if (strlen((char *) btph -> file)) { + strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file)); + dhcp_filename[sizeof(btph -> file)] = 0; + } + + // retrieve DHCP-server IP from IP-header + dhcp_server_ip = iph -> htonl(ip_src); + + dhcp_state = DHCP_STATE_SUCCESS; + } + else { + // It is DHCP - RFC 2131 & RFC 2132 + // opt contains parameters from server + switch (dhcp_state) { + case DHCP_STATE_SELECT : + if (opt.msg_type == DHCPOFFER) { + dhcp_own_ip = htonl(btph -> yiaddr); + dhcp_server_ip = opt.server_ID; + dhcp_send_request(fd); + dhcp_state = DHCP_STATE_REQUEST; + } + return 0; + case DHCP_STATE_REQUEST : + switch (opt.msg_type) { + case DHCPNACK : + dhcp_own_ip = 0; + dhcp_server_ip = 0; + dhcp_state = DHCP_STATE_FAULT; + break; + case DHCPACK : + dhcp_own_ip = htonl(btph -> yiaddr); + dhcp_server_ip = opt.server_ID; + dhcp_siaddr_ip = htonl(btph -> siaddr); + if (opt.flag[DHCP_TFTP_SERVER]) { + strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server); + } + else { + strcpy((char *) dhcp_tftp_name, ""); + if ((opt.overload != DHCP_OVERLOAD_SNAME && + opt.overload != DHCP_OVERLOAD_BOTH) && + !dhcp_siaddr_ip) { + strncpy((char *) dhcp_tftp_name, + (char *) btph->sname, + sizeof(btph -> sname)); + dhcp_tftp_name[sizeof(btph->sname)] = 0; + } + } + + if (opt.flag[DHCP_BOOTFILE]) { + strcpy((char *) dhcp_filename, (char *) opt.bootfile); + } + else { + strcpy((char *) dhcp_filename, ""); + if (opt.overload != DHCP_OVERLOAD_FILE && + opt.overload != DHCP_OVERLOAD_BOTH && + strlen((char *) btph -> file)) { + strncpy((char *) dhcp_filename, + (char *) btph->file, + sizeof(btph->file)); + dhcp_filename[sizeof(btph -> file)] = 0; + } + } + + dhcp_state = DHCP_STATE_SUCCESS; + break; + default: + break; // Unused DHCP-message - do nothing + } + break; + default : + return -1; // Illegal DHCP-client state + } + } + + if (dhcp_state == DHCP_STATE_SUCCESS) { + + // initialize network entity with real own_ip + // to be able to answer for foreign requests + set_ipv4_address(dhcp_own_ip); + + if(response_buffer) { + if(packetsize <= 1720) + memcpy(response_buffer, packet, packetsize); + else + memcpy(response_buffer, packet, 1720); + } + + /* Subnet mask */ + if (opt.flag[DHCP_MASK]) { + /* Router */ + if (opt.flag[DHCP_ROUTER]) { + set_ipv4_router(opt.router_IP); + set_ipv4_netmask(opt.subnet_mask); + } + } + + /* DNS-server */ + if (opt.flag[DHCP_DNS]) { + dns_init(opt.dns_IP, 0, 4); + } + } + + return 0; +} + +/** + * DHCP: Converts "255.255.255.255" -> 32-bit long IP + * + * @param str string to be converted + * @param ip in case of SUCCESS - 32-bit long IP + in case of FAULT - zero + * @return TRUE - IP converted successfully; + * FALSE - error condition occurs (e.g. bad format) + */ +static uint8_t +strtoip(int8_t * str, uint32_t * ip) { + int8_t ** ptr = &str; + int16_t i = 0, res, len; + char octet[256]; + + * ip = 0; + + while (**ptr != 0) { + if (i > 3 || !isdigit(**ptr)) + return 0; + if (strstr((char *) * ptr, ".") != NULL) { + len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") - + (int8_t *) (* ptr)); + strncpy(octet, (char *) * ptr, len); octet[len] = 0; + * ptr += len; + } + else { + strcpy(octet, (char *) * ptr); + * ptr += strlen(octet); + } + res = strtol(octet, NULL, 10); + if ((res > 255) || (res < 0)) + return 0; + * ip = ((* ip) << 8) + res; + i++; + if (** ptr == '.') + (*ptr)++; + } + + if (i != 4) + return 0; + return 1; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h new file mode 100644 index 000000000..69dd49d4a --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcp.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _DHCP_H_ +#define _DHCP_H_ + +#include <stdint.h> + +#ifdef USE_MTFTP +#include <netlib/mtftp.h> +#else +#include <netlib/tftp.h> +#endif + +/** \struct btphdr + * A header for BootP/DHCP-messages. + * For more information see RFC 951 / RFC 2131. + */ +struct btphdr { + uint8_t op; /**< Identifies is it request (1) or reply (2) */ + uint8_t htype; /**< HW address type (ethernet usually) */ + uint8_t hlen; /**< HW address length */ + uint8_t hops; /**< This info used by relay agents (not used) */ + uint32_t xid; /**< This ID is used to match queries and replies */ + uint16_t secs; /**< Unused */ + uint16_t unused; /**< Unused */ + uint32_t ciaddr; /**< Client IP address (if client knows it) */ + uint32_t yiaddr; /**< "Your" (client) IP address */ + uint32_t siaddr; /**< Next server IP address (TFTP server IP) */ + uint32_t giaddr; /**< Gateway IP address (used by relay agents) */ + uint8_t chaddr[16]; /**< Client HW address */ + uint8_t sname[64]; /**< Server host name (TFTP server name) */ + uint8_t file[128]; /**< Boot file name */ + uint8_t vend[64]; /**< Optional parameters field (DHCP-options) */ +}; + +int bootp(char *ret_buffer, filename_ip_t *, unsigned int); +int dhcpv4(char *ret_buffer, filename_ip_t *); +void dhcp_send_release(int fd); + +/* Handles DHCP-packets, which are detected by receive_ether. */ +extern int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c new file mode 100644 index 000000000..4deef30f2 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c @@ -0,0 +1,216 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/socket.h> +#include <time.h> +#include <netlib/ethernet.h> +#include <netlib/ipv6.h> +#include <netlib/udp.h> +#include <netlib/dhcpv6.h> +#include <netlib/tftp.h> +#include <netlib/dns.h> + +static uint8_t tid[3]; +static uint32_t dhcpv6_state = -1; +static filename_ip_t *my_fn_ip; + +static void +generate_transaction_id(void) +{ + /* TODO: as per RFC 3315 transaction IDs should be generated randomly */ + tid[0] = 1; + tid[1] = 2; + tid[2] = 4; +} + +static void +send_info_request(int fd) +{ + uint8_t ether_packet[ETH_MTU_SIZE]; + uint32_t payload_length; + struct dhcp_message_header *dhcph; + + memset(ether_packet, 0, ETH_MTU_SIZE); + + generate_transaction_id(); + + /* Get an IPv6 packet */ + payload_length = sizeof(struct udphdr) + sizeof(struct dhcp_message_header); + fill_ip6hdr (ether_packet + sizeof(struct ethhdr), + payload_length, IPTYPE_UDP, + get_ipv6_address(), &(all_dhcpv6_ll.addr)); + fill_udphdr ( ether_packet + sizeof(struct ethhdr) + sizeof(struct ip6hdr), + payload_length, DHCP_CLIENT_PORT, DHCP_SERVER_PORT); + dhcph = (struct dhcp_message_header *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr) + + sizeof(struct udphdr)); + + /* Fill in DHCPv6 data */ + dhcph->type = DHCP_INFORMATION_REQUEST; + memcpy( &(dhcph->transaction_id), &tid, 3); + dhcph->option.client_id.code = DHCPV6_OPTION_CLIENTID; + dhcph->option.client_id.length = 10; + dhcph->option.client_id.duid_type = DUID_LL; + dhcph->option.client_id.hardware_type = 1; + memcpy( &(dhcph->option.client_id.mac), + get_mac_address(), 6); + dhcph->option.el_time.code = DHCPV6_OPTION_ELAPSED_TIME; + dhcph->option.el_time.length = 2; + dhcph->option.el_time.time = 0x190; /* 4000 ms */ + dhcph->option.option_request_option.code = DHCPV6_OPTION_ORO; + dhcph->option.option_request_option.length= 6; + dhcph->option.option_request_option.option_code[0] = DHCPV6_OPTION_DNS_SERVERS; + dhcph->option.option_request_option.option_code[1] = DHCPV6_OPTION_DOMAIN_LIST; + dhcph->option.option_request_option.option_code[2] = DHCPV6_OPTION_BOOT_URL; + + + send_ipv6(fd, ether_packet + sizeof(struct ethhdr), + sizeof(struct ethhdr)+ sizeof(struct ip6hdr) + + sizeof(struct udphdr) + + sizeof( struct dhcp_message_header) ); +} + +static int32_t +dhcpv6_attempt(int fd) +{ + int sec; + + // Send information request + send_info_request(fd); + + dhcpv6_state = DHCPV6_STATE_SELECT; + + // setting up a timer with a timeout of two seconds + for (sec = 0; sec < 2; sec++) { + set_timer(TICKS_SEC); + do { + receive_ether(fd); + + // Wait until client will switch to Final state or Timeout occurs + switch (dhcpv6_state) { + case DHCP_STATUSCODE_SUCCESS: + return 1; + case DHCP_STATUSCODE_UNSPECFAIL: //FIXME + return 0; + } + } while (get_timer() > 0); + } + + // timeout + return 0; +} + +int32_t +dhcpv6 ( char *ret_buffer, void *fn_ip) +{ + int fd; + + my_fn_ip = (filename_ip_t *) fn_ip; + fd = my_fn_ip->fd; + + if( !dhcpv6_attempt(fd)) { + return -1; + } + + return 0; +} + +static struct dhcp6_received_options * +dhcp6_process_options (uint8_t *option, int32_t option_length) +{ + struct dhcp_boot_url *option_boot_url; + struct client_identifier *option_clientid; + struct server_identifier *option_serverid; + struct dhcp_dns *option_dns; + struct dhcp_dns_list *option_dns_list; + struct dhcp6_gen_option *option_gen; + struct dhcp6_received_options *received_options; + char buffer[256]; + + + received_options = malloc (sizeof(struct dhcp6_received_options)); + while (option_length > 0) { + switch ((uint16_t) *(option+1)) { + case DHCPV6_OPTION_CLIENTID: + option_clientid = (struct client_identifier *) option; + option = option + option_clientid->length + 4; + option_length = option_length - option_clientid->length - 4; + received_options->client_id = 1; + break; + case DHCPV6_OPTION_SERVERID: + option_serverid = (struct server_identifier *) option; + option = option + option_serverid->length + 4; + option_length = option_length - option_serverid->length - 4; + received_options->server_id = 1; + break; + case DHCPV6_OPTION_DNS_SERVERS: + option_dns = (struct dhcp_dns *) option; + option = option + option_dns->length + 4; + option_length = option_length - option_dns->length - 4; + memcpy( &(my_fn_ip->dns_ip6), + option_dns->p_ip6, + IPV6_ADDR_LENGTH); + dns_init(0, option_dns->p_ip6, 6); + break; + case DHCPV6_OPTION_DOMAIN_LIST: + option_dns_list = (struct dhcp_dns_list *) option; + option = option + option_dns_list->length + 4; + option_length = option_length - option_dns_list->length - 4; + break; + case DHCPV6_OPTION_BOOT_URL: + option_boot_url = (struct dhcp_boot_url *) option; + option = option + option_boot_url->length + 4; + option_length = option_length - option_boot_url->length - 4; + strncpy((char *)buffer, + (const char *)option_boot_url->url, + (size_t)option_boot_url->length); + buffer[option_boot_url->length] = 0; + if (parse_tftp_args(buffer, + (char *)my_fn_ip->server_ip6.addr, + (char *)my_fn_ip->filename, + (int)my_fn_ip->fd, + option_boot_url->length) == -1) + return NULL; + break; + default: + option_gen = (struct dhcp6_gen_option *) option; + option = option + option_gen->length + 4; + option_length = option_length - option_gen->length - 4; + } + } + + return received_options; +} + +uint32_t +handle_dhcpv6(uint8_t * packet, int32_t packetsize) +{ + + uint8_t *first_option; + int32_t option_length; + struct dhcp_message_reply *reply; + reply = (struct dhcp_message_reply *) packet; + + if (reply->type == 7) + dhcpv6_state = DHCP_STATUSCODE_SUCCESS; + + first_option = packet + 4; + option_length = packet + packetsize - first_option; + dhcp6_process_options(first_option, option_length); + + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h new file mode 100644 index 000000000..078a9f11f --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _DHCPV6_H_ +#define _DHCPV6_H_ + +#include <stdint.h> +#include <netlib/ethernet.h> + +#define DHCPV6_STATELESS 0 +#define DHCPV6_STATEFUL 1 + +/* DHCP port numbers */ +#define DHCP_CLIENT_PORT 546 +#define DHCP_SERVER_PORT 547 + +/* DHCPv6 message types */ +#define DHCP_SOLICIT 1 +#define DHCP_ADVERTISE 2 +#define DHCP_REQUEST 3 +#define DHCP_CONFIRM 4 +#define DHCP_RENEW 5 +#define DHCP_REBIND 6 +#define DHCP_REPLY 7 +#define DHCP_RELEASE 8 +#define DHCP_DECLINE 9 +#define DHCP_RECONFIGURE 10 +#define DHCP_INFORMATION_REQUEST 11 +#define RELAY_FORW 12 +#define RELAY_REPL 13 + +/* DHCPv6 option types */ +#define DHCPV6_OPTION_CLIENTID 0x0001 +#define DHCPV6_OPTION_SERVERID 0x0002 +#define DHCPV6_OPTION_IA_NA 3 +#define DHCPV6_OPTION_IA_TA 4 +#define DHCPV6_OPTION_IAADDR 5 +#define DHCPV6_OPTION_ORO 6 +#define DHCPV6_OPTION_PREFEREN 7 +#define DHCPV6_OPTION_ELAPSED_TIME 8 +#define DHCPV6_OPTION_RELAY_MS 9 +#define DHCPV6_OPTION_AUTH 11 +#define DHCPV6_OPTION_UNICAST 12 +#define DHCPV6_OPTION_STATUS_C 13 +#define DHCPV6_OPTION_RAPID_CO 14 +#define DHCPV6_OPTION_USER_CLA 15 +#define DHCPV6_OPTION_VENDOR_C 16 +#define DHCPV6_OPTION_VENDOR_O 17 +#define DHCPV6_OPTION_INTERFAC 18 +#define DHCPV6_OPTION_RECONF_M 19 +#define DHCPV6_OPTION_RECONF_A 20 +#define DHCPV6_OPTION_DNS_SERVERS 23 +#define DHCPV6_OPTION_DOMAIN_LIST 24 +#define DHCPV6_OPTION_BOOT_URL 59 + +/* DHCPv6 status codes */ +#define DHCP_STATUSCODE_SUCCESS 0 +#define DHCP_STATUSCODE_UNSPECFAIL 1 +#define DHCP_STATUSCODE_NOADDRAVAIL 2 +#define DHCP_STATUSCODE_NOBINDING 3 +#define DHCP_STATUSCODE_NOTONLINK 4 +#define DHCP_STATUSCODE_USEMULTICAST 5 +#define DHCPV6_STATE_SELECT 6 + +/* DUID types */ +#define DUID_LLT 1 /* DUID based on Link-layer Address Plus Time */ +#define DUID_EN 2 /* DUID based on Assigned by Vendor Based on Enterprise Number */ +#define DUID_LL 3 /* DUID based on Link-layer Address */ + +/* Prototypes */ +int32_t dhcpv6 ( char *ret_buffer, void *fn_ip); +uint32_t handle_dhcpv6(uint8_t * , int32_t); + +struct dhcp6_gen_option { + uint16_t code; + uint16_t length; +}; + +struct client_identifier { + uint16_t code; + uint16_t length; + uint16_t duid_type; + uint16_t hardware_type; + uint8_t mac[6]; +}; + +struct server_identifier { + uint16_t code; + uint16_t length; + uint16_t duid_type; + uint16_t hardware_type; + uint32_t time; + uint8_t mac[6]; +}; + +struct dhcp_info_request { + struct client_identifier client_id; + struct elapsed_time { + uint16_t code; + uint16_t length; + uint16_t time; + } el_time; + struct option_request { + uint16_t code; + uint16_t length; + uint16_t option_code[5]; + } option_request_option; +}; + +struct dhcp_message_header { + uint8_t type; /* Message type */ + uint8_t transaction_id[3]; /* Transaction id */ + struct dhcp_info_request option; +}; + +struct dhcp_dns { + uint16_t code; + uint16_t length; + uint8_t p_ip6[16]; + uint8_t s_ip6[16]; +}__attribute((packed)); + +struct dhcp_dns_list { + uint16_t code; + uint16_t length; + uint8_t domain[256]; +}__attribute((packed)); + +struct dhcp_boot_url { + uint16_t type; + uint16_t length; + uint8_t url[256]; +}; + +struct dhcp6_received_options { + uint8_t filename; + uint8_t ip; + uint8_t client_id; + uint8_t server_id; +}; +struct dhcp_message_reply { + uint8_t type; /* Message type */ + uint8_t transaction_id[3]; /* Transaction id */ + struct client_identifier client_id; + struct server_identifier server_id; +}; + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c new file mode 100644 index 000000000..0ab1346c9 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.c @@ -0,0 +1,527 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/********************** DEFINITIONS & DECLARATIONS ***********************/ + +#include <dns.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <sys/socket.h> + +#include <ethernet.h> +#include <ipv4.h> +#include <ipv6.h> +#include <udp.h> + +#define DNS_FLAG_MSGTYPE 0xF800 /**< Message type mask (opcode) */ +#define DNS_FLAG_SQUERY 0x0000 /**< Standard query type */ +#define DNS_FLAG_SRESPONSE 0x8000 /**< Standard response type */ +#define DNS_FLAG_RD 0x0100 /**< Recursion desired flag */ +#define DNS_FLAG_RCODE 0x000F /**< Response code mask + (stores err.cond.) code */ +#define DNS_RCODE_NERROR 0 /**< "No errors" code */ + +#define DNS_QTYPE_A 1 /**< A 32-bit IP record type */ +#define DNS_QTYPE_AAAA 0x1c /**< 128-bit IPv6 record type */ +#define DNS_QTYPE_CNAME 5 /**< Canonical name record type */ + +#define DNS_QCLASS_IN 1 /**< Query class for internet msgs */ + +/** \struct dnshdr + * A header for DNS-messages (see RFC 1035, paragraph 4.1.1). + * <p> + * DNS-message consist of DNS-header and 4 optional sections, + * arranged in the following order:<ul> + * <li> DNS-header + * <li> question section + * <li> answer section + * <li> authority section + * <li> additional section + * </ul> + */ +struct dnshdr { + uint16_t id; /**< an identifier used to match up replies */ + uint16_t flags; /**< contains op_code, err_code, etc. */ + uint16_t qdcount; /**< specifies the number of entries in the + question section */ + uint16_t ancount; /**< specifies the number of entries in the + answer section */ + uint16_t nscount; /**< specifies the number of entries in the + authority section */ + uint16_t arcount; /**< specifies the number of entries in the + additional section */ +}; + + +/***************************** PROTOTYPES ********************************/ + +static void +dns_send_query(int fd, int8_t * domain_name, uint8_t ip_version); + +static void +fill_dnshdr(uint8_t * packet, int8_t * domain_name, uint8_t ip_version); + +static uint8_t * +dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name); + +static int8_t +urltohost(char * url, char * host_name); + +static int8_t +hosttodomain(char * host_name, char * domain_name); + +/**************************** LOCAL VARIABLES ****************************/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static int32_t dns_server_ip = 0; +static uint8_t dns_server_ipv6[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int32_t dns_result_ip = 0; +static uint8_t dns_result_ipv6[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static int8_t dns_error = 0; /**< Stores error code or 0 */ +static int8_t dns_domain_name[0x100]; /**< Raw domain name */ +static int8_t dns_domain_cname[0x100]; /**< Canonical domain name */ + +/**************************** IMPLEMENTATION *****************************/ + +/** + * DNS: Initialize the environment for DNS client. + * To perfrom DNS-queries use the function dns_get_ip. + * + * @param device_socket a socket number used to send and receive packets + * @param server_ip DNS-server IPv4 address (e.g. 127.0.0.1) + * @return TRUE in case of successful initialization; + * FALSE in case of fault (e.g. can't obtain MAC). + * @see dns_get_ip + */ +int8_t +dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_version) +{ + if(ip_version == 6) + memcpy(dns_server_ipv6, _dns_server_ipv6, 16); + else + dns_server_ip = _dns_server_ip; + return 0; +} + +/** + * DNS: For given URL retrieves IPv4/IPv6 from DNS-server. + * <p> + * URL can be given in one of the following form: <ul> + * <li> scheme with full path with (without) user and password + * <br>(e.g. "http://user:pass@www.host.org/url-path"); + * <li> host name with url-path + * <br>(e.g. "www.host.org/url-path"); + * <li> nothing but host name + * <br>(e.g. "www.host.org"); + * </ul> + * + * @param fd socket descriptor + * @param url the URL to be resolved + * @param domain_ip In case of SUCCESS stores extracted IP. + * In case of FAULT stores zeros (0.0.0.0). + * @return TRUE - IP successfuly retrieved; + * FALSE - error condition occurs. + */ +int8_t +dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version) +{ + /* this counter is used so that we abort after 30 DNS request */ + int32_t i; + /* this buffer stores host name retrieved from url */ + static int8_t host_name[0x100]; + + (* domain_ip) = 0; + + // Retrieve host name from URL + if (!urltohost((char *) url, (char *) host_name)) { + printf("\nERROR:\t\t\tBad URL!\n"); + return 0; + } + + // Reformat host name into a series of labels + if (!hosttodomain((char *) host_name, (char *) dns_domain_name)) { + printf("\nERROR:\t\t\tBad host name!\n"); + return 0; + } + + // Check if DNS server is presented and accessible + if (dns_server_ip == 0) { + printf("\nERROR:\t\t\tCan't resolve domain name " + "(DNS server is not presented)!\n"); + return 0; + } + + // Use DNS-server to obtain IP + if (ip_version == 6) + memset(dns_result_ipv6, 0, 16); + else + dns_result_ip = 0; + dns_error = 0; + strcpy((char *) dns_domain_cname, ""); + + for(i = 0; i < 30; ++i) { + // Use canonical name in case we obtained it + if (strlen((char *) dns_domain_cname)) + dns_send_query(fd, dns_domain_cname, ip_version); + else + dns_send_query(fd, dns_domain_name, ip_version); + + // setting up a timer with a timeout of one seconds + set_timer(TICKS_SEC); + do { + receive_ether(fd); + if (dns_error) + return 0; // FALSE - error + if ((dns_result_ip != 0) && (ip_version == 4)) { + memcpy(domain_ip, &dns_result_ip, 4); + return 1; // TRUE - success (domain IP retrieved) + } + else if ((dns_result_ipv6[0] != 0) && (ip_version == 6)) { + memcpy(domain_ip, dns_result_ipv6, 16); + return 1; // TRUE - success (domain IP retrieved) + } + } while (get_timer() > 0); + } + + printf("\nGiving up after %d DNS requests\n", i); + return 0; // FALSE - domain name wasn't retrieved +} + +/** + * DNS: Handles DNS-messages according to Receive-handle diagram. + * Sets dns_result_ip for given dns_domain_name (see dns_get_ip) + * or signals error condition occurs during DNS-resolving process + * by setting dns_error flag. + * + * @param packet DNS-packet to be handled + * @param packetsize length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see dns_get_ip + * @see receive_ether + * @see dnshdr + */ +int32_t +handle_dns(uint8_t * packet, int32_t packetsize) +{ + struct dnshdr * dnsh = (struct dnshdr *) packet; + uint8_t * resp_section = packet + sizeof(struct dnshdr); + /* This string stores domain name from DNS-packets */ + static int8_t handle_domain_name[0x100]; + int i; + + // verify ID - is it response for our query? + if (dnsh -> id != htons(0x1234)) + return 0; + + // Is it DNS response? + if ((dnsh -> flags & htons(DNS_FLAG_MSGTYPE)) != htons(DNS_FLAG_SRESPONSE)) + return 0; + + // Is error condition occurs? (check error field in incoming packet) + if ((dnsh -> flags & htons(DNS_FLAG_RCODE)) != DNS_RCODE_NERROR) { + dns_error = 1; + return 0; + } + + /* Pass all (qdcount) records in question section */ + + for (i = 0; i < htons(dnsh -> qdcount); i++) { + // pass QNAME + resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section, + handle_domain_name); + if (resp_section == NULL) { + return -1; // incorrect domain name (bad packet) + } + // pass QTYPE & QCLASS + resp_section += 4; + } + + /* Handle all (ancount) records in answer section */ + + for (i = 0; i < htons(dnsh -> ancount); i++) { + // retrieve domain name from the packet + resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section, + handle_domain_name); + + if (resp_section == NULL) { + return -1; // incorrect domain name (bad packet) + } + + // Check the class of the query (should be IN for Internet) + if (* (uint16_t *) (resp_section + 2) == htons(DNS_QCLASS_IN)) { + // check if retrieved name fit raw or canonical domain name + if (!strcmp((char *) handle_domain_name, (char *) dns_domain_name) || + !strcmp((char *) handle_domain_name, (char *) dns_domain_cname)) { + switch (htons(* (uint16_t *) resp_section)) { + + case DNS_QTYPE_A : + // rdata contains IP + dns_result_ip = htonl(* (uint32_t *) (resp_section + 10)); + return 0; // IP successfully obtained + + case DNS_QTYPE_CNAME : + // rdata contains canonical name, store it for further requests + if (dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section + 10, + dns_domain_cname) == NULL) { + // incorrect domain name (bad packet) + return -1; + } + break; + case DNS_QTYPE_AAAA : + memcpy(dns_result_ipv6, (resp_section + 10), 16); + return 0; // IP successfully obtained + break; + } + } + // continue with next record in answer section + resp_section += htons(* (uint16_t *) (resp_section + 8)) + 10; + } + } + return 0; // Packet successfully handled but IP wasn't obtained +} + +/** + * DNS: Sends a standard DNS-query (read request package) to a DNS-server. + * DNS-server respones with host IP or signals some error condition. + * Responses from the server are handled by handle_dns function. + * + * @param fd socket descriptor + * @param domain_name the domain name given as series of labels preceded + * with length(label) and terminated with 0 + * <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0") + * @see handle_dns + */ +static void +dns_send_query(int fd, int8_t * domain_name, uint8_t ip_version) +{ + int qry_len = strlen((char *) domain_name) + 5; + int iphdr_len = (ip_version == 4) ? sizeof(struct iphdr) : sizeof(struct ip6hdr); + ip6_addr_t server_ipv6; + + uint32_t packetsize = iphdr_len + + sizeof(struct udphdr) + sizeof(struct dnshdr) + + qry_len; + + memset(ether_packet, 0, packetsize); + fill_dnshdr(ðer_packet[ + iphdr_len + sizeof(struct udphdr)], + domain_name, + ip_version); + fill_udphdr(ðer_packet[iphdr_len], + sizeof(struct dnshdr) + + sizeof(struct udphdr) + qry_len, + UDPPORT_DNSC, UDPPORT_DNSS); + if (ip_version == 4) { + fill_iphdr(ether_packet, + sizeof(struct dnshdr) + sizeof(struct udphdr) + + iphdr_len + qry_len, + IPTYPE_UDP, 0, dns_server_ip); + } else { + memcpy(server_ipv6.addr, dns_server_ipv6, 16); + fill_ip6hdr(ether_packet, + sizeof(struct dnshdr) + sizeof(struct udphdr) + qry_len, + IPTYPE_UDP, get_ipv6_address(), + &server_ipv6); + } + + send_ip(fd, ether_packet, packetsize); +} + +/** + * DNS: Creates standard DNS-query package. Places DNS-header + * and question section in a packet and fills it with + * corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_udphdr, fill_iphdr, fill_ethhdr). + * + * @param packet Points to the place where ARP-header must be placed. + * @param domain_name the domain name given as series of labels preceded + * with length(label) and terminated with 0 + * <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0") + * @see fill_udphdr + * @see fill_iphdr + * @see fill_ethhdr + */ +static void +fill_dnshdr(uint8_t * packet, int8_t * domain_name, uint8_t ip_version) +{ + struct dnshdr * dnsh = (struct dnshdr *) packet; + uint8_t * qry_section = packet + sizeof(struct dnshdr); + + dnsh -> id = htons(0x1234); + dnsh -> flags = htons(DNS_FLAG_SQUERY) | htons(DNS_FLAG_RD); + dnsh -> qdcount = htons(1); + + strcpy((char *) qry_section, (char *) domain_name); + qry_section += strlen((char *) domain_name) + 1; + + // fill QTYPE (ask for IP) + if (ip_version == 4) + * (uint16_t *) qry_section = htons(DNS_QTYPE_A); + else + * (uint16_t *) qry_section = htons(DNS_QTYPE_AAAA); + qry_section += 2; + // fill QCLASS (IN is a standard class for Internet) + * (uint16_t *) qry_section = htons(DNS_QCLASS_IN); +} + +/** + * DNS: Extracts domain name from the question or answer section of + * the DNS-message. This function is need to support message + * compression requirement (see RFC 1035, paragraph 4.1.4). + * + * @param dnsh Points at the DNS-header. + * @param head Points at the beginning of the domain_name + * which has to be extracted. + * @param domain_name In case of SUCCESS this string stores extracted name. + * In case of FAULT this string is empty. + * @return NULL in case of FAULT (domain name > 255 octets); + * otherwise pointer to the data following the name. + * @see dnshdr + */ +static uint8_t * +dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name) +{ + int8_t * tail = domain_name; + int8_t * ptr = head; + int8_t * next_section = NULL; + + while (1) { + if ((ptr[0] & 0xC0) == 0xC0) { + // message compressed (reference is used) + next_section = ptr + 2; + ptr = (int8_t *) dnsh + (htons(* (uint16_t *) ptr) & 0x3FFF); + continue; + } + if (ptr[0] == 0) { + // message termination + tail[0] = 0; + ptr += 1; + break; + } + // maximum length for domain name is 255 octets w/o termination sym + if (tail - domain_name + ptr[0] + 1 > 255) { + strcpy((char *) domain_name, ""); + return NULL; + } + memcpy(tail, ptr, ptr[0] + 1); + tail += ptr[0] + 1; + ptr += ptr[0] + 1; + } + + if (next_section == NULL) + next_section = ptr; + + return (uint8_t *) next_section; +} + +/** + * DNS: Parses URL and returns host name. + * Input string can be given as: <ul> + * <li> scheme with full path with (without) user and password + * <br>(e.g. "http://user:pass@www.host.org/url-path"); + * <li> host name with url-path + * <br>(e.g. "www.host.org/url-path"); + * <li> nothing but host name + * <br>(e.g. "www.host.org"); + * </ul> + * + * @param url string that stores incoming URL + * @param host_name In case of SUCCESS this string stores the host name, + * In case of FAULT this string is empty. + * @return TRUE - host name retrieved, + * FALSE - host name > 255 octets or empty. + */ +static int8_t +urltohost(char * url, char * host_name) +{ + uint16_t length1; + uint16_t length2; + + strcpy(host_name, ""); + + if (strstr(url, "://") != NULL) + url = strstr(url, "//") + 2; // URL + + if (strstr(url, "@") != NULL) // truncate user & password + url = strstr(url, "@") + 1; + + if (strstr(url, "/") != NULL) // truncate url path + length1 = strstr(url, "/") - url; + else + length1 = strlen(url); + + if (strstr(url, ":") != NULL) // truncate port path + length2 = strstr(url, ":") - url; + else + length2 = strlen(url); + + if(length1 > length2) + length1 = length2; + + if (length1 == 0) + return 0; // string is empty + if(length1 >= 256) + return 0; // host name is too big + + strncpy(host_name, url, length1); + host_name[length1] = 0; + + return 1; // Host name is retrieved +} + +/** + * DNS: Transforms host name string into a series of labels + * each of them preceded with length(label). 0 is a terminator. + * "www.domain.dom" -> "\3,w,w,w,\6,d,o,m,a,i,n,\3,c,o,m,\0" + * <p> + * This format is used in DNS-messages. + * + * @param host_name incoming string with the host name + * @param domain_name resulting string with series of labels + * or empty string in case of FAULT + * @return TRUE - host name transformed, + * FALSE - host name > 255 octets or label > 63 octets. + */ +static int8_t +hosttodomain(char * host_name, char * domain_name) +{ + char * domain_iter = domain_name; + char * host_iter = host_name; + + strcpy(domain_name, ""); + + if(strlen(host_name) > 255) + return 0; // invalid host name (refer to RFC 1035) + + for(; 1; ++host_iter) { + if(*host_iter != '.' && *host_iter != 0) + continue; + *domain_iter = host_iter - host_name; + if (*domain_iter > 63) { + strcpy(domain_name, ""); + return 0; // invalid host name (refer to RFC 1035) + } + ++domain_iter; + strncpy(domain_iter, host_name, host_iter - host_name); + domain_iter += (host_iter - host_name); + if(*host_iter == 0) { + *domain_iter = 0; + break; + } + host_name = host_iter + 1; + } + return 1; // ok +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h new file mode 100644 index 000000000..82eea4e4d --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/dns.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _DNS_H_ +#define _DNS_H_ + +#include <stdint.h> + +/* Initialize the environment for DNS client. */ +extern int8_t dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_version); + +/* For given URL retrieves IPv4 from DNS-server. */ +extern int8_t dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version); + +/* Handles DNS-packets, which are detected by receive_ether. */ +extern int32_t handle_dns(uint8_t * packet, int32_t packetsize); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c new file mode 100644 index 000000000..bbfd6d1c3 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.c @@ -0,0 +1,187 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/** \file netbase.c <pre> + * *********************** Receive-handle diagram ************************* + * + * Note: Every layer calls out required upper layer + * + * lower + * | MAC/LLC Receive packet (receive_ether) + * | | + * | NETWORK +-----------+---------+ + * | | | + * | IPv4 (handle_ipv4) IPv6 (handle_ipv4) + * | ARP (handle_arp) ICMP & NDP + * | ICMP | + * | | | + * | +---------+---------+ + * | | + * | TRANSPORT +---------+---------+ + * | | | + * | TCP (handle_tcp) UDP (handle_udp) + * | | + * | APPLICATION +----------------+-----------+ + * V | | + * upper DNS (handle_dns) BootP / DHCP (handle_bootp_client) + * + * ************************************************************************ + * </pre> */ + + +/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ + +#include <ethernet.h> +#include <string.h> +#include <sys/socket.h> +#include <ipv4.h> +#include <ipv6.h> + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static uint8_t own_mac[6] = {0, 0, 0, 0, 0, 0}; +static uint8_t multicast_mac[] = {0x01, 0x00, 0x5E}; +static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @param own_mac own hardware-address (MAC) + */ +void +set_mac_address(const uint8_t * _own_mac) { + if (_own_mac) + memcpy(own_mac, _own_mac, 6); + else + memset(own_mac, 0, 6); +} + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @return own hardware-address (MAC) + */ +const uint8_t * +get_mac_address(void) { + return own_mac; +} + +/** + * Ethernet: Check if given multicast address is a multicast MAC address + * starting with 0x3333 + * + * @return true or false + */ +static uint8_t +is_multicast_mac(uint8_t * mac) { + + uint16_t mc = 0x3333; + if (memcmp(mac, &mc, 2) == 0) + return 1; + + return 0; +} + + +/** + * Ethernet: Receives an ethernet-packet and handles it according to + * Receive-handle diagram. + * + * @param fd socket fd + * @return ZERO - packet was handled or no packets received; + * NON ZERO - error condition occurs. + */ +int32_t +receive_ether(int fd) { + int32_t bytes_received; + struct ethhdr * ethh; + + memset(ether_packet, 0, ETH_MTU_SIZE); + bytes_received = recv(fd, ether_packet, ETH_MTU_SIZE, 0); + + if (!bytes_received) // No messages + return 0; + + if (bytes_received < sizeof(struct ethhdr)) + return -1; // packet is too small + + ethh = (struct ethhdr *) ether_packet; + + if(memcmp(ethh->dest_mac, broadcast_mac, 6) != 0 + && memcmp(ethh->dest_mac, multicast_mac, 3) != 0 + && memcmp(ethh->dest_mac, own_mac, 6 ) != 0 + && !is_multicast_mac(ethh->dest_mac)) + return -1; // packet is too small + + switch (htons(ethh -> type)) { + case ETHERTYPE_IP: + return handle_ipv4(fd, (uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); + + case ETHERTYPE_IPv6: + return handle_ipv6(fd, ether_packet + sizeof(struct ethhdr), + bytes_received - sizeof(struct ethhdr)); + + case ETHERTYPE_ARP: + return handle_arp(fd, (uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); + default: + break; + } + return -1; // unknown protocol +} + +/** + * Ethernet: Sends an ethernet frame via the initialized file descriptor. + * + * @return number of transmitted bytes + */ +int +send_ether(int fd, void* buffer, int len) +{ + return send(fd, buffer, len, 0); +} + +/** + * Ethernet: Creates Ethernet-packet. Places Ethernet-header in a packet and + * fills it with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_arphdr, fill_iphdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where eth-header must be placed. + * @param eth_type Type of the next level protocol (e.g. IP or ARP). + * @param src_mac Sender MAC address + * @param dest_mac Receiver MAC address + * @see ethhdr + * @see fill_arphdr + * @see fill_iphdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void +fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac) { + struct ethhdr * ethh = (struct ethhdr *) packet; + + ethh -> type = htons(eth_type); + memcpy(ethh -> src_mac, src_mac, 6); + memcpy(ethh -> dest_mac, dest_mac, 6); +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.h new file mode 100644 index 000000000..e541c8f8e --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ethernet.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _ETHERNET_H +#define _ETHERNET_H + +#include <stdint.h> + +#define ETH_MTU_SIZE 1518 /**< Maximum Transfer Unit */ +#define ETH_ALEN 6 /**< HW address length */ +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_IPv6 0x86DD +#define ETHERTYPE_ARP 0x0806 + +/** \struct ethhdr + * A header for Ethernet-packets. + */ +struct ethhdr { + uint8_t dest_mac[ETH_ALEN]; /**< Destination HW address */ + uint8_t src_mac[ETH_ALEN]; /**< Source HW address */ + uint16_t type; /**< Next level protocol type */ +}; + +/* Initializes ethernet layer */ +extern void set_mac_address(const uint8_t * own_mac); +extern const uint8_t * get_mac_address(void); + +/* Receives and handles packets, according to Receive-handle diagram */ +extern int32_t receive_ether(int fd); + +/* Sends an ethernet frame. */ +extern int send_ether(int fd, void* buffer, int len); + +/* fills ethernet header */ +extern void fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c new file mode 100644 index 000000000..be6cc110f --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c @@ -0,0 +1,391 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <netlib/ethernet.h> +#include <netlib/ipv6.h> +#include <netlib/icmpv6.h> +#include <netlib/ndp.h> +#include <netlib/dhcpv6.h> + +static int ra_received = 0; + +/** + * NET: + * @param fd socket fd + */ +void +send_router_solicitation (int fd) +{ + ip6_addr_t dest_addr; + uint8_t ether_packet[ETH_MTU_SIZE]; + struct packeth headers; + + headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr)); + headers.icmp6h = (struct icmp6hdr *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + /* Destination is "All routers multicast address" (link-local) */ + dest_addr.part.prefix = all_routers_ll.addr.part.prefix; + dest_addr.part.interface_id = all_routers_ll.addr.part.interface_id; + + + /* Fill IPv6 header */ + fill_ip6hdr (ether_packet + sizeof(struct ethhdr), + ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation), + 0x3a, //ICMPV6 + get_ipv6_address(), &dest_addr); + + /* Fill ICMPv6 message */ + headers.icmp6h->type = ICMPV6_ROUTER_SOLICITATION; + headers.icmp6h->code = 0; + headers.icmp6h->icmp6body.router_solicit.lladdr.type = 1; + headers.icmp6h->icmp6body.router_solicit.lladdr.length = 1; + memcpy( &(headers.icmp6h->icmp6body.router_solicit.lladdr.mac), + get_mac_address(), 6); + + send_ip (fd, headers.ip6h, sizeof(struct ip6hdr) + + ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation)); +} + +/** + * NET: Process prefix option in Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +handle_prefixoption (uint8_t *option) +{ + ip6_addr_t prefix; + struct ip6addr_list_entry *new_address; + struct option_prefix *prefix_option; + struct prefix_info *prfx_info; + + prefix_option = (struct option_prefix *) option; + memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH); + + /* Link-local adresses in RAs are nonsense */ + if ( (IPV6_LL_PREFIX & (prefix_option->prefix.part.prefix)) == IPV6_LL_PREFIX ) + return; + + if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime) + return; + + /* Add address created from prefix to IPv6 address list */ + new_address = ip6_prefix2addr (prefix); + if (!new_address) + return; + + /* Process only prefixes we don't already have an adress from */ + if (!unknown_prefix (&new_address->addr)) { + return; + } + + /* Fill struct prefix_info from data in RA and store it in new_address */ + prfx_info = ip6_create_prefix_info(); + if (!prfx_info) + return; + memcpy (&(new_address->prfx_info), prfx_info, sizeof(struct prefix_info)); + + /* Add prefix received in RA to list of known prefixes */ + ip6addr_add (new_address); +} + +/** + * NET: Process source link layer addresses in Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +handle_source_lladdr ( struct option_ll_address *option, struct router *rtr) +{ + memcpy (&(rtr->mac), &(option->mac), 6); +} + +/** + * NET: Process ICMPv6 options in Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +process_ra_options (uint8_t *option, int32_t option_length, struct router *r) +{ + while (option_length > 0) { + switch (*option) { + case ND_OPTION_SOURCE_LL_ADDR: + handle_source_lladdr ((struct option_ll_address *) option, r); + break; + case ND_OPTION_PREFIX_INFO: + handle_prefixoption(option); + break; + default: + break; + } + //option+1 is the length field. length is in units of 8 bytes + option_length = option_length - (*(option+1) * 8); + option = option + (*(option+1) * 8); + } + + return; +} + +/** + * NET: Process Router Advertisements + * + * @param ip6_packet pointer to an IPv6 packet + */ +static void +handle_ra (struct icmp6hdr *icmp6h, uint8_t *ip6_packet) +{ + uint8_t *first_option; + int32_t option_length; + struct ip6hdr *ip6h; + struct router_advertisement *ra; + struct router *rtr; + ip6_addr_t *rtr_ip; + uint8_t rtr_mac[] = {0, 0, 0, 0, 0, 0}; + + ip6h = (struct ip6hdr *) ip6_packet; + ra = (struct router_advertisement *) &icmp6h->icmp6body.ra; + rtr_ip = (ip6_addr_t *) &ip6h->src; + + rtr = find_router (&(ip6h->src)); + if (!rtr) { + rtr = router_create (rtr_mac, rtr_ip); + router_add (rtr); + } + + /* store info from router advertisement in router struct */ + rtr->lifetime = ra->router_lifetime; + rtr->reachable_time = ra->reachable_time; + rtr->retrans_timer = ra->retrans_timer; + + /* save flags concerning address (auto-) configuration */ + ip6_state.managed_mode = ra->flags.managed; + ip6_state.other_config = ra->flags.other; + + /* Process ICMPv6 options in Router Advertisement */ + first_option = (uint8_t *) icmp6h + ICMPv6_HEADER_SIZE + 12; + option_length = (uint8_t *) icmp6h + ip6h->pl - first_option; + process_ra_options( (uint8_t *) first_option, option_length, rtr); + + ra_received = 1; +} + +int is_ra_received(void) +{ + return ra_received; +} + +/** + * NET: + * + * @param fd socket fd + * @param ip6_addr_t *dest_ip6 + */ +void +send_neighbour_solicitation (int fd, ip6_addr_t *dest_ip6) +{ + ip6_addr_t snma; + + uint8_t ether_packet[ETH_MTU_SIZE]; + struct packeth headers; + + memset(ether_packet, 0, ETH_MTU_SIZE); + headers.ethh = (struct ethhdr *) ether_packet; + headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr)); + headers.icmp6h = (struct icmp6hdr *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + /* Fill IPv6 header */ + snma.part.prefix = IPV6_SOLIC_NODE_PREFIX; + snma.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID; + snma.addr[13] = dest_ip6->addr[13]; + snma.addr[14] = dest_ip6->addr[14]; + snma.addr[15] = dest_ip6->addr[15]; + fill_ip6hdr((uint8_t *) headers.ip6h, + ICMPv6_HEADER_SIZE + + sizeof(struct neighbour_solicitation), + 0x3a, //ICMPv6 + get_ipv6_address(), &snma); + + /* Fill ICMPv6 message */ + headers.icmp6h->type = ICMPV6_NEIGHBOUR_SOLICITATION; + headers.icmp6h->code = 0; + memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.target), + dest_ip6, IPV6_ADDR_LENGTH ); + headers.icmp6h->icmp6body.nghb_solicit.lladdr.type = 1; + headers.icmp6h->icmp6body.nghb_solicit.lladdr.length = 1; + memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.lladdr.mac), + get_mac_address(), 6); + + send_ip (fd, ether_packet + sizeof(struct ethhdr), + sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE + + sizeof(struct neighbour_solicitation)); +} + +/** + * NET: + * + * @param fd socket fd + * @param ip6_packet pointer to an IPv6 packet + * @param icmp6hdr pointer to the icmp6 header in ip6_packet + * @param na_flags Neighbour advertisment flags + */ +static void +send_neighbour_advertisement (int fd, struct neighbor *target) +{ + struct na_flags na_adv_flags; + uint8_t ether_packet[ETH_MTU_SIZE]; + struct packeth headers; + + + headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr)); + headers.icmp6h = (struct icmp6hdr *) (ether_packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + /* Fill IPv6 header */ + fill_ip6hdr(ether_packet + sizeof(struct ethhdr), + ICMPv6_HEADER_SIZE + + sizeof(struct neighbour_advertisement), + 0x3a, //ICMPv6 + get_ipv6_address(), (ip6_addr_t *) &(target->ip.addr)); + + /* Fill ICMPv6 message */ + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target), + &(target->ip.addr), IPV6_ADDR_LENGTH ); + headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 1; + headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1; + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac), + get_mac_address(), 6); + + na_adv_flags.is_router = 0; + na_adv_flags.na_is_solicited = 1; + na_adv_flags.override = 1; + + headers.icmp6h->type = ICMPV6_NEIGHBOUR_ADVERTISEMENT; + headers.icmp6h->code = 0; + headers.icmp6h->icmp6body.nghb_adv.router = na_adv_flags.is_router; + + headers.icmp6h->icmp6body.nghb_adv.solicited = na_adv_flags.na_is_solicited; + headers.icmp6h->icmp6body.nghb_adv.override = na_adv_flags.override; + headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 2; + headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1; + + memset( &(headers.icmp6h->icmp6body.nghb_adv.target), 0, + IPV6_ADDR_LENGTH ); + + if( na_adv_flags.na_is_solicited ) { + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target), + get_ipv6_address(), IPV6_ADDR_LENGTH); + } + + memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac), + get_mac_address(), 6); + + send_ip (fd, ether_packet + sizeof(struct ethhdr), + sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE + + sizeof(struct neighbour_advertisement)); +} + +/** + * NET: + * + * @param fd socket fd + * @param ip6_packet pointer to an IPv6 packet + */ +static int8_t +handle_na (int fd, uint8_t *packet) +{ + struct neighbor *n = NULL; + struct packeth headers; + ip6_addr_t ip; + + headers.ethh = (struct ethhdr *) packet; + headers.ip6h = (struct ip6hdr *) ((unsigned char *) headers.ethh + + sizeof(struct ethhdr)); + headers.icmp6h = (struct icmp6hdr *) (packet + + sizeof(struct ethhdr) + + sizeof(struct ip6hdr)); + + memcpy(&(ip.addr), &(headers.ip6h->src), IPV6_ADDR_LENGTH); + + n = find_neighbor (&ip); + + if (!n) { + n= (struct neighbor *) + neighbor_create( packet, &headers ); + if (!n) + return 0; + if (!neighbor_add(n)) + return 0; + } else { + memcpy (&(n->mac), &(headers.ethh->src_mac[0]), 6); + + if (n->eth_len > 0) { + struct ethhdr * ethh = (struct ethhdr *) &(n->eth_frame); + memcpy(ethh->dest_mac, &(n->mac), 6); + send_ether (fd, &(n->eth_frame), n->eth_len + sizeof(struct ethhdr)); + n->eth_len = 0; + } + } + + return 1; +} + +/** + * NET: Handles ICMPv6 messages + * + * @param fd socket fd + * @param ip6_packet pointer to an IPv6 packet + * @param packetsize size of ipv6_packet + */ +int8_t +handle_icmpv6 (int fd, struct ethhdr *etherhdr, + uint8_t *ip6_packet) +{ + + struct icmp6hdr *received_icmp6 = NULL; + struct ip6hdr *received_ip6 = NULL; + struct neighbor target; + + received_ip6 = (struct ip6hdr *) ip6_packet; + received_icmp6 = (struct icmp6hdr *) (ip6_packet + + sizeof(struct ip6hdr)); + memcpy( &(target.ip.addr), &(received_ip6->src), + IPV6_ADDR_LENGTH ); + memcpy( &(target.mac), etherhdr->src_mac, 6); + + /* process ICMPv6 types */ + switch(received_icmp6->type) { + case ICMPV6_NEIGHBOUR_SOLICITATION: + send_neighbour_advertisement(fd, &target); + break; + case ICMPV6_NEIGHBOUR_ADVERTISEMENT: + handle_na(fd, (uint8_t *) ip6_packet - sizeof(struct ethhdr)); + break; + case ICMPV6_ROUTER_ADVERTISEMENT: + handle_ra(received_icmp6, (uint8_t *) received_ip6); + break; + default: + return -1; + } + + return 1; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.h new file mode 100644 index 000000000..32797973d --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/icmpv6.h @@ -0,0 +1,135 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _ICMPV6_H_ +#define _ICMPV6_H_ + +#include <stdint.h> +#include <netlib/ethernet.h> +#include <netlib/ipv6.h> + +#define __ICMPV6_DEBUG__ + +#ifdef __ICMPV6_DEBUG__ +#define ICMPV6_DEBUG_PRINT(format, ...) printf(format, ## __VA_ARGS__) +#else +#define ICMPV6_DEBUG_PRINT(format, ...) +#endif + +#define ICMPv6_HEADER_SIZE 4 /* Size of common fields */ +#define IPTYPE_ICMPV6 0x3a + +/* Error message types */ +#define ICMPV6_DEST_UNREACHABLE 1 /* Destination unreachable */ +#define ICMPV6_PACKET_TOO_BIG 2 /* Packet too big */ +#define ICMPV6_TIME_EXCEEDED 3 /* Time exceeded */ +#define ICMPV6_PARAM_PROBLEM 4 /* Parameter problem */ + +/* Informational message types */ +#define ICMPV6_ECHO_REQUEST 128 /* Echo request */ +#define ICMPV6_ECHO_REPLY 129 /* Echo reply */ +#define ICMPV6_MCAST_LISTENER_QUERY 130 /* Multicast listener query */ +#define ICMPV6_MCAST_LISTENER_REPORT 131 /* Multicast listener report */ +#define ICMPv6 MCAST_LISTENER_DONE 132 /* Multicast listener done */ +#define ICMPV6_ROUTER_SOLICITATION 133 /* Router solicitation */ +#define ICMPV6_ROUTER_ADVERTISEMENT 134 /* Router advertisement */ +#define ICMPV6_NEIGHBOUR_SOLICITATION 135 /* Neighbor solicitation */ +#define ICMPV6_NEIGHBOUR_ADVERTISEMENT 136 /* Neighbor advertisement */ +#define ICMPV6_REDIRECT_MSG 137 /* Redirect message */ + +/******** Functions *******************/ +int8_t handle_icmpv6 (int fd, struct ethhdr *etherhdr, uint8_t *ip6_packet); +void send_neighbour_solicitation(int fd, ip6_addr_t *target_ip6); +void send_router_solicitation(int fd); +int is_ra_received(void); + +/* Prefix information */ +struct option_prefix { + uint8_t type; + uint8_t length; + uint8_t prefix_length; + uint8_t onlink:1, + autom:1, + not_router:1, + not_site_prefix:1, + reserved:4; + uint32_t valid_lifetime; + uint32_t preferred_lifetime; + uint32_t reserved2; + ip6_addr_t prefix; +} __attribute((packed)); + +/* Neighbour advertisement/solicitation flags */ +struct na_flags { + uint8_t is_router:1, /* sender (we) is a router */ + na_is_solicited:1, /* this NA was solicited (asked for) */ + override:1, /* receiver shall override its cache entries */ + unused:5; +}__attribute((packed)); + +/* Source/Target Link-layer address */ +struct option_ll_address{ + uint8_t type; + uint8_t length; + uint8_t mac[ETH_ALEN]; +} __attribute((packed)); + +struct neighbour_solicitation { + uint32_t router:1, + solicited:1, + override:1, + reserved:29; + ip6_addr_t target; + struct option_ll_address lladdr; +} __attribute((packed)); + +struct neighbour_advertisement { + uint32_t router:1, + solicited:1, + override:1, + reserved:29; + ip6_addr_t target; + struct option_ll_address lladdr; +} __attribute((packed)); + +struct router_solicitation { + uint32_t reserved; + struct option_ll_address lladdr; +} __attribute((packed)); + +struct router_advertisement { + uint8_t curr_hop_limit; + struct raflags { + uint8_t managed:1, + other:1, + reserved:6; + } flags; + uint16_t router_lifetime; + uint32_t reachable_time; + uint32_t retrans_timer; + struct option_prefix prefix; + struct option_ll_address ll_addr; +} __attribute((packed)); + +struct icmp6hdr { + uint8_t type; + uint8_t code; + uint16_t checksum; + union { + struct neighbour_solicitation nghb_solicit; + struct neighbour_advertisement nghb_adv; + struct router_solicitation router_solicit; + struct router_advertisement ra; + } icmp6body; +} __attribute((packed)); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c new file mode 100644 index 000000000..8185de5e1 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.c @@ -0,0 +1,904 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/ + +#include <ipv4.h> +#include <udp.h> +#include <tcp.h> +#include <ethernet.h> +#include <time.h> +#include <sys/socket.h> +#include <string.h> + +/* ARP Message types */ +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +/* ARP talbe size (+1) */ +#define ARP_ENTRIES 10 + +/* ICMP Message types */ +#define ICMP_ECHO_REPLY 0 +#define ICMP_DST_UNREACHABLE 3 +#define ICMP_SRC_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO_REQUEST 8 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETER_PROBLEM 12 +#define ICMP_TIMESTAMP_REQUEST 13 +#define ICMP_TIMESTAMP_REPLY 14 +#define ICMP_INFORMATION_REQUEST 15 +#define ICMP_INFORMATION_REPLY 16 + +/** \struct arp_entry + * A entry that describes a mapping between IPv4- and MAC-address. + */ +typedef struct arp_entry arp_entry_t; +struct arp_entry { + uint32_t ipv4_addr; + uint8_t mac_addr[6]; + uint8_t eth_frame[ETH_MTU_SIZE]; + int eth_len; + int pkt_pending; +}; + +/** \struct icmphdr + * ICMP packet + */ +struct icmphdr { + unsigned char type; + unsigned char code; + unsigned short int checksum; + union { + /* for type 3 "Destination Unreachable" */ + unsigned int unused; + /* for type 0 and 8 */ + struct echo { + unsigned short int id; + unsigned short int seq; + } echo; + } options; + union { + /* payload for destination unreachable */ + struct dun { + unsigned char iphdr[20]; + unsigned char data[64]; + } dun; + /* payload for echo or echo reply */ + /* maximum size supported is 84 */ + unsigned char data[84]; + } payload; +}; + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +static unsigned short +checksum(unsigned short *packet, int words); + +static void +arp_send_request(int fd, uint32_t dest_ip); + +static void +arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac); + +static void +fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip); + +static arp_entry_t* +lookup_mac_addr(uint32_t ipv4_addr); + +static void +fill_udp_checksum(struct iphdr *ipv4_hdr); + +static int8_t +handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize); + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/* Routing parameters */ +static uint32_t own_ip = 0; +static uint32_t multicast_ip = 0; +static uint32_t router_ip = 0; +static uint32_t subnet_mask = 0; + +/* helper variables */ +static uint32_t ping_dst_ip; +static const uint8_t null_mac_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +/* There are only (ARP_ENTRIES-1) effective entries because + * the entry that is pointed by arp_producer is never used. + */ +static unsigned int arp_consumer = 0; +static unsigned int arp_producer = 0; +static arp_entry_t arp_table[ARP_ENTRIES]; +static arp_entry_t pending_pkt; + +/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ +int (*send_ip) (int fd, void *, int); + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/** + * IPv4: Initialize the environment for the IPv4 layer. + */ +static void +ipv4_init(void) +{ + int i; + + ping_dst_ip = 0; + + // clear ARP table + arp_consumer = 0; + arp_producer = 0; + for(i=0; i<ARP_ENTRIES; ++i) { + arp_table[i].ipv4_addr = 0; + memset(arp_table[i].mac_addr, 0, 6); + arp_table[i].eth_len = 0; + arp_table[i].pkt_pending = 0; + } + + /* Set IP send function to send_ipv4() */ + send_ip = &send_ipv4; +} + +/** + * IPv4: Set the own IPv4 address. + * + * @param _own_ip client IPv4 address (e.g. 127.0.0.1) + */ +void +set_ipv4_address(uint32_t _own_ip) +{ + own_ip = _own_ip; + ipv4_init(); +} + +/** + * IPv4: Get the own IPv4 address. + * + * @return client IPv4 address (e.g. 127.0.0.1) + */ +uint32_t +get_ipv4_address(void) +{ + return own_ip; +} + +/** + * IPv4: Set the IPv4 multicast address. + * + * @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255) + */ +void +set_ipv4_multicast(uint32_t _multicast_ip) +{ + // is this IP Multicast out of range (224.0.0.0 - 239.255.255.255) + if((htonl(_multicast_ip) < 0xE0000000) + || (htonl(_multicast_ip) > 0xEFFFFFFF)) { + multicast_ip = 0; + memset(multicast_mac, 0xFF, 6); + return; + } + + multicast_ip = _multicast_ip; + multicast_mac[0] = 0x01; + multicast_mac[1] = 0x00; + multicast_mac[2] = 0x5E; + multicast_mac[3] = (uint8_t) 0x7F & (multicast_ip >> 16); + multicast_mac[4] = (uint8_t) 0xFF & (multicast_ip >> 8); + multicast_mac[5] = (uint8_t) 0xFF & (multicast_ip >> 0); +} + +/** + * IPv4: Get the IPv4 multicast address. + * + * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set) + */ +uint32_t +get_ipv4_multicast(void) +{ + return multicast_ip; +} + +/** + * IPv4: Set the routers IPv4 address. + * + * @param _router_ip router IPv4 address + */ +void +set_ipv4_router(uint32_t _router_ip) +{ + router_ip = _router_ip; + ipv4_init(); +} + +/** + * IPv4: Get the routers IPv4 address. + * + * @return router IPv4 address + */ +uint32_t +get_ipv4_router(void) +{ + return router_ip; +} + +/** + * IPv4: Set the subnet mask. + * + * @param _subnet_mask netmask of the own IPv4 address + */ +void +set_ipv4_netmask(uint32_t _subnet_mask) +{ + subnet_mask = _subnet_mask; + ipv4_init(); +} + +/** + * IPv4: Get the subnet mask. + * + * @return netmask of the own IPv4 address + */ +uint32_t +get_ipv4_netmask(void) +{ + return subnet_mask; +} + +/** + * IPv4: Creates IP-packet. Places IP-header in a packet and fills it + * with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where IP-header must be placed. + * @param packetsize Size of the packet in bytes incl. this hdr and data. + * @param ip_proto Type of the next level protocol (e.g. UDP). + * @param ip_src Sender IP address + * @param ip_dst Receiver IP address + * @see iphdr + * @see fill_ethhdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void +fill_iphdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) { + struct iphdr * iph = (struct iphdr *) packet; + + iph -> ip_hlv = 0x45; + iph -> ip_tos = 0x10; + iph -> ip_len = htons(packetsize); + iph -> ip_id = htons(0); + iph -> ip_off = 0; + iph -> ip_ttl = 0xFF; + iph -> ip_p = ip_proto; + iph -> ip_src = htonl(ip_src); + iph -> ip_dst = htonl(ip_dst); + iph -> ip_sum = 0; +} + +/** + * IPv4: Handles IPv4-packets according to Receive-handle diagram. + * + * @param fd socket fd + * @param ip_packet IP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see iphdr + */ +int8_t +handle_ipv4(int fd, uint8_t * ip_packet, int32_t packetsize) +{ + struct iphdr * iph; + int32_t old_sum; + static uint8_t ip_heap[65536 + ETH_MTU_SIZE]; + + if (packetsize < sizeof(struct iphdr)) + return -1; // packet is too small + + iph = (struct iphdr * ) ip_packet; + + /* Drop it if destination IPv4 address is no IPv4 Broadcast, no + * registered IPv4 Multicast and not our Unicast address + */ + if((multicast_ip == 0 && iph->ip_dst >= 0xE0000000 && iph->ip_dst <= 0xEFFFFFFF) + || (multicast_ip != iph->ip_dst && iph->ip_dst != 0xFFFFFFFF && + own_ip != 0 && iph->ip_dst != own_ip)) { + return -1; + } + + old_sum = iph -> ip_sum; + iph -> ip_sum = 0; + if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1)) + return -1; // Wrong IP checksum + + // is it the first fragment in a packet? + if (((iph -> ip_off) & 0x1FFF) == 0) { + // is it part of more fragments? + if (((iph -> ip_off) & 0x2000) == 0x2000) { + memcpy(ip_heap, ip_packet, iph->ip_len); + return 0; + } + } + // it's not the first fragment + else { + // get the first fragment + struct iphdr * iph_first = (struct iphdr * ) ip_heap; + + // is this fragment not part of the first one, then exit + if ((iph_first->ip_id != iph->ip_id ) || + (iph_first->ip_p != iph->ip_p ) || + (iph_first->ip_src != iph->ip_src) || + (iph_first->ip_dst != iph->ip_dst)) { + return 0; + } + + // this fragment is part of the first one! + memcpy(ip_heap + sizeof(struct iphdr) + + ((iph -> ip_off) & 0x1FFF) * 8, + ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + + // is it part of more fragments? Then return. + if (((iph -> ip_off) & 0x2000) == 0x2000) { + return 0; + } + + // packet is completly reassambled now! + + // recalculate ip_len and set iph and ip_packet to the + iph_first->ip_len = iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8; + + // set iph and ip_packet to the resulting packet. + ip_packet = ip_heap; + iph = (struct iphdr * ) ip_packet; + } + + switch (iph -> ip_p) { + case IPTYPE_ICMP: + return handle_icmp(fd, iph, ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + case IPTYPE_UDP: + return handle_udp(fd, ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + case IPTYPE_TCP: + return handle_tcp(ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + default: + break; + } + return -1; // Unknown protocol +} + +/** + * IPv4: Send IPv4-packets. + * + * Before the packet is sent there are some patcches performed: + * - IPv4 source address is replaced by our unicast IPV4 address + * if it is set to 0 or 1 + * - IPv4 destination address is replaced by our multicast IPV4 address + * if it is set to 1 + * - IPv4 checksum is calculaded. + * - If payload type is UDP, then the UDP checksum is calculated also. + * + * We send an ARP request first, if this is the first packet sent to + * the declared IPv4 destination address. In this case we store the + * the packet and send it later if we receive the ARP response. + * If the MAC address is known already, then we send the packet immediately. + * If there is already an ARP request pending, then we drop this packet + * and send again an ARP request. + * + * @param fd socket fd + * @param ip_packet IP-packet to be handled + * @param packetsize Length of the packet + * @return -2 - packet dropped (MAC address not resolved - ARP request pending) + * -1 - packet dropped (bad format) + * 0 - packet stored (ARP request sent - packet will be sent if + * ARP response is received) + * >0 - packet send (number of transmitted bytes is returned) + * + * @see receive_ether + * @see iphdr + */ +int +send_ipv4(int fd, void* buffer, int len) +{ + arp_entry_t *arp_entry = 0; + struct iphdr *ip; + const uint8_t *mac_addr = 0; + uint32_t ip_dst = 0; + + if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE) + return -1; + + ip = (struct iphdr *) buffer; + + /* Replace source IPv4 address with our own unicast IPv4 address + * if it's 0 (= own unicast source address not specified). + */ + if(ip->ip_src == 0) { + ip->ip_src = htonl( own_ip ); + } + /* Replace source IPv4 address with our unicast IPv4 address and + * replace destination IPv4 address with our multicast IPv4 address + * if source address is set to 1. + */ + else if(ip->ip_src == 1) { + ip->ip_src = htonl( own_ip ); + ip->ip_dst = htonl( multicast_ip ); + } + + // Calculate the IPv4 checksum + ip->ip_sum = 0; + ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1); + + // if payload type is UDP, then we need to calculate the + // UDP checksum that depends on the IP header + if(ip->ip_p == IPTYPE_UDP) { + fill_udp_checksum(ip); + } + + ip_dst = ip->ip_dst; + // Check if the MAC address is already cached + if(~ip->ip_dst == 0 + || ( ((~subnet_mask) & ip->ip_dst) == ~subnet_mask && + ( subnet_mask & ip->ip_dst) == (subnet_mask & own_ip))) { + arp_entry = &arp_table[arp_producer]; + mac_addr = broadcast_mac; + } + else if(ip->ip_dst == multicast_ip) { + arp_entry = &arp_table[arp_producer]; + mac_addr = multicast_mac; + } + else { + // Check if IP address is in the same subnet as we are + if((subnet_mask & own_ip) == (subnet_mask & ip->ip_dst)) + arp_entry = lookup_mac_addr(ip->ip_dst); + // if not then we need to know the router's IP address + else { + ip_dst = router_ip; + arp_entry = lookup_mac_addr(router_ip); + } + if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0) + mac_addr = arp_entry->mac_addr; + } + + // If we could not resolv the MAC address by our own... + if(!mac_addr) { + // send the ARP request + arp_send_request(fd, ip_dst); + + // drop the current packet if there is already a ARP request pending + if(arp_entry) + return -2; + + // take the next entry in the ARP table to prepare a the new ARP entry. + arp_entry = &arp_table[arp_producer]; + arp_producer = (arp_producer+1)%ARP_ENTRIES; + + // if ARP table is full then we must drop the oldes entry. + if(arp_consumer == arp_producer) + arp_consumer = (arp_consumer+1)%ARP_ENTRIES; + + // store the packet to be send if the ARP reply is received + arp_entry->pkt_pending = 1; + arp_entry->ipv4_addr = ip_dst; + memset(arp_entry->mac_addr, 0, 6); + pending_pkt.ipv4_addr = ip_dst; + memset(pending_pkt.mac_addr, 0, 6); + fill_ethhdr (pending_pkt.eth_frame, htons(ETHERTYPE_IP), + get_mac_address(), null_mac_addr); + memcpy(&pending_pkt.eth_frame[sizeof(struct ethhdr)], + buffer, len); + pending_pkt.eth_len = len + sizeof(struct ethhdr); + + set_timer(TICKS_SEC); + do { + receive_ether(fd); + if (!arp_entry->eth_len) + break; + } while (get_timer() > 0); + + return 0; + } + + // Send the packet with the known MAC address + fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP), + get_mac_address(), mac_addr); + memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len); + return send_ether(fd, arp_entry->eth_frame, len + sizeof(struct ethhdr)); +} + +/** + * IPv4: Calculate UDP checksum. Places the result into the UDP-header. + * <p> + * Use this function after filling the UDP payload. + * + * @param ipv4_hdr Points to the place where IPv4-header starts. + */ + +static void +fill_udp_checksum(struct iphdr *ipv4_hdr) +{ + int i; + unsigned long checksum = 0; + struct iphdr ip_hdr; + char *ptr; + udp_hdr_t *udp_hdr; + + udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1); + udp_hdr->uh_sum = 0; + + memset(&ip_hdr, 0, sizeof(struct iphdr)); + ip_hdr.ip_src = ipv4_hdr->ip_src; + ip_hdr.ip_dst = ipv4_hdr->ip_dst; + ip_hdr.ip_len = udp_hdr->uh_ulen; + ip_hdr.ip_p = ipv4_hdr->ip_p; + + ptr = (char*) udp_hdr; + for (i = 0; i < udp_hdr->uh_ulen; i+=2) + checksum += *((uint16_t*) &ptr[i]); + + ptr = (char*) &ip_hdr; + for (i = 0; i < sizeof(struct iphdr); i+=2) + checksum += *((uint16_t*) &ptr[i]); + + checksum = (checksum >> 16) + (checksum & 0xffff); + checksum += (checksum >> 16); + udp_hdr->uh_sum = ~checksum; + + /* As per RFC 768, if the computed checksum is zero, + * it is transmitted as all ones (the equivalent in + * one's complement arithmetic). + */ + if (udp_hdr->uh_sum == 0) + udp_hdr->uh_sum = ~udp_hdr->uh_sum; +} + +/** + * IPv4: Calculates checksum for IP header. + * + * @param packet Points to the IP-header + * @param words Size of the packet in words incl. IP-header and data. + * @return Checksum + * @see iphdr + */ +static unsigned short +checksum(unsigned short * packet, int words) +{ + unsigned long checksum; + + for (checksum = 0; words > 0; words--) + checksum += *packet++; + checksum = (checksum >> 16) + (checksum & 0xffff); + checksum += (checksum >> 16); + + return ~checksum; +} + +static arp_entry_t* +lookup_mac_addr(uint32_t ipv4_addr) +{ + unsigned int i; + + for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) { + if(arp_table[i].ipv4_addr == ipv4_addr) + return &arp_table[i]; + } + return 0; +} + + +/** + * ARP: Sends an ARP-request package. + * For given IPv4 retrieves MAC via ARP (makes several attempts) + * + * @param fd socket fd + * @param dest_ip IP of the host which MAC should be obtained + */ +static void +arp_send_request(int fd, uint32_t dest_ip) +{ + arp_entry_t *arp_entry = &arp_table[arp_producer]; + + memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr)); + fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST, + get_mac_address(), own_ip, broadcast_mac, dest_ip); + fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, + get_mac_address(), broadcast_mac); + + send_ether(fd, arp_entry->eth_frame, + sizeof(struct ethhdr) + sizeof(struct arphdr)); +} + +/** + * ARP: Sends an ARP-reply package. + * This package is used to serve foreign requests (in case IP in + * foreign request matches our host IP). + * + * @param fd socket fd + * @param src_ip requester IP address (foreign IP) + * @param src_mac requester MAC address (foreign MAC) + */ +static void +arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac) +{ + arp_entry_t *arp_entry = &arp_table[arp_producer]; + + memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr)); + fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, + get_mac_address(), src_mac); + fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY, + get_mac_address(), own_ip, src_mac, src_ip); + + send_ether(fd, arp_entry->eth_frame, + sizeof(struct ethhdr) + sizeof(struct arphdr)); +} + +/** + * ARP: Creates ARP package. Places ARP-header in a packet and fills it + * with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_ethhdr). + * + * @param packet Points to the place where ARP-header must be placed. + * @param opcode Identifies is it request (ARP_REQUEST) + * or reply (ARP_REPLY) package. + * @param src_mac sender MAC address + * @param src_ip sender IP address + * @param dest_mac receiver MAC address + * @param dest_ip receiver IP address + * @see arphdr + * @see fill_ethhdr + */ +static void +fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip) +{ + struct arphdr * arph = (struct arphdr *) packet; + + arph -> hw_type = htons(1); + arph -> proto_type = htons(ETHERTYPE_IP); + arph -> hw_len = 6; + arph -> proto_len = 4; + arph -> opcode = htons(opcode); + + memcpy(arph->src_mac, src_mac, 6); + arph->src_ip = htonl(src_ip); + memcpy(arph->dest_mac, dest_mac, 6); + arph->dest_ip = htonl(dest_ip); +} + +/** + * ARP: Handles ARP-messages according to Receive-handle diagram. + * Updates arp_table for outstanding ARP requests (see arp_getmac). + * + * @param fd socket fd + * @param packet ARP-packet to be handled + * @param packetsize length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see arp_getmac + * @see receive_ether + * @see arphdr + */ +int8_t +handle_arp(int fd, uint8_t * packet, int32_t packetsize) +{ + struct arphdr * arph = (struct arphdr *) packet; + + if (packetsize < sizeof(struct arphdr)) + return -1; // Packet is too small + + if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP)) + return -1; // Unknown hardware or unsupported protocol + + if (arph -> dest_ip != htonl(own_ip)) + return -1; // receiver IP doesn't match our IP + + switch(htons(arph -> opcode)) { + case ARP_REQUEST: + // foreign request + if(own_ip != 0) + arp_send_reply(fd, htonl(arph->src_ip), arph -> src_mac); + return 0; // no error + case ARP_REPLY: { + unsigned int i; + // if it is not for us -> return immediately + if(memcmp(get_mac_address(), arph->dest_mac, 6)) { + return 0; // no error + } + + if(arph->src_ip == 0) { + // we are not interested for a MAC address if + // the IPv4 address is 0.0.0.0 or ff.ff.ff.ff + return -1; + } + + // now let's find the corresponding entry in the ARP table + + for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) { + if(arp_table[i].ipv4_addr == arph->src_ip) + break; + } + if(i == arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr, 6) != 0) { + // we have not asked to resolve this IPv4 address ! + return -1; + } + + memcpy(arp_table[i].mac_addr, arph->src_mac, 6); + + // do we have something to send + if (arp_table[i].pkt_pending) { + struct ethhdr * ethh = (struct ethhdr *) pending_pkt.eth_frame; + memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6); + + send_ether(fd, pending_pkt.eth_frame, pending_pkt.eth_len); + pending_pkt.pkt_pending = 0; + arp_table[i].eth_len = 0; + } + return 0; // no error + } + default: + break; + } + return -1; // Invalid message type +} + +/** + * ICMP: Send an ICMP Echo request to destination IPv4 address. + * This function does also set a global variable to the + * destination IPv4 address. If there is an ICMP Echo Reply + * received later then the variable is set back to 0. + * In other words, reading a value of 0 form this variable + * means that an answer to the request has been arrived. + * + * @param fd socket descriptor + * @param _ping_dst_ip destination IPv4 address + */ +void +ping_ipv4(int fd, uint32_t _ping_dst_ip) +{ + unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)]; + struct icmphdr *icmp; + + ping_dst_ip = _ping_dst_ip; + + if(ping_dst_ip == 0) + return; + + fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP, + 0, ping_dst_ip); + icmp = (struct icmphdr *) (packet + sizeof(struct iphdr)); + icmp->type = ICMP_ECHO_REQUEST; + icmp->code = 0; + icmp->checksum = 0; + icmp->options.echo.id = 0xd476; + icmp->options.echo.seq = 1; + + memset(icmp->payload.data, '*', sizeof(icmp->payload.data)); + + icmp->checksum = + checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1); + send_ipv4(fd, packet, sizeof(struct iphdr) + sizeof(struct icmphdr)); +} + +/** + * ICMP: Return host IPv4 address that we are waiting for a + * ICMP Echo reply message. If this value is 0 then we have + * received an reply. + * + * @return ping_dst_ip host IPv4 address + */ +uint32_t +pong_ipv4(void) +{ + return ping_dst_ip; +} + +/** + * ICMP: Handles ICMP-packets according to Receive-handle diagram. + * + * @param fd socket fd + * @param icmp_packet ICMP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see handle_ipv4 + */ +static int8_t +handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize) +{ + struct icmphdr *icmp = (struct icmphdr *) packet; + + switch(icmp->type) { + case ICMP_ECHO_REPLY: + if (icmp->options.echo.id != 0xd476) + return -1; + if (icmp->options.echo.seq != 1) + return -1; + if(ping_dst_ip != iph->ip_src + || ping_dst_ip == 0) + return -1; + ping_dst_ip = 0; + break; + case ICMP_DST_UNREACHABLE: { + // We've got Destination Unreachable msg + // Inform corresponding upper network layers + struct iphdr * bad_iph = (struct iphdr * ) &icmp->payload; + + switch(bad_iph->ip_p) { + case IPTYPE_TCP: + handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize + - sizeof(struct icmphdr) + - sizeof(struct iphdr), icmp->code); + break; + case IPTYPE_UDP: + handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize + - sizeof(struct icmphdr) + - sizeof(struct iphdr), icmp->code); + break; + } + break; + } + case ICMP_SRC_QUENCH: + break; + case ICMP_REDIRECT: + break; + case ICMP_ECHO_REQUEST: { + // We've got an Echo Request - answer with Echo Replay msg + unsigned char reply_packet[sizeof(struct iphdr) + packetsize]; + struct icmphdr *reply_icmph; + + fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize, + IPTYPE_ICMP, 0, iph->ip_src); + + reply_icmph = (struct icmphdr *) &reply_packet[sizeof(struct iphdr)]; + memcpy(reply_icmph, packet, packetsize); + reply_icmph -> type = ICMP_ECHO_REPLY; + reply_icmph -> checksum = 0; + reply_icmph->checksum = checksum((unsigned short *) reply_icmph, + sizeof(struct icmphdr) >> 1); + + send_ipv4(fd, reply_packet, sizeof(struct iphdr) + packetsize); + break; + } + case ICMP_TIME_EXCEEDED: + break; + case ICMP_PARAMETER_PROBLEM: + break; + case ICMP_TIMESTAMP_REQUEST: + break; + case ICMP_TIMESTAMP_REPLY: + break; + case ICMP_INFORMATION_REQUEST: + break; + case ICMP_INFORMATION_REPLY: + break; + } + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h new file mode 100644 index 000000000..eb719f8b2 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv4.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _IPV4_H_ +#define _IPV4_H_ + +#include <stdint.h> + +#define IPTYPE_ICMP 1 + +/** \struct iphdr + * A header for IP-packets. + * For more information see RFC 791. + */ +struct iphdr { + uint8_t ip_hlv; /**< Header length and version of the header */ + uint8_t ip_tos; /**< Type of Service */ + uint16_t ip_len; /**< Length in octets, inlc. this header and data */ + uint16_t ip_id; /**< ID is used to aid in assembling framents */ + uint16_t ip_off; /**< Info about fragmentation (control, offset) */ + uint8_t ip_ttl; /**< Time to Live */ + uint8_t ip_p; /**< Next level protocol type */ + uint16_t ip_sum; /**< Header checksum */ + uint32_t ip_src; /**< Source IP address */ + uint32_t ip_dst; /**< Destination IP address */ +}; +typedef struct iphdr ipv4_hdr_t; + +/* ICMP Error Codes */ +#define ICMP_NET_UNREACHABLE 0 +#define ICMP_HOST_UNREACHABLE 1 +#define ICMP_PROTOCOL_UNREACHABLE 2 +#define ICMP_PORT_UNREACHABLE 3 +#define ICMP_FRAGMENTATION_NEEDED 4 +#define ICMP_SOURCE_ROUTE_FAILED 5 + +/** \struct arphdr + * A header for ARP-messages, retains info about HW and proto addresses. + * For more information see RFC 826. + */ +struct arphdr { + uint16_t hw_type; /**< HW address space (1 for Ethernet) */ + uint16_t proto_type; /**< Protocol address space */ + uint8_t hw_len; /**< Byte length of each HW address */ + uint8_t proto_len; /**< Byte length of each proto address */ + uint16_t opcode; /**< Identifies is it request (1) or reply (2) */ + uint8_t src_mac[6]; /**< HW address of sender of this packet */ + uint32_t src_ip; /**< Proto address of sender of this packet */ + uint8_t dest_mac[6]; /**< HW address of target of this packet */ + uint32_t dest_ip; /**< Proto address of target of this packet */ +} __attribute((packed)); + +/*>>>>>>>>>>>>> Initialization of the IPv4 network layer. <<<<<<<<<<<<<*/ +extern void set_ipv4_address(uint32_t own_ip); +extern uint32_t get_ipv4_address(void); +extern void set_ipv4_multicast(uint32_t multicast_ip); +extern uint32_t get_ipv4_multicast(void); +extern void set_ipv4_router(uint32_t router_ip); +extern uint32_t get_ipv4_router(void); +extern void set_ipv4_netmask(uint32_t subnet_mask); +extern uint32_t get_ipv4_netmask(void); + +extern int (*send_ip) (int fd, void *, int); + +/* fills ip header */ +extern void fill_iphdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst); + +/* Send a IPv4 packet. Adding the Ethernet-Header and resolving the + * MAC address is done transparent in the background if necessary. + */ +extern int send_ipv4(int fd, void* buffer, int len); + +/* Sends an ICMP Echo request to destination IPv4 address */ +extern void ping_ipv4(int fd, uint32_t _ping_dst_ip); + +/* Returns host IPv4 address that we are waiting for a response */ +extern uint32_t pong_ipv4(void); + +/* Handles IPv4-packets that are detected by receive_ether. */ +extern int8_t handle_ipv4(int fd, uint8_t * packet, int32_t packetsize); + +/* Handles ARP-packets that are detected by receive_ether. */ +extern int8_t handle_arp(int fd, uint8_t * packet, int32_t packetsize); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c new file mode 100644 index 000000000..0cb0a2e7b --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.c @@ -0,0 +1,768 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <ctype.h> +#include <sys/socket.h> +#include <netlib/ethernet.h> +#include <netlib/ipv6.h> +#include <netlib/icmpv6.h> +#include <netlib/ndp.h> +#include <netlib/udp.h> + +#undef IPV6_DEBUG +//#define IPV6_DEBUG +#ifdef IPV6_DEBUG +#define dprintf(_x ...) do { printf(_x); } while (0) +#else +#define dprintf(_x ...) +#endif + +/****************************** PROTOTYPES *******************************/ +int8_t ip6addr_add (struct ip6addr_list_entry *new_address); +static void ipv6_init(int fd); +static int ip6_is_multicast (ip6_addr_t * ip); + +/****************************** LOCAL VARIABLES **************************/ + +/* Own IPv6 address */ +static struct ip6addr_list_entry *own_ip6; + +/* Null IPv6 address */ +static ip6_addr_t null_ip6; + +/* helper variables */ +static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + +/****************************** IMPLEMENTATION ***************************/ + +/** + * IPv6: Set the own IPv6 address. + * + * @param fd Socket descriptor + * @param _own_ip client IPv6 address (e.g. ::1) + */ +void +set_ipv6_address (int fd, ip6_addr_t *_own_ip6) +{ + own_ip6 = malloc (sizeof(struct ip6addr_list_entry)); + + /* If no address was passed as a parameter generate a link-local + * address from our MAC address.*/ + if (_own_ip6 == NULL) + memcpy(&(own_ip6->addr.addr), + ip6_create_ll_address(get_mac_address()), + IPV6_ADDR_LENGTH); + else + memcpy (&(own_ip6->addr.addr), _own_ip6, 16); + + /* Add to our list of IPv6 addresses */ + ip6addr_add (own_ip6); + + ipv6_init(fd); +} + +/** + * IPv6: Get pointer to own IPv6 address. + * + * @return pointer to client IPv6 address (e.g. ::1) + */ +ip6_addr_t * +get_ipv6_address (void) +{ + return (ip6_addr_t *) &(own_ip6->addr); +} + +/** + * IPv6: Search for IPv6 address in list + * + * @return 0 - IPv6 address is not in list + * 1 - IPv6 address is in list + */ +static int8_t +find_ip6addr (ip6_addr_t *ip) +{ + struct ip6addr_list_entry *n = NULL; + + if (ip == NULL) + return 0; + + for (n = first_ip6; n != NULL ; n=n->next) + if (ip6_cmp (&(n->addr), ip)) + return 1; /* IPv6 address is in our list*/ + + return 0; /* not one of our IPv6 addresses*/ +} + +/** + * NET: Handles IPv6-packets + * + * @param fd - Socket descriptor + * @param ip6_packet - Pointer to IPv6 header + * @param packetsize - Size of Ipv6 packet + * @return ERROR - -1 if packet is too small or unknown protocol + * return value of handle_udp + * + * @see handle_udp + * @see ip6hdr + */ +int8_t +handle_ipv6 (int fd, uint8_t * ip6_packet, int32_t packetsize) +{ + + struct ip6hdr *ip6 = NULL; + ip6 = (struct ip6hdr *) ip6_packet; + + /* Only handle packets which are for us */ + if (! find_ip6addr(&(ip6->dst))) + return -1; + + if (packetsize < sizeof(struct ip6hdr)) + return -1; // packet is too small + + switch (ip6->nh) { + case IPTYPE_UDP: + return handle_udp (fd, ip6_packet + sizeof (struct ip6hdr), + ip6->pl); + case IPTYPE_ICMPV6: + return handle_icmpv6 (fd, (struct ethhdr *) ip6_packet - sizeof(struct ethhdr), + ip6_packet); + } + + return -1; // unknown protocol +} + + /** + * NET: Creates IPv6-packet. Places IPv6-header in a packet and fills it + * with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where IPv6-header must be placed. + * @param packetsize Size of payload (i.e. excluding ethhdr and ip6hdr) + * @param ip_proto Type of the next level protocol (e.g. UDP). + * @param ip6_src Sender IPv6 address + * @param ip6_dst Receiver IPv6 address + * @see ip6hdr + * @see fill_iphdr + * @see fill_ethhdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void +fill_ip6hdr (uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst) +{ + + struct ip6hdr * ip6h = (struct ip6hdr *) packet; + + ip6h->ver_tc_fl = 6 << 28; // set version to 6 + ip6h->pl = packetsize; // IPv6 payload size + ip6h->nh = ip_proto; + ip6h->hl = 255; + memcpy (&(ip6h->src), ip6_src, IPV6_ADDR_LENGTH); + memcpy (&(ip6h->dst), ip6_dst, IPV6_ADDR_LENGTH); +} + +/** + * NET: For a given MAC calculates EUI64-Identifier. + * See RFC 4291 "IP Version 6 Addressing Architecture" + * + */ +uint64_t +mac2eui64 (const uint8_t *mac) +{ + uint8_t eui64id[8]; + uint64_t retid; + + memcpy (eui64id, mac, 3); + memcpy (eui64id + 5, mac + 3, 3); + eui64id[3] = 0xff; + eui64id[4] = 0xfe; + + memcpy(&retid, eui64id, 8); + return retid; +} + +/** + * NET: create link-local IPv6 address + * + * @param own_mac MAC of NIC + * @return ll_addr pointer to newly created link-local address + */ +ip6_addr_t * +ip6_create_ll_address (const uint8_t *own_mac) +{ + ip6_addr_t *ll_addr; + + ll_addr = malloc (sizeof (struct ip6addr_list_entry)); + memset (ll_addr, 0, IPV6_ADDR_LENGTH); + ll_addr->part.prefix |= IPV6_LL_PREFIX; + ll_addr->part.interface_id |= mac2eui64((uint8_t *) own_mac); + + return ll_addr; +} + +/* + * NET: check if we already have an address with the same prefix. + * @param struct ip6_addr_list_entry *ip6 + * @return true or false + */ +int8_t +unknown_prefix (ip6_addr_t *ip) +{ + struct ip6addr_list_entry *node; + + for( node = first_ip6; node != NULL; node=node->next ) + if( node->addr.part.prefix == ip->part.prefix ) + return 0; /* address is one of ours */ + + return 1; /* prefix not yet in our list */ +} + +/* + * NET: Create empty element for prefix list and return a pointer to it; + * @return NULL - malloc failed + * ! NULL - pointer to new prefix_info + */ +struct prefix_info * +ip6_create_prefix_info () +{ + struct prefix_info *prfx_info; + + prfx_info = malloc (sizeof(struct prefix_info)); + if (!prfx_info) + return NULL; + + return prfx_info; +} + +/* + * NET: create a new IPv6 address with a given network prefix + * and add it to our IPv6 address list + * + * @param ip6_addr prefix (as received in RA) + * @return NULL - pointer to new ip6addr_list entry + */ +void * +ip6_prefix2addr (ip6_addr_t prefix) +{ + struct ip6addr_list_entry *new_address; + uint64_t interface_id; + + new_address = malloc (sizeof(struct ip6addr_list_entry)); + if( !new_address ) + return NULL; + + /* fill new addr struct */ + /* extract prefix from Router Advertisement */ + memcpy (&(new_address->addr.part.prefix), &prefix, 8 ); + + /* interface id is generated from MAC address */ + interface_id = mac2eui64 (get_mac_address()); + memcpy (&(new_address->addr.part.interface_id), &interface_id, 8); + + return new_address; +} + +/** + * NET: add new IPv6 adress to list + * + * @param ip6_addr *new_address + * @return 0 - passed pointer = NULL; + * 1 - ok + */ +int8_t +ip6addr_add (struct ip6addr_list_entry *new_address) +{ + struct ip6addr_list_entry *solicited_node; + + + if (new_address == NULL) + return 0; + + /* Don't add the same address twice */ + if (find_ip6addr (&(new_address->addr))) + return 0; + + /* If address is a unicast address, we also have to process packets + * for its solicited-node multicast address. + * See RFC 2373 - IP Version 6 Adressing Architecture */ + if (! ip6_is_multicast(&(new_address->addr))) { + + + solicited_node = malloc(sizeof(struct ip6addr_list_entry)); + if (! solicited_node) + return 0; + + solicited_node->addr.part.prefix = IPV6_SOLIC_NODE_PREFIX; + solicited_node->addr.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID; + solicited_node->addr.addr[13] = new_address->addr.addr[13]; + solicited_node->addr.addr[14] = new_address->addr.addr[14]; + solicited_node->addr.addr[15] = new_address->addr.addr[15]; + ip6addr_add (solicited_node); + } + + if (NULL == first_ip6) + first_ip6 = new_address; + last_ip6->next = new_address; + last_ip6 = new_address; + last_ip6->next = NULL; + + return 1; /* no error */ +} + +/** + * NET: Initialize IPv6 + * + * @param fd socket fd + */ +static void +ipv6_init (int fd) +{ + int i = 0; + + send_ip = &send_ipv6; + + /* Address configuration parameters */ + ip6_state.managed_mode = 0; + + /* Null IPv6 address */ + null_ip6.part.prefix = 0; + null_ip6.part.interface_id = 0; + + /* Multicast addresses */ + all_nodes_ll.addr.part.prefix = 0xff02000000000000; + all_nodes_ll.addr.part.interface_id = 1; + all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL; + all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL; + all_routers_ll.addr.part.prefix = 0xff02000000000000; + all_routers_ll.addr.part.interface_id = 2; + + ip6addr_add(&all_nodes_ll); + /* ... */ + + /* Router list */ + first_router = NULL; + last_router = first_router; + + /* Init Neighbour cache */ + first_neighbor = NULL; + last_neighbor = first_neighbor; + + send_router_solicitation (fd); + for(i=0; i < 4 && !is_ra_received(); i++) { + set_timer(TICKS_SEC); + do { + receive_ether(fd); + if (is_ra_received()) + break; + } while (get_timer() > 0); + } +} + +/** + * NET: compare IPv6 adresses + * + * @param ip6_addr ip_1 + * @param ip6_addr ip_2 + */ +int8_t +ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2) +{ + return ((int8_t) !memcmp( &(ip_1->addr[0]), &(ip_2->addr[0]), + IPV6_ADDR_LENGTH )); +} + +/** + * NET: Calculate checksum over IPv6 header and upper-layer protocol + * (e.g. UDP or ICMPv6) + * + * @param *ip - pointer to IPv6 address + * @return true or false + */ +int +ip6_is_multicast (ip6_addr_t * ip) +{ + uint8_t mc = 0xFF; + return ! memcmp(&ip->addr[0], &mc, 1); +} + +/** + * NET: Generate multicast MAC address from IPv6 address + * (e.g. UDP or ICMPv6) + * + * @param *ip - pointer to IPv6 address + * @return pointer to Multicast MAC address + */ +static uint8_t * +ip6_to_multicast_mac (ip6_addr_t * ip) +{ + uint8_t *mc_mac; + + mc_mac = malloc(ETH_ALEN); + if (!mc_mac) + return NULL; + + mc_mac[0] = 0x33; + mc_mac[1] = 0x33; + memcpy (mc_mac+2, (uint8_t *) &(ip->addr)+12, 4); + + return mc_mac; +} + +/** + * NET: calculate checksum over IPv6 header and upper-layer protocol + * (e.g. UDP or ICMPv6) + * + * @param struct ip6hdr *ip6h - pointer to IPv6 header + * @param unsigned short *packet - pointer to header of upper-layer + * protocol + * @param int words - number of words (as in 2 bytes) + * starting from *packet + * @return checksum + */ +static unsigned short +ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words) +{ + int i=0; + unsigned long checksum; + struct ip6hdr pseudo_ip6h; + unsigned short *pip6h; + + memcpy (&pseudo_ip6h, ip6h, sizeof(struct ip6hdr)); + pseudo_ip6h.hl = ip6h->nh; + pseudo_ip6h.ver_tc_fl = 0; + pseudo_ip6h.nh = 0; + pip6h = (unsigned short *) &pseudo_ip6h; + + for (checksum = 0; words > 0; words--) { + checksum += *packet++; + i++; + } + + for (i = 0; i < 20; i++) { + checksum += *pip6h++; + } + + checksum = (checksum >> 16) + (checksum & 0xffff); + checksum += (checksum >> 16); + + return ~checksum; +} + +/** + * NET: Handles IPv6-packets + * + * @param fd socket fd + * @param ip6_packet Pointer to IPv6 header in packet + * @param packetsize Size of IPv6 packet + * @return -1 == ERRROR + * return of handle_udp() or handle_icmp6() + * + * @see receive_ether + * @see ip6hdr + */ +int +send_ipv6 (int fd, void* buffer, int len) +{ + struct neighbor *n; + struct ip6hdr *ip6h; + struct udphdr *udph; + struct icmp6hdr *icmp6h; + ip6_addr_t ip_dst; + uint8_t *mac_addr, mac[6]; + + mac_addr = mac; + + ip6h = (struct ip6hdr *) buffer; + udph = (struct udphdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr)); + icmp6h = (struct icmp6hdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr)); + + memcpy(&ip_dst, &ip6h->dst, 16); + + if(len + sizeof(struct ethhdr) > 1500) + return -1; + + if ( ip6_cmp (&ip6h->src, &null_ip6)) + memcpy (&(ip6h->src), get_ipv6_address(), IPV6_ADDR_LENGTH); + + if (ip6h->nh == 17) {//UDP + udph->uh_sum = ip6_checksum (ip6h, (unsigned short *) udph , + ip6h->pl >> 1); + /* As per RFC 768, if the computed checksum is zero, + * it is transmitted as all ones (the equivalent in + * one's complement arithmetic). + */ + if (udph->uh_sum == 0) + udph->uh_sum = ~udph->uh_sum; + } + else if (ip6h->nh == 0x3a) //ICMPv6 + icmp6h->checksum = ip6_checksum (ip6h, + (unsigned short *) icmp6h, + ip6h->pl >> 1); + + n = find_neighbor (&ip_dst); + + // If packet is a neighbor solicitation + if (icmp6h->type == ICMPV6_NEIGHBOUR_SOLICITATION) { + mac_addr = ip6_to_multicast_mac (&ip_dst); + fill_ethhdr( buffer-sizeof(struct ethhdr), htons(ETHERTYPE_IPv6), + get_mac_address(), + mac_addr); + } + + // If address is a multicast address, create a proper mac address + else if (ip6_is_multicast (&ip_dst)) { + mac_addr = ip6_to_multicast_mac (&ip_dst); + } + else { + // Check if the MAC address is already cached + if (n) { + if (memcmp(n->mac, null_mac, ETH_ALEN) != 0) + memcpy (mac_addr, &(n->mac), ETH_ALEN); /* found it */ + } else { + mac_addr = null_mac; + n = malloc(sizeof(struct neighbor)); + memcpy(&(n->ip.addr[0]), &ip_dst, 16); + n->status = NB_PROBE; + n->times_asked += 1; + neighbor_add(n); + } + + if (! memcmp (mac_addr, &null_mac, 6)) { + if (n->eth_len == 0) { + send_neighbour_solicitation (fd, &ip_dst); + + // Store the packet until we know the MAC address + memset(n->eth_frame, 0, 1500); + fill_ethhdr (n->eth_frame, + htons(ETHERTYPE_IPv6), + get_mac_address(), + mac_addr); + memcpy (&(n->eth_frame[sizeof(struct ethhdr)]), + buffer, len); + n->eth_len = len; + set_timer(TICKS_SEC); + do { + receive_ether(fd); + } while (get_timer() > 0); + } + } + } + + fill_ethhdr (n->eth_frame, htons(ETHERTYPE_IPv6), get_mac_address(), + mac_addr); + memcpy (&(n->eth_frame[sizeof(struct ethhdr)]), buffer, len); + return send_ether (fd, n->eth_frame, len + sizeof(struct ethhdr)); +} + +static int +check_colons(const char *str) +{ + char *pch, *prv; + int col = 0; + int dcol = 0; + + dprintf("str : %s\n",str); + pch = strchr(str, ':'); + while(pch != NULL){ + prv = pch; + pch = strchr(pch+1, ':'); + if((pch-prv) != 1) { + col++; + } else { + col--; /* Its part of double colon */ + dcol++; + } + } + + dprintf("The number of col : %d \n",col); + dprintf("The number of dcol : %d \n",dcol); + + if((dcol > 1) || /* Cannot have 2 "::" */ + ((dcol == 1) && (col > 5)) || /* Too many ':'s */ + ((dcol == 0) && (col != 7)) ) { /* Too few ':'s */ + dprintf(" exiting for check_colons \n"); + return 0; + } + + return (col+dcol); +} + +static int +ipv6str_to_bytes(const char *str, char *ip) +{ + char block[5]; + int res; + char *pos; + uint32_t cnt = 0, len; + + dprintf("str : %s \n",str); + + while (*str != 0) { + if (cnt > 15 || !isxdigit(*str)){ + return 0; + } + if ((pos = strchr(str, ':')) != NULL) { + len = (int16_t) (pos - str); + dprintf("\t len is : %d \n",len); + if (len > 4) + return 0; + strncpy(block, str, len); + block[len] = 0; + dprintf("\t str : %s \n",str); + dprintf("\t block : %s \n",block); + str += len; + } else { + strncpy(block, str, 4); + block[4] = 0; + dprintf("\t str : %s \n",str); + dprintf("\t block : %s \n",block); + str += strlen(block); + } + res = strtol(block, NULL, 16); + dprintf("\t res : %x \n",res); + if ((res > 0xFFFF) || (res < 0)) + return 0; + ip[cnt++] = (res & 0xFF00) >> 8; + ip[cnt++] = (res & 0x00FF); + if (*str == ':'){ + str++; + } + } + + dprintf("cnt : %d\n",cnt); + return cnt; +} + +int str_to_ipv6(const char *str, uint8_t *ip) +{ + int i, k; + uint16_t len; + char *ptr; + char tmp[30], buf[16]; + + memset(ip,0,16); + + if(!check_colons(str)) + return 0; + + if ((ptr = strstr(str, "::")) != NULL) { + /* Handle the ::1 IPv6 loopback */ + if(!strcmp(str,"::1")) { + ip[15] = 1; + return 16; + } + len = (ptr-str); + dprintf(" len : %d \n",len); + if (len >= sizeof(tmp)) + return 0; + strncpy(tmp, str, len); + tmp[len] = 0; + ptr += 2; + + i = ipv6str_to_bytes(ptr, buf); + if(i == 0) + return i; + + #if defined(ARGS_DEBUG) + int j; + dprintf("=========== bottom part i : %d \n",i); + for(j=0; j<i; j++) + dprintf("%02x \t",buf[j]); + #endif + + /* Copy the bottom part i.e bytes following "::" */ + memcpy(ip+(16-i), buf, i); + + k = ipv6str_to_bytes(tmp, buf); + if(k == 0) + return k; + + #if defined(ARGS_DEBUG) + dprintf("=========== top part k : %d \n",k); + for(j=0; j<k; j++) + printf("%02x \t",buf[j]); + #endif + + /* Copy the top part i.e bytes before "::" */ + memcpy(ip, buf, k); + #if defined(ARGS_DEBUG) + dprintf("\n"); + for(j=0; j<16; j++) + dprintf("%02x \t",ip[j]); + #endif + + } else { + i = ipv6str_to_bytes(str, (char *)ip); + } + return i; +} + +void ipv6_to_str(const uint8_t *ip, char *str) +{ + int i, len; + uint8_t byte_even, byte_odd; + char *consec_zero, *strptr; + + *str = 0; + for (i = 0; i < 16; i+=2) { + byte_even = ip[i]; + byte_odd = ip[i+1]; + if (byte_even) + sprintf(str, "%s%x%02x", str, byte_even, byte_odd); + else if (byte_odd) + sprintf(str, "%s%x", str, byte_odd); + else + strcat(str, "0"); + if (i != 14) + strcat(str, ":"); + } + strptr = str; + do { + consec_zero = strstr(strptr, "0:0:"); + if (consec_zero) { + len = consec_zero - strptr; + if (!len) + break; + else if (strptr[len-1] == ':') + break; + else + strptr = consec_zero + 2; + } + } while (consec_zero); + if (consec_zero) { + len = consec_zero - str; + str[len] = 0; + if (len) + strcat(str, ":"); + else + strcat(str, "::"); + strptr = consec_zero + 4; + while (*strptr) { + if (!strncmp(strptr, "0:", 2)) + strptr += 2; + else + break; + } + strcat(str, strptr); + if (!strcmp(str, "::0")) + strcpy(str, "::"); + } +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h new file mode 100644 index 000000000..b496364f3 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ipv6.h @@ -0,0 +1,196 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _IPV6_H_ +#define _IPV6_H_ + +#include <stdint.h> +#include <netlib/ethernet.h> + +#define __IPV6_DEBUG__ + +#ifdef __IPV6_DEBUG__ +#define IPV6_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__); } while (0) +#else +#define IPV6_DEBUG_PRINT(format, ...) +#endif + +#define IPV6_ADDR_LENGTH 16 /* Size of IPv6 adress in bytes */ +#define IPV6_LL_PREFIX 0xFE80000000000000ULL +#define IPV6_SOLIC_NODE_PREFIX 0xFF02000000000000ULL +#define IPV6_SOLIC_NODE_IFACE_ID 0x00000001FF000000ULL + +/** + * An IPv6 Address + */ +typedef union { + uint8_t addr[IPV6_ADDR_LENGTH]; + struct { + uint64_t prefix; + uint64_t interface_id; + } part; +} ip6_addr_t; + +typedef struct { + uint8_t type; + uint8_t pad[7]; + union { + ip6_addr_t v6; + char v4[4]; + } addr; +} netaddr_t; + +/** \struct prefix_info + * + * List of Prefixes we have adresses from + * Used for internal purposes, information derived from prefix option + * in Router Advertisements + * See RFC 4861 section 4.6.2 + */ +struct prefix_info { + uint64_t prefix; + uint8_t on_link:1, /* When set prefix can be used for on-link + * determination */ + autoconf:1, /* Prefix can be used for stateless address + * configuration */ + reserved1:6; + uint32_t valid_lifetime; /* Time until prefix expires */ + uint32_t preferred_lifetime; /* Time until prefix becomes deprecated */ + uint32_t start_time; /* Time when received */ + uint32_t reserved2; + struct prefix_info *next; +}; + + +/* List of IPv6 addresses */ +struct ip6addr_list_entry { + ip6_addr_t addr; + struct prefix_info prfx_info; + struct ip6addr_list_entry *next; +}; + +/** \struct ip6hdr + * A header for IPv6 packets. + * For more information see RFC 2460 + */ +struct ip6hdr { + uint32_t ver_tc_fl; /**< Version, Traffic class, Flow label */ + uint16_t pl; /**< Payload length */ + uint8_t nh; /**< Next header */ + uint8_t hl; /**< Hop limit */ + ip6_addr_t src; /**< IPv6 source address */ + ip6_addr_t dst; /**< IPv6 destination address */ +} __attribute((packed)); + +/** \struct packeth + * Struct with pointers to headers within a packet + */ +struct packeth { + struct ethhdr *ethh; + struct ip6hdr *ip6h; + struct icmp6hdr *icmp6h; + struct udphdr *udph; + /* ... */ +}; + +/** \struct parseip6_state + * Stores information about state of IPv6 address parser + */ +struct parseip6_state { + char *lookahead; + char *ptr; + const char *addr; + int state; + int s1ctr; + int s2ctr; + int blocknr; + int zeroblocks; + int i; + int done; + int errorcode; +}; + +/** \struct ip6_config + * Stores flags wheter we use Stateless- or Stateful Autoconfiguration or DHCPv6 + */ +struct ip6_config { + uint8_t managed_mode:1, + other_config:1, + reserved:6; +} ip6_state; + +/******************** VARIABLES **********************************************/ +/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ +extern int (*send_ip) (int fd, void *, int); + +/* IPv6 link-local multicast addresses */ +struct ip6addr_list_entry all_routers_ll; // Routers +struct ip6addr_list_entry all_dhcpv6_ll; // DHCPv6 servers +struct ip6addr_list_entry all_nodes_ll; // All IPv6 nodes + +/* List of Ipv6 Addresses */ +struct ip6addr_list_entry *first_ip6; +struct ip6addr_list_entry *last_ip6; + +/* Neighbor cache */ +struct neighbor *first_neighbor; +struct neighbor *last_neighbor; + +/* Router list */ +struct router *first_router; +struct router *last_router; + +/******************** FUNCTIONS *********************************************/ +/* Handles IPv6-packets that are detected by receive_ether. */ +int8_t handle_ipv6(int fd, uint8_t * ip6_packet, int32_t packetsize); + +/* Fill IPv6 header */ +void fill_ip6hdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst); + +/* Set own IPv6 address */ +void set_ipv6_address(int fd, ip6_addr_t *own_ip6); + +/* Get own IPv6 address */ +ip6_addr_t *get_ipv6_address(void); + +/* Create link-local address from a given Mac Address */ +ip6_addr_t * ip6_create_ll_address (const uint8_t *own_mac); + +/* For a given MAC calculates EUI64-Identifier.*/ +uint64_t mac2eui64 (const uint8_t *mac); + +/* Create empty element for prefix list and return a pointer to it */ +struct prefix_info * ip6_create_prefix_info(void); + +/* Create a new IPv6 address with a given network prefix + * and add it to our IPv6 address list */ +void * ip6_prefix2addr (ip6_addr_t prefix); + +/* Compare IPv6 adresses */ +int8_t ip6_cmp( ip6_addr_t *ip_1, ip6_addr_t *ip_2 ); + +/* Check if prefix is already in our list */ +int8_t unknown_prefix (ip6_addr_t *ip); + +/* Send IPv6 packet */ +int send_ipv6 (int fd, void* buffer, int len); + +/* Add IPv6 address to list */ +int8_t ip6addr_add (struct ip6addr_list_entry *new_address); + +/* Parse an IPv6 address */ +int parseip6(const char *addr, uint8_t *parsedaddr); +int str_to_ipv6(const char *str, uint8_t *ip); +void ipv6_to_str(const uint8_t *ip, char *str); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c new file mode 100644 index 000000000..ed9d61f4a --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.c @@ -0,0 +1,147 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <netlib/ipv6.h> +#include <netlib/icmpv6.h> +#include <netlib/ndp.h> + +/* + * NET: add new router to list + * @param struct router nghb - new router + * @return true or false + */ +int8_t +router_add (struct router *nghb ) +{ + if (nghb == NULL) + return -1; + + if (first_router == NULL) { + first_router= nghb; + last_router = first_router; + last_router->next = NULL; + } else { + last_router->next = nghb; + last_router = nghb; + last_router->next = NULL; + } + return 1; /* no error */ +} + +/* + * NET: create a new router + * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghSlct) + * @param struct packeth - pointers to headers in packet + * @return pointer to new router + */ +void * +router_create (uint8_t *mac, ip6_addr_t *ip) +{ + struct router *new_router; + + new_router = malloc (sizeof(struct router)); + if( !new_router) { + return 0; + } + memset (new_router, 0, sizeof(struct router)); + + /* fill neighbor struct */ + memcpy (new_router->mac, mac, 6); + memcpy (&(new_router->ip.addr[0]), &(ip->addr[0]), IPV6_ADDR_LENGTH); + + return new_router; +} + +struct router * +find_router( ip6_addr_t *ip ) +{ + struct router *n = NULL; + + for (n = first_router; n != NULL ; n=n->next) + if (ip6_cmp (&(n->ip), ip)) + return n; /* router is already in list*/ + + return NULL; /* router is unknown */ +} + +/* + * NET: add new neighbor to list + * @param struct neighbor nghb - new neighbor + * @return true or false + */ +int8_t +neighbor_add (struct neighbor *nghb) +{ + if (nghb == NULL) + return -1; + + if (first_neighbor == NULL) { + first_neighbor = nghb; + last_neighbor = first_neighbor; + last_neighbor->next = NULL; + } else { + last_neighbor->next = nghb; + last_neighbor = nghb; + last_neighbor->next = NULL; + } + + return 1; /* no error */ +} + +/* + * NET: create a new neighbor + * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghSlct) + * @param struct packeth - pointers to headers in packet + * @return pointer - pointer to new neighbor + * NULL - malloc failed + */ +void * +neighbor_create (uint8_t *packet, struct packeth *headers) +{ + struct neighbor *new_neighbor; + + new_neighbor = malloc (sizeof(struct neighbor)); + if( !new_neighbor ) + return NULL; + + /* fill neighbor struct */ + memcpy (&(new_neighbor->mac), + &(headers->ethh->src_mac[0]), 6); + memcpy (&(new_neighbor->ip.addr), &(headers->ip6h->src), IPV6_ADDR_LENGTH); + new_neighbor->status = NB_INCOMPLETE; + + return new_neighbor; +} + +/** + * NET: Find neighbor with given IPv6 address in Neighbor Cache + * + * @param ip - Pointer to IPv6 address + * @return pointer - pointer to client IPv6 address (e.g. ::1) + * NULL - Neighbor not found + */ +struct neighbor * +find_neighbor (ip6_addr_t *ip) +{ + struct neighbor *n = NULL; + + for (n = first_neighbor; n != NULL ; n=n->next) { + if (ip6_cmp (&(n->ip), ip)) { + return n; /* neighbor is already in cache */ + } + } + + return NULL; /* neighbor is unknown */ +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h new file mode 100644 index 000000000..ee5235fe1 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/ndp.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _NDP_H_ +#define _NDP_H_ + +#include <netlib/ipv6.h> + +#define __NDP_DEBUG__ + +#ifdef __NDP_DEBUG__ +#define NDP_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__); } while (0) +#else +#define NDP_DEBUG_PRINT(format, ...) +#endif + +#define ND_OPTION_SOURCE_LL_ADDR 1 +#define ND_OPTION_TARGET_LL_ADDR 2 +#define ND_OPTION_PREFIX_INFO 3 +#define ND_OPTION_REDIRECT_HDR 4 +#define ND_OPTION_MTU 5 + +/* Default Router List */ +struct router { + uint8_t mac[6]; + ip6_addr_t ip; + uint32_t lifetime; + uint32_t reachable_time; + uint32_t retrans_timer; + struct router *next; +}; + +/* Neighbor cache */ +struct neighbor { + uint8_t mac[6]; + ip6_addr_t ip; + uint8_t is_router; + uint8_t status; + uint8_t times_asked; + /* ... */ + struct neighbor *next; + uint8_t eth_frame[1500]; //FIXME + uint32_t eth_len; + +#define NB_INCOMPLETE 1 +#define NB_REACHABLE 2 +#define NB_STALE 3 +#define NB_DELAY 4 +#define NB_PROBE 5 +}; + +/******************** FUNCTIONS *********************************************/ +int8_t neighbor_add (struct neighbor *); +void * neighbor_create (uint8_t *packet, struct packeth *headers); +struct neighbor * find_neighbor (ip6_addr_t *); + +int8_t router_add(struct router*); +void * router_create(uint8_t *mac, ip6_addr_t *ip); +struct router * find_router(ip6_addr_t *); + +#endif //_NDP_H_ diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c new file mode 100644 index 000000000..5511aa00a --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.c @@ -0,0 +1,50 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ + +#include <tcp.h> +#include <sys/socket.h> + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ + + +/** + * TCP: Handles TCP-packets according to Receive-handle diagram. + * + * @param tcp_packet TCP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + */ +int8_t +handle_tcp(uint8_t * tcp_packet, int32_t packetsize) +{ + return -1; +} + + +/** + * NET: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending TCP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + * @param packet original TCP-packet + * @param packetsize length of the packet + * @see handle_icmp + */ +void +handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code) { +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.h new file mode 100644 index 000000000..375afd771 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tcp.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _TCP_H +#define _TCP_H + +#include <stdint.h> + +#define IPTYPE_TCP 6 + +/* Handles TCP-packets that are detected by any network layer. */ +extern int8_t handle_tcp(uint8_t * udp_packet, int32_t packetsize); + +/* Handles TCP related ICMP-Dest.Unreachable packets that are detected by + * the network layers. */ +extern void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c new file mode 100644 index 000000000..0a7c0ec63 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.c @@ -0,0 +1,597 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <tftp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/socket.h> + +#include <ethernet.h> +#include <ipv4.h> +#include <ipv6.h> +#include <udp.h> + +//#define __DEBUG__ + +#define MAX_BLOCKSIZE 1428 +#define BUFFER_LEN 256 + +#define ENOTFOUND 1 +#define EACCESS 2 +#define EBADOP 4 +#define EBADID 5 +#define ENOUSER 7 +//#define EUNDEF 0 +//#define ENOSPACE 3 +//#define EEXISTS 6 + +#define RRQ 1 +#define WRQ 2 +#define DATA 3 +#define ACK 4 +#define ERROR 5 +#define OACK 6 + +/* Local variables */ +static unsigned char packet[BUFFER_LEN]; +static unsigned char *buffer = NULL; +static unsigned short block = 0; +static unsigned short blocksize; +static char blocksize_str[6]; /* Blocksize string for read request */ +static int received_len = 0; +static int retries = 0; +static int huge_load; +static int len; +static int tftp_finished = 0; +static int lost_packets = 0; +static int tftp_errno = 0; +static int ip_version = 0; +static short port_number = -1; +static tftp_err_t *tftp_err; +static filename_ip_t *fn_ip; + +/** + * dump_package - Prints a package. + * + * @package: package which is to print + * @len: length of the package + */ +#ifdef __DEBUG__ + +static void +dump_package(unsigned char *buffer, unsigned int len) +{ + int i; + + for (i = 1; i <= len; i++) { + printf("%02x%02x ", buffer[i - 1], buffer[i]); + i++; + if ((i % 16) == 0) + printf("\n"); + } + printf("\n"); +} +#endif + +/** + * send_rrq - Sends a read request package. + * + * @fd: Socket Descriptor + */ +static void +send_rrq(int fd) +{ + int ip_len = 0; + int ip6_payload_len = 0; + unsigned short udp_len = 0; + unsigned char mode[] = "octet"; + char *ptr = NULL; + struct iphdr *ip = NULL; + struct ip6hdr *ip6 = NULL; + struct udphdr *udph = NULL; + struct tftphdr *tftp = NULL; + + memset(packet, 0, BUFFER_LEN); + + if (4 == ip_version) { + ip = (struct iphdr *) packet; + udph = (struct udphdr *) (ip + 1); + ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } + else if (6 == ip_version) { + ip6 = (struct ip6hdr *) packet; + udph = (struct udphdr *) (ip6 + 1); + ip6_payload_len = sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2; + ip_len = sizeof(struct ip6hdr) + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), + &(fn_ip->server_ip6)); + + } + udp_len = htons(sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(69)); + + tftp = (struct tftphdr *) (udph + 1); + tftp->th_opcode = htons(RRQ); + + ptr = (char *) &tftp->th_data; + memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1); + + ptr += strlen((char *) fn_ip->filename) + 1; + memcpy(ptr, mode, strlen((char *) mode) + 1); + + ptr += strlen((char *) mode) + 1; + memcpy(ptr, "blksize", strlen("blksize") + 1); + + ptr += strlen("blksize") + 1; + memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1); + + send_ip (fd, packet, ip_len); + +#ifdef __DEBUG__ + printf("tftp RRQ with %d bytes transmitted.\n", ip_len); +#endif + return; +} + +/** + * send_ack - Sends a acknowlege package. + * + * @blckno: block number + * @dport: UDP destination port + */ +static void +send_ack(int fd, int blckno, unsigned short dport) +{ + int ip_len = 0; + int ip6_payload_len = 0; + unsigned short udp_len = 0; + struct iphdr *ip = NULL; + struct ip6hdr *ip6 = NULL; + struct udphdr *udph = NULL; + struct tftphdr *tftp = NULL; + + memset(packet, 0, BUFFER_LEN); + + if (4 == ip_version) { + ip = (struct iphdr *) packet; + udph = (struct udphdr *) (ip + 1); + ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 4; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } + else if (6 == ip_version) { + ip6 = (struct ip6hdr *) packet; + udph = (struct udphdr *) (ip6 + 1); + ip6_payload_len = sizeof(struct udphdr) + 4; + ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) + + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), + &(fn_ip->server_ip6)); + } + udp_len = htons(sizeof(struct udphdr) + 4); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport)); + + tftp = (struct tftphdr *) (udph + 1); + tftp->th_opcode = htons(ACK); + tftp->th_data = htons(blckno); + + send_ip(fd, packet, ip_len); + +#ifdef __DEBUG__ + printf("tftp ACK %d bytes transmitted.\n", ip_len); +#endif + + return; +} + +/** + * send_error - Sends an error package. + * + * @fd: Socket Descriptor + * @error_code: Used sub code for error packet + * @dport: UDP destination port + */ +static void +send_error(int fd, int error_code, unsigned short dport) +{ + int ip_len = 0; + int ip6_payload_len = 0; + unsigned short udp_len = 0; + struct ip6hdr *ip6 = NULL; + struct iphdr *ip = NULL; + struct udphdr *udph = NULL; + struct tftphdr *tftp = NULL; + + memset(packet, 0, BUFFER_LEN); + + if (4 == ip_version) { + ip = (struct iphdr *) packet; + udph = (struct udphdr *) (ip + 1); + ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 5; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } + else if (6 == ip_version) { + ip6 = (struct ip6hdr *) packet; + udph = (struct udphdr *) (ip6 + 1); + ip6_payload_len = sizeof(struct udphdr) + 5; + ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) + + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), + &(fn_ip->server_ip6)); + } + udp_len = htons(sizeof(struct udphdr) + 5); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport)); + + tftp = (struct tftphdr *) (udph + 1); + tftp->th_opcode = htons(ERROR); + tftp->th_data = htons(error_code); + ((char *) &tftp->th_data)[2] = 0; + + send_ip(fd, packet, ip_len); + +#ifdef __DEBUG__ + printf("tftp ERROR %d bytes transmitted.\n", ip_len); +#endif + + return; +} + +static void +print_progress(int urgent, int received_bytes) +{ + static unsigned int i = 1; + static int first = -1; + static int last_bytes = 0; + char buffer[100]; + char *ptr; + + // 1MB steps or 0x400 times or urgent + if(((received_bytes - last_bytes) >> 20) > 0 + || (i & 0x3FF) == 0 || urgent) { + if(!first) { + sprintf(buffer, "%d KBytes", (last_bytes >> 10)); + for(ptr = buffer; *ptr != 0; ++ptr) + *ptr = '\b'; + printf(buffer); + } + printf("%d KBytes", (received_bytes >> 10)); + i = 1; + first = 0; + last_bytes = received_bytes; + } + ++i; +} + +/** + * get_blksize tries to extract the blksize from the OACK package + * the TFTP returned. From RFC 1782 + * The OACK packet has the following format: + * + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 | + * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+ + * + * @param buffer the network packet + * @param len the length of the network packet + * @return the blocksize the server supports or 0 for error + */ +static int +get_blksize(unsigned char *buffer, unsigned int len) +{ + unsigned char *orig = buffer; + /* skip all headers until tftp has been reached */ + buffer += sizeof(struct udphdr); + /* skip opc */ + buffer += 2; + while (buffer < orig + len) { + if (!memcmp(buffer, "blksize", strlen("blksize") + 1)) + return (unsigned short) strtoul((char *) (buffer + + strlen("blksize") + 1), + (char **) NULL, 10); + else { + /* skip the option name */ + buffer = (unsigned char *) strchr((char *) buffer, 0); + if (!buffer) + return 0; + buffer++; + /* skip the option value */ + buffer = (unsigned char *) strchr((char *) buffer, 0); + if (!buffer) + return 0; + buffer++; + } + } + return 0; +} + +/** + * Handle incoming tftp packets after read request was sent + * + * this function also prints out some status characters + * \|-/ for each packet received + * A for an arp packet + * I for an ICMP packet + * #+* for different unexpected TFTP packets (not very good) + * + * @param fd socket descriptor + * @param packet points to the UDP header of the packet + * @param len the length of the network packet + * @return ZERO if packet was handled successfully + * ERRORCODE if error occurred + */ +int32_t +handle_tftp(int fd, uint8_t *pkt, int32_t packetsize) +{ + struct udphdr *udph; + struct tftphdr *tftp; + + /* buffer is only set if we are handling TFTP */ + if (buffer == NULL ) + return 0; + +#ifndef __DEBUG__ + print_progress(0, received_len); +#endif + udph = (struct udphdr *) pkt; + tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr)); + set_timer(TICKS_SEC); + +#ifdef __DEBUG__ + dump_package(pkt, packetsize); +#endif + + port_number = udph->uh_sport; + if (tftp->th_opcode == htons(OACK)) { + /* an OACK means that the server answers our blocksize request */ + blocksize = get_blksize(pkt, packetsize); + if (!blocksize || blocksize > MAX_BLOCKSIZE) { + send_error(fd, 8, port_number); + tftp_errno = -8; + goto error; + } + send_ack(fd, 0, port_number); + } else if (tftp->th_opcode == htons(ACK)) { + /* an ACK means that the server did not answers + * our blocksize request, therefore we will set the blocksize + * to the default value of 512 */ + blocksize = 512; + send_ack(fd, 0, port_number); + } else if ((unsigned char) tftp->th_opcode == ERROR) { +#ifdef __DEBUG__ + printf("tftp->th_opcode : %x\n", tftp->th_opcode); + printf("tftp->th_data : %x\n", tftp->th_data); +#endif + switch ( (uint8_t) tftp->th_data) { + case ENOTFOUND: + tftp_errno = -3; // ERROR: file not found + break; + case EACCESS: + tftp_errno = -4; // ERROR: access violation + break; + case EBADOP: + tftp_errno = -5; // ERROR: illegal TFTP operation + break; + case EBADID: + tftp_errno = -6; // ERROR: unknown transfer ID + break; + case ENOUSER: + tftp_errno = -7; // ERROR: no such user + break; + default: + tftp_errno = -1; // ERROR: unknown error + } + goto error; + } else if (tftp->th_opcode == DATA) { + /* DATA PACKAGE */ + if (block + 1 == tftp->th_data) { + ++block; + } + else if( block == 0xffff && huge_load != 0 + && (tftp->th_data == 0 || tftp->th_data == 1) ) { + block = tftp->th_data; + } + else if (tftp->th_data == block) { +#ifdef __DEBUG__ + printf + ("\nTFTP: Received block %x, expected block was %x\n", + tftp->th_data, block + 1); + printf("\b+ "); +#endif + send_ack(fd, tftp->th_data, port_number); + lost_packets++; + tftp_err->bad_tftp_packets++; + return 0; + } else if (tftp->th_data < block) { +#ifdef __DEBUG__ + printf + ("\nTFTP: Received block %x, expected block was %x\n", + tftp->th_data, block + 1); + printf("\b* "); +#endif + /* This means that an old data packet appears (again); + * this happens sometimes if we don't answer fast enough + * and a timeout is generated on the server side; + * as we already have this packet we just ignore it */ + tftp_err->bad_tftp_packets++; + return 0; + } else { + tftp_err->blocks_missed = block + 1; + tftp_err->blocks_received = tftp->th_data; + tftp_errno = -42; + goto error; + } + tftp_err->bad_tftp_packets = 0; + /* check if our buffer is large enough */ + if (received_len + udph->uh_ulen - 12 > len) { + tftp_errno = -2; + goto error; + } + memcpy(buffer + received_len, &tftp->th_data + 1, + udph->uh_ulen - 12); + send_ack(fd, tftp->th_data, port_number); + received_len += udph->uh_ulen - 12; + /* Last packet reached if the payload of the UDP packet + * is smaller than blocksize + 12 + * 12 = UDP header (8) + 4 bytes TFTP payload */ + if (udph->uh_ulen < blocksize + 12) { + tftp_finished = 1; + return 0; + } + /* 0xffff is the highest block number possible + * see the TFTP RFCs */ + + if (block >= 0xffff && huge_load == 0) { + tftp_errno = -9; + goto error; + } + } else { +#ifdef __DEBUG__ + printf("Unknown packet %x\n", tftp->th_opcode); + printf("\b# "); +#endif + tftp_err->bad_tftp_packets++; + return 0; + } + + return 0; + +error: +#ifdef __DEBUG__ + printf("\nTFTP errno: %d\n", tftp_errno); +#endif + tftp_finished = 1; + return tftp_errno; +} + +/** + * TFTP: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending TFTP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + */ +void +handle_tftp_dun(uint8_t err_code) +{ + tftp_errno = - err_code - 10; + tftp_finished = 1; +} + +/** + * TFTP: Interface function to load files via TFTP. + * + * @param _fn_ip contains the following configuration information: + * client IP, TFTP-server IP, filename to be loaded + * @param _buffer destination buffer for the file + * @param _len size of destination buffer + * @param _retries max number of retries + * @param _tftp_err contains info about TFTP-errors (e.g. lost packets) + * @param _mode NON ZERO - multicast, ZERO - unicast + * @param _blocksize blocksize for DATA-packets + * @return ZERO - error condition occurs + * NON ZERO - size of received file + */ +int +tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len, + unsigned int _retries, tftp_err_t * _tftp_err, + int32_t _mode, int32_t _blocksize, int _ip_version) +{ + retries = _retries; + fn_ip = _fn_ip; + len = _len; + huge_load = _mode; + ip_version = _ip_version; + tftp_errno = 0; + tftp_err = _tftp_err; + tftp_err->bad_tftp_packets = 0; + tftp_err->no_packets = 0; + + /* Default blocksize must be 512 for TFTP servers + * which do not support the RRQ blocksize option */ + blocksize = 512; + + /* Preferred blocksize - used as option for the read request */ + if (_blocksize < 8) + _blocksize = 8; + else if (_blocksize > MAX_BLOCKSIZE) + _blocksize = MAX_BLOCKSIZE; + sprintf(blocksize_str, "%d", _blocksize); + + printf(" Receiving data: "); + print_progress(-1, 0); + + // Setting buffer to a non-zero address enabled handling of received TFTP packets. + buffer = _buffer; + + set_timer(TICKS_SEC); + send_rrq(fn_ip->fd); + + while (! tftp_finished) { + /* if timeout (no packet received) */ + if(get_timer() <= 0) { + /* the server doesn't seem to retry let's help out a bit */ + if (tftp_err->no_packets > 4 && port_number != -1 + && block > 1) { + send_ack(fn_ip->fd, block, port_number); + } + else if (port_number == -1 && block == 0 + && (tftp_err->no_packets&3) == 3) { + printf("\nRepeating TFTP read request...\n"); + send_rrq(fn_ip->fd); + } + tftp_err->no_packets++; + set_timer(TICKS_SEC); + } + + /* handle received packets */ + receive_ether(fn_ip->fd); + + /* bad_tftp_packets are counted whenever we receive a TFTP packet + * which was not expected; if this gets larger than 'retries' + * we just exit */ + if (tftp_err->bad_tftp_packets > retries) { + tftp_errno = -40; + break; + } + + /* no_packets counts the times we have returned from receive_ether() + * without any packet received; if this gets larger than 'retries' + * we also just exit */ + if (tftp_err->no_packets > retries) { + tftp_errno = -41; + break; + } + } + + // Setting buffer to NULL disables handling of received TFTP packets. + buffer = NULL; + + if (tftp_errno) + return tftp_errno; + + print_progress(-1, received_len); + printf("\n"); + if (lost_packets) + printf("Lost ACK packets: %d\n", lost_packets); + + return received_len; +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.h new file mode 100644 index 000000000..1cf1266fb --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/tftp.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _TFTP_H_ +#define _TFTP_H_ + +#include <stdint.h> +#include <netlib/ipv6.h> + +struct tftphdr { + int16_t th_opcode; + uint16_t th_data; +}; + +typedef struct { + uint32_t own_ip; + ip6_addr_t own_ip6; + uint32_t server_ip; + ip6_addr_t server_ip6; + ip6_addr_t dns_ip6; + int8_t filename[256]; + int fd; +} __attribute__ ((packed)) filename_ip_t ; + +typedef struct { + uint32_t bad_tftp_packets; + uint32_t no_packets; + uint32_t blocks_missed; + uint32_t blocks_received; +} tftp_err_t; + +int tftp(filename_ip_t *, unsigned char *, int, unsigned int, + tftp_err_t *, int32_t mode, int32_t blocksize, int ip_version); +int tftp_netsave(filename_ip_t *, uint8_t * buffer, int len, + int use_ci, unsigned int retries, tftp_err_t * tftp_err); + +int32_t handle_tftp(int fd, uint8_t *, int32_t); +void handle_tftp_dun(uint8_t err_code); +int parse_tftp_args(char buffer[], char *server_ip, char filename[], int fd, int len); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c new file mode 100644 index 000000000..db29bc90f --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ + +#include <udp.h> +#include <sys/socket.h> +#include <dhcp.h> +#include <dhcpv6.h> +#include <dns.h> +#ifdef USE_MTFTP +#include <mtftp.h> +#else +#include <tftp.h> +#endif + + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + + +#ifdef USE_MTFTP + +uint16_t net_tftp_uport; +uint16_t net_mtftp_uport; + +void net_set_tftp_port(uint16_t tftp_port) { + net_tftp_uport = tftp_port; +} + +void net_set_mtftp_port(uint16_t tftp_port) { + net_mtftp_uport = tftp_port; +} + +#endif + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ + + +/** + * NET: Handles UDP-packets according to Receive-handle diagram. + * + * @param udp_packet UDP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see udphdr + */ +int8_t +handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize) { + struct udphdr * udph = (struct udphdr *) udp_packet; + + if (packetsize < sizeof(struct udphdr)) + return -1; // packet is too small + + switch (htons(udph -> uh_dport)) { + case UDPPORT_BOOTPC: + if (udph -> uh_sport == htons(UDPPORT_BOOTPS)) + return handle_dhcp(fd, udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else + return -1; + case UDPPORT_DNSC: + if (udph -> uh_sport == htons(UDPPORT_DNSS)) + return handle_dns(udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else + return -1; + case UDPPORT_DHCPV6C: + return handle_dhcpv6(udp_packet+sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + case UDPPORT_TFTPC: +#ifdef USE_MTFTP + return handle_tftp(fd, udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); +#else + return handle_tftp(fd, udp_packet, packetsize); +#endif + default: +#ifdef USE_MTFTP + if (htons(udph -> uh_dport) == net_tftp_uport) + return handle_tftp(fd, udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else if (htons(udph -> uh_dport) == net_mtftp_uport) + return handle_tftp(fd, udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); +#endif + return -1; + } +} + +/** + * NET: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending UDP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + * @param packet original UDP-packet + * @param packetsize length of the packet + * @see handle_icmp + */ +void +handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) { + struct udphdr * udph = (struct udphdr *) udp_packet; + + if (packetsize < sizeof(struct udphdr)) + return; // packet is too small + + switch (htons(udph -> uh_sport)) { + case UDPPORT_TFTPC: + handle_tftp_dun(err_code); + break; + } +} + +/** + * NET: Creates UDP-packet. Places UDP-header in a packet and fills it + * with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_iphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where UDP-header must be placed. + * @param packetsize Size of the packet in bytes incl. this hdr and data. + * @param src_port UDP source port + * @param dest_port UDP destination port + * @see udphdr + * @see fill_ethhdr + * @see fill_iphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void +fill_udphdr(uint8_t * packet, uint16_t packetsize, + uint16_t src_port, uint16_t dest_port) { + struct udphdr * udph = (struct udphdr *) packet; + + udph -> uh_sport = htons(src_port); + udph -> uh_dport = htons(dest_port); + udph -> uh_ulen = htons(packetsize); + udph -> uh_sum = htons(0); +} diff --git a/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h new file mode 100644 index 000000000..1ba9332ce --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/app/netlib/udp.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _UDP_H +#define _UDP_H + +#include <stdint.h> + +#define IPTYPE_UDP 17 + +#define UDPPORT_BOOTPS 67 /**< UDP port of BootP/DHCP-server */ +#define UDPPORT_BOOTPC 68 /**< UDP port of BootP/DHCP-client */ +#define UDPPORT_DNSS 53 /**< UDP port of DNS-server */ +#define UDPPORT_DNSC 32769 /**< UDP port of DNS-client */ +#define UDPPORT_TFTPC 2001 /**< UDP port of TFTP-client */ +#define UDPPORT_DHCPV6C 546 /**< UDP port of DHCPv6-client */ + +/** \struct udphdr + * A header for UDP-packets. + * For more information see RFC 768. + */ +struct udphdr { + uint16_t uh_sport; /**< Source port */ + uint16_t uh_dport; /**< Destinantion port */ + uint16_t uh_ulen; /**< Length in octets, incl. this header and data */ + uint16_t uh_sum; /**< Checksum */ +}; +typedef struct udphdr udp_hdr_t; + +typedef int32_t *(*handle_upper_udp_t)(uint8_t *, int32_t); +typedef void *(*handle_upper_udp_dun_t)(uint8_t); + +/* Handles UDP-packets that are detected by any network layer. */ +extern int8_t handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize); + +/* Handles UDP related ICMP-Dest.Unreachable packets that are detected by + * the network layers. */ +extern void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code); + +/* fills udp header */ +extern void fill_udphdr(uint8_t *packet, uint16_t packetsize, + uint16_t src_port, uint16_t dest_port); + +#ifdef USE_MTFTP +extern void net_set_tftp_port(uint16_t tftp_port); +extern void net_set_mtftp_port(uint16_t tftp_port); +#endif + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/client.lds b/qemu/roms/SLOF/clients/net-snk/client.lds new file mode 100644 index 000000000..39d04594e --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/client.lds @@ -0,0 +1,85 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_entry) + +SECTIONS { + . = 0xF000100; + .text : + { + __client_start = .; + *(.text* .stub .gnu.linkonce.t.*) + *(.sfpr .glink) + } + + . = ALIGN(0x100); + .rodata : + { + *(.rodata* .gnu.linkonce.r.*) + } + + . = ALIGN(0x10); + .data : + { + *(.data* .gnu.linkonce.d.*) + *(.force.data) + *(.toc1) + *(.branch_lt) + } + + . = ALIGN(0x10); + .opd : + { + *(.opd) + } + + . = ALIGN(0x10); + .got : + { + _got = .; + *(.got) + *(.toc) + _got_end = .; + } + + . = ALIGN(0x1000); + .bss : + { + *(*COM* .bss* .gnu.linkonce.b.*) + } + __client_end = .; + + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + . = ALIGN(0x10); + .dynamic : { + *(.dynamic) + } + . = ALIGN(0x10); + .rela.dyn : { + *(.rela*) + } + .hash : { *(.hash) } + + .comment : { + /* + * Discarding this section caused errors on binutils 2.23, + * this is fixed in 2.24. + */ + *(.comment) + } + /DISCARD/ : { + *(.interp) + } +} diff --git a/qemu/roms/SLOF/clients/net-snk/include/crt0.h b/qemu/roms/SLOF/clients/net-snk/include/crt0.h new file mode 100644 index 000000000..d8fce05c9 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/crt0.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _CRT0_H +#define _CRT0_H + +int gen_argv(const char *, int, char **); + + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/include/fcntl.h b/qemu/roms/SLOF/clients/net-snk/include/fcntl.h new file mode 100644 index 000000000..69de2cea3 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/fcntl.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _FCNTL_H +#define _FCNTL_H + +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDRW 02 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#endif /* fcntl.h */ diff --git a/qemu/roms/SLOF/clients/net-snk/include/fileio.h b/qemu/roms/SLOF/clients/net-snk/include/fileio.h new file mode 100644 index 000000000..50f9650b2 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/fileio.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef FILEIO_H +#define FILEIO_H + +#include <of.h> + +#define FILEIO_TYPE_EMPTY 0 +#define FILEIO_TYPE_FILE 1 +#define FILEIO_TYPE_SOCKET 2 + +struct snk_fileio_type { + int type; + ihandle_t ih; +}; +typedef struct snk_fileio_type snk_fileio_t; + +#define FILEIO_MAX 32 +extern snk_fileio_t fd_array[FILEIO_MAX]; + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/include/kernel.h b/qemu/roms/SLOF/clients/net-snk/include/kernel.h new file mode 100644 index 000000000..4d6be2dc2 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/kernel.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef KERNEL_H +#define KERNEL_H + +#include <stddef.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <of.h> + +uint64_t get_time(void); +int getchar(void); + +void *malloc_aligned(size_t size, int align); + +int pre_open_ih(int fd, ihandle_t ih); + +void exception_forward(void); +void undo_exception(void); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/include/of.h b/qemu/roms/SLOF/clients/net-snk/include/of.h new file mode 100644 index 000000000..22411ff98 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/of.h @@ -0,0 +1,70 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef OF_H +#define OF_H + +#include <stdint.h> +#include <stddef.h> + +#define p32 int +#define p32cast (int) (unsigned long) (void*) + +#define phandle_t p32 +#define ihandle_t p32 + +typedef struct +{ + unsigned int serv; + int nargs; + int nrets; + unsigned int args[16]; +} of_arg_t; + + +phandle_t of_finddevice (const char *); +phandle_t of_peer (phandle_t); +phandle_t of_child (phandle_t); +phandle_t of_parent (phandle_t); +phandle_t of_instance_to_package(ihandle_t ihandle); +int of_getprop (phandle_t, const char *, void *, int); +void * of_call_method_3 (const char *, ihandle_t, int); +int of_test(const char *name); +int of_interpret_1(void *s, void *ret); + +ihandle_t of_open (const char *); +void of_close(ihandle_t); +int of_read (ihandle_t , void*, int); +int of_write (ihandle_t, void*, int); +int of_seek (ihandle_t, int, int); + +void * of_claim(void *, unsigned int , unsigned int ); +void of_release(void *, unsigned int ); + +int of_yield(void); +void * of_set_callback(void *); + +unsigned int romfs_lookup(const char *, void **); +int vpd_read(unsigned int , unsigned int , char *); +int vpd_write(unsigned int , unsigned int , char *); +int write_mm_log(char *, unsigned int , unsigned short ); + +int of_get_mac(phandle_t device, char *mac); +uint64_t get_puid(phandle_t node); +void translate_address_dev(uint64_t *, phandle_t); +void translate_address(unsigned long *addr); + +int of_glue_init(unsigned int * timebase, + size_t _client_start, size_t _client_size); +void of_glue_release(void); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/include/pci.h b/qemu/roms/SLOF/clients/net-snk/include/pci.h new file mode 100644 index 000000000..cf584c348 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/pci.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _PCI_H +#define _PCI_H + +unsigned int read_io(void *addr, size_t sz); +int write_io(void *addr, unsigned int value, size_t sz); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/include/rtas.h b/qemu/roms/SLOF/clients/net-snk/include/rtas.h new file mode 100644 index 000000000..25cabf4d6 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/rtas.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef RTAS_H +#define RTAS_H + +#include "of.h" + +typedef struct dtime { + unsigned int year; + unsigned int month; + unsigned int day; + unsigned int hour; + unsigned int minute; + unsigned int second; + unsigned int nano; +} dtime; + +typedef void (*thread_t) (int); + +int rtas_token(const char *); +int rtas_call(int, int, int, int *, ...); +void rtas_init(void); +int rtas_pci_config_read (long long, int, int, int, int); +int rtas_pci_config_write (long long, int, int, int, int, int); +int rtas_set_time_of_day(dtime *); +int rtas_get_time_of_day(dtime *); +int rtas_ibm_update_flash_64(long long, long long); +int rtas_ibm_update_flash_64_and_reboot(long long, long long); +int rtas_system_reboot(void); +int rtas_start_cpu (int, thread_t, int); +int rtas_stop_self (void); +int rtas_ibm_manage_flash(int); + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/include/sys/socket.h b/qemu/roms/SLOF/clients/net-snk/include/sys/socket.h new file mode 100644 index 000000000..e9175be37 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/sys/socket.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _SOCKET_H +#define _SOCKET_H +#include <stdint.h> + +#define AF_PACKET 0 +#define AF_INET 1 +#define AF_INET6 2 + +#define SOCK_RAW 0 +#define SOCK_PACKET 1 +#define SOCK_DGRAM 2 +#define SOCK_STREAM 3 + +#define INADDR_ANY 0xFFFFFFFF + +#define IPPROTO_UDP 1 + +#define ETH_ALEN 6 /**< HW address length */ + +struct sockaddr { + uint16_t tra_port; + + uint16_t ipv4_proto; + uint32_t ipv4_addr; + + // protocol field is only used by "connect"-handler + uint16_t llc_proto; + uint8_t mac_addr[ETH_ALEN]; +}; + +int socket(int, int, int, char *); +int sendto(int, const void *, int, int, const void *, int); +int send(int, const void *, int, int); +int recv(int, void *, int, int); + +#define htonl(x) x +#define htons(x) x + +#endif + diff --git a/qemu/roms/SLOF/clients/net-snk/include/time.h b/qemu/roms/SLOF/clients/net-snk/include/time.h new file mode 100644 index 000000000..14d1c4c57 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/include/time.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _TIME_H_ +#define _TIME_H_ + +typedef unsigned long clock_t; +typedef unsigned long time_t; + +time_t time(time_t *); + +extern unsigned long tb_freq; + +/* setup the timer to start counting from the given parameter */ +void set_timer(int); +/* read the current value from the decrementer */ +int get_timer(void); +/* get the number of ticks for which the decrementer needs 1 second */ +int get_sec_ticks(void); +/* get the number of ticks for which the decrementer needs 1 millisecond */ +int get_msec_ticks(void); + +#define TICKS_MSEC get_msec_ticks() +#define TICKS_SEC get_sec_ticks() + +#endif diff --git a/qemu/roms/SLOF/clients/net-snk/kernel/Makefile b/qemu/roms/SLOF/clients/net-snk/kernel/Makefile new file mode 100644 index 000000000..c4b8164ca --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/kernel/Makefile @@ -0,0 +1,31 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +OBJS = init.o systemcall.o crt0.o timer.o +OBJS2 = entry.o + +all: kernel.o + +kernel.o: $(OBJS) $(OBJS2) + $(LD) $(LDFLAGS) $(OBJS) $(OBJS2) -o $@ -r + +clean: + $(RM) -f *.o *.a *.i + +include $(TOP)/make.depend diff --git a/qemu/roms/SLOF/clients/net-snk/kernel/crt0.c b/qemu/roms/SLOF/clients/net-snk/kernel/crt0.c new file mode 100644 index 000000000..a292273b0 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/kernel/crt0.c @@ -0,0 +1,78 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> + +extern int main (int, char**); +extern int callback (int, char **); + +int _start(char *arg_string, long len); +unsigned long callback_entry(void *base, unsigned long len); + + +#define MAX_ARGV 10 +static int +gen_argv(const char *arg_string, int len, char* argv[]) +{ + const char *str, *str_end, *arg_string_end = arg_string + len; + int i; + + str = arg_string; + for (i = 0; i < MAX_ARGV; i++) + { + str_end = str; + + while((*str_end++ != ' ') && (str_end <= arg_string_end)); + + argv[i] = malloc(str_end-str); + + memcpy (argv[i], str, str_end-str-1); + argv[i][str_end-str-1] = '\0'; + str = str_end-1; + while(*(++str) == ' '); + if (str >= arg_string_end) + break; + } + return i+1; +} + + + +int +_start(char * arg_string, long len) +{ + int rc; + int argc; + char* argv[MAX_ARGV]; + + argc = gen_argv(arg_string, len, argv); + + rc = main(argc, argv); + + return rc; +} + +/* + * Takes a Forth representation of a string and generates an argument array, + * then calls callback(). + */ +unsigned long +callback_entry(void *base, unsigned long len) { + char *argv[MAX_ARGV]; + int argc; + + argc = gen_argv(base, len, argv); + + return (callback(argc, argv)); +} + diff --git a/qemu/roms/SLOF/clients/net-snk/kernel/entry.S b/qemu/roms/SLOF/clients/net-snk/kernel/entry.S new file mode 100644 index 000000000..8849fb9d1 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/kernel/entry.S @@ -0,0 +1,127 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#define STACKSIZE 0x100000 +#include <macros.h> + + + .section ".toc","aw" # TOC entries are needed for relocation +.exception_stack_frame_toc: + .tc exception_stack_frame[TC],exception_stack_frame +.exit_sp_toc: + .tc _exit_sp[TC],_exit_sp +.prom_entry_toc: + .tc _prom_entry[TC],_prom_entry + + .previous + + +/* +Function: + Input: + r3: + r4: + r5: prom entry + Output: + +Decription: Main entry point, called from OF + +*/ +C_ENTRY(_entry) + mr r3, r6 # parm 0 passed in r6 + mr r4, r7 # parm 1 passed in r7 + mr r6, r1 # save stack pointer + mflr r7 # save link register + bcl 20,31,over # branch after pointer table +base: + .align 3 +.LCgot: .quad _got-base+0x8000 +.LCstack: .quad _stack+STACKSIZE-0x80-base +over: + mflr r8 # gpr 8 is the base + ld r1,.LCstack-base(r8) # load new stack pointer + add r1, r1, r8 # add base + std r2, 64(r1) # save got + std r7, 56(r1) # save link register + ld r2, .LCgot-base(r8) # load got pointer + add r2, r2, r8 # add base + std r6, 0(r1) # save stack pointer + + ld r6, .prom_entry_toc@toc(r2) + std r5, 0(r6) # Save prom handle + + ld r10, .exit_sp_toc@toc(r2) # save stack pointer for exit call + std r1, 0(r10) + + bl ._start_kernel # call kernel init code + +the_end: + ld r4, 56(r1) # Restore link register + mtlr r4 + ld r2, 64(r1) # restore got + ld r1, 0(r1) + + blr + +/* + * Function: _callback_entry + * Input: r6 start address of parameter string + * r7 length of parameter string. + * + * Description: If a client application wants to register a callback function, + * this function is registered w/ SLOF, not the application's function. SLOF + * passes the parameter string in Forth representation in R6 and R7. This + * function moves R6 to R3 and R7 to R4 and then calls callback_entry(). + * + */ +C_ENTRY(_callback_entry) + # Save the LR + mflr r0 + std r0, 16(r1) + + # Reserve stack space + stdu r1, -32(r1) + + # SLOF passes the parameters in Registers R6 and R7 but the target + # wants them in registers R3 and R4 + mr r3, r6 + mr r4, r7 + + # Branch to the callback_entry function + bl .callback_entry + + # Destroy stack frame + ld r1, 0(r1) + + # Restore LR + ld r0, 16(r1) + mtlr r0 + + # Return to caller + blr + + .section ".bss" + +_exit_sp: .quad 0 + +.global _prom_entry +_prom_entry: .quad 0 + + .section ".text" + +C_ENTRY(_exit) + ld r1, .exit_sp_toc@toc(r2) + ld r1, 0(r1) + b the_end + + + .lcomm _stack,STACKSIZE,16 diff --git a/qemu/roms/SLOF/clients/net-snk/kernel/init.c b/qemu/roms/SLOF/clients/net-snk/kernel/init.c new file mode 100644 index 000000000..1376b6474 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/kernel/init.c @@ -0,0 +1,67 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <string.h> +#include <stdlib.h> /* malloc */ +#include <of.h> +#include <pci.h> +#include <kernel.h> +#include <cpu.h> +#include <fileio.h> + +/* Application entry point .*/ +extern int _start(unsigned char *arg_string, long len); +extern int main(int, char**); +int _start_kernel(unsigned long p0, unsigned long p1); +void * malloc_aligned(size_t size, int align); + +unsigned long exception_stack_frame; + +snk_fileio_t fd_array[FILEIO_MAX]; + +extern uint64_t tb_freq; + +extern char __client_start; +extern char __client_end; + +void * malloc_aligned(size_t size, int align) +{ + unsigned long p = (unsigned long) malloc(size + align - 1); + p = p + align - 1; + p = p & ~(align - 1); + + return (void *) p; +} + +int _start_kernel(unsigned long p0, unsigned long p1) +{ + int rc; + unsigned int timebase; + + /* initialize all file descriptor by marking them as empty */ + for(rc=0; rc<FILEIO_MAX; ++rc) + fd_array[rc].type = FILEIO_TYPE_EMPTY; + + /* this is step is e.g. resposible to initialize file descriptor 0 and 1 for STDIO */ + rc = of_glue_init(&timebase, (size_t)(unsigned long)&__client_start, + (size_t)(unsigned long)&__client_end - (size_t)(unsigned long)&__client_start); + if(rc < 0) + return -1; + + tb_freq = (uint64_t) timebase; + rc = _start((unsigned char *) p0, p1); + + of_glue_release(); + return rc; +} + diff --git a/qemu/roms/SLOF/clients/net-snk/kernel/systemcall.c b/qemu/roms/SLOF/clients/net-snk/kernel/systemcall.c new file mode 100644 index 000000000..52c45cad7 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/kernel/systemcall.c @@ -0,0 +1,176 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <stdarg.h> +#include <string.h> +#include <fileio.h> +#include <kernel.h> +#include <of.h> +#include <sys/socket.h> + +extern int vsprintf(char *, const char *, va_list); +extern void _exit(int status); + +void exit(int status); + +int open(const char* name, int flags) +{ + int fd; + + /* search free file descriptor */ + for (fd=0; fd<FILEIO_MAX; ++fd) { + if(fd_array[fd].type == FILEIO_TYPE_EMPTY) { + break; + } + } + if (fd == FILEIO_MAX) { + printf("Can not open \"%s\" because file descriptor list is full\n", name); + /* there is no free file descriptor available */ + return -2; + } + + fd_array[fd].ih = of_open(name); + if (fd_array[fd].ih == 0) + return -1; + + fd_array[fd].type = FILEIO_TYPE_FILE; + + return fd; +} + +int pre_open_ih(int fd, ihandle_t ih) +{ + if (fd_array[fd].type != FILEIO_TYPE_EMPTY) + return -2; + fd_array[fd].ih = ih; + fd_array[fd].type = FILEIO_TYPE_FILE; + + return fd; +} + +int socket(int domain, int type, int proto, char *mac_addr) +{ + uint8_t tmpbuf[8]; + int fd; + phandle_t ph; + + /* search free file descriptor */ + for (fd=0; fd<FILEIO_MAX; ++fd) { + if(fd_array[fd].type == FILEIO_TYPE_EMPTY) { + break; + } + } + if (fd == FILEIO_MAX) { + printf("Can not open socket, file descriptor list is full\n"); + /* there is no free file descriptor available */ + return -2; + } + + fd_array[fd].ih = of_interpret_1("my-parent", tmpbuf); + if (fd_array[fd].ih == 0) { + printf("Can not open socket, no parent instance\n"); + return -1; + } + ph = of_instance_to_package(fd_array[fd].ih); + if (ph == -1) { + printf("Can not open socket, no parent package\n"); + return -1; + } + if (of_get_mac(ph, mac_addr) < 0) { + printf("Can not open socket, no MAC address\n"); + return -1; + } + fd_array[fd].type = FILEIO_TYPE_SOCKET; + + return fd; +} + +int close(int fd) +{ + if (fd < 0 || fd >= FILEIO_MAX || + fd_array[fd].type == FILEIO_TYPE_EMPTY) + return -1; + if (fd_array[fd].type == FILEIO_TYPE_FILE) + of_close(fd_array[fd].ih); + fd_array[fd].type = FILEIO_TYPE_EMPTY; + return 0; +} + +ssize_t read(int fd, void *buf, size_t len) +{ + if (fd < 0 || fd >= FILEIO_MAX || + fd_array[fd].type == FILEIO_TYPE_EMPTY) + return -1; + + return of_read(fd_array[fd].ih, buf, len); +} + +ssize_t write (int fd, const void *buf, size_t len) +{ + char dest_buf[512]; + char *dest_buf_ptr; + const char *dbuf = buf; + int i; + + if (fd == 1 || fd == 2) { + dest_buf_ptr = &dest_buf[0]; + for (i = 0; i < len && i < 256; i++) + { + *dest_buf_ptr++ = *dbuf++; + if (dbuf[-1] == '\n') + *dest_buf_ptr++ = '\r'; + } + len = dest_buf_ptr - &dest_buf[0]; + buf = &dest_buf[0]; + } + + if(fd < 0 || fd >= FILEIO_MAX || + fd_array[fd].type == FILEIO_TYPE_EMPTY) + return -1; + + return of_write(fd_array[fd].ih, (void *)buf, len); +} + +ssize_t lseek (int fd, long offset, int whence) +{ + return 0; // this syscall is unused !!! +#if 0 + if (whence != 0) + return -1; + + of_seek (fd_array[fd], (unsigned int) (offset>>32), (unsigned int) (offset & 0xffffffffULL)); + + return offset; +#endif +} + +int recv(int fd, void *packet, int packet_len, int flags) +{ + return read(fd, packet, packet_len); +} + +int send(int fd, const void *packet, int packet_len, int flags) +{ + return write(fd, packet, packet_len); +} + +int sendto(int fd, const void *packet, int packet_len, int flags, + const void *sock_addr, int sock_addr_len) +{ + return send(fd, packet, packet_len, flags); +} + +void exit(int status) +{ + _exit(status); +} diff --git a/qemu/roms/SLOF/clients/net-snk/kernel/timer.c b/qemu/roms/SLOF/clients/net-snk/kernel/timer.c new file mode 100644 index 000000000..2d8705895 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/kernel/timer.c @@ -0,0 +1,39 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include "kernel.h" + +//******************************************************************* +// variable "tb_freq" contains the frequency in Hz +// and is read from the device tree (setup by LLFW) in "init.c" +uint64_t tb_freq; + +//------------------------------------------------------------------- +// Read the current timebase +uint64_t get_time(void) +{ + uint64_t act; + + __asm__ __volatile__( + "0: mftbu %0 ;\ + mftbl %%r0 ; \ + mftbu %%r4 ; \ + cmpw %0,%%r4 ; \ + bne 0b; \ + sldi %0,%0,32; \ + or %0,%0,%%r0" + : "=r"(act) + : /* no inputs */ + : "r0", "r4"); + return act; +} diff --git a/qemu/roms/SLOF/clients/net-snk/libc/Makefile b/qemu/roms/SLOF/clients/net-snk/libc/Makefile new file mode 100644 index 000000000..073f039aa --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/libc/Makefile @@ -0,0 +1,45 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + + +OBJS = sbrk.o +OBJDIRS = time/time.o +SUBDIRS = $(filter-out ./,$(dir $(OBJDIRS))) + + +all: subdirs + $(MAKE) libc-glue.o + +libc-glue.o: $(OBJS) $(OBJDIRS) + $(LD) $(LDFLAGS) $(OBJS) $(OBJDIRS) -o $@ -r + + +subdirs : + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \ + done + +clean: + $(RM) -f *.a *.o + @for dir in $(SUBDIRS); do \ + $(CLEAN) ; \ + $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \ + done + +include $(TOP)/make.depend diff --git a/qemu/roms/SLOF/clients/net-snk/libc/sbrk.c b/qemu/roms/SLOF/clients/net-snk/libc/sbrk.c new file mode 100644 index 000000000..2ec1b5f12 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/libc/sbrk.c @@ -0,0 +1,39 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <unistd.h> + +#define HEAP_SIZE 0x200000 + + +static char heap[HEAP_SIZE]; +static char *actptr; + +void *sbrk(int increment) +{ + char *oldptr; + + /* Called for the first time? Then init the actual pointer */ + if (!actptr) { + actptr = heap; + } + + if (actptr + increment > heap + HEAP_SIZE) { + /* Out of memory */ + return (void *)-1; + } + + oldptr = actptr; + actptr += increment; + + return oldptr; +} diff --git a/qemu/roms/SLOF/clients/net-snk/libc/time/Makefile b/qemu/roms/SLOF/clients/net-snk/libc/time/Makefile new file mode 100644 index 000000000..5db779472 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/libc/time/Makefile @@ -0,0 +1,34 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP + +endif +include $(TOP)/make.rules + + +OBJS = timer.o ftime.o + + +all: time.o + +time.o: $(OBJS) + $(LD) $(LDFLAGS) -r $< -o $@ + +clean: + $(RM) -f *.o *.i *.s + +distclean mrproper: clean + +include $(TOP)/make.depend diff --git a/qemu/roms/SLOF/clients/net-snk/libc/time/ftime.c b/qemu/roms/SLOF/clients/net-snk/libc/time/ftime.c new file mode 100644 index 000000000..e092ba55d --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/libc/time/ftime.c @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include <time.h> +#include <rtas.h> +#include <stdio.h> + +time_t +time(time_t *tod) +{ + dtime ts; + + rtas_get_time_of_day(&ts); + printf("debug!!\n"); + + printf("year : %d\n", ts.year); + printf("month : %d\n", ts.month); + printf("day : %d\n", ts.day); + printf("hour : %d\n", ts.hour); + printf("minute: %d\n", ts.minute); + printf("second: %d\n", ts.second); + printf("nano : %d\n", ts.nano); + printf("debug ende\n"); + +// if(tod) +// *tod = t; + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/libc/time/timer.c b/qemu/roms/SLOF/clients/net-snk/libc/time/timer.c new file mode 100644 index 000000000..b17737276 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/libc/time/timer.c @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <kernel.h> +#include "time.h" + +int get_msec_ticks() +{ + return tb_freq/1000; +} + +int get_sec_ticks() +{ + return tb_freq; +} + +void set_timer(int val) +{ + asm volatile ("mtdec %0"::"r" (val)); +} + +int get_timer() +{ + int val; + asm volatile ("mfdec %0":"=r" (val)); + return val; +} diff --git a/qemu/roms/SLOF/clients/net-snk/make.rules b/qemu/roms/SLOF/clients/net-snk/make.rules new file mode 100644 index 000000000..02160936f --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/make.rules @@ -0,0 +1,25 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ROOTDIR ?= $(TOP)/../.. + +include $(ROOTDIR)/make.rules + +INCLCMNDIR ?= $(ROOTDIR)/include +LIBCMNDIR ?= $(ROOTDIR)/lib +CPPFLAGS = -I$(TOP)/include -I$(LIBCMNDIR)/libc/include -I$(INCLCMNDIR) \ + -I$(LIBCMNDIR)/libbootmsg -I$(INCLCMNDIR)/$(CPUARCH) -I. +CFLAGS += $(FLAG) + +LDFLAGS = -nostdlib -q -n +ASFLAGS = -I. -I$(TOP)/include -Wa,-mregnames -I$(INCLCMNDIR)/$(CPUARCH) +DD = dd diff --git a/qemu/roms/SLOF/clients/net-snk/oflib/Makefile b/qemu/roms/SLOF/clients/net-snk/oflib/Makefile new file mode 100644 index 000000000..aad3e89ff --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/oflib/Makefile @@ -0,0 +1,41 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +OBJS = rtas.o of.o pci.o +OBJS2 = entry.o + +all: oflib.o + + +oflib.o: $(OBJS) $(OBJS2) + $(LD) $(LDFLAGS) $^ -o oflib.o -r + +clean: + $(RM) -f $(OBJS) $(OBJS2) oflib.o + +include $(TOP)/make.depend + + +#mrproper : clean +# rm -rf .depend +# +#depend : +# @rm -rf .depend ; touch .depend ; \ +# makedepend -v -f.depend -- $(CFLAGS) -- $(OBJS:.o=.c) 2> /dev/null ; \ +# $(CC) -M $(CFLAGS) $(OBJS2:.o=.S) >> .depend diff --git a/qemu/roms/SLOF/clients/net-snk/oflib/entry.S b/qemu/roms/SLOF/clients/net-snk/oflib/entry.S new file mode 100644 index 000000000..f08026762 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/oflib/entry.S @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <macros.h> + + .section ".toc","aw" # TOC entries are needed for relocation +.prom_entry_toc: + .tc _prom_entry[TC],_prom_entry + + +C_ENTRY(call_client_interface) + ld r4, .prom_entry_toc@toc(r2) # Load prom entry point + mflr r0 + std r0, 16(r1) + ld r4, 0(r4) + stdu r1, -128(r1) + std r2,40(r1) + mtctr r4 + bctrl + ld r2,40(r1) + addi r1, r1, 128 + ld r0, 16(r1) + mtlr r0 + blr + + +C_ENTRY(rtas_call_entry) + mtctr r5 + bctr diff --git a/qemu/roms/SLOF/clients/net-snk/oflib/of.c b/qemu/roms/SLOF/clients/net-snk/oflib/of.c new file mode 100644 index 000000000..5c502ac60 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/oflib/of.c @@ -0,0 +1,715 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <of.h> +#include <rtas.h> +#include <string.h> +#include <libbootmsg.h> +#include <kernel.h> + +extern void call_client_interface(of_arg_t *); + +static int claim_rc = 0; +static void* client_start; +static size_t client_size; + +static inline int +of_0_1(const char *serv) +{ + of_arg_t arg = { + p32cast serv, + 0, 1, + { 0 } + }; + + call_client_interface(&arg); + + return arg.args[0]; +} + +static inline void +of_1_0(const char *serv, int arg0) +{ + of_arg_t arg = { + p32cast serv, + 1, 0, + {arg0, 0} + }; + + call_client_interface(&arg); +} + +static inline unsigned int +of_1_1(const char *serv, int arg0) +{ + of_arg_t arg = { + p32cast serv, + 1, 1, + {arg0, 0} + }; + + call_client_interface(&arg); + return arg.args[1]; +} + +static inline unsigned int +of_1_2(const char *serv, int arg0, int *ret0) +{ + of_arg_t arg = { + p32cast serv, + 1, 2, + {arg0, 0, 0} + }; + + call_client_interface(&arg); + *ret0 = arg.args[2]; + return arg.args[1]; +} + +static inline void +of_2_0(const char *serv, int arg0, int arg1) +{ + of_arg_t arg = { + p32cast serv, + 2, 0, + {arg0, arg1, 0} + }; + + call_client_interface(&arg); +} + +static inline unsigned int +of_2_1(const char *serv, int arg0, int arg1) +{ + of_arg_t arg = { + p32cast serv, + 2, 1, + {arg0, arg1, 0} + }; + + call_client_interface(&arg); + return arg.args[2]; +} + +static inline unsigned int +of_2_2(const char *serv, int arg0, int arg1, int *ret0) +{ + of_arg_t arg = { + p32cast serv, + 2, 2, + {arg0, arg1, 0, 0} + }; + + call_client_interface(&arg); + *ret0 = arg.args[3]; + return arg.args[2]; +} + +static inline unsigned int +of_2_3(const char *serv, int arg0, int arg1, int *ret0, int *ret1) +{ + of_arg_t arg = { + p32cast serv, + 2, 3, + {arg0, arg1, 0, 0, 0} + }; + + call_client_interface(&arg); + *ret0 = arg.args[3]; + *ret1 = arg.args[4]; + return arg.args[2]; +} + +static inline void +of_3_0(const char *serv, int arg0, int arg1, int arg2) +{ + of_arg_t arg = { + p32cast serv, + 3, 0, + {arg0, arg1, arg2, 0} + }; + + call_client_interface(&arg); + return; +} + +static inline unsigned int +of_3_1(const char *serv, int arg0, int arg1, int arg2) +{ + of_arg_t arg = { + p32cast serv, + 3, 1, + {arg0, arg1, arg2, 0} + }; + + call_client_interface(&arg); + return arg.args[3]; +} + +static inline unsigned int +of_3_2(const char *serv, int arg0, int arg1, int arg2, int *ret0) +{ + of_arg_t arg = { + p32cast serv, + 3, 2, + {arg0, arg1, arg2, 0, 0} + }; + + call_client_interface(&arg); + *ret0 = arg.args[4]; + return arg.args[3]; +} + +static inline unsigned int +of_3_3(const char *serv, int arg0, int arg1, int arg2, int *ret0, int *ret1) +{ + of_arg_t arg = { + p32cast serv, + 3, 3, + {arg0, arg1, arg2, 0, 0, 0} + }; + + call_client_interface(&arg); + *ret0 = arg.args[4]; + *ret1 = arg.args[5]; + return arg.args[3]; +} + +static inline unsigned int +of_4_1(const char *serv, int arg0, int arg1, int arg2, int arg3) +{ + of_arg_t arg = { + p32cast serv, + 4, 1, + {arg0, arg1, arg2, arg3, 0} + }; + + call_client_interface(&arg); + return arg.args[4]; +} + +int +of_test(const char *name) +{ + return (int) of_1_1("test", p32cast name); +} + +int +of_interpret_1(void *s, void *ret) +{ + return of_1_2("interpret", p32cast s, ret); +} + +void +of_close(ihandle_t ihandle) +{ + of_1_0("close", ihandle); +} + +int +of_write(ihandle_t ihandle, void *s, int len) +{ + return of_3_1("write", ihandle, p32cast s, len); +} + +int +of_read(ihandle_t ihandle, void *s, int len) +{ + return of_3_1("read", ihandle, p32cast s, len); +} + +int +of_seek(ihandle_t ihandle, int poshi, int poslo) +{ + return of_3_1("seek", ihandle, poshi, poslo); +} + +int +of_getprop(phandle_t phandle, const char *name, void *buf, int len) +{ + return of_4_1("getprop", phandle, p32cast name, p32cast buf, len); +} + +phandle_t +of_peer(phandle_t phandle) +{ + return (phandle_t) of_1_1("peer", phandle); +} + +phandle_t +of_child(phandle_t phandle) +{ + return (phandle_t) of_1_1("child", phandle); +} + +phandle_t +of_parent(phandle_t phandle) +{ + return (phandle_t) of_1_1("parent", phandle); +} + +phandle_t +of_instance_to_package(ihandle_t ihandle) +{ + return (phandle_t) of_1_1("instance-to-package", ihandle); +} + + +phandle_t +of_finddevice(const char *name) +{ + return (phandle_t) of_1_1("finddevice", p32cast name); +} + +ihandle_t +of_open(const char *name) +{ + return (ihandle_t) of_1_1("open", p32cast name); +} + +void * +of_claim(void *start, unsigned int size, unsigned int align) +{ + return(void *)(long)(size_t)of_3_1("claim", p32cast start, size, align); +} + +void +of_release(void *start, unsigned int size) +{ + (void) of_2_0("release", p32cast start, size); +} + +void * +of_call_method_3(const char *name, ihandle_t ihandle, int arg0) +{ + int entry, rc; + rc = of_3_2("call-method", p32cast name, ihandle, arg0, &entry); + return rc != 0 ? 0 : (void *) (long) entry; +} + +int +vpd_read(unsigned int offset, unsigned int length, char *data) +{ + int result; + long tmp = (long) data; + result = of_3_1("rtas-read-vpd", offset, length, (int) tmp); + return result; +} + +int +vpd_write(unsigned int offset, unsigned int length, char *data) +{ + int result; + long tmp = (long) data; + result = of_3_1("rtas-write-vpd", offset, length, (int) tmp); + return result; +} + +static void +ipmi_oem_led_set(int type, int instance, int state) +{ + return of_3_0("set-led", type, instance, state); +} + +int +write_mm_log(char *data, unsigned int length, unsigned short type) +{ + long tmp = (long) data; + + ipmi_oem_led_set(2, 0, 1); + return of_3_1("write-mm-log", (int) tmp, length, type); +} + +int +of_yield(void) +{ + return of_0_1("yield"); +} + +void * +of_set_callback(void *addr) +{ + return (void *) (long) (size_t) of_1_1("set-callback", p32cast addr); +} + +void +bootmsg_warning(short id, const char *str, short lvl) +{ + (void) of_3_0("bootmsg-warning", id, lvl, p32cast str); +} + +void +bootmsg_error(short id, const char *str) +{ + (void) of_2_0("bootmsg-error", id, p32cast str); +} + +/* +void +bootmsg_debugcp(short id, const char *str, short lvl) +{ + (void) of_3_0("bootmsg-debugcp", id, lvl, p32cast str); +} + +void +bootmsg_cp(short id) +{ + (void) of_1_0("bootmsg-cp", id); +} +*/ + +#define CONFIG_SPACE 0 +#define IO_SPACE 1 +#define MEM_SPACE 2 + +#define ASSIGNED_ADDRESS_PROPERTY 0 +#define REG_PROPERTY 1 + +#define DEBUG_TRANSLATE_ADDRESS 0 +#if DEBUG_TRANSLATE_ADDRESS != 0 +#define DEBUG_TR(str...) printf(str) +#else +#define DEBUG_TR(str...) +#endif + +/** + * pci_address_type tries to find the type for which a + * mapping should be done. This is PCI specific and is done by + * looking at the first 32bit of the phys-addr in + * assigned-addresses + * + * @param node the node of the device which requests + * translatation + * @param address the address which needs to be translated + * @param prop_type the type of the property to search in (either REG_PROPERTY or ASSIGNED_ADDRESS_PROPERTY) + * @return the corresponding type (config, i/o, mem) + */ +static int +pci_address_type(phandle_t node, uint64_t address, uint8_t prop_type) +{ + char *prop_name = "assigned-addresses"; + if (prop_type == REG_PROPERTY) + prop_name = "reg"; + /* #address-cells */ + const unsigned int nac = 3; //PCI + /* #size-cells */ + const unsigned int nsc = 2; //PCI + /* up to 11 pairs of (phys-addr(3) size(2)) */ + unsigned char buf[11 * (nac + nsc) * sizeof(int)]; + unsigned int *assigned_ptr; + int result = -1; + int len; + len = of_getprop(node, prop_name, buf, 11 * (nac + nsc) * sizeof(int)); + assigned_ptr = (unsigned int *) &buf[0]; + while (len > 0) { + if ((prop_type == REG_PROPERTY) + && ((assigned_ptr[0] & 0xFF) != 0)) { + //BARs and Expansion ROM must be in assigned-addresses... so in reg + // we only look for those without config space offset set... + assigned_ptr += (nac + nsc); + len -= (nac + nsc) * sizeof(int); + continue; + } + DEBUG_TR("%s %x size %x\n", prop_name, assigned_ptr[2], + assigned_ptr[4]); + if (address >= assigned_ptr[2] + && address <= assigned_ptr[2] + assigned_ptr[4]) { + DEBUG_TR("found a match\n"); + result = (assigned_ptr[0] & 0x03000000) >> 24; + break; + } + assigned_ptr += (nac + nsc); + len -= (nac + nsc) * sizeof(int); + } + /* this can only handle 32bit memory space and should be + * removed as soon as translations for 64bit are available */ + return (result == 3) ? MEM_SPACE : result; +} + +/** + * this is a hack which returns the lower 64 bit of any number of cells + * all the higher bits will silently discarded + * right now this works pretty good as long 64 bit addresses is all we want + * + * @param addr a pointer to the first address cell + * @param nc number of cells addr points to + * @return the lower 64 bit to which addr points + */ +static uint64_t +get_dt_address(uint32_t *addr, uint32_t nc) +{ + uint64_t result = 0; + while (nc--) + result = (result << 32) | *(addr++); + return result; +} + +/** + * this functions tries to find a mapping for the given address + * it assumes that if we have #address-cells == 3 that we are trying + * to do a PCI translation + * + * @param addr a pointer to the address that should be translated + * if a translation has been found the address will + * be modified + * @param type this is required for PCI devices to find the + * correct translation + * @param ranges this is one "range" containing the translation + * information (one range = nac + pnac + nsc) + * @param nac the OF property #address-cells + * @param nsc the OF property #size-cells + * @param pnac the OF property #address-cells from the parent node + * @return -1 if no translation was possible; else 0 + */ +static int +map_one_range(uint64_t *addr, int type, uint32_t *ranges, uint32_t nac, + uint32_t nsc, uint32_t pnac) +{ + long offset; + /* cm - child mapping */ + /* pm - parent mapping */ + uint64_t cm, size, pm; + /* only check for the type if nac == 3 (PCI) */ + DEBUG_TR("type %x, nac %x\n", ranges[0], nac); + if (((ranges[0] & 0x03000000) >> 24) != type && nac == 3) + return -1; + /* okay, it is the same type let's see if we find a mapping */ + size = get_dt_address(ranges + nac + pnac, nsc); + if (nac == 3) /* skip type if PCI */ + cm = get_dt_address(ranges + 1, nac - 1); + else + cm = get_dt_address(ranges, nac); + + DEBUG_TR("\t\tchild_mapping %lx\n", cm); + DEBUG_TR("\t\tsize %lx\n", size); + DEBUG_TR("\t\t*address %lx\n", (uint64_t) * addr); + if (cm + size <= (uint64_t) * addr || cm > (uint64_t) * addr) + /* it is not inside the mapping range */ + return -1; + /* get the offset */ + offset = *addr - cm; + /* and add the offset on the parent mapping */ + if (pnac == 3) /* skip type if PCI */ + pm = get_dt_address(ranges + nac + 1, pnac - 1); + else + pm = get_dt_address(ranges + nac, pnac); + DEBUG_TR("\t\tparent_mapping %lx\n", pm); + *addr = pm + offset; + DEBUG_TR("\t\t*address %lx\n", *addr); + return 0; +} + +/** + * translate_address_dev tries to translate the device specific address + * to a host specific address by walking up in the device tree + * + * @param address a pointer to a 64 bit value which will be + * translated + * @param current_node phandle of the device from which the + * translation will be started + */ +void +translate_address_dev(uint64_t *addr, phandle_t current_node) +{ + unsigned char buf[1024]; + phandle_t parent; + unsigned int pnac; + unsigned int nac; + unsigned int nsc; + int addr_type; + int len; + unsigned int *ranges; + unsigned int one_range; + DEBUG_TR("translate address %lx, node: %lx\n", *addr, current_node); + of_getprop(current_node, "name", buf, 400); + DEBUG_TR("current node: %s\n", buf); + addr_type = + pci_address_type(current_node, *addr, ASSIGNED_ADDRESS_PROPERTY); + if (addr_type == -1) { + // check in "reg" property if not found in "assigned-addresses" + addr_type = pci_address_type(current_node, *addr, REG_PROPERTY); + } + DEBUG_TR("address_type %x\n", addr_type); + current_node = of_parent(current_node); + while (1) { + parent = of_parent(current_node); + if (!parent) { + DEBUG_TR("reached root node...\n"); + break; + } + of_getprop(current_node, "#address-cells", &nac, 4); + of_getprop(current_node, "#size-cells", &nsc, 4); + of_getprop(parent, "#address-cells", &pnac, 4); + one_range = nac + pnac + nsc; + len = of_getprop(current_node, "ranges", buf, 400); + if (len < 0) { + DEBUG_TR("no 'ranges' property; not translatable\n"); + return; + } + ranges = (unsigned int *) &buf[0]; + while (len > 0) { + if (!map_one_range + ((uint64_t *) addr, addr_type, ranges, nac, nsc, + pnac)) + /* after a successful mapping we stop + * going through the ranges */ + break; + ranges += one_range; + len -= one_range * sizeof(int); + } + DEBUG_TR("address %lx\n", *addr); + of_getprop(current_node, "name", buf, 400); + DEBUG_TR("current node: %s\n", buf); + DEBUG_TR("\t#address-cells: %x\n", nac); + DEBUG_TR("\t#size-cells: %x\n", nsc); + of_getprop(parent, "name", buf, 400); + DEBUG_TR("parent node: %s\n", buf); + DEBUG_TR("\t#address-cells: %x\n", pnac); + current_node = parent; + } +} + +static phandle_t +get_boot_device(void) +{ + char buf[1024]; + phandle_t dev = of_finddevice("/chosen"); + + if (dev == -1) { + dev = of_finddevice("/aliases"); + if (dev == -1) + return dev; + of_getprop(dev, "net", buf, 1024); + } else + of_getprop(dev, "bootpath", buf, 1024); + + return of_finddevice(buf); +} + +/** + * translate_address tries to translate the device specific address + * of the boot device to a host specific address + * + * @param address a pointer to a 64 bit value which will be + * translated + */ +void +translate_address(unsigned long *addr) +{ + translate_address_dev((uint64_t*) addr, get_boot_device()); +} + +/** + * get_puid walks up in the device tree until it finds a parent + * node without a reg property. get_puid is assuming that if the + * parent node has no reg property it has found the pci host bridge + * + * this is not the correct way to find PHBs but it seems to work + * for all our systems + * + * @param node the device for which to find the puid + * + * @return the puid or 0 + */ +uint64_t +get_puid(phandle_t node) +{ + uint64_t puid = 0; + uint64_t tmp = 0; + phandle_t curr_node, last_node; + + curr_node = last_node = of_parent(node); + + while (curr_node) { + puid = tmp; + if (of_getprop(curr_node, "reg", &tmp, 8) < 8) { + /* if the found PHB is not directly under + * root we need to translate the found address */ + translate_address_dev(&puid, last_node); + return puid; + } + last_node = curr_node; + curr_node = of_parent(curr_node); + } + + return 0; +} + +int of_get_mac(phandle_t device, char *mac) +{ + uint8_t localmac[8]; + int len; + + len = of_getprop(device, "local-mac-address", localmac, 8); + if (len <= 0) + return -1; + + if (len == 8) { + /* Some bad FDT nodes like veth use a 8-byte wide + * property instead of 6-byte wide MACs... :-( */ + memcpy(mac, &localmac[2], 6); + } + else { + memcpy(mac, localmac, 6); + } + return 0; +} + +static void +get_timebase(unsigned int *timebase) +{ + phandle_t cpu; + phandle_t cpus = of_finddevice("/cpus"); + + if (cpus == -1) + return; + + cpu = of_child(cpus); + + if (cpu == -1) + return; + + of_getprop(cpu, "timebase-frequency", timebase, 4); +} + +int of_glue_init(unsigned int * timebase, + size_t _client_start, size_t _client_size) +{ + phandle_t chosen = of_finddevice("/chosen"); + ihandle_t stdin_ih, stdout_ih; + + client_start = (void *) (long) _client_start; + client_size = _client_size; + + if (chosen == -1) + return -1; + + of_getprop(chosen, "stdin", &stdin_ih, sizeof(ihandle_t)); + of_getprop(chosen, "stdout", &stdout_ih, sizeof(ihandle_t)); + pre_open_ih(0, stdin_ih); + pre_open_ih(1, stdout_ih); + pre_open_ih(2, stdout_ih); + get_timebase(timebase); + rtas_init(); + + claim_rc=(int)(long)of_claim(client_start, client_size, 0); + + return 0; +} + +void of_glue_release(void) +{ + if (claim_rc >= 0) { + of_release(client_start, client_size); + } +} diff --git a/qemu/roms/SLOF/clients/net-snk/oflib/pci.c b/qemu/roms/SLOF/clients/net-snk/oflib/pci.c new file mode 100644 index 000000000..89003ae3e --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/oflib/pci.c @@ -0,0 +1,60 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <rtas.h> +#include <of.h> +#include <pci.h> +#include <string.h> +#include <kernel.h> +#include <cpu.h> +#include <cache.h> + +unsigned int read_io(void *addr, size_t sz) +{ + unsigned int ret; + + switch (sz) { + case 1: + ret = ci_read_8(addr); + break; + case 2: + ret = ci_read_16(addr); + break; + case 4: + ret = ci_read_32(addr); + break; + default: + ret = 0; + } + + return ret; +} + +int write_io(void *addr, unsigned int value, size_t sz) +{ + switch (sz) { + case 1: + ci_write_8(addr, value); + break; + case 2: + ci_write_16(addr, value); + break; + case 4: + ci_write_32(addr, value); + break; + default: + return -1; + } + + return 0; +} diff --git a/qemu/roms/SLOF/clients/net-snk/oflib/rtas.c b/qemu/roms/SLOF/clients/net-snk/oflib/rtas.c new file mode 100644 index 000000000..c514c7079 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/oflib/rtas.c @@ -0,0 +1,226 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <stdarg.h> +#include <stdio.h> +#include <rtas.h> +#include <of.h> +#include <kernel.h> + +typedef int rtas_arg_t; + +typedef struct { + int token; + int nargs; + int nret; + rtas_arg_t args[16]; + rtas_arg_t *rets; /* Pointer to return values in args[]. */ +} rtas_args_t; + +rtas_args_t rtas_args; + +typedef struct { + void *rtas_start; + void *rtas_entry; + int rtas_size; + phandle_t dev; +} rtas_t; + +extern rtas_t _rtas; +static int instantiate_rtas(void); +void rtas_call_entry(rtas_args_t *, void *, void *); + +int +rtas_token(const char *service) +{ + int token; + int retVal; + if (_rtas.dev == 0) + instantiate_rtas(); + + retVal = of_getprop(_rtas.dev, service, &token, sizeof(token)); + if (retVal == -1) { + token = 0; + } + return token; +} + +int +rtas_call(int token, int nargs, int nret, int *outputs, ...) +{ + va_list list; + int i; + + rtas_args.token = token; + rtas_args.nargs = nargs; + rtas_args.nret = nret; + rtas_args.rets = (rtas_arg_t *) & (rtas_args.args[nargs]); + va_start(list, outputs); + for (i = 0; i < nargs; ++i) { + rtas_args.args[i] = (rtas_arg_t) (va_arg(list, unsigned int)); + } + va_end(list); + + for (i = 0; i < nret; ++i) + rtas_args.rets[i] = 0; + + rtas_call_entry(&rtas_args, _rtas.rtas_start, _rtas.rtas_entry); + if (nret > 0 && outputs != 0) + for (i = 0; i < nret; i++) + outputs[i] = rtas_args.rets[i]; +#if 0 + printf("rtas call %x %x %x args: %x %x %x %x %x %x %x %x\n", + token, nargs, nret, + rtas_args.args[0], + rtas_args.args[1], + rtas_args.args[2], + rtas_args.args[3], + rtas_args.args[4], rtas_args.args[5], outputs[0], outputs[1]); +#endif + return ((nret > 0) ? rtas_args.rets[0] : 0); +} + +rtas_t _rtas; + +static int +instantiate_rtas(void) +{ + long long *rtas_mem_space; + ihandle_t ihandle; + + _rtas.dev = of_finddevice("/rtas"); + if ((long) _rtas.dev < 0) { + printf("\nCould not open /rtas\n"); + return -1; + } + + of_getprop(_rtas.dev, "rtas-size", &_rtas.rtas_size, + sizeof(_rtas.rtas_size)); + + if (_rtas.rtas_size <= 0) { + printf("\nSize of rtas (%x) too small to make sense\n", + _rtas.rtas_size); + return -1; + } + + rtas_mem_space = (long long *) malloc_aligned(_rtas.rtas_size, 0x100); + + if (!rtas_mem_space) { + printf("\nFailed to allocated memory for RTAS\n"); + return -1; + } + + ihandle = of_open("/rtas"); + + if ((long) ihandle < 0) { + printf("Could not open /rtas\n"); + return -1; + } + + if ((long) (_rtas.rtas_entry = of_call_method_3("instantiate-rtas", + ihandle, + p32cast rtas_mem_space)) + > 0) { + _rtas.rtas_start = rtas_mem_space; + } else { + printf("instantiate-rtas failed\n"); + return -1; + } +#if 0 + printf("\ninstantiate-rtas at %x size %x entry %x\n", + _rtas.rtas_start, _rtas.rtas_size, _rtas.rtas_entry); +#endif + return 0; +} + +static int read_pci_config_token = 0; +static int write_pci_config_token = 0; +static int ibm_read_pci_config_token = 0; +static int ibm_write_pci_config_token = 0; +static int get_time_of_day_token = 0; + +void +rtas_init() +{ + int ret; + ret = instantiate_rtas(); + if (ret) + return; + read_pci_config_token = rtas_token("read-pci-config"); + ibm_read_pci_config_token = rtas_token("ibm,read-pci-config"); + write_pci_config_token = rtas_token("write-pci-config"); + ibm_write_pci_config_token = rtas_token("ibm,write-pci-config"); + get_time_of_day_token = rtas_token("get-time-of-day"); +} + + +int +rtas_pci_config_read(long long puid, int size, int bus, int devfn, int offset) +{ + int value[2]; + + if (ibm_read_pci_config_token && puid) { + rtas_call(ibm_read_pci_config_token, 4, 2, value, + bus << 16 | devfn << 8 | offset, + puid >> 32, puid & 0xffffffffULL, size); + } else if (read_pci_config_token) { + rtas_call(read_pci_config_token, 2, 2, value, + bus << 16 | devfn << 8 | offset, size); + } + + return value[1]; +} + +int +rtas_pci_config_write(long long puid, int size, int bus, int devfn, + int offset, int value) +{ + int rc; + + if (ibm_write_pci_config_token && puid) { + rtas_call(ibm_write_pci_config_token, 5, 1, &rc, + bus << 16 | devfn << 8 | offset, + puid >> 32, puid & 0xffffffffULL, size, value); + } else + rtas_call(write_pci_config_token, 3, 1, &rc, + bus << 16 | devfn << 8 | offset, size, value); + + return rc; +} + +int +rtas_get_time_of_day(dtime * get) +{ + int rc = -1; + unsigned int year; + unsigned int month; + unsigned int day; + unsigned int hour; + unsigned int minute; + unsigned int second; + unsigned int nano; + + if (get_time_of_day_token) + rtas_call(get_time_of_day_token, 0, 8, &rc, &year, &month, &day, + &hour, &minute, &second, &nano); + + get->year = year; + get->month = month; + get->day = day; + get->hour = hour; + get->minute = minute; + get->second = second; + get->nano = nano; + + return rc; +} diff --git a/qemu/roms/SLOF/clients/net-snk/sec-client.lds b/qemu/roms/SLOF/clients/net-snk/sec-client.lds new file mode 100644 index 000000000..0eefdda95 --- /dev/null +++ b/qemu/roms/SLOF/clients/net-snk/sec-client.lds @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_entry) + +SECTIONS { + .client 0x200000: + { + __client_start = .; + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.sfpr .glink) + *(.rodata .rodata.* .gnu.linkonce.r.*) + KEEP (*(.opd)) + . = ALIGN(256); + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(256); +/* *(*COM* .bss .gnu.linkonce.b.*) */ + } =0x60000000 + + .got : + { + . = ALIGN(8); + _got = .; + *(.got .toc) + _got_end = .; + } + .bss : + { + *(*COM* .bss .gnu.linkonce.b.*) + __client_end = .; + } +} diff --git a/qemu/roms/SLOF/clients/takeover/Makefile b/qemu/roms/SLOF/clients/takeover/Makefile new file mode 100644 index 000000000..f71f7ecdf --- /dev/null +++ b/qemu/roms/SLOF/clients/takeover/Makefile @@ -0,0 +1,60 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include $(TOPCMNDIR)/make.rules + +SNKDIR = $(TOPCMNDIR)/clients/net-snk + +CFLAGS += -fno-builtin -I$(LIBCMNDIR)/libc/include +CFLAGS += -I$(SNKDIR)/include -I. $(CPUARCHDEF) +CFLAGS += -I$(INCLBRDDIR) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) +CFLAGS += -O2 -msoft-float -Wa,-mregnames $(RELEASE) + +OBJS = $(SNKDIR)/kernel/kernel.o +OBJS += $(SNKDIR)/oflib/oflib.o +OBJS += $(SNKDIR)/libc/time/timer.o +OBJS += entry.o main.o of.elf takeover.o +OBJS += $(LIBCMNDIR)/libelf.a $(LIBCMNDIR)/libc.a + +%.o: %.S + $(CC) $(CFLAGS) -c $^ + +all: takeover.elf + +takeover.elf: ppc32wrap.o takeover.elf32 + @echo " ====== Building $@ ======" + $(LD) -N -melf32ppclinux -static -nostdlib \ + -Ttext=0x400000 -Tdata=0x400100 \ + $(LDFLAGS) $^ -o $@ + +takeover.elf64: entry.o main.o takeover.o $(SNKDIR)/libc/time/timer.o of.elf + $(MAKE) -C $(LIBCMNDIR) libc + $(MAKE) -C $(CLIENTSDIR) + $(LD) $(LDFLAGS) -o $@ -Tclient.lds $(OBJS) + +of.elf: ../../boot_rom.bin + $(OBJCOPY) --input-target=binary --binary-architecture=powerpc -O elf64-powerpc $< $@ + +takeover.elf32: takeover.elf64 + $(OBJCOPY) -O binary $^ takeover.tmp + $(OBJCOPY) --input-target=binary --binary-architecture=powerpc -O elf32-powerpc takeover.tmp $@ + +ppc32wrap.o: ppc32wrap.S + $(CROSS)gcc -m32 $(CFLAGS) -c $< -o $@ + +clean distclean: + $(MAKE) -C $(LIBCMNDIR) $@ + $(MAKE) -C $(CLIENTSDIR) $@ + $(RM) *.o *.bin *.elf + $(RM) takeover.elf32 takeover.elf64 takeover.tmp +%.o: %.oco + cp -f $< $@ diff --git a/qemu/roms/SLOF/clients/takeover/client.lds b/qemu/roms/SLOF/clients/takeover/client.lds new file mode 100644 index 000000000..2701d8e1e --- /dev/null +++ b/qemu/roms/SLOF/clients/takeover/client.lds @@ -0,0 +1,60 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_entry) + +SECTIONS { + .client 0x400100: + { + __client_start = .; + *(.start) + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.sfpr .glink) + *(.rodata .rodata.* .gnu.linkonce.r.*) + KEEP (*(.opd)) + . = ALIGN(256); + *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(256); + } =0x60000000 + + .diag_table : + { + _diag_init_start = .; + *(.diag_init) + _diag_init_end = .; + } + .lowmem : + { + _lowmem_start = .; + *(.lowmem) + _lowmem_end = .; + } + + .got : + { + . = ALIGN(8); + _got = .; + *(.got .toc) + _got_end = .; + } + .comment : { *(.comment) } + .branch_lt : { *(.branch_lt) } + .bss : + { + __bssStart = .; + *(*COM* .bss .gnu.linkonce.b.*) + __client_end = .; + __bssSize = . - __bssStart; + } +} diff --git a/qemu/roms/SLOF/clients/takeover/entry.S b/qemu/roms/SLOF/clients/takeover/entry.S new file mode 100644 index 000000000..a1030eb40 --- /dev/null +++ b/qemu/roms/SLOF/clients/takeover/entry.S @@ -0,0 +1,99 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <macros.h> +#include "takeover.h" + + .globl _wrapclient + .section ".start" + .align 3 + +_wrapclient: + bcl 20,31,over # branch after pointer table +base: + .align 3 +.LCgot: .quad _got-base+0x8000 +over: + mflr r8 # gpr 8 is the base + ld r2, .LCgot-base(r8) # load got pointer + add r2, r2, r8 # add base + li 14, 0 + oris 14, 14, __bssSize@h + ori 14, 14, __bssSize@l + addi 14,14,7 + srwi 14,14,3 + mtctr 14 + li 14, 0 + oris 14, 14, __bssStart@h + ori 14, 14, __bssStart@l + subi 14, 14, 8 + li 15, 0 +1: + stdu 15,8(14) + bdnz 1b + + bl ._entry + + + + .globl slaveLoopNoTakeover +slaveLoopNoTakeover: + mr 28,3 + + li 14,0 + oris 14, 14, slaveQuitt@h + ori 14, 14, slaveQuitt@l + + li 3,0 + std 3,0(14) +1: + ld 3,0(14) + cmpld 3,28 + bne 1b + + li 3,0 + std 3,0(14) + + LOAD64(r3, (TAKEOVERBASEADDRESS+0x150)) + mtctr r3 + bctr + + + .globl slaveLoop +slaveLoop: + mr 28,3 + li r3, 0x5124 + li r0, -1; .long 0x44000022 + + li 14,0 + oris 14, 14, slaveQuitt@h + ori 14, 14, slaveQuitt@l + li 3,0 + std 3,0(14) +1: + ld 3,0(14) + cmpld 3,28 + bne 1b + + li 3,0 + std 3,0(14) + + LOAD64(r3, (TAKEOVERBASEADDRESS+0x150)) + mtctr r3 + bctr + + +C_ENTRY(m_sync) + isync + sync + nop + blr diff --git a/qemu/roms/SLOF/clients/takeover/main.c b/qemu/roms/SLOF/clients/takeover/main.c new file mode 100644 index 000000000..360d8eaed --- /dev/null +++ b/qemu/roms/SLOF/clients/takeover/main.c @@ -0,0 +1,163 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <of.h> +#include <pci.h> +#include <cpu.h> +#include <ioctl.h> +#include <takeover.h> + +extern void call_client_interface(of_arg_t *); +extern void m_sync(void); + +int callback(int argc, char *argv[]); + +#define boot_rom_bin_start _binary_______boot_rom_bin_start +#define boot_rom_bin_end _binary_______boot_rom_bin_end + +extern char boot_rom_bin_start; +extern char boot_rom_bin_end; + +#if defined(__GNUC__) +# define UNUSED __attribute__((unused)) +#else +# define UNUSED +#endif + +void * +sbrk(int incr) +{ + return (void *) -1; +} + +static void +doWait(void) +{ + static const char *wheel = "|/-\\"; + static int i = 0; + volatile int dly = 0xf0000; + while (dly--) + asm volatile (" nop "); + printf("\b%c", wheel[i++]); + i &= 0x3; +} + +static void +quiesce(void) +{ + of_arg_t arg = { + p32cast "quiesce", + 0, 0, + }; + call_client_interface(&arg); +} + +static int +startCpu(int num, int addr, int reg) +{ + of_arg_t arg = { + p32cast "start-cpu", + 3, 0, + {num, addr, reg} + }; + call_client_interface(&arg); + return arg.args[3]; +} + +volatile unsigned long slaveQuitt; +int takeoverFlag; + +void +main(int argc, char *argv[]) +{ + phandle_t cpus; + phandle_t cpu; + unsigned long slaveMask; + extern int slaveLoop[]; + extern int slaveLoopNoTakeover[]; + int index = 0; + int delay = 100; + unsigned long reg; + unsigned long msr; + + asm volatile ("mfmsr %0":"=r" (msr)); + if (msr & 0x1000000000000000) + takeoverFlag = 0; + else + takeoverFlag = 1; + + cpus = of_finddevice("/cpus"); + cpu = of_child(cpus); + slaveMask = 0; + while (cpu) { + char devType[100]; + *devType = '\0'; + of_getprop(cpu, "device_type", devType, sizeof(devType)); + if (strcmp(devType, "cpu") == 0) { + of_getprop(cpu, "reg", ®, sizeof(reg)); + if (index) { + printf("\r\n takeover on cpu%d (%x, %lx) ", index, + cpu, reg); + slaveQuitt = -1; + if (takeoverFlag) + startCpu(cpu, (int)(unsigned long)slaveLoop, index); + else + startCpu(cpu, (int)(unsigned long)slaveLoopNoTakeover, + index); + slaveMask |= 0x1 << index; + delay = 100; + while (delay-- && slaveQuitt) + doWait(); + } + index++; + } + cpu = of_peer(cpu); + } + + + printf("\r\n takeover on master cpu "); + quiesce(); + + delay = 5; + while (delay--) + doWait(); + if (takeoverFlag) + takeover(); + + memcpy((void*)TAKEOVERBASEADDRESS, &boot_rom_bin_start, &boot_rom_bin_end - &boot_rom_bin_start); + flush_cache((void *)TAKEOVERBASEADDRESS, &boot_rom_bin_end - &boot_rom_bin_start); + index = 0; + + while (slaveMask) { + m_sync(); + unsigned long shifter = 0x1 << index; + if (shifter & slaveMask) { + slaveQuitt = index; + while (slaveQuitt) + m_sync(); + slaveMask &= ~shifter; + } + index++; + } + + asm volatile(" mtctr %0 ; bctr " : : "r" (TAKEOVERBASEADDRESS+0x180) ); +} + +int +callback(int argc, char *argv[]) +{ + /* Dummy, only for takeover */ + return (0); +} diff --git a/qemu/roms/SLOF/clients/takeover/ppc32wrap.S b/qemu/roms/SLOF/clients/takeover/ppc32wrap.S new file mode 100644 index 000000000..90afa268d --- /dev/null +++ b/qemu/roms/SLOF/clients/takeover/ppc32wrap.S @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + .globl _start + .section ".text" + .align 3 + +_start: + nop + bl over + .llong 0x9000000000003000 +over: + li 14, 0 + oris 14, 14, _binary_takeover_tmp_start@h + ori 14, 14, _binary_takeover_tmp_start@l + mtsrr0 14 + mflr 15 + ld 14,0(15) + mtsrr1 14 + rfid + diff --git a/qemu/roms/SLOF/clients/takeover/takeover.h b/qemu/roms/SLOF/clients/takeover/takeover.h new file mode 100644 index 000000000..f348e2359 --- /dev/null +++ b/qemu/roms/SLOF/clients/takeover/takeover.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#if defined(CPU_CBEA) +#define TAKEOVERBASEADDRESS 0x0e000000 +#elif defined(CPU_PPC970) +#define TAKEOVERBASEADDRESS 0x00000000 +#else +#error no processor specified +#endif + +#ifndef __ASSEMBLER__ +int takeover(void); +#endif diff --git a/qemu/roms/SLOF/clients/takeover/takeover.oco b/qemu/roms/SLOF/clients/takeover/takeover.oco Binary files differnew file mode 100644 index 000000000..6e2a1a6ab --- /dev/null +++ b/qemu/roms/SLOF/clients/takeover/takeover.oco diff --git a/qemu/roms/SLOF/include/allocator.h b/qemu/roms/SLOF/include/allocator.h new file mode 100644 index 000000000..0f75fce35 --- /dev/null +++ b/qemu/roms/SLOF/include/allocator.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2007, 2012, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +extern void SLOF_bm_print(unsigned long handle); +extern unsigned long SLOF_bm_allocator_init(unsigned long start, + unsigned long size, + unsigned long blocksize); +extern unsigned long SLOF_bm_alloc(unsigned long handle, unsigned long size); +extern void SLOF_bm_free(unsigned long handle, unsigned long ptr, unsigned long size); + +#endif /* _ALLOCATOR_H */ diff --git a/qemu/roms/SLOF/include/byteorder.h b/qemu/roms/SLOF/include/byteorder.h new file mode 100644 index 000000000..60ca67267 --- /dev/null +++ b/qemu/roms/SLOF/include/byteorder.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * Common byteorder (endianness) macros + */ + +#ifndef BYTEORDER_H +#define BYTEORDER_H + +#include <stdint.h> + +static inline uint16_t +bswap_16 (uint16_t x) +{ + return __builtin_bswap16(x); +} + +static inline uint32_t +bswap_32 (uint32_t x) +{ + return __builtin_bswap32(x); +} + +static inline uint64_t +bswap_64 (uint64_t x) +{ + return __builtin_bswap64(x); +} + +static inline void +bswap_16p (uint16_t *x) +{ + *x = __builtin_bswap16(*x); +} + +static inline void +bswap_32p (uint32_t *x) +{ + *x = __builtin_bswap32(*x); +} + +static inline void +bswap_64p (uint64_t *x) +{ + *x = __builtin_bswap64(*x); +} + + +/* gcc defines __BIG_ENDIAN__ on big endian targets */ +#ifdef __BIG_ENDIAN__ + +#define cpu_to_be16(x) (x) +#define cpu_to_be32(x) (x) +#define cpu_to_be64(x) (x) + +#define be16_to_cpu(x) (x) +#define be32_to_cpu(x) (x) +#define be64_to_cpu(x) (x) + +#define le16_to_cpu(x) bswap_16(x) +#define le32_to_cpu(x) bswap_32(x) +#define le64_to_cpu(x) bswap_64(x) + +#define cpu_to_le16(x) bswap_16(x) +#define cpu_to_le32(x) bswap_32(x) +#define cpu_to_le64(x) bswap_64(x) + +#else + +#define cpu_to_be16(x) bswap_16(x) +#define cpu_to_be32(x) bswap_32(x) +#define cpu_to_be64(x) bswap_64(x) + +#define be16_to_cpu(x) bswap_16(x) +#define be32_to_cpu(x) bswap_32(x) +#define be64_to_cpu(x) bswap_64(x) + +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) + +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) + +#endif /* __BIG_ENDIAN__ */ + +#endif /* BYTEORDER_H */ diff --git a/qemu/roms/SLOF/include/calculatecrc.h b/qemu/roms/SLOF/include/calculatecrc.h new file mode 100644 index 000000000..216847813 --- /dev/null +++ b/qemu/roms/SLOF/include/calculatecrc.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef CALCULATECRC_H +#define CALCULATECRC_H + + #define FLASHFS_DATADDR 0x18 // uint64_t position of pointer to data + #define FLASHFS_FILE_SIZE_ADDR 0x08 // uint64_t pos of total flashimage size value relative to data + #define FLASHFS_HEADER_SIZE_ADDR 0x08 // uint64_t position of total flash header size value + + #ifdef __ASSEMBLER__ + // "CRC_GENERATOR" must contain equal inforamtion as "CRC_METHODE" + #define CRC_GENERATOR 0x0000000004C11DB7 + #define CRC_REGISTERMASK 0x00000000FFFFFFFF + #define CRC_REGISTERLENGTH 32 + #endif /* __ASSEMBLER__ */ + + #ifndef __ASSEMBLER__ + #define FLASHFS_ROMADDR 0x00 // uint64_t position of pointer to next file + #define FLASHFS_HEADER_DATA_SIZE 0x68 // 104 bytes of total header data size + #define CRC_METHODE Ethernet_32 // define the CRc genarator (CRC 16 bit to 64 is supported) + + //--- header format --------------------------------- + struct stH { + char magic[8]; // (generic!) headerfile + uint64_t flashlen; // dyn + char version[16]; // $DRIVER_INFO alignment! + char platform_name[32]; // (hardware) headerfile + char date[6]; // dyn (format -> JB) + char padding1[2]; // padding byte + char mdate[6]; // modify date + char padding2[2]; // padding byte + char platform_revision[4];// (hardware) headerfile + uint32_t padding; + uint64_t ui64CRC; // insert calculated CRC here + uint64_t ui64FileEnd; // = 0xFFFF FFFF FFFF FFFF + }; + #endif /* __ASSEMBLER__ */ + +#endif /* CALCULATECRC_H */ + +/*--- supported CRC Generators ------------------------- ++ Name length usage Generator ++ Tap_16 16 bit Tape 0x00008005 ++ Floppy_16 16 bit Floppy 0x00001021 ++ Ethernet_32 32 bit Ethernet 0x04C11DB7 ++ SPTrEMBL_64 64 bit white noise like date 0x0000001B ++ SPTrEMBL_improved_64 64 bit DNA code like date 0xAD93D23594C9362D ++ DLT1_64 64 bit Tape 0x42F0E1EBA9EA3693 ++ ++ CRC_REGISTERLENGTH = bit length ++ CRC_REGISTERMASK = -1 for a n-bit numer where n = bit length ++ example TAP_16: CRC_REGSISTERLENGTH = 16 ++ CRC_REGISTERMASK = 0xFFFFFFFF = (-1 if 16 bit number is used) ++ ++ TrEMBL see also http://www.cs.ud.ac.uk/staff/D.Jones/crcbote.pdf ++ DLT1 se also http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf ++--------------------------------------------------------*/ diff --git a/qemu/roms/SLOF/include/helpers.h b/qemu/roms/SLOF/include/helpers.h new file mode 100644 index 000000000..fb105345e --- /dev/null +++ b/qemu/roms/SLOF/include/helpers.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) 2007, 2012, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * USB SLOF Prototypes + */ + +#ifndef _USB_SLOF_H +#define _USB_SLOF_H + +#include <stdint.h> + +extern uint32_t SLOF_GetTimer(void); +extern void SLOF_msleep(uint32_t time); +extern void SLOF_usleep(uint32_t time); +extern void *SLOF_dma_alloc(long size); +extern void SLOF_dma_free(void *virt, long size); +extern void *SLOF_alloc_mem(long size); +extern void *SLOF_alloc_mem_aligned(long size, long align); +extern void SLOF_free_mem(void *addr, long size); +extern long SLOF_dma_map_in(void *virt, long size, int cacheable); +extern void SLOF_dma_map_out(long phys, void *virt, long size); +extern long SLOF_pci_config_read32(long offset); +extern long SLOF_pci_config_read16(long offset); +extern void SLOF_pci_config_write32(long offset, long value); +extern void SLOF_pci_config_write16(long offset, long value); +extern void *SLOF_translate_my_address(void *addr); + +#define offset_of(type, member) ((long) &((type *)0)->member) +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member)* struct_ptr = (ptr); \ + (type *)((char *)struct_ptr - offset_of(type, member)); }) + +#endif diff --git a/qemu/roms/SLOF/include/libelf.h b/qemu/roms/SLOF/include/libelf.h new file mode 100644 index 000000000..5fbf27927 --- /dev/null +++ b/qemu/roms/SLOF/include/libelf.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * ELF loader library + */ + +#ifndef __LIBELF_H +#define __LIBELF_H + +#include <stdint.h> + +/* ELF object file types */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ + +/* ELF object endian */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +/* Generic ELF header */ +struct ehdr { + uint32_t ei_ident; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_pad[9]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; +}; + +/* Section types (sh_type) */ +#define SHT_NULL 0 /* Unused section header */ +#define SHT_PROGBITS 1 /* Information defined by the program */ +#define SHT_SYMTAB 2 /* Linker symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* "Rela" type relocation entries */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking tables */ +#define SHT_NOTE 7 /* Note information */ +#define SHT_NOBITS 8 /* Uninitialized space */ +#define SHT_REL 9 /* "Rel" type relocation entries */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic loader symbol table */ + +/* Section attributs (sh_flags) */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 + +/* Segment types (p_type) */ +#define PT_NULL 0 /* Unused entry */ +#define PT_LOAD 1 /* Loadable segment */ +#define PT_DYNAMIC 2 /* Dynamic linking tables */ +#define PT_INTERP 3 /* Program interpreter path name */ +#define PT_NOTE 4 /* Note sections */ + + +int elf_load_file(void *file_addr, unsigned long *entry, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)); +int elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)); + +void elf_byteswap_header32(void *file_addr); +void elf_byteswap_header64(void *file_addr); + +unsigned int elf_load_segments32(void *file_addr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)); +unsigned long elf_load_segments64(void *file_addr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)); + +long elf_get_base_addr(void *file_addr); +long elf_get_base_addr32(void *file_addr); +long elf_get_base_addr64(void *file_addr); +uint32_t elf_get_eflags_32(void *file_addr); +uint32_t elf_get_eflags_64(void *file_addr); + +void elf_relocate64(void *file_addr, signed long offset); + +int elf_forth_claim(void *addr, long size); + +#endif /* __LIBELF_H */ diff --git a/qemu/roms/SLOF/include/macros.h b/qemu/roms/SLOF/include/macros.h new file mode 100644 index 000000000..f519bb8a7 --- /dev/null +++ b/qemu/roms/SLOF/include/macros.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#define LOAD64(rn,name) \ + lis rn,name##@highest; \ + ori rn,rn,name##@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name##@h; \ + ori rn,rn,name##@l + +#define LOAD32(rn, name) \ + lis rn,name##@h; \ + ori rn,rn,name##@l + +// load 32 bit constant in little endian order +#define LOAD32le(rn,name) \ + lis rn,(((name>>8)&0x00FF)|((name<<8)&0xFF00)); \ + ori rn,rn,(((name>>24)&0x00FF)|((name>>8)&0xFF00)) + +// load 16 bit constant in little endian order +#define LOAD16le(rn,name) \ + li rn,(((name>>8)&0x00FF)|((name<<8)&0xFF00)) + +#define ENTRY(func_name) \ + .text; \ + .align 2; \ + .globl .func_name; \ + .func_name: \ + .globl func_name; \ + func_name: + +#define C_ENTRY(func_name) \ + .section ".text"; \ + .align 2; \ + .globl func_name; \ + .section ".opd","aw"; \ + .align 3; \ + func_name: \ + .quad .func_name,.TOC.@tocbase,0; \ + .previous; \ + .size func_name,24; \ + .type .func_name,@function; \ + .globl .func_name; \ + .func_name: + +#define ASM_ENTRY(fn) \ + .globl fn; \ +fn: + diff --git a/qemu/roms/SLOF/include/memmap.h b/qemu/roms/SLOF/include/memmap.h new file mode 100644 index 000000000..abf3c1f03 --- /dev/null +++ b/qemu/roms/SLOF/include/memmap.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef MEMMAP_H +#define MEMMAP_H + +#define MEG 0x100000 + +#define SLAVELOOP_LOADBASE 0x0000000000003f00 +#define STAGE2_LOADBASE (60 * MEG) +#define OF_LOADBASE 0x000000000000a000 + +#define MEM_HALF (512 * MEG) + +/* BE Engines Offsets */ +#define BE_MIC_BASE 0x50A000 + +#endif diff --git a/qemu/roms/SLOF/include/netdriver.h b/qemu/roms/SLOF/include/netdriver.h new file mode 100644 index 000000000..d81134eac --- /dev/null +++ b/qemu/roms/SLOF/include/netdriver.h @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + ******************************************************************************/ + +#ifndef _NETDRIVER_H +#define _NETDRIVER_H + +#include <stdint.h> + +typedef struct net_driver { + uint8_t mac_addr[6]; + uint32_t reg; + int running; +} net_driver_t; + +#endif diff --git a/qemu/roms/SLOF/include/pcd.h b/qemu/roms/SLOF/include/pcd.h new file mode 100644 index 000000000..9794b767f --- /dev/null +++ b/qemu/roms/SLOF/include/pcd.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef PCD_H +#define PCD_H + +#define PCD_START_ADDR 0xFF00000 // FIXME: this should not interfere with + // other parts of the firmware +#define PCD_HDR_SIZE (6 * 8) /* only use for ctrl file */ + +/* PCD File Definition ****************************************/ +/* File = "p:ctrl" 0x703a6374726c0000 */ +/* Data : */ +/* [00:07] - pointer to header of last file which was created */ +/* [08:0f] - pointer to header of next file for creation */ +/**************************************************************/ +#define PCDF_CTRL_LAST 0 +#define PCDF_CTRL_NEXT 8 + +/* PCD File Definition ****************************************/ +/* File = "p:pXmem" */ +/* Data : */ +/* [00:07] - number of memory segments */ +/* [08:0f] - real base of memory segment #n */ +/* [10:17] - real size of memory segment #n */ +/* [18:1f] - real base of memory segment #n+1 */ +/* [20:27] - real size of memory segment #n+1 */ +/* ... and so on.. */ +/**************************************************************/ +#define PCDF_MEM_NUM 0 +#define PCDF_MEMN_BASE(N) (8 + ((N) * 16)) +#define PCDF_MEMN_SIZE(M) (PCDF_MEMN_BASE(M) + 8) + +/* PCD File Definition ****************************************/ +/* File = "p:pXcfg" */ +/* Data : */ +/* [00:07] - number of memory segments */ +/* [08:0f] - real base of memory segment #n */ +/* [10:17] - real size of memory segment #n */ +/* [18:1f] - real base of memory segment #n+1 */ +/* [20:27] - real size of memory segment #n+1 */ +/* ... and so on.. */ +/**************************************************************/ +#define PCDF_PCFG_IOCBASE (0 * 8) +#define PCDF_PCFG_BPBASE (1 * 8) +#define PCDF_PCFG_SPUMAP (2 * 8) +#define PCDF_PCFG_TIMEBASE (3 * 8) +#define PCDF_PCFG_CPUFREQ (4 * 8) + +#endif diff --git a/qemu/roms/SLOF/include/ppc970/cache.h b/qemu/roms/SLOF/include/ppc970/cache.h new file mode 100644 index 000000000..b74868986 --- /dev/null +++ b/qemu/roms/SLOF/include/ppc970/cache.h @@ -0,0 +1,86 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __CACHE_H +#define __CACHE_H + +#include <cpu.h> +#include <stdint.h> + +#define cache_inhibited_access(type,name) \ + static inline type ci_read_##name(type * addr) \ + { \ + type val; \ + set_ci(); \ + val = *addr; \ + clr_ci(); \ + return val; \ + } \ + static inline void ci_write_##name(type * addr, type data) \ + { \ + set_ci(); \ + *addr = data; \ + clr_ci(); \ + } + +cache_inhibited_access(uint8_t, 8) +cache_inhibited_access(uint16_t, 16) +cache_inhibited_access(uint32_t, 32) +cache_inhibited_access(uint64_t, 64) + +#define _FWOVERLAP(s, d, size) ((d >= s) && ((type_u)d < ((type_u)s + size))) + +// 3.1 +#define _FWMOVE(s, d, size, t) \ + { t *s1=(t *)s, *d1=(t *)d; \ + while (size > 0) { *d1++ = *s1++; size -= sizeof(t); } } + +#define _BWMOVE(s, d, size, t) { \ + t *s1=(t *)((char *)s+size), *d1=(t *)((char *)d+size); \ + while (size > 0) { *--d1 = *--s1; size -= sizeof(t); } \ +} + + +#define _MOVE(s, d, size, t) if _FWOVERLAP(s, d, size) _BWMOVE(s, d, size, t) else _FWMOVE(s, d, size, t) + +#define _FASTMOVE(s, d, size) \ + switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \ + case 0: _MOVE(s, d, size, type_u); break; \ + case sizeof(type_l): _MOVE(s, d, size, type_l); break; \ + case sizeof(type_w): _MOVE(s, d, size, type_w); break; \ + default: _MOVE(s, d, size, type_c); break; \ + } + +// Device IO block data helpers +#define _FWRMOVE(s, d, size, t) \ + { t *s1=(t *)s, *d1=(t *)d; SET_CI; \ + while (size > 0) { *d1++ = *s1++; size -= sizeof(t); } \ + CLR_CI; \ +} + +#define _BWRMOVE(s, d, size, t) { \ + t *s1=(t *)((char *)s+size), *d1=(t *)((char *)d+size); SET_CI; \ + while (size > 0) { *--d1 = *--s1; size -= sizeof(t); } \ + CLR_CI; \ +} + +#define _RMOVE(s, d, size, t) if _FWOVERLAP(s, d, size) _BWRMOVE(s, d, size, t) else _FWRMOVE(s, d, size, t) + +#define _FASTRMOVE(s, d, size) \ + switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \ + case 0: _RMOVE(s, d, size, type_u); break; \ + case sizeof(type_l): _RMOVE(s, d, size, type_l); break; \ + case sizeof(type_w): _RMOVE(s, d, size, type_w); break; \ + default: _RMOVE(s, d, size, type_c); break; \ + } + +#endif diff --git a/qemu/roms/SLOF/include/ppc970/cpu.h b/qemu/roms/SLOF/include/ppc970/cpu.h new file mode 100644 index 000000000..0e66dff36 --- /dev/null +++ b/qemu/roms/SLOF/include/ppc970/cpu.h @@ -0,0 +1,113 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __PPC970_H +#define __PPC970_H + +/* SPRs numbers */ + +#define CTRL_RD 136 +#define CTRL_WR 152 +#define PVR 287 +#define HSPRG0 304 +#define HSPRG1 305 +#define HIOR 311 +#define HID0 1008 +#define HID1 1009 +#define HID4 1012 +#define HID6 1017 +#define PIR 1023 + +#define SETCI(r) sync; \ + mfspr r, HID4; \ + sync; \ + rldicl r, r, 32,0; \ + ori r, r, 0x0100; \ + rldicl r, r, 32,0; \ + sync; \ + slbia; \ + mtspr HID4, r; \ + isync; \ + eieio; + +#define CLRCI(r) sync; \ + mfspr r, HID4; \ + sync; \ + rldicl r, r, 32, 0; \ + ori r, r, 0x0100; \ + xori r, r, 0x0100; \ + rldicl r, r, 32, 0; \ + sync; \ + slbia; \ + mtspr HID4, r; \ + isync; \ + eieio; + +/* This macro uses r0 */ +#define FLUSH_CACHE(r, n) add n, n, r; \ + addi n, n, 127; \ + rlwinm r, r, 0,0,24; \ + rlwinm n, n, 0,0,24; \ + sub n, n, r; \ + srwi n, n, 7; \ + mtctr n; \ + 0: dcbst 0, r; \ + sync; \ + icbi 0, r; \ + sync; \ + isync; \ + addi r, r, 128; \ + bdnz 0b; + +#ifndef __ASSEMBLER__ +#define STRINGIFY(x...) #x +#define EXPAND(x) STRINGIFY(x) + +static inline void +set_ci(void) +{ + unsigned long tmp; + asm volatile(EXPAND(SETCI(%0)) : "=r"(tmp) :: "memory", "cc"); +} + +static inline void +clr_ci(void) +{ + unsigned long tmp; + asm volatile(EXPAND(CLRCI(%0)) : "=r"(tmp) :: "memory", "cc"); +} + +static inline void eieio(void) +{ + asm volatile ("eieio":::"memory"); +} + +static inline void barrier(void) +{ + asm volatile("" : : : "memory"); +} +#define cpu_relax() barrier() + +static inline void sync(void) +{ + asm volatile ("sync" ::: "memory"); +} +#define mb() sync() + +static inline void flush_cache(void* r, long n) +{ + asm volatile(EXPAND(FLUSH_CACHE(%0, %1)) : "+r"(r), "+r"(n) :: "memory", "cc", "r0", "ctr"); +} + +#endif /* __ASSEMBLER__ */ + +#endif diff --git a/qemu/roms/SLOF/include/ppcp7/cache.h b/qemu/roms/SLOF/include/ppcp7/cache.h new file mode 100644 index 000000000..dc6837196 --- /dev/null +++ b/qemu/roms/SLOF/include/ppcp7/cache.h @@ -0,0 +1,150 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __CACHE_H +#define __CACHE_H + +#include <cpu.h> +#include <stdint.h> + +// XXX FIXME: Use proper CI load/store */ +#define cache_inhibited_access(type,size) \ + static inline type ci_read_##size(type * addr) \ + { \ + register uint64_t arg0 asm ("r3"); \ + register uint64_t arg1 asm ("r4"); \ + register uint64_t arg2 asm ("r5"); \ + \ + arg0 = 0x3c; /* H_LOGICAL_CI_LOAD*/ \ + arg1 = size / 8; \ + arg2 = (uint64_t)addr; \ + \ + asm volatile( \ + ".long 0x44000022 \n" /* HVCALL */ \ + : "=&r" (arg0), "=&r"(arg1), "=&r"(arg2) \ + : "0"(arg0), "1"(arg1), "2"(arg2) \ + : "r0", "r6", "r7", "r8", "r9", "r10", "r11", \ + "r12", "memory", "cr0", "cr1", "cr5", \ + "cr6", "cr7", "ctr", "xer"); \ + return arg0 ? (type)-1 : arg1; \ + } \ + static inline void ci_write_##size(type * addr, type data) \ + { \ + register uint64_t arg0 asm ("r3"); \ + register uint64_t arg1 asm ("r4"); \ + register uint64_t arg2 asm ("r5"); \ + register uint64_t arg3 asm ("r6"); \ + \ + arg0 = 0x40; /* H_LOGICAL_CI_STORE*/ \ + arg1 = size / 8; \ + arg2 = (uint64_t)addr; \ + arg3 = (uint64_t)data; \ + \ + asm volatile( \ + ".long 0x44000022 \n" /* HVCALL */ \ + : "=&r"(arg0),"=&r"(arg1),"=&r"(arg2),"=&r"(arg3) \ + : "0"(arg0),"1"(arg1),"2"(arg2),"3"(arg3) \ + : "r0", "r7", "r8", "r9", "r10", "r11", \ + "r12", "memory", "cr0", "cr1", "cr5", \ + "cr6", "cr7", "ctr", "xer"); \ + } + +cache_inhibited_access(uint8_t, 8) +cache_inhibited_access(uint16_t, 16) +cache_inhibited_access(uint32_t, 32) +cache_inhibited_access(uint64_t, 64) + +#define _FWOVERLAP(s, d, size) ((d >= s) && ((type_u)d < ((type_u)s + size))) + +// 3.1 +#define _FWMOVE(s, d, size, t) \ + { t *s1=(t *)s, *d1=(t *)d; \ + while (size > 0) { *d1++ = *s1++; size -= sizeof(t); } } + +#define _BWMOVE(s, d, size, t) { \ + t *s1=(t *)((char *)s+size), *d1=(t *)((char *)d+size); \ + while (size > 0) { *--d1 = *--s1; size -= sizeof(t); } \ +} + + +#define _MOVE(s, d, size, t) if _FWOVERLAP(s, d, size) _BWMOVE(s, d, size, t) else _FWMOVE(s, d, size, t) + +#define _FASTMOVE(s, d, size) \ + switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) { \ + case 0: _MOVE(s, d, size, type_u); break; \ + case sizeof(type_l): _MOVE(s, d, size, type_l); break; \ + case sizeof(type_w): _MOVE(s, d, size, type_w); break; \ + default: _MOVE(s, d, size, type_c); break; \ + } + +static inline void ci_rmove(void *dst, void *src, unsigned long esize, + unsigned long count) +{ + register uint64_t arg0 asm ("r3"); + register uint64_t arg1 asm ("r4"); + register uint64_t arg2 asm ("r5"); + register uint64_t arg3 asm ("r6"); + register uint64_t arg4 asm ("r7"); + register uint64_t arg5 asm ("r8"); + + arg0 = 0xf001; /* KVMPPC_H_LOGICAL_MEMOP */ + arg1 = (uint64_t)dst; + arg2 = (uint64_t)src; + arg3 = esize; + arg4 = count; + arg5 = 0; /* 0 = copy */ + + asm volatile(".long 0x44000022 \n" /* HVCALL */ + : "=&r"(arg0),"=&r"(arg1),"=&r"(arg2), + "=&r"(arg3),"=&r"(arg4),"=&r"(arg5) + : "0"(arg0),"1"(arg1),"2"(arg2), + "3"(arg3),"4"(arg4),"5"(arg5) + : "r0", "r9", "r10", "r11", + "r12", "memory", "cr0", "cr1", "cr5", + "cr6", "cr7", "ctr", "xer"); +} + +#define _FASTRMOVE(s, d, size) do { \ + switch (((type_u)s | (type_u)d | size) & (sizeof(type_u)-1)) {\ + case 0: ci_rmove(d,s,3,size>>3); break; \ + case sizeof(type_l): ci_rmove(d,s,2,size>>2); break; \ + case sizeof(type_w): ci_rmove(d,s,1,size>>1); break; \ + default: ci_rmove(d,s,0,size); break; \ + } \ + } while(0) + +static inline uint16_t bswap16_load(uint64_t addr) +{ + unsigned int val; + asm volatile ("lhbrx %0, 0, %1":"=r" (val):"r"(addr)); + return val; +} + +static inline uint32_t bswap32_load(uint64_t addr) +{ + unsigned int val; + asm volatile ("lwbrx %0, 0, %1":"=r" (val):"r"(addr)); + return val; +} + +static inline void bswap16_store(uint64_t addr, uint16_t val) +{ + asm volatile ("sthbrx %0, 0, %1"::"r" (val), "r"(addr)); +} + +static inline void bswap32_store(uint64_t addr, uint32_t val) +{ + asm volatile ("stwbrx %0, 0, %1"::"r" (val), "r"(addr)); +} + +#endif /* __CACHE_H */ + diff --git a/qemu/roms/SLOF/include/ppcp7/cpu.h b/qemu/roms/SLOF/include/ppcp7/cpu.h new file mode 100644 index 000000000..1b1fadd82 --- /dev/null +++ b/qemu/roms/SLOF/include/ppcp7/cpu.h @@ -0,0 +1,66 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __CPU_H +#define __CPU_H + +/* Used in boot_abort.S, will need something better for KVM */ +#define HSPRG0 304 + +/* XXX FIXME: Can be more efficient, no dcbst nor loop needed on P7 */ +/* This macro uses r0 */ +#define FLUSH_CACHE(r, n) add n, n, r; \ + addi n, n, 127; \ + rlwinm r, r, 0,0,24; \ + rlwinm n, n, 0,0,24; \ + sub n, n, r; \ + srwi n, n, 7; \ + mtctr n; \ + 0: dcbst 0, r; \ + sync; \ + icbi 0, r; \ + sync; \ + isync; \ + addi r, r, 128; \ + bdnz 0b; + +#ifndef __ASSEMBLER__ +#define STRINGIFY(x...) #x +#define EXPAND(x) STRINGIFY(x) + +static inline void flush_cache(void* r, long n) +{ + asm volatile(EXPAND(FLUSH_CACHE(%0, %1)) + : "+r"(r), "+r"(n) + :: "memory", "cc", "r0", "ctr"); +} + +static inline void eieio(void) +{ + asm volatile ("eieio":::"memory"); +} + +static inline void barrier(void) +{ + asm volatile("" : : : "memory"); +} +#define cpu_relax() barrier() + +static inline void sync(void) +{ + asm volatile ("sync" ::: "memory"); +} +#define mb() sync() + +#endif /* __ASSEMBLER__ */ + +#endif diff --git a/qemu/roms/SLOF/include/romfs.h b/qemu/roms/SLOF/include/romfs.h new file mode 100644 index 000000000..7228502c9 --- /dev/null +++ b/qemu/roms/SLOF/include/romfs.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef ROMFS_H +#define ROMFS_H + +#define RFS_T_SIZE 0x00 +#define RFS_T_FLAGS 0x08 +#define RFS_T_FILEADDR 0x10 +#define RFS_T_NEXT 0x18 +#define RFS_T_NAME 0x20 +#define RFS_T_DATA 0x28 + +#define RFS_H_NEXT 0x00 +#define RFS_H_SIZE 0x08 +#define RFS_H_FLAGS 0x10 +#define RFS_H_DATA 0x18 +#define RFS_H_NAME 0x20 + +#define ROMFS_HDR_NEXT (0 * 8) +#define ROMFS_HDR_LEN (1 * 8) +#define ROMFS_HDR_FLAG (2 * 8) +#define ROMFS_HDR_DPTR (3 * 8) +#define ROMFS_HDR_NAME (4 * 8) + +#ifndef __ASSEMBLER__ +/* no not change except if you change romfs.S */ +struct romfs_t { + unsigned long size; + unsigned long flags; + unsigned long fileaddr; + unsigned long nexfile; + unsigned char *namep; + unsigned char *datap; +}; + +struct romfs_lookup_t { + unsigned long addr_header; + unsigned long addr_data; + unsigned long size_data; + unsigned long flags; +}; + +int romfs_stat(char *filename, struct romfs_t *hnd); + +int romfs_stat_file(char *filename, struct romfs_t *hnd); + +int c_romfs_lookup(char *filename, unsigned long rombase, + struct romfs_lookup_t *ret); + +#endif /* __ASSEMBLER__ */ +#endif /* ROMFS_H */ diff --git a/qemu/roms/SLOF/include/rtas.h b/qemu/roms/SLOF/include/rtas.h new file mode 100644 index 000000000..e44dedb1e --- /dev/null +++ b/qemu/roms/SLOF/include/rtas.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __RTAS_H +#define __RTAS_H + +#ifndef __ASSEMBLER__ + +#include <stddef.h> + +typedef int rtas_arg_t; +typedef struct { + int token; + int nargs; + int nret; + rtas_arg_t args[16]; +} rtas_args_t; + +#else + +#define RTAS_STACKSIZE 0x1000 + +#define RTAS_PARM_0 0x0c +#define RTAS_PARM_1 0x10 +#define RTAS_PARM_2 0x14 +#define RTAS_PARM_3 0x18 +#define RTAS_PARM_4 0x1C +#define RTAS_PARM_5 0x20 +#define RTAS_PARM_6 0x24 +#define RTAS_PARM_7 0x28 + +#endif /* __ASSEMBLER__ */ +#endif /* __RTAS_H */ diff --git a/qemu/roms/SLOF/include/rtas_table.h b/qemu/roms/SLOF/include/rtas_table.h new file mode 100644 index 000000000..cdf9db7cd --- /dev/null +++ b/qemu/roms/SLOF/include/rtas_table.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __RTAS_TABLE_H +#define __RTAS_TABLE_H + + +typedef struct { + char *name; + void (*func)(rtas_args_t *args); + unsigned long flags; +} rtas_funcdescr_t; + + +// Flags for the RTAS table: +#define RTAS_TBLFLG_INTERNAL 1 + + +extern const rtas_funcdescr_t rtas_func_tab[]; +extern const int rtas_func_tab_size; + + +#endif // __RTAS_TABLE_H diff --git a/qemu/roms/SLOF/include/termctrl.h b/qemu/roms/SLOF/include/termctrl.h new file mode 100644 index 000000000..502ecae4c --- /dev/null +++ b/qemu/roms/SLOF/include/termctrl.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef TERMCTRL_H +#define TERMCTRL_H + +/* foreground colors */ +#define TERM_FG_BLACK "[30m" +#define TERM_FG_RED "[31m" +#define TERM_FG_GREEN "[32m" +#define TERM_FG_YELLOW "[33m" +#define TERM_FG_BLUE "[34m" +#define TERM_FG_MAGENTA "[35m" +#define TERM_FG_CYAN "[36m" +#define TERM_FG_WHITE "[37m" + +/* background colors */ +#define TERM_BG_BLACK "[40m" +#define TERM_BG_RED "[41m" +#define TERM_BG_GREEN "[42m" +#define TERM_BG_YELLOW "[43m" +#define TERM_BG_BLUE "[44m" +#define TERM_BG_MAGENTA "[45m" +#define TERM_BG_CYAN "[46m" +#define TERM_BG_WHITE "[47m" + +/* control */ +#define TERM_CTRL_RESET "[0m" +#define TERM_CTRL_BRIGHT "[1m" +#define TERM_CTRL_DIM "[2m" +#define TERM_CTRL_UNDERSCORE "[3m" +#define TERM_CTRL_BLINK "[4m" +#define TERM_CTRL_REVERSE "[5m" +#define TERM_CTRL_HIDDEN "[6m" +#define TERM_CTRL_CLEAR "[2J" +#define TERM_CTRL_HOME "[H" + +#define TERM_CTRL_1UP "[1A" +#define TERM_CTRL_1BACK "[1D" +#define TERM_CTRL_SAVECRS "[s" +#define TERM_CTRL_RESTCRS "[u" +#define TERM_CTRL_CRSON "[?25h" +#define TERM_CTRL_CRSOFF "[?25l" +#define TERM_CTRL_CRSFWDN "[%dC" +#define TERM_CTRL_CRSX "[%dC" +#define TERM_CTRL_CRSY "[%dB" +#define TERM_CTRL_CRSXY "[%d;%dH" /* y,x */ + +/* keys */ +#define KEY_CTRL 0x1b +#define KEY_UP 0x41 +#define KEY_DN 0x42 + +#endif diff --git a/qemu/roms/SLOF/include/xvect.h b/qemu/roms/SLOF/include/xvect.h new file mode 100644 index 000000000..5926b1869 --- /dev/null +++ b/qemu/roms/SLOF/include/xvect.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __XVECT_H +#define __XVECT_H + +#define XVECT_M_HANDLER 0x2ff0 /* Master Handler */ +#define XVECT_S_HANDLER 0x2ff8 /* Slave Handler */ +#define XVECT_TOPADDR 0x3fff +#define XVECT_SLP_ENTRY SLAVELOOP_LOADBASE + +#endif diff --git a/qemu/roms/SLOF/lib/Makefile b/qemu/roms/SLOF/lib/Makefile new file mode 100644 index 000000000..ed8a3597e --- /dev/null +++ b/qemu/roms/SLOF/lib/Makefile @@ -0,0 +1,35 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \ + libusb libveth libe1k libbcm + +all: subdirs + +.PHONY : subdirs $(SUBDIRS) clean distclean + + +subdirs: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ $(MAKEARG) + +# Rules for making clean: +clean: + @for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir clean || exit 1; \ + done + +distclean: + @for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir distclean || exit 1; \ + done diff --git a/qemu/roms/SLOF/lib/libbases/Makefile b/qemu/roms/SLOF/lib/libbases/Makefile new file mode 100644 index 000000000..add4ed18c --- /dev/null +++ b/qemu/roms/SLOF/lib/libbases/Makefile @@ -0,0 +1,40 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) -I. -I../../include +LDFLAGS = -nostdlib + +all: + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + + +# Include dependency file if available: +-include Makefile.dep + diff --git a/qemu/roms/SLOF/lib/libbases/libbases.code b/qemu/roms/SLOF/lib/libbases/libbases.code new file mode 100644 index 000000000..128b94ab2 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbases/libbases.code @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <southbridge.h> +#include <nvram.h> + +// : get-nvram-base ( -- base ) +PRIM(get_X2d_nvram_X2d_base) + PUSH; + TOS.u = SB_NVRAM_adr; +MIRP + +// : get-nvram-size ( -- size ) +PRIM(get_X2d_nvram_X2d_size) + PUSH; + TOS.u = get_nvram_size(); +MIRP + +// : get-flash-base ( -- base ) +PRIM(get_X2d_flash_X2d_base) + PUSH; + TOS.u = SB_FLASH_adr; +MIRP + +// : get-flash-size ( -- size ) +PRIM(get_X2d_flash_X2d_size) + PUSH; + TOS.u = FLASH_LENGTH; +MIRP + +// : get-mbx-base ( -- base ) +PRIM(get_X2d_mbx_X2d_base) + PUSH; + TOS.u = SB_MAILBOX_adr; +MIRP diff --git a/qemu/roms/SLOF/lib/libbases/libbases.in b/qemu/roms/SLOF/lib/libbases/libbases.in new file mode 100644 index 000000000..844a55de1 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbases/libbases.in @@ -0,0 +1,17 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +cod(get-nvram-base) +cod(get-nvram-size) +cod(get-flash-base) +cod(get-flash-size) +cod(get-mbx-base) diff --git a/qemu/roms/SLOF/lib/libbcm/Makefile b/qemu/roms/SLOF/lib/libbcm/Makefile new file mode 100644 index 000000000..1aead4c5e --- /dev/null +++ b/qemu/roms/SLOF/lib/libbcm/Makefile @@ -0,0 +1,53 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008, 2013 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) + +#CFLAGS += -O2 -I. -I../common -I$(TOP)/clients/net-snk/include -I$(TOP)/lib/libc/include -fno-builtin -ffreestanding -msoft-float -Wall -nostdinc + +LDFLAGS = -nostdlib + +TARGET = ../libbcm.a + + +all: $(TARGET) Makefile.dep + +SRCS = bcm57xx.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/lib/libbcm/bcm.code b/qemu/roms/SLOF/lib/libbcm/bcm.code new file mode 100644 index 000000000..308ebbaa2 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbcm/bcm.code @@ -0,0 +1,57 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libbcm Forth wrapper + */ + +#include <bcm57xx.h> + +// : bcm57xx-open ( -- false | [ driver true ] ) +PRIM(BCM57XX_X2d_OPEN) +{ + net_driver_t *net_driver = bcm57xx_open(); + if (net_driver) { + PUSH; + TOS.u = (unsigned long)net_driver; PUSH; + TOS.n = -1; + } else { + PUSH; + TOS.n = 0; + } +} +MIRP + +// : bcm57xx-close ( driver -- ) +PRIM(BCM57XX_X2d_CLOSE) +{ + net_driver_t *driver = TOS.a; POP; + bcm57xx_close(driver); +} +MIRP + + +// : bcm57xx-read ( addr len -- actual ) +PRIM(BCM57XX_X2d_READ) +{ + int len = TOS.u; POP; + TOS.n = bcm57xx_read(TOS.a, len); +} +MIRP + +// : bcm57xx-write ( addr len -- actual ) +PRIM(BCM57XX_X2d_WRITE) +{ + int len = TOS.u; POP; + TOS.n = bcm57xx_write(TOS.a, len); +} +MIRP diff --git a/qemu/roms/SLOF/lib/libbcm/bcm.in b/qemu/roms/SLOF/lib/libbcm/bcm.in new file mode 100644 index 000000000..ee50a6e65 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbcm/bcm.in @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libbcm bindings for Forth - definitions + */ + +cod(BCM57XX-OPEN) +cod(BCM57XX-CLOSE) +cod(BCM57XX-READ) +cod(BCM57XX-WRITE) diff --git a/qemu/roms/SLOF/lib/libbcm/bcm57xx.c b/qemu/roms/SLOF/lib/libbcm/bcm57xx.c new file mode 100644 index 000000000..2ecb517f1 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbcm/bcm57xx.c @@ -0,0 +1,3461 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * + ****************************************************************************** + * reference: + * Broadcom 57xx + * Host Programmer Interface Specification for the + * NetXtreme Family of Highly-Integrated Media Access Controlers + */ +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <byteorder.h> +#include <helpers.h> +#include <netdriver.h> +#include "bcm57xx.h" + +/* + * local defines + ****************************************************************************** + */ + + +// #define BCM_VLAN_TAG ( (uint32_t) 0x1 ) + +// number of tx/rx rings +// NOTE: 5714 only uses 1 rx/tx ring, but memory +// for the other rings is cleaned anyways for +// sanity & future use +#define BCM_MAX_TX_RING 16 +#define BCM_MAX_RXRET_RING 16 +#define BCM_MAX_RXPROD_RCB 3 + +// bd descriptions +#define BCM_RXPROD_RING_SIZE 512 // don't change +#define BCM_RXRET_RING_SIZE 512 // don't change +#define BCM_TX_RING_SIZE 512 // don't change +#define BCM_BUF_SIZE 1536 // don't change +#define BCM_MTU_MAX_LEN 1522 +#define BCM_MAX_RX_BUF 64 +#define BCM_MAX_TX_BUF 16 + +// number of MAC addresses in NIC +#define BCM_NUM_MAC_ADDR 4 +#define BCM_NUM_MAC5704_ADDR 12 +// offset of mac address field(s) in bcm register space +#define MAC5704_ADDR_OFFS ( (uint16_t) 0x0530 ) + +// offset of NIC memory start address from base address +#define BCM_MEMORY_OFFS ( (uint64_t) 0x8000 ) + +// offset of statistics block in NIC memory +#define BCM_STATISTIC_OFFS ( (uint64_t) 0x0300 ) +// size of statistic block in NIC memory +#define BCM_STATISTIC_SIZE 0x800 + +// offsets of NIC rx/tx rings in NIC memory +#define BCM_NIC_TX_OFFS ( (uint16_t) 0x4000 ) +#define BCM_NIC_RX_OFFS ( (uint16_t) 0x6000 ) +#define BCM_NIC_TX_SIZE ( (uint16_t) ( ( BCM_TX_RING_SIZE * BCM_RCB_SIZE_u16 ) / 4 ) ) + +// device mailboxes +#define BCM_FW_MBX ( (uint16_t) 0x0b50 ) +#define BCM_FW_MBX_CMD ( (uint16_t) 0x0b78 ) +#define BCM_FW_MBX_LEN ( (uint16_t) 0x0b7c ) +#define BCM_FW_MBX_DATA ( (uint16_t) 0x0b80 ) +#define BCM_NICDRV_STATE_MBX ( (uint16_t) 0x0c04 ) + +// device mailbox commands +#define BCM_NICDRV_ALIVE ( (uint32_t) 0x00000001 ) +#define BCM_NICDRV_PAUSE_FW ( (uint32_t) 0x00000002 ) + +// device values +#define BCM_MAGIC_NUMBER ( (uint32_t) 0x4b657654 ) + +// device states +#define NIC_FWDRV_STATE_START ( (uint32_t) 0x00000001 ) +#define NIC_FWDRV_STATE_START_DONE ( (uint32_t) 0x80000001 ) +#define NIC_FWDRV_STATE_UNLOAD ( (uint32_t) 0x00000002 ) +#define NIC_FWDRV_STATE_UNLOAD_DONE ( (uint32_t) 0x80000002 ) +#define NIC_FWDRV_STATE_SUSPEND ( (uint32_t) 0x00000004 ) + +// timer prescaler value +#define BCM_TMR_PRESCALE ( (uint32_t) 0x41 ) + +// offset of transmit rcb's in NIC memory +#define BCM_TX_RCB_OFFS ( (uint16_t) 0x0100 ) +// offset of receive return rcb's in NIC memory +#define BCM_RXRET_RCB_OFFS ( (uint16_t) 0x0200 ) + +// register offsets for ring indices +#define TX_PROD_IND ( (uint16_t) 0x0304 ) +#define TX_CONS_IND ( (uint16_t) 0x3cc0 ) +#define RXPROD_PROD_IND ( (uint16_t) 0x026c ) +#define RXPROD_CONS_IND ( (uint16_t) 0x3c54 ) +#define RXRET_PROD_IND ( (uint16_t) 0x3c80 ) +#define RXRET_CONS_IND ( (uint16_t) 0x0284 ) +// NIC producer index only needed for initialization +#define TX_NIC_PROD_IND ( (uint16_t) 0x0384 ) + +/* + * predefined register values used during initialization + * may be adapted by user + */ +#define DMA_RW_CTRL_VAL_5714 ( (uint32_t) 0x76144000 ) +#define DMA_RW_CTRL_VAL ( (uint32_t) 0x760F0000 ) +#define TX_MAC_LEN_VAL ( (uint32_t) 0x00002620 ) + +#define RX_LST_PLC_CFG_VAL ( (uint32_t) 0x00000109 ) +#define RX_LST_PLC_STAT_EN_VAL ( (uint32_t) 0x007e000f ) +#define NVM_ADDR_MSK ( (uint32_t) 0x000fffff ) + +// Number of Receive Rules /w or /wo SOL enabled +#define RX_RULE_CFG_VAL ( (uint32_t) 0x00000008 ) +#define NUM_RX_RULE ( (uint32_t) 16 ) +#define NUM_RX_RULE_ASF ( (uint32_t) ( NUM_RX_RULE - 4 ) ) + +// RCB register offsets +#define BCM_RXPROD_RCB_JUM ( (uint16_t) 0x2440 ) +#define BCM_RXPROD_RCB_STD ( (uint16_t) 0x2450 ) +#define BCM_RXPROD_RCB_MIN ( (uint16_t) 0x2460 ) + +// macros needed for new addressing method +#define BCM_RCB_HOSTADDR_HI_u16( rcb ) ( (uint16_t) rcb + 0x00 ) +#define BCM_RCB_HOSTADDR_LOW_u16( rcb ) ( (uint16_t) rcb + 0x04 ) +#define BCM_RCB_LENFLAG_u16( rcb ) ( (uint16_t) rcb + 0x08 ) +#define BCM_RCB_NICADDR_u16( rcb ) ( (uint16_t) rcb + 0x0c ) +#define BCM_RCB_SIZE_u16 ( (uint16_t) 0x0010 ) + +// RCB flags +#define RCB_FLAG_RING_DISABLED BIT32( 1 ) + +// BCM device ID masks +#define BCM_DEV_5714 ( (uint64_t) 0x1 ) +#define BCM_DEV_5704 ( (uint64_t) 0x2 ) +#define BCM_DEV_5703 ( (uint64_t) 0x4 ) +#define BCM_DEV_SERDES ( (uint64_t) 0x80000000 ) +#define BCM_DEV_COPPER ( (uint64_t) 0x40000000 ) + +#define IS_5714 ( ( bcm_device_u64 & BCM_DEV_5714 ) != 0 ) +#define IS_5704 ( ( bcm_device_u64 & BCM_DEV_5704 ) != 0 ) +#define IS_5703 ( ( bcm_device_u64 & BCM_DEV_5703 ) != 0 ) +#define IS_SERDES ( ( bcm_device_u64 & BCM_DEV_SERDES ) != 0 ) +#define IS_COPPER_PHY ( ( bcm_device_u64 & BCM_DEV_COPPER ) != 0 ) + +#define BUFFERED_FLASH_PAGE_POS 9 +#define BUFFERED_FLASH_BYTE_ADDR_MASK ((<<BUFFERED_FLASH_PAGE_POS) - 1) +#define BUFFERED_FLASH_PAGE_SIZE 264 +#define BUFFERED_FLASH_PHY_SIZE 512 +#define MANUFACTURING_INFO_SIZE 140 +#define CRC32_POLYNOMIAL 0xEDB88320 + +/* + * local types + ****************************************************************************** + */ +typedef struct { + uint32_t m_dev_u32; + uint64_t m_devmsk_u64; +} bcm_dev_t; + +/* + * BCM common data structures + * BCM57xx Programmer's Guide: Section 5 + */ + +/* + * 64bit host address in a way the NIC is able to understand it + */ +typedef struct { + uint32_t m_hi_u32; + uint32_t m_lo_u32; +} bcm_addr64_t; +/* + * ring control block + */ +typedef struct { + bcm_addr64_t m_hostaddr_st; + uint32_t m_lenflags_u32; // upper 16b: len, lower 16b: flags + uint32_t m_nicaddr_u32; +} bcm_rcb_t; + +/* + * tx buffer descriptor + */ +typedef struct { + bcm_addr64_t m_hostaddr_st; + uint32_t m_lenflags_u32; // upper 16b: len, lower 16b: flags + uint32_t m_VLANtag_u32; // lower 16b: vtag +} bcm_txbd_t; + +/* + * rx buffer descriptor + */ +typedef struct { + bcm_addr64_t m_hostaddr_st; + uint32_t m_idxlen_u32; // upper 16b: idx, lower 16b: len + uint32_t m_typeflags_u32; // upper 16b: type, lower 16b: flags + uint32_t m_chksum_u32; // upper 16b: ip, lower 16b: tcp/udp + uint32_t m_errvlan_u32; // upper 16b: err, lower 16b: vlan tag + uint32_t m_reserved_u32; + uint32_t m_opaque_u32; +} bcm_rxbd_t; + +/* + * bcm status block + * NOTE: in fact the status block is not used and configured + * so that it is not updated by the NIC. Still it has to be + * set up so the NIC is satisfied + */ +typedef struct { + uint32_t m_st_word_u32; + uint32_t m_st_tag_u32; + uint16_t m_rxprod_cons_u16; + uint16_t m_unused_u16; + uint32_t m_unused_u32; + uint16_t m_tx_cons_u16; + uint16_t m_rxret_prod_u16; +} bcm_status_t; + +/* + * local constants + ****************************************************************************** + */ +static const bcm_dev_t bcm_dev[] = { + { 0x166b, BCM_DEV_5714 }, + { 0x1668, BCM_DEV_5714 }, + { 0x1669, BCM_DEV_5714 }, + { 0x166a, BCM_DEV_5714 }, + { 0x1648, BCM_DEV_5704 }, + { 0x1649, BCM_DEV_5704 | BCM_DEV_SERDES }, + { 0x16a8, BCM_DEV_5704 | BCM_DEV_SERDES }, + { 0x16a7, BCM_DEV_5703 | BCM_DEV_SERDES }, + { 0x16c7, BCM_DEV_5703 | BCM_DEV_SERDES }, + { 0 , 0 } +}; + +/* + * local variables + ****************************************************************************** + */ +static uint64_t bcm_device_u64; +static uint32_t bcm_rxret_ring_sz; +static uint64_t bcm_baseaddr_u64; +static uint64_t bcm_memaddr_u64; + +/* + * rings & their buffers + */ +// the rings made of buffer descriptors +static bcm_txbd_t bcm_tx_ring[BCM_TX_RING_SIZE]; +static bcm_rxbd_t bcm_rxprod_ring[BCM_RXPROD_RING_SIZE]; +static bcm_rxbd_t bcm_rxret_ring[BCM_RXRET_RING_SIZE*2]; + +// the buffers used in the rings +static uint8_t bcm_tx_buffer_pu08[BCM_MAX_TX_BUF][BCM_BUF_SIZE]; +static uint8_t bcm_rx_buffer_pu08[BCM_MAX_RX_BUF][BCM_BUF_SIZE]; + +// tx ring index of first/last bd +static uint32_t bcm_tx_start_u32; +static uint32_t bcm_tx_stop_u32; +static uint32_t bcm_tx_bufavail_u32; + +/* + * status block + */ +static bcm_status_t bcm_status; + +/* + * implementation + ****************************************************************************** + */ + + +/* + * global functions + ****************************************************************************** + */ + + +/* + * local helper functions + ****************************************************************************** + */ +#if 0 +static char * +memcpy( char *dest, const char *src, size_t n ) +{ + char *ret = dest; + while( n-- ) { + *dest++ = *src++; + } + + return( ret ); +} +#endif + +static char * +memset_ci( char *dest, int c, size_t n ) +{ + char *ret = dest; + + while( n-- ) { + wr08( dest, c ); + dest++; + } + + return( ret ); +} + +#if 0 +static char * +memset( char *dest, int c, size_t n ) +{ + char *ret = dest; + while( n-- ) { + *dest++ = (char) c; + } + + return( ret ); +} +#endif + +static uint32_t +bcm_nvram_logical_to_physical_address(uint32_t address) +{ + uint32_t page_no = address / BUFFERED_FLASH_PAGE_SIZE; + uint32_t page_addr = address % BUFFERED_FLASH_PAGE_SIZE; + + return (page_no << BUFFERED_FLASH_PAGE_POS) + page_addr; +} + +/* + * read/write functions to access NIC registers & memory + * NOTE: all functions are executed with cache inhibitation (dead slow :-) ) + */ +static uint32_t +bcm_read_mem32( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd32( bcm_memaddr_u64 + (uint64_t) f_offs_u16 ); +} + +/* not used so far +static uint16_t +bcm_read_mem16( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd16( bcm_memaddr_u64 + (uint64_t) f_offs_u16 ); +}*/ +/* not used so far +static uint8_t +bcm_read_mem08( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd08( bcm_memaddr_u64 + (uint64_t) f_offs_u16 ); +}*/ + +static uint32_t +bcm_read_reg32_indirect( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + SLOF_pci_config_write32(REG_BASE_ADDR_REG, f_offs_u16); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_BASE_ADDR_REG, + f_offs_u16 );*/ + return bswap_32(SLOF_pci_config_read32(REG_DATA_REG)); + /*return (uint32_t) bswap_32( snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_DATA_REG ) ) ;*/ +} + +static uint32_t +bcm_read_reg32( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400) + return bcm_read_reg32_indirect( f_offs_u16 + 0x5600 ); + return rd32( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +} + +static uint16_t +bcm_read_reg16( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +} +/* not used so far +static uint8_t +bcm_read_reg08( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +}*/ + +static void +bcm_write_mem32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + SLOF_pci_config_write32(MEM_BASE_ADDR_REG, f_offs_u16); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + MEM_BASE_ADDR_REG, + f_offs_u16 );*/ + SLOF_pci_config_write32(MEM_DATA_REG, bswap_32(f_val_u32)); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + MEM_DATA_REG, + bswap_32 ( f_val_u32 ) );*/ +} + +static void +bcm_write_mem32( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + if(f_offs_u16 >= BCM_RXRET_RCB_OFFS && + f_offs_u16 < BCM_RXRET_RCB_OFFS + (BCM_MAX_RXRET_RING*BCM_RCB_SIZE_u16)) + bcm_write_mem32_indirect( f_offs_u16, f_val_u32 ); + else if(f_offs_u16 >= BCM_TX_RCB_OFFS && + f_offs_u16 < BCM_TX_RCB_OFFS + (BCM_MAX_TX_RING*BCM_RCB_SIZE_u16)) + bcm_write_mem32_indirect( f_offs_u16, f_val_u32 ); + else + wr32( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u32 ); +} +/* not used so far +static void +bcm_write_mem16( uint16_t f_offs_u16, uint16_t f_val_u16 ) +{ // caution: shall only be used after initialization! + wr16( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 ); +}*/ +/* not used so far +static void +bcm_write_mem08( uint16_t f_offs_u16, uint8_t f_val_u08 ) +{ // caution: shall only be used after initialization! + wr08( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_write_reg32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + SLOF_pci_config_write32(REG_BASE_ADDR_REG, f_offs_u16); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_BASE_ADDR_REG, + f_offs_u16 );*/ + SLOF_pci_config_write32(REG_DATA_REG, bswap_32(f_val_u32)); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_DATA_REG, + bswap_32 ( f_val_u32 ) );*/ +} + +static void +bcm_write_reg32( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400) + bcm_write_reg32_indirect( f_offs_u16 + 0x5600, f_val_u32 ); + else + wr32( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u32 ); +} + +static void +bcm_write_reg16( uint16_t f_offs_u16, uint16_t f_val_u16 ) +{ // caution: shall only be used after initialization! + wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 ); +} +/* not used so far +static void +bcm_write_reg08( uint16_t f_offs_u16, uint8_t f_val_u08 ) +{ // caution: shall only be used after initialization! + wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_setb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 ) +{ + uint32_t v; + + v = bcm_read_reg32( f_offs_u16 ); + v |= f_mask_u32; + bcm_write_reg32( f_offs_u16, v ); +} +/* not used so far +static void +bcm_setb_reg16( uint16_t f_offs_u16, uint16_t f_mask_u16 ) +{ + uint16_t v; + v = rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); + v |= f_mask_u16; + wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ +/* not used so far +static void +bcm_setb_reg08( uint16_t f_offs_u16, uint8_t f_mask_u08 ) +{ + uint8_t v; + v = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); + v |= f_mask_u08; + wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clrb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 ) +{ + uint32_t v; + + v = bcm_read_reg32( f_offs_u16 ); + v &= ~f_mask_u32; + bcm_write_reg32( f_offs_u16, v ); +} + +static void +bcm_clrb_reg16( uint16_t f_offs_u16, uint16_t f_mask_u16 ) +{ + uint16_t v; + + v = bcm_read_reg16( f_offs_u16 ); + v &= ~f_mask_u16; + bcm_write_reg16( f_offs_u16, v ); +} +/* not used so far +static void +bcm_clrb_reg08( uint16_t f_offs_u16, uint8_t f_mask_u08 ) +{ + uint8_t v; + v = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); + v &= ~f_mask_u32; + wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clr_wait_bit32( uint16_t r, uint32_t b ) +{ + uint32_t i; + + bcm_clrb_reg32( r, b ); + + i = 1000; + while( --i ) { + + if( ( bcm_read_reg32( r ) & b ) == 0 ) { + break; + } + + SLOF_usleep( 10 ); + } +#ifdef BCM_DEBUG + if( ( bcm_read_reg32( r ) & b ) != 0 ) { + printf( "bcm57xx: bcm_clear_wait_bit32 failed (0x%04X)!\n", r ); + } +#endif +} + +/* + * (g)mii bus access + */ +#if 0 +// not used so far +static int32_t +bcm_mii_write16( uint32_t f_reg_u32, uint16_t f_value_u16 ) +{ + static const uint32_t WR_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 26 ) ); + int32_t l_autopoll_i32 = 0; + uint32_t l_wrval_u32; + uint32_t i; + + /* + * only 0x00-0x1f are valid registers + */ + if( f_reg_u32 > (uint32_t) 0x1f ) { + return -1; + } + + /* + * disable auto polling if enabled + */ + if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { + l_autopoll_i32 = (int32_t) !0; + bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); + SLOF_usleep( 40 ); + } + + /* + * construct & write mi com register value + */ + l_wrval_u32 = ( WR_VAL | ( f_reg_u32 << 16 ) | (uint32_t) f_value_u16 ); + bcm_write_reg32( MI_COM_R, l_wrval_u32 ); + + /* + * wait for transaction to complete + */ + i = 25; + while( ( --i ) && + ( ( bcm_read_reg32( MI_COM_R ) & BIT32( 29 ) ) != 0 ) ) { + SLOF_usleep( 10 ); + } + + /* + * re-enable auto polling if necessary + */ + if( l_autopoll_i32 ) { + bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) ); + } + + // return on error + if( i == 0 ) { + return -1; + } + + return 0; +} +#endif + +static int32_t +bcm_mii_read16( uint32_t f_reg_u32, uint16_t *f_value_pu16 ) +{ + static const uint32_t RD_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 27 ) ); + int32_t l_autopoll_i32 = 0; + uint32_t l_rdval_u32; + uint32_t i; + uint16_t first_not_busy; + + /* + * only 0x00-0x1f are valid registers + */ + if( f_reg_u32 > (uint32_t) 0x1f ) { + return -1; + } + + /* + * disable auto polling if enabled + */ + if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { + l_autopoll_i32 = ( int32_t ) !0; + bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); + SLOF_usleep( 40 ); + } + + /* + * construct & write mi com register value + */ + l_rdval_u32 = ( RD_VAL | ( f_reg_u32 << 16 ) ); + bcm_write_reg32( MI_COM_R, l_rdval_u32 ); + + /* + * wait for transaction to complete + * ERRATA workaround: must read two "not busy" states to indicate transaction complete + */ + i = 25; + first_not_busy = 0; + l_rdval_u32 = bcm_read_reg32( MI_COM_R ); + while( ( --i ) && + ( (first_not_busy == 0) || ( ( l_rdval_u32 & BIT32( 29 ) ) != 0 ) ) ) { + /* Is this the first clear BUSY state? */ + if ( ( l_rdval_u32 & BIT32( 29 ) ) == 0 ) + first_not_busy++; + SLOF_usleep( 10 ); + l_rdval_u32 = bcm_read_reg32( MI_COM_R ); + } + + /* + * re-enable autopolling if necessary + */ + if( l_autopoll_i32 ) { + bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) ); + } + + /* + * return on read transaction error + * (check read failed bit) + */ + if( ( i == 0 ) || + ( ( l_rdval_u32 & BIT32( 28 ) ) != 0 ) ) { + return -1; + } + + /* + * return read value + */ + *f_value_pu16 = (uint16_t) ( l_rdval_u32 & (uint32_t) 0xffff ); + + return 0; +} + +/* + * ht2000 dump (not complete) + */ +#if 0 +static void +bcm_dump( void ) +{ + uint32_t i, j; + + printf( "*** DUMP ***********************************************************************\n\n" ); + + printf( "* PCI Configuration Registers:\n" ); + for( i = 0, j = 0; i < 0x40; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Private PCI Configuration Registers:\n" ); + for( i = 0x68, j = 0; i < 0x88; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* VPD Config:\n" ); + printf( "%04X: %08X \n", 0x94, bcm_read_reg32( 0x94 ) ); + + printf( "\n* Dual MAC Control Registers:\n" ); + for( i = 0xb8, j = 0; i < 0xd0; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Ethernet MAC Control Registers:\n" ); + for( i = 0x400, j = 0; i < 0x590; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Send Data Initiator Control:\n" ); + for( i = 0xc00, j = 0; i < 0xc10; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Send Data Completion Control:\n" ); + printf( "%04X: %08X ", 0x1000, bcm_read_reg32( 0x1000 ) ); + printf( "%04X: %08X \n", 0x1008, bcm_read_reg32( 0x1008 ) ); + + printf( "\n* Send BD Ring Selector Control:\n" ); + printf( "%04X: %08X ", 0x1400, bcm_read_reg32( 0x1400 ) ); + printf( "%04X: %08X ", 0x1404, bcm_read_reg32( 0x1404 ) ); + printf( "%04X: %08X \n", 0x1408, bcm_read_reg32( 0x1408 ) ); + + printf( "\n* Send BD Initiator Control:\n" ); + printf( "%04X: %08X ", 0x1800, bcm_read_reg32( 0x1800 ) ); + printf( "%04X: %08X \n", 0x1804, bcm_read_reg32( 0x1804 ) ); + + printf( "\n* Send BD Completion Control:\n" ); + printf( "%04X: %08X ", 0x1c00, bcm_read_reg32( 0x1c00 ) ); + + printf( "\n* Receive List Placement Control:\n" ); + for( i = 0x2000, j = 0; i < 0x2020; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Receive Data & Receive BD Initiator Control:\n" ); + printf( "%04X: %08X ", 0x2400, bcm_read_reg32( 0x2400 ) ); + printf( "%04X: %08X \n", 0x2404, bcm_read_reg32( 0x2404 ) ); + + printf( "\n* Jumbo Receive BD Ring RCB:\n" ); + for( i = 0x2440, j = 0; i < 0x2450; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Standard Receive BD Ring RCB:\n" ); + for( i = 0x2450, j = 0; i < 0x2460; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Mini Receive BD Ring RCB:\n" ); + for( i = 0x2460, j = 0; i < 0x2470; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\nRDI Timer Mode Register:\n" ); + printf( "%04X: %08X \n", 0x24f0, bcm_read_reg32( 0x24f0 ) ); + + printf( "\n* Receive BD Initiator Control:\n" ); + for( i = 0x2c00, j = 0; i < 0x2c20; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Receive BD Completion Control:\n" ); + for( i = 0x3000, j = 0; i < 0x3014; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } +} +#endif + + + +/* + * NVRAM access + */ + +static int +bcm_nvram_lock( void ) +{ + int i; + + /* + * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) + */ +// bcm_setb_reg32( SW_ARB_R, BIT32( 0 ) ); + bcm_setb_reg32( SW_ARB_R, BIT32( 1 ) ); + + i = 2000; + while( ( --i ) && +// ( bcm_read_reg32( SW_ARB_R ) & BIT32( 8 ) ) == 0 ) { + ( bcm_read_reg32( SW_ARB_R ) & BIT32( 9 ) ) == 0 ) { + SLOF_msleep( 1 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf("bcm57xx: failed to lock nvram"); +#endif + return -1; + } + + return 0; +} + +static void +bcm_nvram_unlock( void ) +{ + /* + * release NVRam lock (CLR0) + */ +// bcm_setb_reg32( SW_ARB_R, BIT32( 4 ) ); + bcm_setb_reg32( SW_ARB_R, BIT32( 5 ) ); +} + +static void +bcm_nvram_init( void ) +{ + /* + * enable access to NVRAM registers + */ + if(IS_5714) { + bcm_setb_reg32( NVM_ACC_R, BIT32( 1 ) | BIT32( 0 ) ); + } + + /* + * disable bit-bang method 19& disable interface bypass + */ + bcm_clrb_reg32( NVM_CFG1_R, BIT32( 31 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 14 ) | BIT32( 16 ) ); + bcm_setb_reg32( NVM_CFG1_R, BIT32 ( 13 ) | BIT32 ( 17 )); + + /* + * enable Auto SEEPROM Access + */ + bcm_setb_reg32( MISC_LOCAL_CTRL_R, BIT32 ( 24 ) ); + + /* + * NVRAM write enable + */ + bcm_setb_reg32( MODE_CTRL_R, BIT32 ( 21 ) ); +} + +static int32_t +bcm_nvram_read( uint32_t f_addr_u32, uint32_t *f_val_pu32, uint32_t lock ) +{ + uint32_t i; + + /* + * parameter check + */ + if( f_addr_u32 > NVM_ADDR_MSK ) { + return -1; + } + + /* + * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) + */ + if( lock && (bcm_nvram_lock() == -1) ) { + return -1; + } + + /* + * setup address to read + */ + bcm_write_reg32( NVM_ADDR_R, + bcm_nvram_logical_to_physical_address(f_addr_u32) ); +// bcm_write_reg32( NVM_ADDR_R, f_addr_u32 ); + + /* + * get the command going + */ + bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) | + BIT32( 4 ) | BIT32( 3 ) ); + + /* + * wait for command completion + */ + i = 2000; + while( ( --i ) && + ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) { + SLOF_msleep( 1 ); + } + + /* + * read back data if no error + */ + if( i != 0 ) { + /* + * read back data + */ + *f_val_pu32 = bcm_read_reg32( NVM_READ_R ); + } + + if(lock) + bcm_nvram_unlock(); + + // error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf("bcm57xx: reading from NVRAM failed\n"); +#endif + return -1; + } + + // success + return 0; +} + +static int32_t +bcm_nvram_write( uint32_t f_addr_u32, uint32_t f_value_u32, uint32_t lock ) +{ + uint32_t i; + + /* + * parameter check + */ + if( f_addr_u32 > NVM_ADDR_MSK ) { + return -1; + } + + /* + * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) + */ + if( lock && (bcm_nvram_lock() == -1) ) { + return -1; + } + + /* + * setup address to write + */ + bcm_write_reg32( NVM_ADDR_R, bcm_nvram_logical_to_physical_address( f_addr_u32 ) ); + + /* + * setup write data + */ + bcm_write_reg32( NVM_WRITE_R, f_value_u32 ); + + /* + * get the command going + */ + bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) | + BIT32( 5 ) | BIT32( 4 ) | BIT32( 3 ) ); + + /* + * wait for command completion + */ + i = 2000; + while( ( --i ) && + ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) { + SLOF_msleep( 1 ); + } + + /* + * release NVRam lock (CLR0) + */ + if(lock) + bcm_nvram_unlock(); + + // error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf("bcm57xx: writing to NVRAM failed\n"); +#endif + return -1; + } + + // success + return 0; +} + +/* + * PHY initialization + */ +static int32_t +bcm_mii_phy_init( void ) +{ + static const uint32_t PHY_STAT_R = (uint32_t) 0x01; + static const uint32_t AUX_STAT_R = (uint32_t) 0x19; + static const uint32_t MODE_GMII = BIT32( 3 ); + static const uint32_t MODE_MII = BIT32( 2 ); + static const uint32_t NEG_POLARITY = BIT32( 10 ); + static const uint32_t MII_MSK = ( MODE_GMII | MODE_MII ); + static const uint16_t GIGA_ETH = ( BIT16( 10 ) | BIT16( 9 ) ); + int32_t i; + uint16_t v; + + /* + * enable MDI communication + */ + bcm_write_reg32( MDI_CTRL_R, (uint32_t) 0x0 ); + + /* + * check link up + */ + i = 2500; + do { + SLOF_msleep( 1 ); + // register needs to be read twice! + bcm_mii_read16( PHY_STAT_R, &v ); + bcm_mii_read16( PHY_STAT_R, &v ); + } while( ( --i ) && + ( ( v & BIT16( 2 ) ) == 0 ) ); + + if( i == 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: link is down\n" ); +#endif + return -1; + } + +#ifdef BCM_DEBUG + printf( "bcm57xx: link is up\n" ); +#endif + if( !IS_COPPER_PHY ) { + return 0; + } + + /* + * setup GMII or MII interface + */ + i = bcm_read_reg32( ETH_MAC_MODE_R ); + /* + * read status register twice, since the first + * read fails once between here and the moon... + */ + bcm_mii_read16( AUX_STAT_R, &v ); + bcm_mii_read16( AUX_STAT_R, &v ); + + if( ( v & GIGA_ETH ) == GIGA_ETH ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: running PHY in GMII mode (1000BaseT)\n" ); +#endif + // GMII device + if( ( i & MII_MSK ) != MODE_GMII ) { + i &= ~MODE_MII; + i |= MODE_GMII; + } + + } else { +#ifdef BCM_DEBUG + printf( "bcm57xx: running PHY in MII mode (10/100BaseT)\n" ); +#endif + // MII device + if( ( i & MII_MSK ) != MODE_MII ) { + i &= ~MODE_GMII; + i |= MODE_MII; + } + + } + + if( IS_5704 && !IS_SERDES ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: set the link ready signal for 5704C to negative polarity\n" ); +#endif + i |= NEG_POLARITY; // set the link ready signal for 5704C to negative polarity + } + + bcm_write_reg32( ETH_MAC_MODE_R, i ); + + return 0; +} + +static int32_t +bcm_tbi_phy_init( void ) +{ + int32_t i; +#if 0 + /* + * set TBI mode full duplex + */ + bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 1 ) ); + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) ); + + /* + * enable MDI communication + */ + bcm_write_reg32( MDI_CTRL_R, (uint32_t) 0x0 ); + + /* Disable link change interrupt. */ + bcm_write_reg32( ETH_MAC_EVT_EN_R, 0 ); + + /* + * set link polarity + */ + bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 10 ) ); + + /* + * wait for sync/config changes + */ + for( i = 0; i < 100; i++ ) { + bcm_write_reg32( ETH_MAC_STAT_R, + BIT32( 3 ) | BIT32( 4 ) ); + + SLOF_usleep( 20 ); + + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & + ( BIT32( 3 ) | BIT32( 4 ) ) ) == 0 ) { + break; + } + + } +#endif + /* + * wait for sync to come up + */ + for( i = 0; i < 100; i++ ) { + + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) != 0 ) { + break; + } + + SLOF_usleep( 20 ); + } + + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0) { +#ifdef BCM_DEBUG + printf( "bcm57xx: link is down\n" ); +#endif + return -1; + } +#if 0 + /* + * clear all attentions + */ + bcm_write_reg32( ETH_MAC_STAT_R, (uint32_t) ~0 ); +#endif + +#ifdef BCM_DEBUG + printf( "bcm57xx: link is up\n" ); +#endif + return 0; +} + +static int32_t +bcm_phy_init( void ) +{ + static const uint16_t SRAM_HW_CFG = (uint16_t) 0x0b58; + uint32_t l_val_u32; + int32_t l_ret_i32 = 0; + + /* + * get HW configuration from SRAM + */ + l_val_u32 = bcm_read_mem32( SRAM_HW_CFG ); + l_val_u32 &= ( BIT32( 5 ) | BIT32( 4 ) ); + + switch( l_val_u32 ) { + case 0x10: { + #ifdef BCM_DEBUG + printf( "bcm57xx: copper PHY detected\n" ); + #endif + + bcm_device_u64 |= BCM_DEV_COPPER; + l_ret_i32 = bcm_mii_phy_init(); + } break; + + case 0x20: { + #ifdef BCM_DEBUG + printf( "bcm57xx: fiber PHY detected\n" ); + #endif + + if( !IS_SERDES ) { + #ifdef BCM_DEBUG + printf( "bcm57xx: running PHY in gmii/mii mode\n" ); + #endif + l_ret_i32 = bcm_mii_phy_init(); + } else { + #ifdef BCM_DEBUG + printf( "bcm57xx: running PHY in tbi mode\n" ); + #endif + l_ret_i32 = bcm_tbi_phy_init(); + } + + } break; + + default: { + #ifdef BCM_DEBUG + printf( "bcm57xx: unknown PHY type detected, terminating\n" ); + #endif + l_ret_i32 = -1; + } + + } + + return l_ret_i32; +} + +/* + * ring initialization + */ +static void +bcm_init_rxprod_ring( void ) +{ + uint32_t v; + uint32_t i; + + /* + * clear out the whole rx prod ring for sanity + */ + memset( (void *) &bcm_rxprod_ring, + 0, + BCM_RXPROD_RING_SIZE * sizeof( bcm_rxbd_t ) ); + mb(); + + /* + * assign buffers & indices to the ring members + */ + for( i = 0; i < BCM_MAX_RX_BUF; i++ ) { + bcm_rxprod_ring[i].m_hostaddr_st.m_hi_u32 = + (uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] >> 32 ); + bcm_rxprod_ring[i].m_hostaddr_st.m_lo_u32 = + (uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] & + (uint64_t) 0xffffffff ); + bcm_rxprod_ring[i].m_idxlen_u32 = ( i << 16 ); + bcm_rxprod_ring[i].m_idxlen_u32 += BCM_BUF_SIZE; + } + + /* + * clear rcb registers & disable rings + * NOTE: mini & jumbo rings are not supported, + * still rcb's are cleaned out for sanity + */ + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_JUM ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_MIN ), 0 ); + + /* + * clear rx producer index of std producer ring + */ + bcm_write_reg32( RXPROD_PROD_IND, 0 ); + + /* + * setup rx standard rcb using recommended NIC addr (hard coded) + */ + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), + (uint32_t) ( (uint64_t) &bcm_rxprod_ring >> 32 ) ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), + (uint32_t) ( (uint64_t) &bcm_rxprod_ring & (uint64_t) 0xffffffff ) ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), + (uint32_t) BCM_NIC_RX_OFFS ); + + if( IS_5704 || IS_5703 ) { + // 5704: length field = max buffer len + v = (uint32_t) BCM_BUF_SIZE << 16; + } else { + // 5714: length field = number of ring entries + v = (uint32_t) BCM_RXPROD_RING_SIZE << 16; + } + + v &= (uint32_t) ~RCB_FLAG_RING_DISABLED; + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), v ); +} + +static void +bcm_init_rxret_ring( void ) +{ + uint32_t i; + uint16_t v; + + /* + * clear out the whole rx ret ring for sanity + */ + memset( (void *) &bcm_rxret_ring, + 0, + 2 * BCM_RXRET_RING_SIZE * sizeof( bcm_rxbd_t ) ); + mb(); + + /* + * setup return ring size dependent on installed device + */ + bcm_rxret_ring_sz = BCM_RXRET_RING_SIZE; + if( IS_5704 || IS_5703 ) { + bcm_rxret_ring_sz *= 2; + } + + /* + * clear rcb memory & disable rings + * NOTE: 5714 only supports one return ring, + * still all possible rcb's are cleaned out for sanity + */ + v = BCM_RXRET_RCB_OFFS; + for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * clear rx consumer index of return ring + */ + bcm_write_reg32( RXRET_CONS_IND, 0 ); + + /* + * setup rx ret rcb + * NOTE: NIC address not aplicable in return rings + */ + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXRET_RCB_OFFS ), + (uint32_t) ( (uint64_t) &bcm_rxret_ring >> 32 ) ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXRET_RCB_OFFS ), + (uint32_t) ( (uint64_t) &bcm_rxret_ring & + (uint64_t) 0xffffffff ) ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_RXRET_RCB_OFFS ), 0 ); + + i = bcm_rxret_ring_sz; + i <<= 16; + i &= (uint32_t) ~RCB_FLAG_RING_DISABLED; + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXRET_RCB_OFFS ), i ); +} + +static void +bcm_init_tx_ring( void ) +{ + uint32_t i; + uint16_t v; + + /* + * clear out the whole tx ring for sanity + */ + memset( (void *) &bcm_tx_ring, + 0, + BCM_TX_RING_SIZE * sizeof( bcm_txbd_t ) ); + mb(); + + /* + * assign buffers to the ring members & setup invariant flags + */ + for( i = 0; i < BCM_MAX_TX_BUF; i++ ) { + bcm_tx_ring[i].m_hostaddr_st.m_hi_u32 = + (uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] >> 32 ); + bcm_tx_ring[i].m_hostaddr_st.m_lo_u32 = + (uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] & + (uint64_t) 0xffffffff ); + // flags: indicate last packet & coal now + // -last packet is always true (only one send packet supported) + // -coal now needed to always get the consumed bd's (since + // only a few bd's are set up which permanently are recycled) + bcm_tx_ring[i].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) ); + bcm_tx_ring[i].m_VLANtag_u32 = (uint32_t) 0; // not used + } + + /* + * clear rcb memory & disable rings + * NOTE: 5714 only supports one send ring, + * still all possible rcb's are cleaned out for sanity + */ + v = BCM_TX_RCB_OFFS; + for( i = 0; i < BCM_MAX_TX_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * clear host/nic producer indices + */ + bcm_write_reg32( TX_NIC_PROD_IND, 0 ); + bcm_write_reg32( TX_PROD_IND, 0 ); + + /* + * setup tx rcb using recommended NIC addr (hard coded) + */ + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_TX_RCB_OFFS ), + (uint32_t) ( (uint64_t) &bcm_tx_ring >> 32 ) ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_TX_RCB_OFFS ), + (uint32_t) ( (uint64_t) &bcm_tx_ring & + (uint64_t) 0xffffffff ) ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_TX_RCB_OFFS ), + (uint32_t) BCM_NIC_TX_OFFS ); + + if( IS_5704 || IS_5703 ) { + // 5704: length field = max buffer len + i = (uint32_t) BCM_BUF_SIZE << 16; + } else { + // 5714: length field = number of ring entries + i = (uint32_t) BCM_TX_RING_SIZE << 16; + } + + i &= ( uint32_t ) ~RCB_FLAG_RING_DISABLED; + bcm_write_mem32( BCM_RCB_LENFLAG_u16( BCM_TX_RCB_OFFS ), i ); + + /* + * remember the next bd index to be used + * & number of available buffers + */ + bcm_tx_stop_u32 = BCM_MAX_TX_BUF; + bcm_tx_bufavail_u32 = BCM_MAX_TX_BUF; +} + +static int32_t +bcm_mac_init( uint8_t *f_mac_pu08 ) +{ + static const uint16_t MEM_MAC_LO = (uint16_t) 0x0c18; + static const uint16_t MEM_MAC_HI = (uint16_t) 0x0c14; + + uint32_t NVR_MAC_LO = (uint16_t) 0x80; + uint32_t NVR_MAC_HI = (uint16_t) 0x7c; + + bcm_addr64_t l_mac_st; + uint32_t i; + uint32_t v; + + /* + * Use MAC address from device tree if possible + */ + for( i = 0, v = 0; i < 6; i++ ) { + v += (uint32_t) f_mac_pu08[i]; + } + + if( v != 0 ) { + l_mac_st.m_hi_u32 = ( ( (uint32_t) f_mac_pu08[0]) << 8 ); + l_mac_st.m_hi_u32 |= ( ( (uint32_t) f_mac_pu08[1]) << 0 ); + l_mac_st.m_lo_u32 = ( ( (uint32_t) f_mac_pu08[2]) << 24 ); + l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[3]) << 16 ); + l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[4]) << 8 ); + l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[5]) << 0 ); + } else { + /* + * try to read MAC address from MAC mailbox + */ + l_mac_st.m_hi_u32 = bcm_read_mem32( MEM_MAC_HI ); + + if( ( l_mac_st.m_hi_u32 >> 16 ) == (uint32_t) 0x484b ) { + l_mac_st.m_hi_u32 &= (uint32_t) 0xffff; + l_mac_st.m_lo_u32 = bcm_read_mem32( MEM_MAC_LO ); + } else { + int32_t l_err_i32; + + /* + * otherwise retrieve MAC address from NVRam + */ + if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) != 0 ) { + // secondary MAC is in use, address in NVRAM changes + NVR_MAC_LO += 0x50; + NVR_MAC_HI += 0x50; + } + + l_err_i32 = bcm_nvram_read( NVR_MAC_LO, &l_mac_st.m_lo_u32, 1 ); + l_err_i32 += bcm_nvram_read( NVR_MAC_HI, &l_mac_st.m_hi_u32, 1 ); + + // return on read error + if( l_err_i32 < 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: failed to retrieve MAC address\n" ); +#endif + return -1; + } + } + } + + /* + * write the mac addr into the NIC's register area + */ + bcm_write_reg32( MAC_ADDR_OFFS_HI(0), l_mac_st.m_hi_u32 ); + bcm_write_reg32( MAC_ADDR_OFFS_LO(0), l_mac_st.m_lo_u32 ); + for( i = 1; i < BCM_NUM_MAC_ADDR; i++ ) { + bcm_write_reg32( MAC_ADDR_OFFS_HI(i), 0 ); + bcm_write_reg32( MAC_ADDR_OFFS_LO(i), 0 ); + } + + /* + * WY 26.01.07 + * not needed anymore, s.a. + if( IS_5704 != 0 ) { + + v = MAC5704_ADDR_OFFS; + for( i = 0; i < BCM_NUM_MAC5704_ADDR; i++ ) { + bcm_write_reg32( v, l_mac_st.m_hi_u32 ); + v += sizeof( uint32_t ); + bcm_write_reg32( v, l_mac_st.m_lo_u32 ); + v += sizeof( uint32_t ); + } + + } + */ + + /* + * return MAC address as string + */ + f_mac_pu08[0] = (uint8_t) ( ( l_mac_st.m_hi_u32 >> 8 ) & (uint32_t) 0xff ); + f_mac_pu08[1] = (uint8_t) ( ( l_mac_st.m_hi_u32 ) & (uint32_t) 0xff ); + f_mac_pu08[2] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 24 ) & (uint32_t) 0xff ); + f_mac_pu08[3] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 16 ) & (uint32_t) 0xff ); + f_mac_pu08[4] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 8 ) & (uint32_t) 0xff ); + f_mac_pu08[5] = (uint8_t) ( ( l_mac_st.m_lo_u32 ) & (uint32_t) 0xff ); + +#ifdef BCM_DEBUG + do { + int32_t i; + printf( "bcm57xx: retrieved MAC address " ); + + for( i = 0; i < 6; i++ ) { + printf( "%02X", f_mac_pu08[i] ); + + if( i != 5 ) { + printf( ":" ); + } + + } + + printf( "\n" ); + } while( 0 ); +#endif + + return 0; +} + + +/* + ****************************************************************************** + * ASF Firmware + ****************************************************************************** + */ + + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_ASF_REGS +static void +bcm_asf_check_register( void ) +{ + uint32_t i; + + i = bcm_read_reg32( ASF_CTRL_R ); + printf( "bcm57xx: ASF control : %x\n", i ); + + i = bcm_read_reg32( ASF_WATCHDOG_TIMER_R ); + printf( "bcm57xx: ASF Watchdog Timer : %x\n", i ); + + i = bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ); + printf( "bcm57xx: ASF Heartbeat Timer : %x\n", i ); + + i = bcm_read_reg32( ASF_POLL_TIMER_R ); + printf( "bcm57xx: ASF Poll Timer : %x\n", i ); + + i = bcm_read_reg32( POLL_LEGACY_TIMER_R ); + printf( "bcm57xx: Poll Legacy Timer : %x\n", i ); + + i = bcm_read_reg32( RETRANSMISSION_TIMER_R ); + printf( "bcm57xx: Retransmission Timer : %x\n", i ); + + i = bcm_read_reg32( TIME_STAMP_COUNTER_R ); + printf( "bcm57xx: Time Stamp Counter : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_MODE_R ); + printf( "bcm57xx: RX RISC Mode : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_STATE_R ); + printf( "bcm57xx: RX RISC State : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_PC_R ); + printf( "bcm57xx: RX RISC Prg. Counter : %x\n", i ); +} +#endif +#endif + +static int +bcm_fw_halt( void ) +{ + int i; + + bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_PAUSE_FW ); + bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) ); + + /* Wait for RX cpu to ACK the event. */ + for (i = 0; i < 100; i++) { + if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 )) + break; + SLOF_msleep(1); + } + if( i>= 100) + return -1; + return 0; +} + + +#ifdef BCM_SW_AUTONEG +static void +bcm_sw_autoneg( void ) { + uint32_t i, j, k; + uint32_t SerDesCfg; + uint32_t SgDigControl; + uint32_t SgDigStatus; + uint32_t ExpectedSgDigControl; + int AutoNegJustInitiated = 0; + + // step 1: init TX 1000BX Autoneg. Register to zero + bcm_write_reg32(TX_1000BX_AUTONEG_R, 0); + + // step 2&3: set TBI mode + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) ); + SLOF_usleep(10); + + // step 4: enable link attention + bcm_setb_reg32( ETH_MAC_EVT_EN_R, BIT32( 12 ) ); + + // step 5: preserve voltage regulator bits + SerDesCfg = bcm_read_reg32(SERDES_CTRL_R) & ( BIT32( 20 ) | BIT32( 21 ) + | BIT32( 22 ) | BIT32( 23 ) ); + + // step 6: preserve voltage regulator bits + SgDigControl = bcm_read_reg32(HW_AUTONEG_CTRL_R); + + // step 7: if device is NOT set-up for auto negotiation, then go to step 26 + // goto bcm_setup_phy_step26; + + // We want to use auto negotiation + + // step 8: we don't want to use flow control + ExpectedSgDigControl = 0x81388400; // no flow control + + // step 9: compare SgDigControl with 0x81388400 + if(SgDigControl == ExpectedSgDigControl) { + goto bcm_setup_phy_step17; + } +#ifdef BCM_DEBUG + printf("bcm57xx: SgDigControl = %08X\n", SgDigControl); +#endif + // step 10 + bcm_write_reg32(SERDES_CTRL_R, SerDesCfg | 0xC011880); + + // step 11: restart auto negotiation + bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl | BIT32( 30 ) ); + + // step 12: read back HW_AUTONEG_CTRL_R + bcm_read_reg32(HW_AUTONEG_CTRL_R); + + // step 13 + SLOF_usleep( 5 ); + + // step 14,15,16: same as step 11, but don't restart auto neg. + bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl); + AutoNegJustInitiated = 1; + goto bcm_setup_phy_step30; + + // step 17: + bcm_setup_phy_step17: + if( ( bcm_read_reg32(ETH_MAC_STAT_R) & ( BIT32( 1 ) | BIT32( 0 ) ) ) == 0 ) { + goto bcm_setup_phy_step30; + } + + // step 18: Get HW Autoneg. Status + SgDigStatus = bcm_read_reg32(HW_AUTONEG_STAT_R); + + // step 19: + if( ( SgDigStatus & BIT32(1) ) + && ( bcm_read_reg32(ETH_MAC_STAT_R) & BIT32(0) ) ) { + // resolve the current flow control? + AutoNegJustInitiated = 0; + goto bcm_setup_phy_step30; + } + + // step 20 + if( SgDigStatus & BIT32(1) ) { + goto bcm_setup_phy_step30; + } + if( AutoNegJustInitiated != 0) { + AutoNegJustInitiated = 0; + goto bcm_setup_phy_step29; + } + + // step 21, 22, 23, 24: fallback to 1000Mbps-FullDuplex forced mode + if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) { + // port 0 + bcm_write_reg32( SERDES_CTRL_R, 0xC010880 ); + } + else { // port 1 + bcm_write_reg32( SERDES_CTRL_R, 0x4010880 ); + } + // set to 1000Mbps-FullDuplex + bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400); + // read back + bcm_read_reg32(HW_AUTONEG_CTRL_R); + SLOF_usleep( 40 ); + + // step 25: a little bit reduces... + goto bcm_setup_phy_step30; + + // step 26: check if auto negotiation bit is NOT set +// bcm_setup_phy_step26: + if( ( SgDigControl & BIT32(31) )== 0 ) { + printf("No autoneg.\n"); + goto bcm_setup_phy_step29; + } + + // step 27: + if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) { + // port 0 + bcm_write_reg32( SERDES_CTRL_R, 0xC010880 ); + } + else { // port 1 + bcm_write_reg32( SERDES_CTRL_R, 0x4010880 ); + } + + // step 28: disable auto neg. and force 1000FD mode + bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400); + + // step 29-31: omitted for 5704S + bcm_setup_phy_step29: + bcm_setup_phy_step30: + + // step 32: clear link attentions + i = bcm_read_reg32( ETH_MAC_STAT_R ) | BIT32( 3 ) | BIT32( 4 ); + k = 100; + do { + bcm_write_reg32( ETH_MAC_STAT_R, i ); + j = bcm_read_reg32( ETH_MAC_STAT_R ); + if( ( j & BIT32( 3 ) ) != 0 ) + i = i & ~(BIT32( 3 )); + if( ( j & BIT32( 4 ) ) != 0 ) + i = i & ~(BIT32( 4 )); + --k; + } while( i & k); + + // step 33 + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0 ) { + goto bcm_setup_phy_step35; + } + + // step 34 + i = bcm_read_reg32( ETH_MAC_MODE_R ); + i|= BIT32( 17 ); + bcm_write_reg32( ETH_MAC_MODE_R, i ); + + SLOF_usleep( 1 ); + + i = bcm_read_reg32( ETH_MAC_STAT_R ); + i&= ~BIT32( 17 ); + bcm_write_reg32( ETH_MAC_STAT_R, i ); + + // step 35 & 36: done + bcm_setup_phy_step35: +#ifdef BCM_DEBUG + printf("bcm57xx: SetupPhy\n"); +#endif + return; +} +#endif + +static int +bcm_handle_events( void ) { +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_ASF_REGS + // ASF REGISTER CHECK + // ------------------ + // check if watchdog timer expired + if( bcm_read_reg32( ASF_WATCHDOG_TIMER_R ) == 0 ) { + // Show ASF registers + bcm_asf_check_register(); + + // rearm watchdog timer + bcm_write_reg32( ASF_WATCHDOG_TIMER_R, 5 ); + } +#endif +#endif + +#ifdef BCM_SW_AUTONEG + // AUTO NEGOTIATION + // ---------------- + + // Check event for Auto Negotiation + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & + ( BIT32( 12 ) | BIT32( 3 ) | BIT32( 0 ) ) ) != 0 ) { + // link timer procedure + bcm_sw_autoneg(); + } +#endif + + // ASF FW HEARTBEAT + // ---------------- + + // check if heartsbeat timer expired + if( bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ) <= 2) { + int i; + + // Send heartbeat event + bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_ALIVE ); + bcm_write_mem32( BCM_FW_MBX_LEN, 4 ); + bcm_write_mem32( BCM_FW_MBX_DATA, 5 ); + bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) ); + + // Wait for RX cpu to ACK the event. + for (i = 100; i > 0; i--) { + if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 )) + break; + SLOF_msleep(1); + } + if( i == 0) { +#ifdef BCM_DEBUG + printf( "bcm57xx: RX cpu did not acknowledge heartbeat event\n" ); +#endif + return -1; + } + + // rearm heartbeat timer + bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 5 ); + } + return 0; +} + +/* + * interface + ****************************************************************************** + */ + +/* + * bcm_receive + */ +static int +bcm_receive( char *f_buffer_pc, int f_len_i ) +{ + uint32_t l_rxret_prod_u32 = bcm_read_reg32( RXRET_PROD_IND ); + uint32_t l_rxret_cons_u32 = bcm_read_reg32( RXRET_CONS_IND ); + uint32_t l_rxprod_prod_u32 = bcm_read_reg32( RXPROD_PROD_IND ); + int l_ret_i; +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_RCV_DATA + int i, j; +#endif +#endif + + /* + * NOTE: dummy read to ensure data has already been DMA'd is + * done by the indice reads + */ + + bcm_handle_events(); + + /* + * if producer index == consumer index then nothing was received + */ + if( l_rxret_prod_u32 == l_rxret_cons_u32 ) { + return 0; + } + + /* + * discard erroneous packets + */ + if( ( bcm_rxret_ring[l_rxret_cons_u32].m_typeflags_u32 & BIT32( 10 ) ) != 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: erroneous frame received\n" ); + printf( " : frame discarded\n" ); +#endif + l_ret_i = 0; + } else { + /* + * get packet length, throw away checksum (last 4 bytes) + */ + l_ret_i = (int) ( bcm_rxret_ring[l_rxret_cons_u32].m_idxlen_u32 & + (uint32_t) 0xffff ) - (int) 4; + + /* + * discard oversized packets + */ + if( l_ret_i > f_len_i ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: receive packet length error:\n" ); + printf( " : incoming 0x%X bytes, available buffer 0x%X bytes\n", l_ret_i, f_len_i ); + printf( " : frame discarded\n" ); +#endif + l_ret_i = 0; + } + + } + + /* + * copy & update data & indices + */ + if( l_ret_i != 0 ) { + uint64_t l_cpyaddr_u64; + + l_cpyaddr_u64 = + ( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_hi_u32 << 32 ); + l_cpyaddr_u64 += + ( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_lo_u32 ); + +// FIXME: + if(l_cpyaddr_u64 == 0) { +#ifdef BCM_DEBUG + printf("bcm57xx: NULL address\n"); +#endif + return 0; + } +// + memcpy( (void *) f_buffer_pc, + (void *) l_cpyaddr_u64, + (size_t) l_ret_i ); + + } + + /* + * replenish bd to producer ring + */ + bcm_rxprod_ring[l_rxprod_prod_u32] = + bcm_rxret_ring[l_rxret_cons_u32]; + bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 = + ( l_rxprod_prod_u32 << 16 ); + bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 += + (uint32_t) BCM_BUF_SIZE; + + /* + * update producer ring's producer index + */ + l_rxprod_prod_u32 = ( l_rxprod_prod_u32 + 1 ) & ( BCM_RXPROD_RING_SIZE - 1 ); + + /* + * move to the next bd in return ring + */ + l_rxret_cons_u32 = ( l_rxret_cons_u32 + 1 ) & ( bcm_rxret_ring_sz - 1 ); + + /* + * synchronize before new indices are send to NIC + */ + mb(); + + /* + * write back new indices + */ + bcm_write_reg32( RXRET_CONS_IND, l_rxret_cons_u32 ); + bcm_write_reg32( RXPROD_PROD_IND, l_rxprod_prod_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_RCV + if( l_ret_i != 0 ) { + printf( "bcm57xx: received bytes: %d\n", l_ret_i ); + } +#ifdef BCM_SHOW_RCV_DATA + for( i = 0, j = 0; i < l_ret_i; i++ ) { + printf( "%02X ", ( uint32_t ) f_buffer_pc[i] ); + + if( ( ++j % 0x18 ) == 0 ) { + printf( "\n" ); + } + } + + if( ( i % 0x18 ) != 0 ) { + printf( "\n" ); + } +#endif +#endif +#endif + + /* + * return packet length + */ + return l_ret_i; +} + +static int +bcm_xmit( char *f_buffer_pc, int f_len_i ) +{ + uint32_t l_tx_cons_u32 = bcm_read_reg32( TX_CONS_IND ); + uint32_t l_tx_prod_u32 = bcm_read_reg32( TX_PROD_IND ); + uint64_t l_cpyaddr_u64; + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_DATA + int i, j; +#endif +#ifdef BCM_SHOW_IDX + printf( "\n" ); + printf( "bcm57xx: TX_PROD_IND : 0x%03X\n", l_tx_prod_u32 ); + printf( "bcm57xx: TX_CONS_IND : 0x%03X\n", l_tx_cons_u32 ); + printf( "bcm57xx: RXPROD_PROD_IND: 0x%03X\n", bcm_read_reg32( RXPROD_PROD_IND ) ); + printf( "bcm57xx: RXPROD_CONS_IND: 0x%03X\n", bcm_read_reg32( RXPROD_CONS_IND ) ); + printf( "bcm57xx: RXRET_PROD_IND : 0x%03X\n", bcm_read_reg32( RXRET_PROD_IND ) ); + printf( "bcm57xx: RXRET_CONS_IND : 0x%03X\n", bcm_read_reg32( RXRET_CONS_IND ) ); + printf( "bcm57xx: available txb : 0x%03X\n", bcm_tx_bufavail_u32 ); +#endif +#ifdef BCM_SHOW_STATS + printf( "bcm57xx: bcm_status.m_st_word_u32: %08X\n", bcm_status.m_st_word_u32 ); + printf( "bcm57xx: bcm_status.m_st_tag_u32 : %08X\n", bcm_status.m_st_tag_u32 ); + printf( "bcm57xx: bcm_status.m_rxprod_cons_u16: %04X\n", ( uint32_t ) bcm_status.m_rxprod_cons_u16 ); + printf( "bcm57xx: bcm_status.m_unused_u16: %04X\n", ( uint32_t ) bcm_status.m_unused_u16 ); + printf( "bcm57xx: bcm_status.m_unused_u32: %08X\n", bcm_status.m_unused_u32 ); + printf( "bcm57xx: bcm_status.m_tx_cons_u16: %04X\n", ( uint32_t ) bcm_status.m_tx_cons_u16 ); + printf( "bcm57xx: bcm_status.m_rxret_prod_u16: %04X\n", ( uint32_t ) bcm_status.m_rxret_prod_u16 ); +#endif +#endif + + bcm_handle_events(); + + /* + * make all consumed bd's available in the ring again + * this way only a few buffers are needed instead of + * having 512 buffers allocated + */ + while( bcm_tx_start_u32 != l_tx_cons_u32 ) { + bcm_tx_ring[bcm_tx_stop_u32] = bcm_tx_ring[bcm_tx_start_u32]; + bcm_tx_stop_u32 = ( bcm_tx_stop_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); + bcm_tx_start_u32 = ( bcm_tx_start_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); + bcm_tx_bufavail_u32++; + } + + /* + * check for tx buffer availability + */ + if( bcm_tx_bufavail_u32 == 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: no more transmit buffers available\n" ); +#endif + return 0; + } + + /* + * setup next available bd in tx ring + */ + bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) /*| BIT32( 6 )*/ ); + bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 += ( (uint32_t) f_len_i << 16 ); +// bcm_tx_ring[l_tx_prod_u32].m_VLANtag_u32 = BCM_VLAN_TAG; + + l_cpyaddr_u64 = ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_hi_u32 << 32 ); + l_cpyaddr_u64 += ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_lo_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_STATS + printf("bcm57xx: xmit: l_cpyaddr_u64: 0x%lx\n", l_cpyaddr_u64 ); + printf(" f_buffer_pc : 0x%lx\n", f_buffer_pc ); + printf(" f_len_i : %d\n", f_len_i ); +#endif +#endif + memcpy( (void *) l_cpyaddr_u64, (void *) f_buffer_pc, (size_t) f_len_i ); + + /* + * update tx producer index & available buffers + */ + l_tx_prod_u32 = ( l_tx_prod_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); + bcm_tx_bufavail_u32--; + + /* + * synchronize before new index is send to NIC + */ + mb(); + + bcm_write_reg32( TX_PROD_IND, l_tx_prod_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT + printf( "bcm57xx: sent bytes: %d\n", f_len_i ); +#ifdef BCM_SHOW_XMIT_DATA + for( i = 0, j = 0; i < f_len_i; i++ ) { + printf( "%02X ", ( uint32_t ) f_buffer_pc[i] ); + + if( ( ++j % 0x18 ) == 0 ) { + printf( "\n" ); + } + + } + if( ( i % 0x18 ) != 0 ) { + printf( "\n" ); + } +#endif +#endif + +#ifdef BCM_SHOW_STATS + // coalesce status block now + bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 3 ) | BIT32( 1 ) ); +#endif + +#endif + return f_len_i; +} + +static int +check_driver( uint16_t vendor_id, uint16_t device_id ) +{ + uint64_t i; + + /* + * checks whether the driver is handling this device + * by verifying vendor & device id + * vendor id 0x14e4 == Broadcom + */ + if( vendor_id != 0x14e4 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: netdevice not supported, illegal vendor id\n" ); +#endif + return -1; + } + + for( i = 0; bcm_dev[i].m_dev_u32 != 0; i++ ) { + if( bcm_dev[i].m_dev_u32 == (uint32_t) device_id ) { + // success + break; + } + } + + if(bcm_dev[i].m_dev_u32 == 0) { +#ifdef BCM_DEBUG + printf( "bcm57xx: netdevice not supported, illegal device ID\n" ); +#endif + return -1; + } + + /* + * initialize static variables + */ + bcm_device_u64 = bcm_dev[i].m_devmsk_u64; + bcm_rxret_ring_sz = 0; + bcm_baseaddr_u64 = 0; + bcm_memaddr_u64 = 0; + + bcm_tx_start_u32 = 0; + bcm_tx_stop_u32 = 0; + bcm_tx_bufavail_u32 = 0; + + return 0; +} + +static void +bcm_wol_activate(void) +{ +#ifdef BCM_DEBUG + uint16_t reg_pwr_cap; +#endif + uint16_t reg_pwr_crtl; + uint32_t wol_mode; + + wol_mode = bcm_read_reg32( WOL_MODE_R ); + bcm_write_reg32( WOL_MODE_R, wol_mode | BIT32(0) ); + +#ifdef BCM_DEBUG + printf( "bcm57xx: WOL activating..." ); +#endif + +// bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_WOL ); +// SLOF_msleep( 100 ); + +#ifdef BCM_DEBUG + reg_pwr_cap = SLOF_pci_config_read16(0x4a); + /*reg_pwr_cap = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4a );*/ + printf( "bcm57xx: PM Capability Register: %04X\n", reg_pwr_cap ); +#endif + /* get curretn power control register */ + reg_pwr_crtl = SLOF_pci_config_read16(0x4c); + /*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c );*/ + +#ifdef BCM_DEBUG + printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + + /* switch to power state D0 */ + reg_pwr_crtl |= 0x8000; + reg_pwr_crtl &= ~(0x0003); + SLOF_pci_config_write16(0x4c, reg_pwr_crtl); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c, + reg_pwr_crtl );*/ + SLOF_msleep(10); + +/* + bcm_write_mem32( BCM_NICDRV_WOL_MBX, BCM_WOL_MAGIC_NUMBER | + NIC_WOLDRV_STATE_SHUTDOWN | + NIC_WOLDRV_WOL | + NIC_WOLDRV_SET_MAGIC_PKT ); +*/ + + /* switch to power state D3hot */ +/* + reg_pwr_crtl |= 0x0103; + SLOF_pci_config_write16(0x4c, reg_pwr_crtl); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c, + reg_pwr_crtl ); + SLOF_msleep(10); +*/ + +#ifdef BCM_DEBUG + reg_pwr_crtl = SLOF_pci_config_read16(0x4c); + /*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c );*/ + + printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + +#ifdef BCM_DEBUG + printf( "bcm57xx: WOL activated" ); +#endif +} + +static int +bcm_init( net_driver_t *driver ) +{ + static const uint32_t lc_Maxwait_u32 = (uint32_t) 1000; + uint32_t l_baseaddrL_u32; + uint32_t l_baseaddrH_u32; + uint32_t i; + uint8_t *mac_addr = driver->mac_addr; + + if(driver->running != 0) { + return 0; + } +#ifdef BCM_DEBUG + printf( "bcm57xx: detected device " ); + if( IS_5703 ) { + printf( "5703S\n" ); + } else if( IS_5704 ) { + printf( "5704" ); + + if( IS_SERDES ) { + printf( "S\n" ); + } else { + printf( "C\n" ); + } + + } else if( IS_5714 ) { + printf( "5714\n" ); + } +#endif + /* + * setup register & memory base addresses of NIC + */ + l_baseaddrL_u32 = (uint32_t) ~0xf & + (uint32_t) SLOF_pci_config_read32(PCI_BAR1_R); + /*l_baseaddrL_u32 = ( (uint32_t) ~0xf & + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR1_R ) );*/ + + l_baseaddrH_u32 = (uint32_t) SLOF_pci_config_read32(PCI_BAR2_R); + /*l_baseaddrH_u32 = + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR2_R );*/ + bcm_baseaddr_u64 = (uint64_t) l_baseaddrH_u32; + bcm_baseaddr_u64 <<= 32; + bcm_baseaddr_u64 += (uint64_t) l_baseaddrL_u32; + bcm_baseaddr_u64 = + (uint64_t) SLOF_translate_my_address((void *)bcm_baseaddr_u64); + /*snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));*/ + bcm_memaddr_u64 = bcm_baseaddr_u64 + BCM_MEMORY_OFFS; + +#ifdef BCM_DEBUG + printf( "bcm57xx: device's register base high address = 0x%08X\n", l_baseaddrH_u32 ); + printf( "bcm57xx: device's register base low address = 0x%08X\n", l_baseaddrL_u32 ); + printf( "bcm57xx: device's register address = 0x%llx\n", bcm_baseaddr_u64 ); +#endif + + /* + * 57xx hardware initialization + * BCM57xx Programmer's Guide: Section 8, "Initialization" + * steps 1 through 101 + */ + + // step 1: enable bus master & memory space in command reg + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i );*/ + // step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i );*/ + + /* + * from now on access may be made through the local + * read/write functions + */ + + // step 3: Save ahche line size register + // omitted, because register is not used for 5704 + + // step 4: acquire the nvram lock + if( bcm_nvram_lock() != 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: locking NVRAM failed\n" ); +#endif + return -1; + } + + // step 5: prepare the chip for writing TG3_MAGIC_NUMBER + bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) ); + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i );*/ + bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) | + BIT32( 17 ) | BIT32( 16 ) | + BIT32( 14 ) | BIT32( 13 ) | + BIT32( 5 ) | BIT32( 4 ) | + BIT32( 2 ) | BIT32( 1 ) ); + + // step 6: write TG3_MAGIC_NUMBER + bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER ); + + // step 7: reset core clocks + + if( IS_5714 ) { + bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) ); + } else { + bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) ); + } + // step 8 + SLOF_msleep( 20 ); + + // step 9: disable & mask interrupts & enable indirect addressing mode & + // enable pci byte/word swapping initialize the misc host control register + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i );*/ + + // step 10: set but master et cetera + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i );*/ + + // step 11: disable PCI-X relaxed ordering + bcm_clrb_reg16( PCI_X_COM_R, BIT16( 1 ) ); + + // step 12: enable the MAC memory arbiter + bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) ); + + // step 13: omitted, only for BCM5700 + // step 14: s. step 10 + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i );*/ + // step 15: set byte swapping (incl. step 27/28/29/30) + // included prohibition of tx/rx interrupts + bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) | + BIT32( 17 ) | BIT32( 16 ) | + BIT32( 14 ) | BIT32( 13 ) | + BIT32( 5 ) | BIT32( 4 ) | + BIT32( 2 ) | BIT32( 1 ) ); + // step 16: omitted + i = 1000; + while( ( --i ) && + ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) { +#ifdef BCM_DEBUG + printf( "." ); +#endif + SLOF_msleep( 1 ); + } + + // return on error + if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { + printf( "bootcode not loaded: %x\n", bcm_read_mem32( BCM_FW_MBX ) ); +#ifdef BCM_DEBUG + printf( "failed\n" ); +#endif + return -1; + } + + + // if ASF Firmware enabled + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); + SLOF_msleep( 10 ); + + // step 17: write ethernet mac mode register + /* + * WY 07.02.07 + * omitted for correct SOL function + */ + /* + if( IS_SERDES ) { + bcm_write_reg32( ETH_MAC_MODE_R, (uint32_t) 0xc ); + } else { + bcm_write_reg32( ETH_MAC_MODE_R, (uint32_t) 0x0 ); + } + */ + + // step 18/19: omitted + // step 20: enable hw bugfix for 5704 + if( IS_5704 || IS_5703 ) { + bcm_setb_reg32( MSG_DATA_R, BIT32( 26 ) | + BIT32( 28 ) | + BIT32( 29 ) ); + } + + // step 21: omitted + // step 22: omitted + // step 23: 5704 clear statistics block + if( IS_5703 || IS_5704 ) { + memset_ci( (void *) ( bcm_memaddr_u64 + BCM_STATISTIC_OFFS ), + 0, + BCM_STATISTIC_SIZE ); + } + + // step 24/25: omitted + // step 26: set DMA Read/Write Control register + // NOTE: recommended values from the spec are used here + if( IS_5714 ) { + bcm_write_reg32( DMA_RW_CTRL_R, DMA_RW_CTRL_VAL_5714 ); + } else { + uint32_t l_PCIState_u32 = bcm_read_reg32( PCI_STATE_R ); + uint32_t l_DMAVal_u32 = DMA_RW_CTRL_VAL; + + if( ( l_PCIState_u32 & BIT32( 2 ) ) != 0 ) { // PCI + l_DMAVal_u32 |= (uint32_t) 0x300000; + } else { // PCI-X + l_DMAVal_u32 |= (uint32_t) 0x900000; + + if( ( bcm_read_reg32( PCI_CLK_CTRL_R ) & (uint32_t) 0x1f ) + >= (uint32_t) 6 ) { + l_DMAVal_u32 |= (uint32_t) 0x4000; + } + + } + + bcm_write_reg32( DMA_RW_CTRL_R, l_DMAVal_u32 ); + } + + // step 27/28/29: s. step 14 + + // step 30: Configure TCP/UDP pseudo header checksum offloading + // already done in step 14: offloading disabled + + // step 31: setup timer prescaler + i = bcm_read_reg32( MISC_CFG_R ); + i &= (uint32_t) ~0xfe; // clear bits 7-1 first + i |= ( BCM_TMR_PRESCALE << 1 ); + bcm_write_reg32( MISC_CFG_R, i ); + + // step 32: 5703/4 configure Mbuf pool address/length + // step 33: 5703/4 configure MAC DMA resource pool + // step 34: configure MAC memory pool watermarks + // step 35: 5703/4 configure DMA resource watermarks + // using recommended settings (hard coded) + if( IS_5703 || IS_5704 ) { + + if( IS_5703 ) { + bcm_write_reg32( MBUF_POOL_ADDR_R, (uint32_t) 0x8000 ); + bcm_write_reg32( MBUF_POOL_LEN_R, (uint32_t) 0x18000 ); + } else { + bcm_write_reg32( MBUF_POOL_ADDR_R, (uint32_t) 0x10000 ); + bcm_write_reg32( MBUF_POOL_LEN_R, (uint32_t) 0x10000 ); + } + + bcm_write_reg32( DMA_DESC_POOL_ADDR_R, (uint32_t) 0x2000 ); + bcm_write_reg32( DMA_DESC_POOL_LEN_R, (uint32_t) 0x2000 ); + + bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (uint32_t) 0x50 ); + bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x20 ); + bcm_write_reg32( MBUF_HIGH_WMARK_R, (uint32_t) 0x60 ); + + bcm_write_reg32( DMA_DESC_LOW_WM_R, (uint32_t) 5 ); + bcm_write_reg32( DMA_DESC_HIGH_WM_R, (uint32_t) 10 ); + } else { + bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (uint32_t) 0x00 ); + bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x10 ); + bcm_write_reg32( MBUF_HIGH_WMARK_R, (uint32_t) 0x60 ); + } + + // step 35: omitted + // step 36: Configure flow control behaviour + // using recommended settings (hard coded) + bcm_write_reg32( LOW_WMARK_MAX_RXFRAM_R, (uint32_t) 0x02 ); + + // step 37/38: enable buffer manager & wait for successful start + bcm_setb_reg32( BUF_MAN_MODE_R, BIT32( 2 ) | BIT32( 1 ) ); + + i = lc_Maxwait_u32; + while( ( --i ) && + ( ( bcm_read_reg32( BUF_MAN_MODE_R ) & BIT32( 1 ) ) == 0 ) ) { + SLOF_usleep( 10 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: init step 38: enable buffer manager failed\n" ); +#endif + return -1; + } + + // step 39: enable internal hardware queues + bcm_write_reg32( FTQ_RES_R, (uint32_t) ~0 ); + bcm_write_reg32( FTQ_RES_R, (uint32_t) 0 ); + + // step 40/41/42: initialize rx producer ring + bcm_init_rxprod_ring(); + + // step 43: set rx producer ring replenish threshold + // using recommended setting of maximum allocated BD's/8 + bcm_write_reg32( STD_RXPR_REP_THR_R, (uint32_t) BCM_MAX_RX_BUF / 8 ); + + // step 44/45/46: initialize send rings + bcm_init_tx_ring(); + bcm_init_rxret_ring(); + + // steps 47-50 done in ring init functions + // step 51: configure MAC unicast address + bcm_nvram_init(); + if( bcm_mac_init( (uint8_t *) mac_addr ) < 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: init step 51: configure MAC unicast address failed\n" ); +#endif + return -1; + } + memcpy(driver->mac_addr, mac_addr, 6); + + // step 52: configure backoff random seed for transmit + // using recommended algorithm + i = (uint32_t) mac_addr[0] + (uint32_t) mac_addr[1] + + (uint32_t) mac_addr[2] + (uint32_t) mac_addr[3] + + (uint32_t) mac_addr[4] + (uint32_t) mac_addr[5]; + i &= (uint32_t) 0x03ff; + bcm_write_reg32( ETH_TX_RND_BO_R, i ); + + // step 53: configure message transfer unit MTU size + bcm_write_reg32( RX_MTU_SIZE_R, (uint32_t) BCM_MTU_MAX_LEN ); + + // step 54: configure IPG for transmit + // using recommended value (through #define) + bcm_write_reg32( TX_MAC_LEN_R, TX_MAC_LEN_VAL ); + + // step 55: configure receive rules + + // set RX rule default class + bcm_write_reg32( RX_RULE_CFG_R, RX_RULE_CFG_VAL ); + + // step 56: configure the number of receive lists + bcm_write_reg32( RX_LST_PLACE_CFG_R, RX_LST_PLC_CFG_VAL ); + bcm_write_reg32( RX_LST_PLACE_STAT_EN_R, RX_LST_PLC_STAT_EN_VAL ); + +/* + // rule 1: accept frames for our MAC address + bcm_write_reg32( RX_RULE_CTRL_R ( 0 ), + BIT32( 31 ) | // enable rule + BIT32( 30 ) | // and with next + BIT32( 26 ) | // split value register + BIT32( 8 ) ); // class 1 + bcm_write_reg32( RX_RULE_VAL_R ( 0 ), + (uint32_t) 0xffff0000 | + ( bcm_read_reg32( MAC_ADDR_OFFS_HI(0) ) & + (uint32_t) 0xffff ) ); + + bcm_write_reg32( RX_RULE_CTRL_R ( 1 ), + BIT32( 31 ) | // enable rule + BIT32( 8 ) | // class 1 + BIT32( 1 ) ); // offset 2 + bcm_write_reg32( RX_RULE_VAL_R ( 1 ), + bcm_read_reg32( MAC_ADDR_OFFS_LO(0) ) ); + + // rule 2: accept broadcast frames + bcm_write_reg32( RX_RULE_CTRL_R ( 2 ), + BIT32( 31 ) | // enable rule + BIT32( 30 ) | // and with next + BIT32( 26 ) | // split value register + BIT32( 8 ) ); // class 1 + bcm_write_reg32( RX_RULE_VAL_R ( 2 ), + (uint32_t) ~0 ); + + bcm_write_reg32( RX_RULE_CTRL_R ( 3 ), + BIT32( 31 ) | // enable rule + BIT32( 8 ) | // class 1 + BIT32( 1 ) ); // offset 2 + bcm_write_reg32( RX_RULE_VAL_R ( 3 ), + (uint32_t) ~0 ); +*/ + for( i=0; i<NUM_RX_RULE_ASF; ++i) { + bcm_write_reg32( RX_RULE_CTRL_R ( i ), 0 ); + bcm_write_reg32( RX_RULE_VAL_R ( i ), 0 ); + } + + // step 57-60: enable rx/tx statistics + // omitted, no need for statistics (so far) + + // step 61/62: disable host coalescing engine/wait 20ms + bcm_write_reg32( HOST_COAL_MODE_R, (uint32_t) 0 ); + + i = lc_Maxwait_u32 * 2; + while( ( --i ) && + ( bcm_read_reg32( HOST_COAL_MODE_R ) != 0 ) ) { + SLOF_usleep( 10 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: init step 62: disable host coal. engine failed\n" ); +#endif + return -1; + } + + // step 63-66: initialize coalescing engine + // NOTE: status block is unused in this driver, + // therefore the coal. engine status block + // automatic update is disabled (by writing + // 0 to every counter + bcm_write_reg32( RX_COAL_TICKS_R, 0 ); + bcm_write_reg32( TX_COAL_TICKS_R, 0 ); + bcm_write_reg32( RX_COAL_MAX_BD_R, 0 ); + bcm_write_reg32( TX_COAL_MAX_BD_R, 0 ); + bcm_write_reg32( RX_COAL_TICKS_INT_R, 0 ); + bcm_write_reg32( TX_COAL_TICKS_INT_R, 0 ); + bcm_write_reg32( RX_COAL_MAX_BD_INT_R, 0 ); + bcm_write_reg32( TX_COAL_MAX_BD_INT_R, 0 ); + + // step 67: initialize host status block address + // NOTE: status block is not needed in this driver, + // still it needs to be set up + i = (uint32_t) ( (uint64_t) &bcm_status >> 32 ); + bcm_write_reg32( STB_HOST_ADDR_HI_R, i ); + i = (uint32_t) ( (uint64_t) &bcm_status & (uint64_t) 0xffffffff ); + bcm_write_reg32( STB_HOST_ADDR_LO_R, i ); + + // 5704/3 adaption + if( IS_5703 || IS_5704 ) { + // step 68: 5704, for now omitted + // step 69: 5704 set the statistics coalescing tick counter + bcm_write_reg32( STAT_TICK_CNT_R, 0 ); + // step 70: 5704 configure statistics block address in NIC memory + // using recommended values (hard coded) + bcm_write_reg32( STAT_NIC_ADDR_R, (uint32_t) 0x300 ); + // step 71: 5704 configure status block address in NIC memory + // using recommended values (hard coded) + bcm_write_reg32( STB_NIC_ADDR_R, (uint32_t) 0xb00 ); + } + + // step 72: enable host coalescing engine + bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 12 ) | BIT32( 11 ) | BIT32( 1 ) ); + + // step 73: enable rx bd completion functional block + bcm_write_reg32( RX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + + // step 74: enable rx list placement functional block + bcm_write_reg32( RX_LST_PLACE_MODE_R, BIT32( 1 ) ); + // 5704/3 adaption + if( IS_5703 || IS_5704 ) { + // step 75: 5704/3 enable receive list selector func block + bcm_write_reg32( RX_LST_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + } + + // step 76: enable DMA engines + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 23 ) | BIT32( 22 ) | BIT32( 21 ) ); + /* + * WY 26.10.07 This is wrong for 5714, better leave it alone + if( IS_5714 ) { + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 20 ) ); + } + */ + + // step 77: omitted, statistics are not used + // step 78: Configure the General Misc Local Control register + // NOTE: as known so far nothing needs to be done here, + // default values should work fine + //bcm_setb_reg32( MISC_LOCAL_CTRL_R, 0 ); + + // step 79: clear interrupts in INT_MBX0_R low word + bcm_write_reg32( INT_MBX0_R, 0 ); + // 5704/3 adaption + // step 80: 5704/3 enable DMA completion functional block + if( IS_5703 || IS_5704 ) { + bcm_write_reg32( DMA_COMPL_MODE_R, BIT32( 1 ) ); + } + + // step 81/82: configure write/read DMA mode registers + // disable MSI + bcm_write_reg32( RD_DMA_MODE_R, BIT32( 10 ) | BIT32( 9 ) | BIT32( 8 ) | + BIT32( 7 ) | BIT32( 6 ) | BIT32( 5 ) | + BIT32( 4 ) | BIT32( 3 ) | BIT32( 2 ) | + BIT32( 1 ) ); + bcm_write_reg32( WR_DMA_MODE_R, BIT32( 9 ) | BIT32( 8 ) | BIT32( 7 ) | + BIT32( 6 ) | BIT32( 5 ) | BIT32( 4 ) | + BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) ); + bcm_clrb_reg32( MSI_MODE_R, BIT32( 1 ) ); + SLOF_usleep( 100 ); + + // step 83-91: enable all these functional blocks... + bcm_write_reg32( RX_DAT_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + + if( IS_5703 || IS_5704 ) { + bcm_write_reg32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) ); + } + + bcm_write_reg32( TX_DAT_COMPL_MODE_R, BIT32( 1 ) ); + bcm_write_reg32( TX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + bcm_write_reg32( RX_BD_INIT_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + bcm_write_reg32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_write_reg32( TX_DAT_INIT_MODE_R, BIT32( 1 ) | BIT32( 3 ) ); + bcm_write_reg32( TX_BD_INIT_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + bcm_write_reg32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + + // step 92: omitted + // step 93/94: Enable Tx/Rx MAC + bcm_setb_reg32( TX_MAC_MODE_R, BIT32( 1 ) ); +// bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); // set BIT32( 8 ) for promiscious mode! + bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) ); // set BIT32( 8 ) for promiscious mode! + // set BIT32( 10) for VLAN + + // step 95: disable auto polling: + // bcm_phy_init takes care of this + // step 96: omitted + // step 97: omitted, may change though, but is not important + // step 98: activate link & enable MAC functional block + // NOTE autopolling is enabled so bit 0 needs not to be set + //bcm_setb_reg32( MI_STATUS_R, BIT32( 0 ) ); + + // step 99: setup PHY + // return if link is down + if( bcm_phy_init() < 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: init step 99: PHY initialization failed\n" ); +#endif + return -1; + } + + // step 100: setup multicast filters + bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0 ); + bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0 ); + bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0 ); + bcm_write_reg32( MAC_HASH3_R, (uint32_t) 0 ); +/* + // accept all multicast frames + bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH3_R, (uint32_t) 0xffffffff ); +*/ + // step 101: omitted, no interrupts used + + // make initial receive buffers available for NIC + // this step has to be done here after RX DMA engine has started (step 94) + bcm_write_reg32( RXPROD_PROD_IND, BCM_MAX_RX_BUF ); + + // if ASF Firmware enabled + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE ); + SLOF_msleep( 10 ); + + // enable heartbeat timer + + bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 0x5 ); + + driver->running = 1; + // off we go.. + return 0; +} + +static int +bcm_reset( void ) +{ + uint32_t i; + +#ifdef BCM_DEBUG + printf( "bcm57xx: resetting controller.." ); +#endif + + bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER ); + + if( IS_5714 ) { + bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) ); + } else { + bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) ); + } + + SLOF_msleep( 20 ); + + /* + * after reset local read/write functions cannot be used annymore + * until bus master & stuff is set up again + */ + + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i );*/ + + // step 9 & 13: disable & mask interrupts & enable indirect addressing mode & + // enable pci byte/word swapping initialize the misc host control register + i = ( BIT32( 7 ) | BIT32( 5 ) | BIT32( 4 ) | + BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i );*/ + + // step 16: poll for bootcode completion by waiting for the one's + // complement of the magic number previously written + i = 1000; + while( ( --i ) && + ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) { +#ifdef BCM_DEBUG + printf( "." ); +#else + SLOF_msleep( 1 ); +#endif + } + + // return on error + if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { +#ifdef BCM_DEBUG + printf( "failed\n" ); +#endif + return -1; + } + +#ifdef BCM_DEBUG + printf( "done\n" ); +#endif + return 0; +} + +static int +bcm_term( void ) +{ + uint32_t i; + uint16_t v; + +#ifdef BCM_DEBUG + printf( "bcm57xx: driver shutdown.." ); +#endif + + /* + * halt ASF firmware + */ + bcm_fw_halt(); + + /* + * unload ASF firmware + */ + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD ); + + /* + * disable RX producer rings + */ + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_JUM ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_MIN ), 0 ); + + /* + * disable RX return rings + */ + v = BCM_RXRET_RCB_OFFS; + for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * disable TX rings + */ + v = BCM_TX_RCB_OFFS; + for( i = 0; i < BCM_MAX_TX_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * remove receive rules + */ + bcm_write_reg32( RX_RULE_CTRL_R ( 0 ), 0 ); + bcm_write_reg32( RX_RULE_VAL_R ( 0 ), 0 ); + bcm_write_reg32( RX_RULE_CTRL_R ( 1 ), 0 ); + bcm_write_reg32( RX_RULE_VAL_R ( 1 ), 0 ); + + /* + * shutdown sequence + * BCM57xx Programmer's Guide: Section 8, "Shutdown" + * the enable bit of every state machine of the 57xx + * has to be reset. + */ + + /* + * receive path shutdown sequence + */ + bcm_clr_wait_bit32( RX_MAC_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_LST_PLACE_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_DAT_COMPL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_BD_COMPL_MODE_R, BIT32( 1 ) ); + + if( IS_5704 || IS_5703 ) { + bcm_clr_wait_bit32( RX_LST_SEL_MODE_R, BIT32( 1 ) ); + } + + /* + * transmit path & memory shutdown sequence + */ + bcm_clr_wait_bit32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( TX_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( TX_DAT_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RD_DMA_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( TX_DAT_COMPL_MODE_R, BIT32( 1 ) ); + + if( IS_5704 ) { + bcm_clr_wait_bit32( DMA_COMPL_MODE_R, BIT32( 1 ) ); + } + + bcm_clr_wait_bit32( TX_BD_COMPL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( ETH_MAC_MODE_R, BIT32( 21 ) ); + bcm_clr_wait_bit32( TX_MAC_MODE_R, BIT32( 1 ) ); + + bcm_clr_wait_bit32( HOST_COAL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( WR_DMA_MODE_R, BIT32( 1 ) ); + + if( IS_5704 || IS_5703 ) { + bcm_clr_wait_bit32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) ); + } + + bcm_write_reg32( FTQ_RES_R, (uint32_t) ~0 ); + bcm_write_reg32( FTQ_RES_R, (uint32_t) 0 ); + + if( IS_5704 || IS_5703 ) { + bcm_clr_wait_bit32( BUF_MAN_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( MEMARB_MODE_R, BIT32( 1 ) ); + } + +#ifdef BCM_DEBUG + printf( "done.\n" ); +#endif + /* + * controller reset + */ + if( bcm_reset() != 0 ) { + return -1; + } + + /* + * restart ASF firmware + */ + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD ); + SLOF_msleep( 10 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD_DONE ); + SLOF_msleep( 100 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); + SLOF_msleep( 10 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE ); + + /* + * activate Wake-on-LAN + */ + bcm_wol_activate(); + + /* + * PCI shutdown + */ + bcm_clrb_reg32( PCI_MISC_HCTRL_R, BIT32( 3 ) | BIT32( 2 ) ); + + /* + * from now on local rw functions cannot be used anymore + */ + +// bcm_clrb_reg32( PCI_COM_R, BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + + SLOF_pci_config_write32(PCI_COM_R, BIT32(8) | BIT32(6)); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + BIT32(8) | BIT32(6) );*/ + + // no more networking... + return 0; +} + +static int +bcm_getmac(uint32_t addr, char mac[6]) +{ + uint32_t t1, t2; + uint64_t t3; + + if (bcm_nvram_read(addr, &t1, 1) != 0) + return -1; + if (bcm_nvram_read(addr+4, &t2, 1) != 0) + return -1; + t3 = ((uint64_t)t1 << 32) + t2; + + mac[0] = (t3 >> 40) & 0xFF; + mac[1] = (t3 >> 32) & 0xFF; + mac[2] = (t3 >> 24) & 0xFF; + mac[3] = (t3 >> 16) & 0xFF; + mac[4] = (t3 >> 8) & 0xFF; + mac[5] = (t3 >> 0) & 0xFF; + + return 0; +} + +static char* +print_itoa(char *text, uint32_t value) +{ + if(value >= 10) + text = print_itoa(text, value / 10); + *text = '0' + (value % 10); + ++text; + return text; +} + +static int +bcm_get_version(char *text) +{ + uint32_t t1; + + if (bcm_nvram_read(0x94, &t1, 1) != 0) + return -1; + + text = print_itoa(text, (t1 >> 8) & 0xFF); + text[0] = '.'; + text = print_itoa(&text[1], t1 & 0xFF); + text[0] = '\n'; + return 0; +} + +static uint32_t +util_gen_crc( char *pcDatabuf, uint32_t ulDatalen, uint32_t ulCrc_in) +{ + unsigned char data; + uint32_t idx, bit, crc = ulCrc_in; + + for(idx = 0; idx < ulDatalen; idx++) { + data = *pcDatabuf++; + for(bit = 0; bit < 8; bit++, data >>= 1) { + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? + CRC32_POLYNOMIAL : 0); + } + } + return bswap_32(~crc); +} + +static int +bcm_setmac(char mac_addr1[6], char mac_addr2[6]) +{ + uint64_t mac1 = 0, mac2 = 0; + uint32_t manu[MANUFACTURING_INFO_SIZE/4]; + int addr, i; + uint32_t crc, val1, val2, val3, val4; + +#ifdef BCM_DEBUG + printf("Flashing MAC 1: %02X:%02X:%02X:%02X:%02X:%02X\n", + ((unsigned int) mac_addr1[0]) & 0xFF, + ((unsigned int) mac_addr1[1]) & 0xFF, + ((unsigned int) mac_addr1[2]) & 0xFF, + ((unsigned int) mac_addr1[3]) & 0xFF, + ((unsigned int) mac_addr1[4]) & 0xFF, + ((unsigned int) mac_addr1[5]) & 0xFF); + + printf("Flashing MAC 2: %02X:%02X:%02X:%02X:%02X:%02X\n", + ((unsigned int) mac_addr2[0]) & 0xFF, + ((unsigned int) mac_addr2[1]) & 0xFF, + ((unsigned int) mac_addr2[2]) & 0xFF, + ((unsigned int) mac_addr2[3]) & 0xFF, + ((unsigned int) mac_addr2[4]) & 0xFF, + ((unsigned int) mac_addr2[5]) & 0xFF); +#endif + + mac1 |= ((uint64_t) mac_addr1[0]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[1]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[2]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[3]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[4]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[5]) & 0xFF; + + mac2 |= ((uint64_t) mac_addr2[0]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[1]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[2]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[3]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[4]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[5]) & 0xFF; + + /* Extract the manufacturing data, starts at 0x74 */ + if(bcm_nvram_lock() == -1) { + return -1; + } + + addr = 0x74; + for (i = 0; i < (MANUFACTURING_INFO_SIZE/4); i++) { + if (bcm_nvram_read(addr, &manu[i], 0) != 0) { + printf("\nREAD FAILED\n"); + bcm_nvram_unlock(); + return -1; + } + addr+=4; + } + bcm_nvram_unlock(); + + /* Store the new MAC address in the manufacturing data */ + val1 = mac1 >> 32; + val2 = mac1 & 0xFFFFFFFF; + val3 = mac2 >> 32; + val4 = mac2 & 0xFFFFFFFF; + manu[(0x7C-0x74)/4] = val1; + manu[(0x80-0x74)/4] = val2; + manu[(0xCC-0x74)/4] = val3; + manu[(0xD0-0x74)/4] = val4; + + /* Calculate the new manufacturing datas CRC */ + crc = util_gen_crc(((char *)manu), + MANUFACTURING_INFO_SIZE - 4, 0xFFFFFFFF); + + /* Now write the new MAC addresses and CRC */ + if ((bcm_nvram_write(0x7C, val1, 1) != 0) || + (bcm_nvram_write(0x80, val2, 1) != 0) || + (bcm_nvram_write(0xCC, val3, 1) != 0) || + (bcm_nvram_write(0xD0, val4, 1) != 0) || + (bcm_nvram_write(0xFC, crc, 1) != 0) ) + { + /* Disastor ! */ +#ifdef BCM_DEBUG + printf("failed to write MAC address\n"); +#endif + return -1; + } + + /* Success !!!! */ + return 0; +} + +static int +bcm_ioctl( int request, void* data ) +{ + uint32_t l_baseaddrL_u32; + uint32_t l_baseaddrH_u32; + uint32_t i; + int ret_val = 0; + char mac_addr[6]; + ioctl_net_data_t *ioctl_data = (ioctl_net_data_t*) data; + + if(request != SIOCETHTOOL) { + return -1; + } + +#ifdef BCM_DEBUG + printf( "bcm57xx: detected device " ); + if( IS_5703 ) { + printf( "5703S" ); + } else if( IS_5704 ) { + printf( "5704" ); + if( IS_SERDES ) { + printf( "S\n" ); + } else { + printf( "C\n" ); + } + } else if( IS_5714 ) { + printf( "5714\n" ); + } +#endif + /* + * setup register & memory base addresses of NIC + */ + l_baseaddrL_u32 = (uint32_t) ~0xf & + SLOF_pci_config_read32(PCI_BAR1_R); + /*l_baseaddrL_u32 = ( (uint32_t) ~0xf & + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR1_R ) );*/ + + l_baseaddrH_u32 = SLOF_pci_config_read32(PCI_BAR2_R); + /*l_baseaddrH_u32 = + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR2_R );*/ + + bcm_baseaddr_u64 = (uint64_t) l_baseaddrH_u32; + bcm_baseaddr_u64 <<= 32; + bcm_baseaddr_u64 += (uint64_t) l_baseaddrL_u32; + bcm_baseaddr_u64 = + (uint64_t)SLOF_translate_my_address((void *)bcm_baseaddr_u64); + /*snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));*/ + bcm_memaddr_u64 = bcm_baseaddr_u64 + BCM_MEMORY_OFFS; + + /* + * 57xx hardware initialization + * BCM57xx Programmer's Guide: Section 8, "Initialization" + * steps 1 through 101 + */ + + // step 1: enable bus master & memory space in command reg + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i );*/ + + // step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode + i = ( BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i );*/ + + bcm_nvram_init(); + + switch(ioctl_data->subcmd) { + case ETHTOOL_GMAC: + switch(ioctl_data->data.mac.idx) { + case 0: + ret_val = bcm_getmac(0x7C, ioctl_data->data.mac.address); + break; + case 1: + ret_val = bcm_getmac(0xCC, ioctl_data->data.mac.address); + break; + default: + ret_val = -1; + break; + } + break; + case ETHTOOL_SMAC: + switch(ioctl_data->data.mac.idx) { + case 0: + ret_val = bcm_getmac(0xCC, mac_addr); + if(ret_val == 0) + ret_val = bcm_setmac(ioctl_data->data.mac.address, mac_addr); + break; + case 1: + ret_val = bcm_getmac(0x7C, mac_addr); + if(ret_val == 0) + ret_val = bcm_setmac(mac_addr, ioctl_data->data.mac.address); + break; + default: + ret_val = -1; + break; + } + break; + case ETHTOOL_VERSION: { + char *text = ioctl_data->data.version.text; + memcpy(text, " BCM57xx Boot code level: ", 27); + ret_val = bcm_get_version(&text[27]); + break; + } + default: + ret_val = -1; + break; + } + + bcm_term(); + return ret_val; +} + +net_driver_t *bcm57xx_open(void) +{ + net_driver_t *driver; + uint16_t vendor_id, device_id; + + vendor_id = SLOF_pci_config_read16(0); + device_id = SLOF_pci_config_read16(2); + if (check_driver(vendor_id, device_id)) + return NULL; + + driver = SLOF_alloc_mem(sizeof(*driver)); + if (!driver) { + printf("Unable to allocate virtio-net driver\n"); + return NULL; + } + memset(driver, 0, sizeof(*driver)); + + if (bcm_init(driver)) + goto FAIL; + + return driver; + +FAIL: SLOF_free_mem(driver, sizeof(*driver)); + return NULL; + + return 0; +} + +void bcm57xx_close(net_driver_t *driver) +{ + if (driver->running == 0) + return; + + bcm_term(); + driver->running = 0; + SLOF_free_mem(driver, sizeof(*driver)); +} + +int bcm57xx_read(char *buf, int len) +{ + if (buf) + return bcm_receive(buf, len); + return -1; +} + +int bcm57xx_write(char *buf, int len) +{ + if (buf) + return bcm_xmit(buf, len); + return -1; +} diff --git a/qemu/roms/SLOF/lib/libbcm/bcm57xx.h b/qemu/roms/SLOF/lib/libbcm/bcm57xx.h new file mode 100644 index 000000000..efaba60c6 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbcm/bcm57xx.h @@ -0,0 +1,323 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cache.h> +#include <netdriver.h> + +// Debug switches +//#define BCM_DEBUG // main debug switch, w/o it the other ones don't work +//#define BCM_SHOW_RCV +//#define BCM_SHOW_RCV_DATA +//#define BCM_SHOW_XMIT +//#define BCM_SHOW_XMIT_DATA +//#define BCM_SHOW_XMIT_STATS +//#define BCM_SHOW_IDX +//#define BCM_SHOW_STATS +//#define BCM_SHOW_ASF_REGS + +// Switch to enable SW AUTO-NEG +// don't try, it's still incomplete +//#define BCM_SW_AUTONEG + +/* + * used register offsets + */ +// PCI command register +#define PCI_COM_R ( (uint16_t) 0x0004 ) +// PCI Cache Line Size register +#define PCI_CACHELS_R ( (uint16_t) 0x000c ) +// PCI bar1 register +#define PCI_BAR1_R ( (uint16_t) 0x0010 ) +// PCI bar2 register +#define PCI_BAR2_R ( (uint16_t) 0x0014 ) +// PCI bar1 register +#define PCI_SUBID_R ( (uint16_t) 0x002e ) +// PCI-X Comand register +#define PCI_X_COM_R ( (uint16_t) 0x0042 ) +// Message Data Register +#define MSG_DATA_R ( (uint16_t) 0x0064 ) +// PCI misc host contrl register +#define PCI_MISC_HCTRL_R ( (uint16_t) 0x0068 ) +// DMA Read/Write Control register +#define DMA_RW_CTRL_R ( (uint16_t) 0x006c ) +// PCI State register +#define PCI_STATE_R ( (uint16_t) 0x0070 ) +// PCI_Clock Control register +#define PCI_CLK_CTRL_R ( (uint16_t) 0x0074 ) +// Register Base Address Register +#define REG_BASE_ADDR_REG ( (uint16_t) 0x0078 ) +// Memory Window Base Address Register +#define MEM_BASE_ADDR_REG ( (uint16_t) 0x007c ) +// Register Data Register +#define REG_DATA_REG ( (uint16_t) 0x0080 ) +// Memory Window Data Register +#define MEM_DATA_REG ( (uint16_t) 0x0084 ) +// MAC Function register +#define MAC_FUNC_R ( (uint16_t) 0x00b8 ) +// Interrupt Mailbox 0 register +#define INT_MBX0_R ( (uint16_t) 0x0204 ) +// Ethernet MAC Mode register +#define ETH_MAC_MODE_R ( (uint16_t) 0x0400 ) +// Ethernet MAC Addresses registers +#define MAC_ADDR_OFFS_HI( idx ) ( (uint16_t) ( (idx*2 + 0)*sizeof( uint32_t ) + 0x0410 ) ) +#define MAC_ADDR_OFFS_LO( idx ) ( (uint16_t) ( (idx*2 + 1)*sizeof( uint32_t ) + 0x0410 ) ) +// Ethernet MAC Status register +#define ETH_MAC_STAT_R ( (uint16_t) 0x0404 ) +// Ethernet MAC Event Enable register +#define ETH_MAC_EVT_EN_R ( (uint16_t) 0x0408 ) +// Ethernet Transmit Random Backoff register +#define ETH_TX_RND_BO_R ( (uint16_t) 0x0438 ) +// Receive MTU Size register +#define RX_MTU_SIZE_R ( (uint16_t) 0x043c ) +// Transmit 1000BASE-X Auto Negotiation register +#define TX_1000BX_AUTONEG_R ( (uint16_t) 0x0444 ) +// Receive 1000BASE-X Auto Negotiation register +#define RX_1000BX_AUTONEG_R ( (uint16_t) 0x0448 ) +// MI Communication register +#define MI_COM_R ( (uint16_t) 0x044c ) +// MI Status Register +#define MI_STATUS_R ( (uint16_t) 0x0450 ) +// MI Mode register +#define MI_MODE_R ( (uint16_t) 0x0454 ) +// Transmit MAC Mode register +#define TX_MAC_MODE_R ( (uint16_t) 0x045c ) +// Transmit MAC Length register +#define TX_MAC_LEN_R ( (uint16_t) 0x0464 ) +// Receive MAC Mode register +#define RX_MAC_MODE_R ( (uint16_t) 0x0468 ) +// MAC Hash 0 register* VPD Config: +#define MAC_HASH0_R ( (uint16_t) 0x0470 ) +// MAC Hash 1 register +#define MAC_HASH1_R ( (uint16_t) 0x0474 ) +// MAC Hash 2 register +#define MAC_HASH2_R ( (uint16_t) 0x0478 ) +// MAC Hash 3 register +#define MAC_HASH3_R ( (uint16_t) 0x047c ) +// Receive Rules Control register +#define RX_RULE_CTRL_R( idx ) ( (uint16_t) ( idx*8 + 0x0480 ) ) +// Receive Rules Value register +#define RX_RULE_VAL_R( idx ) ( (uint16_t) ( idx*8 + 0x0484 ) ) +// Receive Rules Configuration register +#define RX_RULE_CFG_R ( (uint16_t) 0x0500 ) +// Low Watermark Max Receive Frames register +#define LOW_WMARK_MAX_RXFRAM_R ( (uint16_t) 0x0504 ) +// SerDes Control Register +#define SERDES_CTRL_R ( (uint16_t) 0x0590 ) +// Hardware Auto Negotiation Control Register +#define HW_AUTONEG_CTRL_R ( (uint16_t) 0x05B0 ) +// Hardware Auto Negotiation Status Register +#define HW_AUTONEG_STAT_R ( (uint16_t) 0x05B4 ) +// Send Data Initiator Mode register +#define TX_DAT_INIT_MODE_R ( (uint16_t) 0x0c00 ) +// Send Data Completion Mode register +#define TX_DAT_COMPL_MODE_R ( (uint16_t) 0x1000 ) +// Send BD Ring Selector Mode register +#define TX_BD_RING_SEL_MODE_R ( (uint16_t) 0x1400 ) +// Send BD Initiator Mode register +#define TX_BD_INIT_MODE_R ( (uint16_t) 0x1800 ) +// Send BD Completion Mode register +#define TX_BD_COMPL_MODE_R ( (uint16_t) 0x1c00 ) +// Receive List Placement Mode register +#define RX_LST_PLACE_MODE_R ( (uint16_t) 0x2000 ) +// Receive List Placement Configuration register +#define RX_LST_PLACE_CFG_R ( (uint16_t) 0x2010 ) +// Receive List Placement Statistics Enable Mask register +#define RX_LST_PLACE_STAT_EN_R ( (uint16_t) 0x2018 ) +// Receive Data & Receive BD Initiator Mode register +#define RX_DAT_BD_INIT_MODE_R ( (uint16_t) 0x2400 ) +// Receive Data Completion Mode register +#define RX_DAT_COMPL_MODE_R ( (uint16_t) 0x2800 ) +// Receive BD Initiator Mode register +#define RX_BD_INIT_MODE_R ( (uint16_t) 0x2c00 ) +// Standard Receive Producer Ring Replenish Threshold register +#define STD_RXPR_REP_THR_R ( (uint16_t) 0x2c18 ) +// Receive BD Completion Mode register +#define RX_BD_COMPL_MODE_R ( (uint16_t) 0x3000 ) +// Receive List Selector Mode register +#define RX_LST_SEL_MODE_R ( (uint16_t) 0x3400 ) +// MBUF Cluster Free Mode register +#define MBUF_CLSTR_FREE_MODE_R ( (uint16_t) 0x3800 ) +// Host Coalescing Mode register +#define HOST_COAL_MODE_R ( (uint16_t) 0x3c00 ) +// Receive Coalescing Ticks register +#define RX_COAL_TICKS_R ( (uint16_t) 0x3c08 ) +// Send Coalescing Ticks register +#define TX_COAL_TICKS_R ( (uint16_t) 0x3c0c ) +// Receive Max Coalesced BD Count register +#define RX_COAL_MAX_BD_R ( (uint16_t) 0x3c10 ) +// Send Max Coalesced BD Count register +#define TX_COAL_MAX_BD_R ( (uint16_t) 0x3c14 ) +// Receive Coalescing Ticks During Int register +#define RX_COAL_TICKS_INT_R ( (uint16_t) 0x3c18 ) +// Send Coalescing Ticks During Int register +#define TX_COAL_TICKS_INT_R ( (uint16_t) 0x3c1c ) +// Receive Max Coalesced BD Count During Int register +#define RX_COAL_MAX_BD_INT_R ( (uint16_t) 0x3c18 ) +// Send Max Coalesced BD Count During Int register +#define TX_COAL_MAX_BD_INT_R ( (uint16_t) 0x3c1c ) +// Statistics Ticks Counter register +#define STAT_TICK_CNT_R ( (uint16_t) 0x3c28 ) +// Status Block Host Address Low register +#define STB_HOST_ADDR_HI_R ( (uint16_t) 0x3c38 ) +// Status Block Host Address High register +#define STB_HOST_ADDR_LO_R ( (uint16_t) 0x3c3c ) +// Statistics Base Address register +#define STAT_NIC_ADDR_R ( (uint16_t) 0x3c40 ) +// Status Block Base Address register +#define STB_NIC_ADDR_R ( (uint16_t) 0x3c44 ) +// Memory Arbiter Mode register +#define MEMARB_MODE_R ( (uint16_t) 0x4000 ) +// Buffer Manager Mode register +#define BUF_MAN_MODE_R ( (uint16_t) 0x4400 ) +// MBuf Pool Address register +#define MBUF_POOL_ADDR_R ( (uint16_t) 0x4408 ) +// MBuf Pool Length register +#define MBUF_POOL_LEN_R ( (uint16_t) 0x440c ) +// Read DMA Mbuf Low Watermark register +#define DMA_RMBUF_LOW_WMARK_R ( (uint16_t) 0x4410 ) +// MAC Rx Mbuf Low Watermark register +#define MAC_RXMBUF_LOW_WMARK_R ( (uint16_t) 0x4414 ) +// Mbuf High Watermark register +#define MBUF_HIGH_WMARK_R ( (uint16_t) 0x4418 ) +// DMA Descriptor Pool Address register +#define DMA_DESC_POOL_ADDR_R ( (uint16_t) 0x442c ) +// DMA Descriptor Pool Length register +#define DMA_DESC_POOL_LEN_R ( (uint16_t) 0x4430 ) +// DMA Descriptor Low Watermark register +#define DMA_DESC_LOW_WM_R ( (uint16_t) 0x4434 ) +// DMA Descriptor HIGH Watermark register +#define DMA_DESC_HIGH_WM_R ( (uint16_t) 0x4438 ) +// Read DMA Mode register +#define RD_DMA_MODE_R ( (uint16_t) 0x4800 ) +// Write DMA Mode register +#define WR_DMA_MODE_R ( (uint16_t) 0x4c00 ) +// FTQ Reset register +#define FTQ_RES_R ( (uint16_t) 0x5c00 ) +// MSI Mode register +#define MSI_MODE_R ( (uint16_t) 0x6000 ) +// DMA completion Mode register +#define DMA_COMPL_MODE_R ( (uint16_t) 0x6400 ) +// Mode Control register +#define MODE_CTRL_R ( (uint16_t) 0x6800 ) +// Misc Configuration register +#define MISC_CFG_R ( (uint16_t) 0x6804 ) +// Misc Local Control register +#define MISC_LOCAL_CTRL_R ( (uint16_t) 0x6808 ) +// RX-Risc Mode Register +#define RX_CPU_MODE_R ( (uint16_t) 0x5000 ) +// RX-Risc State Register +#define RX_CPU_STATE_R ( (uint16_t) 0x5004 ) +// RX-Risc Program Counter +#define RX_CPU_PC_R ( (uint16_t) 0x501c ) +// RX-Risc Event Register +#define RX_CPU_EVENT_R ( (uint16_t) 0x6810 ) +// MDI Control register +#define MDI_CTRL_R ( (uint16_t) 0x6844 ) +// WOL Mode register +#define WOL_MODE_R ( (uint16_t) 0x6880 ) +// WOL Config register +#define WOL_CFG_R ( (uint16_t) 0x6884 ) +// WOL Status register +#define WOL_STATUS_R ( (uint16_t) 0x6888 ) + +// ASF Control register +#define ASF_CTRL_R ( (uint16_t) 0x6c00 ) +// ASF Watchdog Timer register +#define ASF_WATCHDOG_TIMER_R ( (uint16_t) 0x6c0c ) +// ASF Heartbeat Timer register +#define ASF_HEARTBEAT_TIMER_R ( (uint16_t) 0x6c10 ) +// Poll ASF Timer register +#define ASF_POLL_TIMER_R ( (uint16_t) 0x6c14 ) +// Poll Legacy Timer register +#define POLL_LEGACY_TIMER_R ( (uint16_t) 0x6c18 ) +// Retransmission Timer register +#define RETRANSMISSION_TIMER_R ( (uint16_t) 0x6c1c ) +// Time Stamp Counter register +#define TIME_STAMP_COUNTER_R ( (uint16_t) 0x6c20 ) + +// NVM Command register +#define NVM_COM_R ( (uint16_t) 0x7000 ) +// NVM Write register +#define NVM_WRITE_R ( (uint16_t) 0x7008 ) +// NVM Address register +#define NVM_ADDR_R ( (uint16_t) 0x700c ) +// NVM Read registertg3_phy_copper_begin +#define NVM_READ_R ( (uint16_t) 0x7010 ) +// NVM Access register +#define NVM_ACC_R ( (uint16_t) 0x7024 ) +// NVM Config 1 register +#define NVM_CFG1_R ( (uint16_t) 0x7014 ) +// Software arbitration register +#define SW_ARB_R ( (uint16_t) 0x7020 ) + +/* + * useful def's + */ +#define rd08(a) ci_read_8((uint8_t *)(a)) +#define rd16(a) ci_read_16((uint16_t *)(a)) +#define rd32(a) ci_read_32((uint32_t *)(a)) +#define wr08(a,v) ci_write_8((uint8_t *)(a), (v)) +#define wr16(a,v) ci_write_16((uint16_t *)(a), (v)) +#define wr32(a,v) ci_write_32((uint32_t *)(a), (v)) + +#define BIT08( bit ) ( (uint8_t) 0x1 << (bit) ) +#define BIT16( bit ) ( (uint16_t) 0x1 << (bit) ) +#define BIT32( bit ) ( (uint32_t) 0x1 << (bit) ) + +/* + * type definition + */ + +/* + * Constants for different kinds of IOCTL requests + */ + +#define SIOCETHTOOL 0x1000 + +/* + * special structure and constants for IOCTL requests of type ETHTOOL + */ + +#define ETHTOOL_GMAC 0x03 +#define ETHTOOL_SMAC 0x04 +#define ETHTOOL_VERSION 0x05 + +typedef struct { + int idx; + char address[6]; +} ioctl_ethtool_mac_t; + +typedef struct { + unsigned int length; + char *text; +} ioctl_ethtool_version_t; + + +/* + * default structure and constants for IOCTL requests + */ + +#define IF_NAME_SIZE 0xFF + +typedef struct { + char if_name[IF_NAME_SIZE]; + int subcmd; + union { + ioctl_ethtool_mac_t mac; + ioctl_ethtool_version_t version; + } data; +} ioctl_net_data_t; + +extern net_driver_t *bcm57xx_open(void); +extern void bcm57xx_close(net_driver_t *driver); +extern int bcm57xx_read(char *buf, int len); +extern int bcm57xx_write(char *buf, int len); diff --git a/qemu/roms/SLOF/lib/libbootmsg/Makefile b/qemu/roms/SLOF/lib/libbootmsg/Makefile new file mode 100644 index 000000000..642c970ac --- /dev/null +++ b/qemu/roms/SLOF/lib/libbootmsg/Makefile @@ -0,0 +1,75 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) -I. -I../../include +LDFLAGS = -nostdlib + +TARGET = ../libbootmsg.a + + +all: $(TARGET) + +ifeq ($(CPUARCH),cbea) +SRCS = +SRCSS = bootmsg_lvl.S +else +ifeq ($(CPUARCH),ppc970) +SRCS = +SRCSS = bootmsg_lvl.S +else +ifeq ($(CPUARCH),p5) +SRCS = +SRCSS = bootmsg_lvl.S +else +ifeq ($(CPUARCH),ppcp7) +SRCS = +SRCSS = bootmsg_lvl.S +else +SRCS = bootmsg.c +SRCSS = +endif +endif +endif +endif + +OBJS = $(SRCS:%.c=%.o) $(SRCSS:%.S=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +%.o: %.S + $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep + diff --git a/qemu/roms/SLOF/lib/libbootmsg/bootmsg.code b/qemu/roms/SLOF/lib/libbootmsg/bootmsg.code new file mode 100644 index 000000000..ae370af08 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbootmsg/bootmsg.code @@ -0,0 +1,61 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <libbootmsg.h> + +// : cp ( cp-id -- ) +PRIM(bootmsg_X2d_cp) + int cpid = TOS.n; POP; + bootmsg_cp(cpid); +MIRP + +// : bootmsg-warning ( cp-id lvl pstr -- ) +PRIM(bootmsg_X2d_warning) + char* str = TOS.a; POP; + short lvl = TOS.n; POP; + short cpid = TOS.n; POP; + bootmsg_warning(cpid, (const char*)str, lvl); +MIRP + +// : bootmsg-error ( cp-id pstr -- ) +PRIM(bootmsg_X2d_error) + char* str = TOS.a; POP; + short cpid = TOS.n; POP; + bootmsg_error(cpid, (const char*)str); +MIRP + +// : bootmsg-debugcp ( cp-id lvl pstr -- ) +PRIM(bootmsg_X2d_debugcp) + char* str = TOS.a; POP; + short lvl = TOS.n; POP; + short cpid = TOS.n; POP; + bootmsg_debugcp(cpid, (const char*)str, lvl); +MIRP + +// : bootmsg-setlevel ( area lvl -- ) +PRIM(bootmsg_X2d_setlevel) + char lvl = TOS.n; POP; + short area = TOS.n; POP; + bootmsg_setlevel(area, lvl); +MIRP + +// : bootmsg-checklevel ( area lvl -- [true|false] ) +PRIM(bootmsg_X2d_checklevel) + char lvl = TOS.n; POP; + short area = TOS.n; POP; + PUSH; + TOS.n = (bootmsg_checklevel(area, lvl)) ? -1 : 0; +MIRP + +// : bootmsg-nvupdate ( -- ) +PRIM(bootmsg_X2d_nvupdate) + bootmsg_nvupdate(); +MIRP diff --git a/qemu/roms/SLOF/lib/libbootmsg/bootmsg.in b/qemu/roms/SLOF/lib/libbootmsg/bootmsg.in new file mode 100644 index 000000000..73e01e3d5 --- /dev/null +++ b/qemu/roms/SLOF/lib/libbootmsg/bootmsg.in @@ -0,0 +1,19 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +cod(bootmsg-cp) +cod(bootmsg-warning) +cod(bootmsg-error) +cod(bootmsg-debugcp) +cod(bootmsg-setlevel) +cod(bootmsg-nvupdate) +cod(bootmsg-checklevel) diff --git a/qemu/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S b/qemu/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S new file mode 100644 index 000000000..2e4c1359a --- /dev/null +++ b/qemu/roms/SLOF/lib/libbootmsg/bootmsg_lvl.S @@ -0,0 +1,204 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#define _ASM_ +#include "macros.h" +#include "southbridge.h" +#include "nvramlog.h" + +#define bootmsg_area_size 128 + + .text + .align 3 + +// Declare the warning level for all 128 possibilities of AC/pCKG kombinations + WRNG_LVL: + .rept bootmsg_area_size + .byte 0x0 + .endr + + +//***************************************************************************** +// Check UserWarningLevel against SystemWarningLevel +// input : r3=cp-id, r5=level +// change: r6,r7 +// output: CR0 ( compared user vs system level ) +// example: +// bl GET_WRNG_LVL +// ble print_warning +// bgt do_not_print_warning +ENTRY(GET_WRNG_LVL) + mflr r7 // save linkage register + bl 0f // get current +0: mflr r6 // Instruction Address + mtlr r7 // restore linkage register + addi r6,r6,WRNG_LVL-0b // calc addr of WRNG_LVL array + rldic r7,r3,56,57 // calc index into array + lbzux r7,r6,r7 // read the warning level + cmpw r5,r7 // and compare it + blr + +//***************************************************************************** +// Print CheckPoint +// input : r3=cp-id +// change: r3, r4, r5, r6, r7, r11 +// output: none +ENTRY(bootmsg_cp) + mflr r11 + mr r9, r3 // save checkpoint ID + li r3, 'C' + bl io_putchar // print character + mr r3, r9 + bl io_printhex16 // print checkpoint ID + .rept 5 + li r3,'\b' + bl io_putchar // print backspaces + .endr + mtlr r11 + blr + +//***************************************************************************** +// Print a general BootMessage +// input : r3=cp-id, r4=string, r5=char (type C,W,E) +// change: r3,r4,r5,r6,r7,r9,r10,r11,r12 +// output: none +ENTRY(print_msg) + mflr r11 // Save linkage register + mr r9, r3 // Save ID + mr r10, r4 // Save ptr to string + mr r12, r5 // Save type (char [CWE]) + li r3, '\n' // make it a new line + bl io_putchar + li r3, '\r' + bl io_putchar + mr r3, r12 // restore type + bl io_putchar // print character + mr r3, r9 // restore ID + bl io_printhex16 // print checkpoint ID + li r3, ' ' // print a space + bl io_putchar + mr r3, r10 // restore ptr to string + bl io_print // print message + li r3, '\n' // add a new line + bl io_putchar + li r3, '\r' + bl io_putchar + mtlr r11 // restore linkage register + blr + +//***************************************************************************** +// Print an Error Boot Message +// input : r3=cp-id, r4=string-ptr +// change : r3,r4,r5,r6,r7,r9,r10,r11,r12 +// output : none +ENTRY(bootmsg_error) + li r5, 'E' // E is for Error + b print_msg // and print this message + +//***************************************************************************** +// Print a Warning Boot Message +// input : r3=cp-id, r4=string-ptr, r5=level +// change : r3,r4,r5,r6,r7,r9,r10,r11,r12 +// output : none +ENTRY(bootmsg_warning) + mflr r11 // save linkage register + bl GET_WRNG_LVL // check UserLevel against SystemLevel + mtlr r11 // restore linkage register + li r5, 'W' // 'W' is for Warning + ble print_msg // if UserLevel<=SystemLevel print and return + blr // else return + +//***************************************************************************** +// Print a Debug Checkpoint +// input : r3=cp-id, r4=string-ptr, r5=level +// change : r3,r4,r5,r6,r7,r9,r10,r11,r12 +// output : none +// r3=cp-id, r4=string, r5=level +ENTRY(bootmsg_debugcp) + mflr r11 // save linkage register + addi r5,r5,0x20 // add checkpoint offset + bl GET_WRNG_LVL // check UserLevel against SystemLevel + mtlr r11 // restore linkage register + li r5, 'D' // 'D' is for Debug CheckPoint + ble print_msg // if UserLevel<=SystemLevel print and return + blr // else return + +//***************************************************************************** +// Check warning level +// input : r3=cp-id, r4=level +// change : r3,r4,r5,r6,r7,r9,r10,r11 +// output : r3 (true, false) +// r3=cp-id, r4=level +ENTRY(bootmsg_checklevel) + mflr r11 + mr r5, r4 + slwi r3, r3, 8 + bl GET_WRNG_LVL // check UserLevel against SystemLevel + li r3, 0 // return 0 + bgt 0f // IF ( UserLevel < SystemLevel ) + li r3, 1 // | return 1 +0: mtlr r11 // FI + blr + +// r3=area|pkg, r4=level +ENTRY(bootmsg_setlevel) + mflr r5 + bl WarningMsg // calc current IA + WarningMsg: + mflr r6 // get current IA + addi r6,r6,WRNG_LVL-WarningMsg + andi. r3, r3, 0x7F + add r6,r3,r6 // address | + stb r4,0(r6) // store level |_ stwbrx r4,r3,r6 + +#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM) + LOAD64(r6, SB_NVRAM_FWONLY_adr + 8 ) + add r6,r6,r3 + stb r4,0(r6) +#endif + mtlr r5 + blr + +ENTRY(bootmsg_nvupdate) +#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM) + mflr r10 + LOAD64(r3, SB_NVRAM_FWONLY_adr) + lwz r4, 0(r3) + cmpwi r4, 0x424E // find bootmsg area header + bne 0f + + LOAD64(r5, bootmsg_area_size/8) + mtctr r5 + bl WngMsg + WngMsg: + mflr r5 + addi r5,r5,WRNG_LVL-WngMsg-8 + +1: + ldu r4, 8(r3) + stdu r4, 8(r5) + bdnz+ 1b + b 2f + +0: + LOAD64(r5, bootmsg_area_size) + mtctr r5 + li r4, 0x424E // clear bootmsg log area + stw r4, 0(r3) + li r4, 0 + +1: stdu r4, 8(r3) + bdnz+ 1b + +2: // the end + mtlr r10 +#endif + blr diff --git a/qemu/roms/SLOF/lib/libbootmsg/libbootmsg.h b/qemu/roms/SLOF/lib/libbootmsg/libbootmsg.h new file mode 100644 index 000000000..9d0bd157d --- /dev/null +++ b/qemu/roms/SLOF/lib/libbootmsg/libbootmsg.h @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef _LIBBOOTMSG_H +#define _LIBBOOTMSG_H +void bootmsg_cp(short p); +void bootmsg_error(short p, const char *str); +void bootmsg_warning(short p, const char *str, short lvl); +void bootmsg_debugcp(short p, const char *str, short lvl); +void bootmsg_setlevel(short p, short level); +int bootmsg_checklevel(short p, short level); +void *bootmsg_nvupdate(void); +#endif /* _LIBBOOTMSG_H */ diff --git a/qemu/roms/SLOF/lib/libc/Makefile b/qemu/roms/SLOF/lib/libc/Makefile new file mode 100644 index 000000000..0c762ec8b --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/Makefile @@ -0,0 +1,61 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +LIBCCMNDIR = $(shell pwd) +STRINGCMNDIR = $(LIBCCMNDIR)/string +CTYPECMNDIR = $(LIBCCMNDIR)/ctype +STDLIBCMNDIR = $(LIBCCMNDIR)/stdlib +STDIOCMNDIR = $(LIBCCMNDIR)/stdio +GETOPTCMNDIR = $(LIBCCMNDIR)/getopt + +include $(TOPCMNDIR)/make.rules + + +CPPFLAGS = -I$(LIBCCMNDIR)/include +LDFLAGS= -nostdlib + +TARGET = ../libc.a + + +all: $(TARGET) + +# Use the following target to build a native version of the lib +# (for example for debugging purposes): +native: + $(MAKE) CROSS="" CC=$(HOSTCC) NATIVEBUILD=1 + + +include $(STRINGCMNDIR)/Makefile.inc +include $(CTYPECMNDIR)/Makefile.inc +include $(STDLIBCMNDIR)/Makefile.inc +include $(STDIOCMNDIR)/Makefile.inc +include $(GETOPTCMNDIR)/Makefile.inc + +OBJS = $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) $(GETOPT_OBJS) + +ifneq ($(NATIVEBUILD),1) +# These parts of the libc use assembler, so they can only be compiled when +# we are _not_ building a native version. +endif + + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean diff --git a/qemu/roms/SLOF/lib/libc/README.txt b/qemu/roms/SLOF/lib/libc/README.txt new file mode 100644 index 000000000..eaafdf4af --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/README.txt @@ -0,0 +1,49 @@ + + Standard C library for the SLOF firmware project + ================================================ + +To use this library, link your target against the "libc.a" archive. + +However, there are some prerequisites before you can use certain parts of the +library: + +1) If you want to use malloc() and the like, you have to supply an implemen- + tation of sbrk() in your own code. malloc() uses sbrk() to get new, free + memory regions. + + Prototype: void *sbrk(int incr); + Description: sbrk() increments the available data space by incr bytes and + returns a pointer to the start of the new area. + + See the man-page of sbrk for details about this function. + +2) Before you can use the stdio output functions like printf(), puts() and the + like, you have to provide a standard write() function in your code. + printf() and the like use write() to print out the strings to the standard + output. + + Prototype: ssize_t write(int fd, const void *buf, size_t cnt); + Description: Write cnt byte from the buffer buf to the stream associated + with the file descriptor fd. + + The stdio functions will print their output to the stdout channel which is + assigned with the file descriptor 1 by default. Note that the stdio + functions will not use open() before calling write(), so if the stdout + cannel needs to be opened first, you should do that in your start-up code + before using the libc functions for the first time. + +3) Before you can use the stdio input functions like scanf() and the + like, you have to provide a standard read() function in your code. + scanf() and the like use read() to get the characters from the standard + input. + + Prototype: ssize_t read(int fd, void *buf, size_t cnt); + Description: Read cnt byte from the stream associated with the file + descriptor fd and put them into the buffer buf. + + The stdio functions will get their input from the stdin channel which is + assigned with the file descriptor 0 by default. Note that the stdio + functions will not use open() before calling read(), so if the stdin + cannel needs to be opened first, you should do that in your start-up code + before using the libc functions for the first time. + diff --git a/qemu/roms/SLOF/lib/libc/ctype/Makefile.inc b/qemu/roms/SLOF/lib/libc/ctype/Makefile.inc new file mode 100644 index 000000000..25513a9a7 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/ctype/Makefile.inc @@ -0,0 +1,20 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +CTYPE_SRC_C = isdigit.c isprint.c isspace.c isxdigit.c tolower.c toupper.c +CTYPE_SRC_ASM = +CTYPE_SRCS = $(CTYPE_SRC_C:%=$(CTYPECMNDIR)/%) $(CTYPE_SRC_ASM:%=$(CTYPECMNDIR)/%) +CTYPE_OBJS = $(CTYPE_SRC_C:%.c=%.o) $(CTYPE_SRC_ASM:%.S=%.o) + +%.o : $(CTYPECMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/qemu/roms/SLOF/lib/libc/ctype/isdigit.c b/qemu/roms/SLOF/lib/libc/ctype/isdigit.c new file mode 100644 index 000000000..62d08a1cf --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/ctype/isdigit.c @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <ctype.h> + +int isdigit(int ch) +{ + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return 1; + + default: + return 0; + } +} diff --git a/qemu/roms/SLOF/lib/libc/ctype/isprint.c b/qemu/roms/SLOF/lib/libc/ctype/isprint.c new file mode 100644 index 000000000..c74880f1c --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/ctype/isprint.c @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <ctype.h> + +int isprint(int ch) +{ + return (ch >= 32 && ch < 127); +} diff --git a/qemu/roms/SLOF/lib/libc/ctype/isspace.c b/qemu/roms/SLOF/lib/libc/ctype/isspace.c new file mode 100644 index 000000000..51230192f --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/ctype/isspace.c @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <ctype.h> + +int isspace(int ch) +{ + switch (ch) { + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + return 1; + + default: + return 0; + } +} diff --git a/qemu/roms/SLOF/lib/libc/ctype/isxdigit.c b/qemu/roms/SLOF/lib/libc/ctype/isxdigit.c new file mode 100644 index 000000000..9d323f3c0 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/ctype/isxdigit.c @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <ctype.h> + +int isxdigit(int ch) +{ + return ( + (ch >= '0' && ch <= '9') | + (ch >= 'A' && ch <= 'F') | + (ch >= 'a' && ch <= 'f') ); +} diff --git a/qemu/roms/SLOF/lib/libc/ctype/tolower.c b/qemu/roms/SLOF/lib/libc/ctype/tolower.c new file mode 100644 index 000000000..f775e9096 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/ctype/tolower.c @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <ctype.h> + +int tolower(int c) +{ + return (((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a' ) : c); +} diff --git a/qemu/roms/SLOF/lib/libc/ctype/toupper.c b/qemu/roms/SLOF/lib/libc/ctype/toupper.c new file mode 100644 index 000000000..9bcee523d --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/ctype/toupper.c @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "ctype.h" + +int toupper (int cha) +{ + if((cha >= 'a') && (cha <= 'z')) + return(cha - 'a' + 'A'); + return(cha); +} diff --git a/qemu/roms/SLOF/lib/libc/getopt/Makefile.inc b/qemu/roms/SLOF/lib/libc/getopt/Makefile.inc new file mode 100644 index 000000000..8a2e32f00 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/getopt/Makefile.inc @@ -0,0 +1,17 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +GETOPT_SRC_C = getopt.c +GETOPT_OBJS = $(GETOPT_SRC_C:%.c=%.o) + +%.o : $(GETOPTCMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/qemu/roms/SLOF/lib/libc/getopt/getopt.c b/qemu/roms/SLOF/lib/libc/getopt/getopt.c new file mode 100644 index 000000000..be626ddc2 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/getopt/getopt.c @@ -0,0 +1,470 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * includes + ******************************************************************************* + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +/* + * global variables, types & constants + * may be removed if already defined + ******************************************************************************* + */ +int opterr = 1; +int optopt = 0; +int optind = 1; +char *optarg = NULL; + +/* + * internal values needed by getopt + * DO NOT CHANGE or REMOVE + */ +enum { + OPTIONAL_ARG = 0, + MANDATORY_ARG = 1, + NO_ARG = 2 +}; + +/* + * variables needed by getopt & getopt_long! + * DO NOT REMOVE + */ +static char *optstart = NULL; + +int +getopt(int argc, char **argv, const char *options) +{ + char *optptr; + char *argptr; + int optman; + int idx; + int ret = 0; + int argpresent; + + /* + * reset used global values + */ + optopt = 0; + optarg = NULL; + + /* + * reset getopt if a new argv pointer is passed + */ + if (optstart != argv[0]) { + optopt = 0; + optind = 1; + optarg = NULL; + optstart = argv[0]; + } + + /* + * return if no more arguments are available + */ + if (optind >= argc) { + return -1; + } + + /* + * start parsing argv[optind] + */ + idx = 0; + + /* + * return if the option does not begin with a '-' or has more than 2 characters + */ + if (argv[optind][idx] != '-') { + + if (opterr != 0) { + printf("unknown option \'%s\', expecting \'-\'\n", + argv[optind]); + } + + optopt = (int) argv[optind][idx]; + optind++; + + return '?'; + } + + /* + * continue to the next character in argv[optind] + */ + idx++; + + /* + * identify the option + * make sure if an option contains a ':' to invalidate the option + */ + optptr = strchr(argv[optind], ':'); + + if (optptr == NULL) { + optptr = strchr(options, (int) argv[optind][idx]); + } else { + optptr = NULL; + } + + /* + * check whether the option is present + */ + if (optptr == NULL) { + /* + * unknown option detected + */ + if (opterr != 0) { + printf("unknown option \'%s\'\n", argv[optind]); + } + + optopt = (int) argv[optind][idx]; + optind++; + + return '?'; + } + + /* + * the option is present in the option string + * setup return value + */ + ret = (int) *optptr; + + /* + * get option argument if needed + */ + optptr++; + + /* + * determine between mandatory and optional argument + */ + optman = NO_ARG; + + if (*optptr == ':') { + optman--; // now set to MANDATORY_ARG + } + + if (optman == MANDATORY_ARG) { + optptr++; + + if (*optptr == ':') { + optman--; // now set to OPTIONAL_ARG + } + + } + + /* + * if strlen( argv[optind ) is greater than 2, + * the argument is in the same argv + */ + if (strlen(argv[optind]) > 2) { + argptr = &argv[optind][2]; + + /* + * do not allow '-' in an argument + */ + if (strchr(argptr, '-') != NULL) { + + if (opterr != 0) { + printf + ("illegal argument value \'%s\' for option \'-%c\'\n", + argptr, ret); + } + + optopt = ret; + + return '?'; + } + + } else { + /* + * move on to the next argv + * it now either contains an argument or the next option + */ + optind++; + + /* + * make sure not to overflow + */ + if (optind < argc) { + argptr = argv[optind]; + } else { + argptr = NULL; + } + + } + + /* + * do the needed actions for the argument state + */ + switch (optman) { + case OPTIONAL_ARG: + + if (argptr == NULL) { + break; + } + + if (*argptr != '-') { + /* + * argument present + */ + optarg = argptr; + optind++; + + } + + + break; + + case MANDATORY_ARG: + argpresent = (argptr != NULL); + + if (argpresent) { + argpresent = (*argptr != '-'); + } + + if (argpresent) { + /* + * argument present + */ + optarg = argptr; + optind++; + } else { + /* + * mandatory argument missing + */ + if (opterr != 0) { + printf + ("missing argument for option \'-%c\'\n", + ret); + } + + optopt = ret; + + /* + * if the first character of options is a ':' + * return a ':' instead of a '?' in case of + * a missing argument + */ + if (*options == ':') { + ret = ':'; + } else { + ret = '?'; + } + + } + + + break; + + case NO_ARG: + + if (strlen(argv[optind - 1]) > 2) { + + if (opterr != 0) { + printf + ("too many arguments for option \'-%c\'\n", + ret); + } + + optopt = ret; + ret = '?'; + } + + + break; + + } + + return ret; +} + +int +getopt_long(int argc, char **argv, const char *shortopts, + const struct option *longopts, int *indexptr) +{ + struct option *optptr = (struct option *) longopts; + int optidx = 0; + int idx; + int ret = 0; + int argpresent; + + /* + * reset used global values + */ + optopt = 0; + optarg = NULL; + + /* + * reset indexptr + */ + *indexptr = -1; + + /* + * reset getopt if a new argv pointer is passed + */ + if (optstart != argv[0]) { + optopt = 0; + optind = 1; + optarg = NULL; + optstart = argv[0]; + } + + /* + * return if no more arguments are available + */ + if (optind >= argc) { + return -1; + } + + /* + * start parsing argv[optind] + */ + idx = 0; + + /* + * return if the option does not begin with a '-' + */ + if (argv[optind][idx] != '-') { + printf("unknown option \'%s\', expecting \'-\'\n", + argv[optind]); + + optind++; + + return '?'; + } + + /* + * move on to the next character in argv[optind] + */ + idx++; + + /* + * return getopt() in case of a short option + */ + if (argv[optind][idx] != '-') { + return getopt(argc, argv, shortopts); + } + + /* + * handle a long option + */ + idx++; + + while (optptr->name != NULL) { + + if (strcmp(&argv[optind][idx], optptr->name) == 0) { + break; + } + + optptr++; + optidx++; + } + + /* + * no matching option found + */ + if (optptr->name == NULL) { + printf("unknown option \'%s\'\n", argv[optind]); + + optind++; + + return '?'; + } + + /* + * option was found, set up index pointer + */ + *indexptr = optidx; + + /* + * get argument + */ + optind++; + + switch (optptr->has_arg) { + case no_argument: + /* + * nothing to do + */ + + break; + + case required_argument: + argpresent = (optind != argc); + + if (argpresent) { + argpresent = (argv[optind][0] != '-'); + } + + if (argpresent) { + /* + * argument present + */ + optarg = argv[optind]; + optind++; + } else { + /* + * mandatory argument missing + */ + printf("missing argument for option \'%s\'\n", + argv[optind - 1]); + + ret = '?'; + } + + + break; + + case optional_argument: + + if (optind == argc) { + break; + } + + if (argv[optind][0] != '-') { + /* + * argument present + */ + optarg = argv[optind]; + optind++; + } + + + break; + + default: + printf("unknown argument option for option \'%s\'\n", + argv[optind - 1]); + + ret = '?'; + + break; + + } + + /* + * setup return values + */ + if (ret != '?') { + + if (optptr->flag == NULL) { + ret = optptr->val; + } else { + *optptr->flag = optptr->val; + ret = 0; + } + + } + + return ret; +} diff --git a/qemu/roms/SLOF/lib/libc/include/ctype.h b/qemu/roms/SLOF/lib/libc/include/ctype.h new file mode 100644 index 000000000..9051a7563 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/ctype.h @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _CTYPE_H +#define _CTYPE_H + +int isdigit(int c); +int isxdigit(int c); +int isprint(int c); +int isspace(int c); + +int tolower(int c); +int toupper(int c); + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/errno.h b/qemu/roms/SLOF/lib/libc/include/errno.h new file mode 100644 index 000000000..d5859347e --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/errno.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _ERRNO_H +#define _ERRNO_H + +extern int errno; + +/* + * Error number definitions + */ +#define EPERM 1 /* not permitted */ +#define ENOENT 2 /* file or directory not found */ +#define EIO 5 /* input/output error */ +#define ENOMEM 12 /* not enough space */ +#define EACCES 13 /* permission denied */ +#define EFAULT 14 /* bad address */ +#define EBUSY 16 /* resource busy */ +#define EEXIST 17 /* file already exists */ +#define ENODEV 19 /* device not found */ +#define EINVAL 22 /* invalid argument */ +#define EDOM 33 /* math argument out of domain of func */ +#define ERANGE 34 /* math result not representable */ + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/getopt.h b/qemu/roms/SLOF/lib/libc/include/getopt.h new file mode 100644 index 000000000..5956986a5 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/getopt.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef GETOPT_H +#define GETOPT_H + +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +enum { + no_argument = 0, + required_argument, + optional_argument +}; + +int getopt(int argc, char **, const char *); +int getopt_long(int argc, char **, const char *, const struct option *, int *); + +#endif /* GETOPT_H */ diff --git a/qemu/roms/SLOF/lib/libc/include/limits.h b/qemu/roms/SLOF/lib/libc/include/limits.h new file mode 100644 index 000000000..4726835c2 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/limits.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _LIMITS_H +#define _LIMITS_H + +#define UCHAR_MAX 255 +#define SCHAR_MAX 127 +#define SCHAR_MIN (-128) + +#define USHRT_MAX 65535 +#define SHRT_MAX 32767 +#define SHRT_MIN (-32768) + +#define UINT_MAX (4294967295U) +#define INT_MAX 2147483647 +#define INT_MIN (-2147483648) + +#define ULONG_MAX ((unsigned long)-1L) +#define LONG_MAX (ULONG_MAX/2) +#define LONG_MIN ((-LONG_MAX)-1) + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/stdarg.h b/qemu/roms/SLOF/lib/libc/include/stdarg.h new file mode 100644 index 000000000..d3d12f778 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/stdarg.h @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _STDARG_H +#define _STDARG_H + +typedef __builtin_va_list va_list; + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_arg(v,l) __builtin_va_arg(v,l) +#define va_end(v) __builtin_va_end(v) + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/stdbool.h b/qemu/roms/SLOF/lib/libc/include/stdbool.h new file mode 100644 index 000000000..5b7d36a7e --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/stdbool.h @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus +typedef enum { false = 0, true } bool; +#endif + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/stddef.h b/qemu/roms/SLOF/lib/libc/include/stddef.h new file mode 100644 index 000000000..ba2d96098 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/stddef.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _STDDEF_H +#define _STDDEF_H + + +#define NULL ((void *)0) + + +typedef unsigned int size_t; + + +#endif + + diff --git a/qemu/roms/SLOF/lib/libc/include/stdint.h b/qemu/roms/SLOF/lib/libc/include/stdint.h new file mode 100644 index 000000000..518a72305 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/stdint.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _STDINT_H +#define _STDINT_H + +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; + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/stdio.h b/qemu/roms/SLOF/lib/libc/include/stdio.h new file mode 100644 index 000000000..84cddea07 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/stdio.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _STDIO_H +#define _STDIO_H + +#include <stdarg.h> +#include "stddef.h" + +#define EOF (-1) + +#define _IONBF 0 +#define _IOLBF 1 +#define _IOFBF 2 +#define BUFSIZ 80 + +typedef struct { + int fd; + int mode; + int pos; + char *buf; + int bufsiz; +} FILE; + +extern FILE stdin_data; +extern FILE stdout_data; +extern FILE stderr_data; + +#define stdin (&stdin_data) +#define stdout (&stdout_data) +#define stderr (&stderr_data) + +int fileno(FILE *stream); +int printf(const char *format, ...) __attribute__((format (printf, 1, 2))); +int fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +int sprintf(char *str, const char *format, ...) __attribute__((format (printf, 2, 3))); +int vfprintf(FILE *stream, const char *format, va_list); +int vsprintf(char *str, const char *format, va_list); +int vsnprintf(char *str, size_t size, const char *format, va_list); +void setbuf(FILE *stream, char *buf); +int setvbuf(FILE *stream, char *buf, int mode , size_t size); + +int putc(int ch, FILE *stream); +int putchar(int ch); +int puts(char *str); + +int scanf(const char *format, ...) __attribute__((format (scanf, 1, 2))); +int fscanf(FILE *stream, const char *format, ...) __attribute__((format (scanf, 2, 3))); +int vfscanf(FILE *stream, const char *format, va_list); +int vsscanf(const char *str, const char *format, va_list); +int getc(FILE *stream); +int getchar(void); + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/stdlib.h b/qemu/roms/SLOF/lib/libc/include/stdlib.h new file mode 100644 index 000000000..dff57f577 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/stdlib.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _STDLIB_H +#define _STDLIB_H + +#include "stddef.h" + +#define RAND_MAX 32767 + + +void *malloc(size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); +void *memalign(size_t boundary, size_t size); + +int atoi(const char *str); +long atol(const char *str); +unsigned long int strtoul(const char *nptr, char **endptr, int base); +long int strtol(const char *nptr, char **endptr, int base); + +int rand(void); + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/string.h b/qemu/roms/SLOF/lib/libc/include/string.h new file mode 100644 index 000000000..0163c9a67 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/string.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _STRING_H +#define _STRING_H + +#include "stddef.h" + +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, size_t n); +char *strcat(char *dest, const char *src); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +int strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +size_t strlen(const char *s); +char *strstr(const char *hay, const char *needle); +char *strtok(char *src, const char *pattern); + +void *memset(void *s, int c, size_t n); +void *memchr(const void *s, int c, size_t n); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); + +#endif diff --git a/qemu/roms/SLOF/lib/libc/include/unistd.h b/qemu/roms/SLOF/lib/libc/include/unistd.h new file mode 100644 index 000000000..07210d69a --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/include/unistd.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include <stddef.h> + +typedef long ssize_t; + +extern int open(const char *name, int flags); +extern int close(int fd); +extern ssize_t read(int fd, void *buf, size_t count); +extern ssize_t write(int fd, const void *buf, size_t count); +extern ssize_t lseek(int fd, long offset, int whence); + +extern void *sbrk(int increment); + +#endif diff --git a/qemu/roms/SLOF/lib/libc/stdio/Makefile.inc b/qemu/roms/SLOF/lib/libc/stdio/Makefile.inc new file mode 100644 index 000000000..ac5302d01 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/Makefile.inc @@ -0,0 +1,23 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +STDIO_SRC_C = fscanf.c sprintf.c vfprintf.c vsnprintf.c vsprintf.c fprintf.c \ + printf.c setvbuf.c putc.c puts.c putchar.c scanf.c stdchnls.c \ + vfscanf.c vsscanf.c fileno.c + +STDIO_SRC_ASM = +STDIO_SRCS = $(STDIO_SRC_C:%=$(STDIOCMNDIR)/%) $(STDIO_SRC_ASM:%=$(STDIOCMNDIR)/%) +STDIO_OBJS = $(STDIO_SRC_C:%.c=%.o) $(STDIO_SRC_ASM:%.S=%.o) + +%.o : $(STDIOCMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/qemu/roms/SLOF/lib/libc/stdio/fileno.c b/qemu/roms/SLOF/lib/libc/stdio/fileno.c new file mode 100644 index 000000000..6e239511d --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/fileno.c @@ -0,0 +1,19 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> + +int +fileno(FILE *stream) +{ + return stream->fd; +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/fprintf.c b/qemu/roms/SLOF/lib/libc/stdio/fprintf.c new file mode 100644 index 000000000..866df3934 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/fprintf.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "stdio.h" + + +int fprintf(FILE *stream, const char* fmt, ...) +{ + int count; + va_list ap; + + va_start(ap, fmt); + count = vfprintf(stream, fmt, ap); + va_end(ap); + + return count; +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/fscanf.c b/qemu/roms/SLOF/lib/libc/stdio/fscanf.c new file mode 100644 index 000000000..321b1630a --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/fscanf.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> + +int +fscanf(FILE *stream, const char *fmt, ...) +{ + int count; + va_list ap; + + va_start(ap, fmt); + count = vfscanf(stream, fmt, ap); + va_end(ap); + + return count; +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/printf.c b/qemu/roms/SLOF/lib/libc/stdio/printf.c new file mode 100644 index 000000000..01f4592dd --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/printf.c @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "stdio.h" + + +int printf(const char* fmt, ...) +{ + int count; + va_list ap; + + va_start(ap, fmt); + count = vfprintf(stdout, fmt, ap); + va_end(ap); + + return count; +} + diff --git a/qemu/roms/SLOF/lib/libc/stdio/putc.c b/qemu/roms/SLOF/lib/libc/stdio/putc.c new file mode 100644 index 000000000..230e9d196 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/putc.c @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "stdio.h" +#include "unistd.h" + +int +putc(int ch, FILE *stream) +{ + unsigned char outchar = ch; + + if (write(stream->fd, &outchar, 1) == 1) + return outchar; + else + return EOF; +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/putchar.c b/qemu/roms/SLOF/lib/libc/stdio/putchar.c new file mode 100644 index 000000000..5c750d90a --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/putchar.c @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "stdio.h" + + +int +putchar(int ch) +{ + return putc(ch, stdout); +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/puts.c b/qemu/roms/SLOF/lib/libc/stdio/puts.c new file mode 100644 index 000000000..3f48dbfda --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/puts.c @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "stdio.h" +#include "string.h" +#include "unistd.h" + + +int +puts(char *str) +{ + int ret; + + ret = write(stdout->fd, str, strlen(str)); + write(stdout->fd, "\r\n", 2); + + return ret; +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/scanf.c b/qemu/roms/SLOF/lib/libc/stdio/scanf.c new file mode 100644 index 000000000..96b639980 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/scanf.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> + +int +scanf(const char *fmt, ...) +{ + int count; + va_list ap; + + va_start(ap, fmt); + count = vfscanf(stdin, fmt, ap); + va_end(ap); + + return count; +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/setvbuf.c b/qemu/roms/SLOF/lib/libc/stdio/setvbuf.c new file mode 100644 index 000000000..9b62dd8ff --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/setvbuf.c @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> + +int setvbuf(FILE *stream, char *buf, int mode , size_t size) +{ + if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) + return -1; + stream->buf = buf; + stream->mode = mode; + stream->bufsiz = size; + return 0; +} + +void setbuf(FILE *stream, char *buf) +{ + setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ); +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/sprintf.c b/qemu/roms/SLOF/lib/libc/stdio/sprintf.c new file mode 100644 index 000000000..9c4540e2e --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/sprintf.c @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> + + +int sprintf(char *buff, const char *format, ...) +{ + va_list ar; + int count; + + if ((buff==NULL) || (format==NULL)) + return(-1); + + va_start(ar, format); + count = vsprintf(buff, format, ar); + va_end(ar); + + return(count); +} + diff --git a/qemu/roms/SLOF/lib/libc/stdio/stdchnls.c b/qemu/roms/SLOF/lib/libc/stdio/stdchnls.c new file mode 100644 index 000000000..41ed958bf --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/stdchnls.c @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "stdio.h" + +static char stdin_buffer[BUFSIZ], stdout_buffer[BUFSIZ]; + +FILE stdin_data = { .fd = 0, .mode = _IOLBF, .pos = 0, + .buf = stdin_buffer, .bufsiz = BUFSIZ }; +FILE stdout_data = { .fd = 1, .mode = _IOLBF, .pos = 0, + .buf = stdout_buffer, .bufsiz = BUFSIZ }; +FILE stderr_data = { .fd = 2, .mode = _IONBF, .pos = 0, + .buf = NULL, .bufsiz = 0 }; diff --git a/qemu/roms/SLOF/lib/libc/stdio/vfprintf.c b/qemu/roms/SLOF/lib/libc/stdio/vfprintf.c new file mode 100644 index 000000000..765feeace --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/vfprintf.c @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "stdio.h" +#include "unistd.h" + + +int vfprintf(FILE *stream, const char *fmt, va_list ap) +{ + int count; + char buffer[320]; + + count = vsnprintf(buffer, sizeof(buffer), fmt, ap); + write(stream->fd, buffer, count); + + return count; +} + diff --git a/qemu/roms/SLOF/lib/libc/stdio/vfscanf.c b/qemu/roms/SLOF/lib/libc/stdio/vfscanf.c new file mode 100644 index 000000000..4ddd210a9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/vfscanf.c @@ -0,0 +1,266 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "string.h" +#include "ctype.h" +#include "stdlib.h" +#include "stdio.h" +#include "unistd.h" + + +static int +_getc(FILE * stream) +{ + int count; + char c; + + if (stream->mode == _IONBF || stream->buf == NULL) { + if (read(stream->fd, &c, 1) == 1) + return (int) c; + else + return EOF; + } + + if (stream->pos == 0 || stream->pos >= BUFSIZ || + stream->buf[stream->pos] == '\0') { + count = read(stream->fd, stream->buf, BUFSIZ); + if (count < 0) + count = 0; + if (count < BUFSIZ) + stream->buf[count] = '\0'; + stream->pos = 0; + } + + return stream->buf[stream->pos++]; +} + +static void +_ungetc(int ch, FILE * stream) +{ + if (stream->mode != _IONBF && stream->pos > 0) + stream->pos--; +} + +static int +_is_voidage(int ch) +{ + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\0') + return 1; + else + return 0; +} + + +static int +_scanf(FILE * stream, const char *fmt, va_list * ap) +{ + int i = 0; + int length = 0; + + fmt++; + + while (*fmt != '\0') { + + char tbuf[256]; + char ch; + + switch (*fmt) { + case 'd': + case 'i': + ch = _getc(stream); + if (length == 0) { + while (!_is_voidage(ch) && isdigit(ch)) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } else { + while (!_is_voidage(ch) && i < length + && isdigit(ch)) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } + /* We tried to understand what this is good for... + * but we did not. We know for sure that it does not + * work on SLOF if this is active. */ + /* _ungetc(ch, stream); */ + tbuf[i] = '\0'; + + /* ch = _getc(stream); */ + if (!_is_voidage(ch)) + _ungetc(ch, stream); + + if (strlen(tbuf) == 0) + return 0; + + *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 10); + break; + case 'X': + case 'x': + ch = _getc(stream); + if (length == 0) { + while (!_is_voidage(ch) && isxdigit(ch)) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } else { + while (!_is_voidage(ch) && i < length + && isxdigit(ch)) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } + /* _ungetc(ch, stream); */ + tbuf[i] = '\0'; + + /* ch = _getc(stream); */ + if (!_is_voidage(ch)) + _ungetc(ch, stream); + + if (strlen(tbuf) == 0) + return 0; + + *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 16); + break; + case 'O': + case 'o': + ch = _getc(stream); + if (length == 0) { + while (!_is_voidage(ch) + && !(ch < '0' || ch > '7')) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } else { + while (!_is_voidage(ch) && i < length + && !(ch < '0' || ch > '7')) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } + /* _ungetc(ch, stream); */ + tbuf[i] = '\0'; + + /* ch = _getc(stream); */ + if (!_is_voidage(ch)) + _ungetc(ch, stream); + + if (strlen(tbuf) == 0) + return 0; + + *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 8); + break; + case 'c': + ch = _getc(stream); + while (_is_voidage(ch)) + ch = _getc(stream); + + *(va_arg(*ap, char *)) = ch; + + ch = _getc(stream); + if (!_is_voidage(ch)) + _ungetc(ch, stream); + + break; + case 's': + ch = _getc(stream); + if (length == 0) { + while (!_is_voidage(ch)) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } else { + while (!_is_voidage(ch) && i < length) { + tbuf[i] = ch; + ch = _getc(stream); + i++; + } + } + /* _ungetc(ch, stream); */ + tbuf[i] = '\0'; + + /* ch = _getc(stream); */ + if (!_is_voidage(ch)) + _ungetc(ch, stream); + + strcpy(va_arg(*ap, char *), tbuf); + break; + default: + if (*fmt >= '0' && *fmt <= '9') + length += *fmt - '0'; + break; + } + fmt++; + } + + return 1; +} + + + +int +vfscanf(FILE * stream, const char *fmt, va_list ap) +{ + int args = 0; + + while (*fmt != '\0') { + + if (*fmt == '%') { + + char formstr[20]; + int i = 0; + + do { + formstr[i] = *fmt; + fmt++; + i++; + } while (! + (*fmt == 'd' || *fmt == 'i' || *fmt == 'x' + || *fmt == 'X' || *fmt == 'p' || *fmt == 'c' + || *fmt == 's' || *fmt == '%' || *fmt == 'O' + || *fmt == 'o')); + formstr[i++] = *fmt; + formstr[i] = '\0'; + if (*fmt != '%') { + if (_scanf(stream, formstr, &ap) <= 0) + return args; + else + args++; + } + + } + + fmt++; + + } + + return args; +} + +int +getc(FILE * stream) +{ + return _getc(stream); +} + +int +getchar(void) +{ + return _getc(stdin); +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c b/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c new file mode 100644 index 000000000..e78fb3d8e --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c @@ -0,0 +1,242 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" + +const static unsigned long long convert[] = { + 0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL +}; + + + +static int +print_itoa(char **buffer,unsigned long value, unsigned short int base) +{ + const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + static char sign = 0; + + if(base <= 2 || base > 16) + return 0; + + if(value < 0) { + sign = 1; + value *= -1; + } + + if(value < base) { + if(sign) { + **buffer = '-'; + *buffer += 1; + sign = 0; + } + **buffer = zeichen[value]; + *buffer += 1; + } else { + print_itoa(buffer, value / base, base); + **buffer = zeichen[(value % base)]; + *buffer += 1; + } + + return 1; +} + + +static unsigned int +print_intlen(unsigned long value, unsigned short int base) +{ + int i = 0; + + while(value > 0) { + value /= base; + i++; + } + if(i == 0) i = 1; + return i; +} + + +static int +print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int base, char c, int optlen) +{ + int i, sizei, len; + + sizei = strtoul(sizec, NULL, 10); + len = print_intlen(size, base) + optlen; + if(sizei > len) { + for(i = 0; i < (sizei - len); i++) { + **buffer = c; + *buffer += 1; + } + } + + return 0; +} + + +static int +print_format(char **buffer, const char *format, void *var) +{ + unsigned long start; + unsigned int i = 0, sizei = 0, len = 0, length_mod = sizeof(int); + unsigned long value = 0; + unsigned long signBit; + char *form, sizec[32]; + char sign = ' '; + + form = (char *) format; + start = (unsigned long) *buffer; + + form++; + if(*form == '0' || *form == '.') { + sign = '0'; + form++; + } + + while(*form != '\0') { + switch(*form) { + case 'u': + case 'd': + case 'i': + sizec[i] = '\0'; + value = (unsigned long) var; + signBit = 0x1ULL << (length_mod * 8 - 1); + if (signBit & value) { + **buffer = '-'; + *buffer += 1; + value = (-(unsigned long)value) & convert[length_mod]; + } + print_fill(buffer, sizec, value, 10, sign, 0); + print_itoa(buffer, value, 10); + break; + case 'X': + case 'x': + sizec[i] = '\0'; + value = (unsigned long) var & convert[length_mod]; + print_fill(buffer, sizec, value, 16, sign, 0); + print_itoa(buffer, value, 16); + break; + case 'O': + case 'o': + sizec[i] = '\0'; + value = (long int) var & convert[length_mod]; + print_fill(buffer, sizec, value, 8, sign, 0); + print_itoa(buffer, value, 8); + break; + case 'p': + sizec[i] = '\0'; + print_fill(buffer, sizec, (unsigned long) var, 16, ' ', 2); + **buffer = '0'; + *buffer += 1; + **buffer = 'x'; + *buffer += 1; + print_itoa(buffer,(unsigned long) var, 16); + break; + case 'c': + sizec[i] = '\0'; + print_fill(buffer, sizec, 1, 10, ' ', 0); + **buffer = (unsigned long) var; + *buffer += 1; + break; + case 's': + sizec[i] = '\0'; + sizei = strtoul(sizec, NULL, 10); + len = strlen((char *) var); + if(sizei > len) { + for(i = 0; i < (sizei - len); i++) { + **buffer = ' '; + *buffer += 1; + } + } + for(i = 0; i < strlen((char *) var); i++) { + **buffer = ((char *) var)[i]; + *buffer += 1; + } + break; + case 'l': + form++; + if(*form == 'l') { + length_mod = sizeof(long long int); + } else { + form--; + length_mod = sizeof(long int); + } + break; + case 'h': + form++; + if(*form == 'h') { + length_mod = sizeof(signed char); + } else { + form--; + length_mod = sizeof(short int); + } + break; + default: + if(*form >= '0' && *form <= '9') + sizec[i++] = *form; + } + form++; + } + + + return (long int) (*buffer - start); +} + + +/* + * The vsnprintf function prints a formated strings into a buffer. + * BUG: buffer size checking does not fully work yet + */ +int +vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg) +{ + char *ptr, *bstart; + + bstart = buffer; + ptr = (char *) format; + + while(*ptr != '\0' && (buffer - bstart) < bufsize) + { + if(*ptr == '%') { + char formstr[20]; + int i=0; + + do { + formstr[i] = *ptr; + ptr++; + i++; + } while(!(*ptr == 'd' || *ptr == 'i' || *ptr == 'u' || *ptr == 'x' || *ptr == 'X' + || *ptr == 'p' || *ptr == 'c' || *ptr == 's' || *ptr == '%' + || *ptr == 'O' || *ptr == 'o' )); + formstr[i++] = *ptr; + formstr[i] = '\0'; + if(*ptr == '%') { + *buffer++ = '%'; + } else { + print_format(&buffer, formstr, va_arg(arg, void *)); + } + ptr++; + } else { + + *buffer = *ptr; + + buffer++; + ptr++; + } + } + + *buffer = '\0'; + + return (buffer - bstart); +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/vsprintf.c b/qemu/roms/SLOF/lib/libc/stdio/vsprintf.c new file mode 100644 index 000000000..0dfd737bc --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/vsprintf.c @@ -0,0 +1,19 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "stdio.h" + +int +vsprintf(char *buffer, const char *format, va_list arg) +{ + return vsnprintf(buffer, 0x7fffffff, format, arg); +} diff --git a/qemu/roms/SLOF/lib/libc/stdio/vsscanf.c b/qemu/roms/SLOF/lib/libc/stdio/vsscanf.c new file mode 100644 index 000000000..b9603e98b --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdio/vsscanf.c @@ -0,0 +1,131 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" + + +static void +_scanf(const char **buffer, const char *fmt, va_list *ap) +{ + int i; + int length = 0; + + fmt++; + + while(*fmt != '\0') { + + char tbuf[256]; + + switch(*fmt) { + case 'd': + case 'i': + if(length == 0) length = 256; + + for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) { + tbuf[i] = **buffer; + *buffer += 1; + } + tbuf[i] = '\0'; + + *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 10); + break; + case 'X': + case 'x': + if(length == 0) length = 256; + + for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) { + tbuf[i] = **buffer; + *buffer += 1; + } + tbuf[i] = '\0'; + + *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 16); + break; + case 'O': + case 'o': + if(length == 0) length = 256; + + for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) { + tbuf[i] = **buffer; + *buffer += 1; + } + tbuf[i] = '\0'; + + *(va_arg(*ap, int *)) = strtol(tbuf, NULL, 8); + break; + case 'c': + *(va_arg(*ap, char *)) = **buffer; + *buffer += 1; + if(length > 1) + for(i = 1; i < length; i++) + *buffer += 1; + break; + case 's': + if(length == 0) length = 256; + + for(i = 0; **buffer != ' ' && **buffer != '\t' && **buffer != '\n' && i < length; i++) { + tbuf[i] = **buffer; + *buffer += 1; + } + + tbuf[i] = '\0'; + + strcpy(va_arg(*ap, char *), tbuf); + break; + default: + if(*fmt >= '0' && *fmt <= '9') + length += *fmt - '0'; + break; + } + fmt++; + } + +} + + +int +vsscanf(const char *buffer, const char *fmt, va_list ap) +{ + + while(*fmt != '\0') { + + if(*fmt == '%') { + + char formstr[20]; + int i=0; + + do { + formstr[i] = *fmt; + fmt++; + i++; + } while(!(*fmt == 'd' || *fmt == 'i' || *fmt == 'x' || *fmt == 'X' + || *fmt == 'p' || *fmt == 'c' || *fmt == 's' || *fmt == '%' + || *fmt == 'O' || *fmt == 'o' )); + formstr[i++] = *fmt; + formstr[i] = '\0'; + if(*fmt != '%') { + while(*buffer == ' ' || *buffer == '\t' || *buffer == '\n') + buffer++; + _scanf(&buffer, formstr, &ap); + } + + } + + fmt++; + + } + + return 0; +} + diff --git a/qemu/roms/SLOF/lib/libc/stdlib/Makefile.inc b/qemu/roms/SLOF/lib/libc/stdlib/Makefile.inc new file mode 100644 index 000000000..702f6d7cf --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/Makefile.inc @@ -0,0 +1,22 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +STDLIB_SRC_C = error.c atoi.c atol.c strtoul.c strtol.c rand.c \ + malloc.c memalign.c realloc.c free.c + +STDLIB_SRC_ASM = +STDLIB_SRCS = $(STDLIB_SRC_C:%=$(STDLIBCMNDIR)/%) $(STDLIB_SRC_ASM:%=$(STDLIBCMNDIR)/%) +STDLIB_OBJS = $(STDLIB_SRC_C:%.c=%.o) $(STDLIB_SRC_ASM:%.S=%.o) + +%.o : $(STDLIBCMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/qemu/roms/SLOF/lib/libc/stdlib/atoi.c b/qemu/roms/SLOF/lib/libc/stdlib/atoi.c new file mode 100644 index 000000000..d2fb33b88 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/atoi.c @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> + +int atoi(const char *str) +{ + return strtol(str, NULL, 0); +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/atol.c b/qemu/roms/SLOF/lib/libc/stdlib/atol.c new file mode 100644 index 000000000..a6aa47ba5 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/atol.c @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> + +long atol(const char *str) +{ + return strtol(str, NULL, 0); +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/error.c b/qemu/roms/SLOF/lib/libc/stdlib/error.c new file mode 100644 index 000000000..81020ca55 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/error.c @@ -0,0 +1,15 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +int errno; + diff --git a/qemu/roms/SLOF/lib/libc/stdlib/free.c b/qemu/roms/SLOF/lib/libc/stdlib/free.c new file mode 100644 index 000000000..900545099 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/free.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "stdlib.h" +#include "malloc_defs.h" + +void +free(void *ptr) +{ + struct chunk *header; + + header = (struct chunk *) ptr; + header--; + header->inuse = 0; + +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/malloc.c b/qemu/roms/SLOF/lib/libc/stdlib/malloc.c new file mode 100644 index 000000000..b2a3138eb --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/malloc.c @@ -0,0 +1,157 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "stddef.h" +#include "stdlib.h" +#include "unistd.h" +#include "malloc_defs.h" + + +static int clean(void); + + +/* act points to the end of the initialized heap and the start of uninitialized heap */ +static char *act; + +/* Pointers to start and end of heap: */ +static char *heap_start, *heap_end; + + +/* + * Standard malloc function + */ +void * +malloc(size_t size) +{ + char *header; + void *data; + size_t blksize; /* size of memory block including the chunk */ + + blksize = size + sizeof(struct chunk); + + /* has malloc been called for the first time? */ + if (act == 0) { + size_t initsize; + /* add some space so we have a good initial playground */ + initsize = (blksize + 0x1000) & ~0x0fff; + /* get initial memory region with sbrk() */ + heap_start = sbrk(initsize); + if (heap_start == (void*)-1) + return NULL; + heap_end = heap_start + initsize; + act = heap_start; + } + + header = act; + data = act + sizeof(struct chunk); + + /* Check if there is space left in the uninitialized part of the heap */ + if (act + blksize > heap_end) { + //search at begin of heap + header = heap_start; + + while ((((struct chunk *) header)->inuse != 0 + || ((struct chunk *) header)->length < size) + && header < act) { + header = header + sizeof(struct chunk) + + ((struct chunk *) header)->length; + } + + // check if heap is full + if (header >= act) { + if (clean()) { + // merging of free blocks succeeded, so try again + return malloc(size); + } else if (sbrk(blksize) == heap_end) { + // succeeded to get more memory, so try again + heap_end += blksize; + return malloc(size); + } else { + // No more memory available + return 0; + } + } + + // Check if we need to split this memory block into two + if (((struct chunk *) header)->length > blksize) { + //available memory is too big + int alt; + + alt = ((struct chunk *) header)->length; + ((struct chunk *) header)->inuse = 1; + ((struct chunk *) header)->length = size; + data = header + sizeof(struct chunk); + + //mark the rest of the heap + header = data + size; + ((struct chunk *) header)->inuse = 0; + ((struct chunk *) header)->length = + alt - blksize; + } else { + //new memory matched exactly in available memory + ((struct chunk *) header)->inuse = 1; + data = header + sizeof(struct chunk); + } + + } else { + + ((struct chunk *) header)->inuse = 1; + ((struct chunk *) header)->length = size; + + act += blksize; + } + + return data; +} + + +/* + * Merge free memory blocks in initialized heap if possible + */ +static int +clean(void) +{ + char *header; + char *firstfree = 0; + char check = 0; + + header = heap_start; + //if (act == 0) // This should never happen + // act = heap_end; + + while (header < act) { + + if (((struct chunk *) header)->inuse == 0) { + if (firstfree == 0) { + /* First free block in a row, only save address */ + firstfree = header; + + } else { + /* more than one free block in a row, merge them! */ + ((struct chunk *) firstfree)->length += + ((struct chunk *) header)->length + + sizeof(struct chunk); + check = 1; + } + } else { + firstfree = 0; + + } + + header = header + sizeof(struct chunk) + + ((struct chunk *) header)->length; + + } + + return check; +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/malloc_defs.h b/qemu/roms/SLOF/lib/libc/stdlib/malloc_defs.h new file mode 100644 index 000000000..19330267e --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/malloc_defs.h @@ -0,0 +1,16 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +struct chunk { + unsigned inuse : 4; + unsigned length : 28; +} __attribute__((packed)); diff --git a/qemu/roms/SLOF/lib/libc/stdlib/memalign.c b/qemu/roms/SLOF/lib/libc/stdlib/memalign.c new file mode 100644 index 000000000..3b678aaf5 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/memalign.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "stdlib.h" + + +void * +memalign(size_t blocksize, size_t bytes) +{ + void *x; + + x = malloc(bytes + blocksize); + x = (void *) (((unsigned long) x + blocksize - 1) & ~(blocksize - 1)); + + return (void *) x; +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/rand.c b/qemu/roms/SLOF/lib/libc/stdlib/rand.c new file mode 100644 index 000000000..87e3efd29 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/rand.c @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> + + +static unsigned long _rand = 1; + +int +rand(void) +{ + _rand = _rand * 25364735 + 34563; + + return ((unsigned int) (_rand << 16) & RAND_MAX); +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/realloc.c b/qemu/roms/SLOF/lib/libc/stdlib/realloc.c new file mode 100644 index 000000000..652e90077 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/realloc.c @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#include "stdlib.h" +#include "string.h" +#include "malloc_defs.h" + +void * +realloc(void *ptr, size_t size) +{ + struct chunk *header; + char *newptr, *start; + + header = (struct chunk *) ptr; + header--; + + if (size <= header->length) + return ptr; + + newptr = (char *) malloc(size); + if (newptr == NULL) + return 0; + + start = newptr; + memcpy((void *) newptr, (const void *) ptr, header->length); + + header->inuse = 0; + + return start; +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/strtol.c b/qemu/roms/SLOF/lib/libc/stdlib/strtol.c new file mode 100644 index 000000000..474597a23 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/strtol.c @@ -0,0 +1,115 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> + +long int strtol(const char *S, char **PTR,int BASE) +{ + long rval = 0; + short int negative = 0; + short int digit; + // *PTR is S, unless PTR is NULL, in which case i override it with my own ptr + char* ptr; + if (PTR == 0) + { + //override + PTR = &ptr; + } + // i use PTR to advance through the string + *PTR = (char *) S; + //check if BASE is ok + if ((BASE < 0) || BASE > 36) + { + return 0; + } + // ignore white space at beginning of S + while ((**PTR == ' ') + || (**PTR == '\t') + || (**PTR == '\n') + || (**PTR == '\r') + ) + { + (*PTR)++; + } + // check if S starts with "-" in which case the return value is negative + if (**PTR == '-') + { + negative = 1; + (*PTR)++; + } + // if BASE is 0... determine the base from the first chars... + if (BASE == 0) + { + // if S starts with "0x", BASE = 16, else 10 + if ((**PTR == '0') && (*((*PTR)+1) == 'x')) + { + BASE = 16; + (*PTR)++; + (*PTR)++; + } + else + { + BASE = 10; + } + } + if (BASE == 16) + { + // S may start with "0x" + if ((**PTR == '0') && (*((*PTR)+1) == 'x')) + { + (*PTR)++; + (*PTR)++; + } + } + //until end of string + while (**PTR) + { + if (((**PTR) >= '0') && ((**PTR) <= '9')) + { + //digit (0..9) + digit = **PTR - '0'; + } + else if (((**PTR) >= 'a') && ((**PTR) <='z')) + { + //alphanumeric digit lowercase(a (10) .. z (35) ) + digit = (**PTR - 'a') + 10; + } + else if (((**PTR) >= 'A') && ((**PTR) <='Z')) + { + //alphanumeric digit uppercase(a (10) .. z (35) ) + digit = (**PTR - 'A') + 10; + } + else + { + //end of parseable number reached... + break; + } + if (digit < BASE) + { + rval = (rval * BASE) + digit; + } + else + { + //digit found, but its too big for current base + //end of parseable number reached... + break; + } + //next... + (*PTR)++; + } + if (negative) + { + return rval * -1; + } + //else + return rval; +} diff --git a/qemu/roms/SLOF/lib/libc/stdlib/strtoul.c b/qemu/roms/SLOF/lib/libc/stdlib/strtoul.c new file mode 100644 index 000000000..754e7db4b --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/stdlib/strtoul.c @@ -0,0 +1,105 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> + +unsigned long int strtoul(const char *S, char **PTR,int BASE) +{ + unsigned long rval = 0; + short int digit; + // *PTR is S, unless PTR is NULL, in which case i override it with my own ptr + char* ptr; + if (PTR == 0) + { + //override + PTR = &ptr; + } + // i use PTR to advance through the string + *PTR = (char *) S; + //check if BASE is ok + if ((BASE < 0) || BASE > 36) + { + return 0; + } + // ignore white space at beginning of S + while ((**PTR == ' ') + || (**PTR == '\t') + || (**PTR == '\n') + || (**PTR == '\r') + ) + { + (*PTR)++; + } + // if BASE is 0... determine the base from the first chars... + if (BASE == 0) + { + // if S starts with "0x", BASE = 16, else 10 + if ((**PTR == '0') && (*((*PTR)+1) == 'x')) + { + BASE = 16; + (*PTR)++; + (*PTR)++; + } + else + { + BASE = 10; + } + } + if (BASE == 16) + { + // S may start with "0x" + if ((**PTR == '0') && (*((*PTR)+1) == 'x')) + { + (*PTR)++; + (*PTR)++; + } + } + //until end of string + while (**PTR) + { + if (((**PTR) >= '0') && ((**PTR) <='9')) + { + //digit (0..9) + digit = **PTR - '0'; + } + else if (((**PTR) >= 'a') && ((**PTR) <='z')) + { + //alphanumeric digit lowercase(a (10) .. z (35) ) + digit = (**PTR - 'a') + 10; + } + else if (((**PTR) >= 'A') && ((**PTR) <='Z')) + { + //alphanumeric digit uppercase(a (10) .. z (35) ) + digit = (**PTR - 'A') + 10; + } + else + { + //end of parseable number reached... + break; + } + if (digit < BASE) + { + rval = (rval * BASE) + digit; + } + else + { + //digit found, but its too big for current base + //end of parseable number reached... + break; + } + //next... + (*PTR)++; + } + //done + return rval; +} + diff --git a/qemu/roms/SLOF/lib/libc/string/Makefile.inc b/qemu/roms/SLOF/lib/libc/string/Makefile.inc new file mode 100644 index 000000000..7ccf3c405 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/Makefile.inc @@ -0,0 +1,22 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + + +STRING_SRC_C = strcat.c strchr.c strcmp.c strcpy.c strlen.c strncmp.c \ + strncpy.c strstr.c memset.c memcpy.c memmove.c memchr.c \ + memcmp.c strcasecmp.c strncasecmp.c strtok.c +STRING_SRC_ASM = +STRING_SRCS = $(STRING_SRC_C:%=$(STRINGCMNDIR)/%) $(STRING_SRC_ASM:%=$(STRINGCMNDIR)/%) +STRING_OBJS = $(STRING_SRC_C:%.c=%.o) $(STRING_SRC_ASM:%.S=%.o) + +%.o : $(STRINGCMNDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ diff --git a/qemu/roms/SLOF/lib/libc/string/memchr.c b/qemu/roms/SLOF/lib/libc/string/memchr.c new file mode 100644 index 000000000..c3fe751c6 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/memchr.c @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "string.h" + + +void * +memchr(const void *ptr, int c, size_t n) +{ + unsigned char ch = (unsigned char)c; + const unsigned char *p = ptr; + + while (n-- > 0) { + if (*p == ch) + return (void *)p; + p += 1; + } + + return NULL; +} diff --git a/qemu/roms/SLOF/lib/libc/string/memcmp.c b/qemu/roms/SLOF/lib/libc/string/memcmp.c new file mode 100644 index 000000000..3b69cefb9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/memcmp.c @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "string.h" + + +int +memcmp(const void *ptr1, const void *ptr2, size_t n) +{ + const unsigned char *p1 = ptr1; + const unsigned char *p2 = ptr2; + + while (n-- > 0) { + if (*p1 != *p2) + return (*p1 - *p2); + p1 += 1; + p2 += 1; + } + + return 0; +} diff --git a/qemu/roms/SLOF/lib/libc/string/memcpy.c b/qemu/roms/SLOF/lib/libc/string/memcpy.c new file mode 100644 index 000000000..00f419b80 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/memcpy.c @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "string.h" + +void * +memcpy(void *dest, const void *src, size_t n) +{ + char *cdest; + const char *csrc = src; + + cdest = dest; + while (n-- > 0) { + *cdest++ = *csrc++; + } + + return dest; +} diff --git a/qemu/roms/SLOF/lib/libc/string/memmove.c b/qemu/roms/SLOF/lib/libc/string/memmove.c new file mode 100644 index 000000000..3acf1a973 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/memmove.c @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "string.h" + + +void * +memmove(void *dest, const void *src, size_t n) +{ + char *cdest; + const char *csrc; + int i; + + /* Do the buffers overlap in a bad way? */ + if (src < dest && src + n >= dest) { + /* Copy from end to start */ + cdest = dest + n - 1; + csrc = src + n - 1; + for (i = 0; i < n; i++) { + *cdest-- = *csrc--; + } + } + else { + /* Normal copy is possible */ + cdest = dest; + csrc = src; + for (i = 0; i < n; i++) { + *cdest++ = *csrc++; + } + } + + return dest; +} diff --git a/qemu/roms/SLOF/lib/libc/string/memset.c b/qemu/roms/SLOF/lib/libc/string/memset.c new file mode 100644 index 000000000..f8dfbf524 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/memset.c @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "string.h" + +void * +memset(void *dest, int c, size_t size) +{ + unsigned char *d = (unsigned char *)dest; + + while (size-- > 0) { + *d++ = (unsigned char)c; + } + + return dest; +} diff --git a/qemu/roms/SLOF/lib/libc/string/strcasecmp.c b/qemu/roms/SLOF/lib/libc/string/strcasecmp.c new file mode 100644 index 000000000..f75294fb9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strcasecmp.c @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <ctype.h> + +int +strcasecmp(const char *s1, const char *s2) +{ + while (*s1 != 0 && *s2 != 0) { + if (toupper(*s1) != toupper(*s2)) + break; + ++s1; + ++s2; + } + + return *s1 - *s2; +} + diff --git a/qemu/roms/SLOF/lib/libc/string/strcat.c b/qemu/roms/SLOF/lib/libc/string/strcat.c new file mode 100644 index 000000000..eb597a025 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strcat.c @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + +char * +strcat(char *dst, const char *src) +{ + int p; + + p = strlen(dst); + strcpy(&dst[p], src); + + return dst; +} diff --git a/qemu/roms/SLOF/lib/libc/string/strchr.c b/qemu/roms/SLOF/lib/libc/string/strchr.c new file mode 100644 index 000000000..528a319c9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strchr.c @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + +char * +strchr(const char *s, int c) +{ + char cb = c; + + while (*s != 0) { + if (*s == cb) { + return (char *)s; + } + s += 1; + } + + return NULL; +} diff --git a/qemu/roms/SLOF/lib/libc/string/strcmp.c b/qemu/roms/SLOF/lib/libc/string/strcmp.c new file mode 100644 index 000000000..48eaed246 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strcmp.c @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + + +int +strcmp(const char *s1, const char *s2) +{ + while (*s1 != 0 && *s2 != 0) { + if (*s1 != *s2) + break; + s1 += 1; + s2 += 1; + } + + return *s1 - *s2; +} + diff --git a/qemu/roms/SLOF/lib/libc/string/strcpy.c b/qemu/roms/SLOF/lib/libc/string/strcpy.c new file mode 100644 index 000000000..48eb62cb5 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strcpy.c @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + +char * +strcpy(char *dst, const char *src) +{ + char *ptr = dst; + + do { + *ptr++ = *src; + } while (*src++ != 0); + + return dst; +} diff --git a/qemu/roms/SLOF/lib/libc/string/strlen.c b/qemu/roms/SLOF/lib/libc/string/strlen.c new file mode 100644 index 000000000..37a1b7812 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strlen.c @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + +size_t +strlen(const char *s) +{ + int len = 0; + + while (*s != 0) { + len += 1; + s += 1; + } + + return len; +} + diff --git a/qemu/roms/SLOF/lib/libc/string/strncasecmp.c b/qemu/roms/SLOF/lib/libc/string/strncasecmp.c new file mode 100644 index 000000000..4140931e3 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strncasecmp.c @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <ctype.h> + + +int +strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n < 1) + return 0; + + while (*s1 != 0 && *s2 != 0 && --n > 0) { + if (toupper(*s1) != toupper(*s2)) + break; + ++s1; + ++s2; + } + + return toupper(*s1) - toupper(*s2); +} + diff --git a/qemu/roms/SLOF/lib/libc/string/strncmp.c b/qemu/roms/SLOF/lib/libc/string/strncmp.c new file mode 100644 index 000000000..a886736a9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strncmp.c @@ -0,0 +1,31 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + if (n < 1) + return 0; + + while (*s1 != 0 && *s2 != 0 && --n > 0) { + if (*s1 != *s2) + break; + s1 += 1; + s2 += 1; + } + + return *s1 - *s2; +} + diff --git a/qemu/roms/SLOF/lib/libc/string/strncpy.c b/qemu/roms/SLOF/lib/libc/string/strncpy.c new file mode 100644 index 000000000..0f41f93c9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strncpy.c @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + +char * +strncpy(char *dst, const char *src, size_t n) +{ + char *ret = dst; + + /* Copy string */ + while (*src != 0 && n > 0) { + *dst++ = *src++; + n -= 1; + } + + /* strncpy always clears the rest of destination string... */ + while (n > 0) { + *dst++ = 0; + n -= 1; + } + + return ret; +} diff --git a/qemu/roms/SLOF/lib/libc/string/strstr.c b/qemu/roms/SLOF/lib/libc/string/strstr.c new file mode 100644 index 000000000..3e090d2c5 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strstr.c @@ -0,0 +1,37 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + +char * +strstr(const char *hay, const char *needle) +{ + char *pos; + int hlen, nlen; + + if (hay == NULL || needle == NULL) + return NULL; + + hlen = strlen(hay); + nlen = strlen(needle); + if (nlen < 1) + return (char *)hay; + + for (pos = (char *)hay; pos < hay + hlen; pos++) { + if (strncmp(pos, needle, nlen) == 0) { + return pos; + } + } + + return NULL; +} + diff --git a/qemu/roms/SLOF/lib/libc/string/strtok.c b/qemu/roms/SLOF/lib/libc/string/strtok.c new file mode 100644 index 000000000..665c08db6 --- /dev/null +++ b/qemu/roms/SLOF/lib/libc/string/strtok.c @@ -0,0 +1,45 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> + +char * +strtok(char *src, const char *pattern) +{ + static char *nxtTok; + char *retVal = NULL; + + if (!src) + src = nxtTok; + + while (*src) { + const char *pp = pattern; + while (*pp) { + if (*pp == *src) { + break; + } + pp++; + } + if (!*pp) { + if (!retVal) + retVal = src; + else if (!src[-1]) + break; + } else + *src = '\0'; + src++; + } + + nxtTok = src; + + return retVal; +} diff --git a/qemu/roms/SLOF/lib/libe1k/Makefile b/qemu/roms/SLOF/lib/libe1k/Makefile new file mode 100644 index 000000000..0c3169f02 --- /dev/null +++ b/qemu/roms/SLOF/lib/libe1k/Makefile @@ -0,0 +1,51 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008, 2013 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) + +LDFLAGS = -nostdlib + +TARGET = ../libe1k.a + + +all: $(TARGET) Makefile.dep + +SRCS = e1k.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/lib/libe1k/e1k.c b/qemu/roms/SLOF/lib/libe1k/e1k.c new file mode 100644 index 000000000..4dd7d2eb9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libe1k/e1k.c @@ -0,0 +1,1000 @@ +/****************************************************************************** + * Copyright (c) 2007, 2011, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * e1000 Gigabit Ethernet Driver for SLOF + * + * Reference: + * PCI/PCI-X Family of Gigabit Ethernet Controllers + * Software Developer's Manual Rev. 3.3, Intel, December 2006 + */ + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <byteorder.h> +#include <helpers.h> +#include <netdriver.h> +#include "e1k.h" + +/* + * local defines + ****************************************************************************** + */ +#define E1K_NUM_RX_DESC 128 // do not change +#define E1K_NUM_TX_DESC 128 // do not change +#define E1K_BUF_SIZE 2096 // do not change + +#define NUM_MAC_ADDR 16 // number of mac address register pairs +#define EEPROM_MAC_OFFS 0 // position of mac address in eeprom + +/* + * local types + ****************************************************************************** + */ +typedef struct { + uint32_t m_dev_u32; + uint64_t m_devmsk_u64; + char *m_name; +} e1k_dev_t; + +/* + * e1k common data structures + */ + +/* + * transmit buffer descriptor + */ +typedef struct { + uint64_t m_buffer_u64; + uint16_t m_len_u16; + uint8_t m_cso_u08; + uint8_t m_cmd_u08; + uint8_t m_sta_u08; + uint8_t m_css_u08; + uint16_t m_spe_u16; +} __attribute__ ((packed)) e1k_tx_desc_st; + + +/* + * receive buffer descriptor + */ +typedef struct { + uint64_t m_buffer_u64; + uint16_t m_len_u16; + uint16_t m_csm_u16; + uint8_t m_sta_u08; + uint8_t m_err_u08; + uint16_t m_spe_u16; +} __attribute__ ((packed)) e1k_rx_desc_st; + +/* + * e1k device structure + */ +typedef struct { + /* + * device identification mask + */ + uint64_t m_device_u64; + + /* + * memory mapped base address of NIC + */ + uint64_t m_baseaddr_u64; + + /* + * transmit & receive rings + * must be 16 byte aligned + */ + e1k_tx_desc_st m_tx_ring_pst[E1K_NUM_TX_DESC]; + e1k_rx_desc_st m_rx_ring_pst[E1K_NUM_RX_DESC]; + + /* + * transmit & receive buffers + * must be 16 byte aligned + */ + uint8_t m_tx_buffer_pu08[E1K_NUM_TX_DESC][E1K_BUF_SIZE]; + uint8_t m_rx_buffer_pu08[E1K_NUM_RX_DESC][E1K_BUF_SIZE]; + + /* + * next receive descriptor index + */ + uint32_t m_rx_next_u32; + + /* + * command register storage + */ + uint16_t m_com_r_u16; + + /* + * padding to make the size of the structure a multiple of 16 byte + */ + uint16_t m_pad16_u16; + uint64_t m_pad64_u32; + +} __attribute__ ((packed)) e1k_st; + +/* + * local constants + ****************************************************************************** + */ +#define E1K_82540 ((uint64_t) 0x1) +#define E1K_82541 ((uint64_t) 0x2) +#define E1K_82544 ((uint64_t) 0x4) +#define E1K_82545 ((uint64_t) 0x8) +#define E1K_82546 ((uint64_t) 0x10) +#define E1K_82547 ((uint64_t) 0x20) + +#define IS_82541 ((m_e1k.m_device_u64 & E1K_82541) != 0) +#define IS_82546 ((m_e1k.m_device_u64 & E1K_82546) != 0) +#define IS_82547 ((m_e1k.m_device_u64 & E1K_82547) != 0) + +static const e1k_dev_t e1k_dev[] = { + { 0x1019, E1K_82547, "82547EI/GI Copper" }, + { 0x101A, E1K_82547, "82547EI Mobile" }, + { 0x1010, E1K_82546, "52546EB Copper, Dual Port" }, + { 0x1012, E1K_82546, "82546EB Fiber, Dual Port" }, +/* { 0x101D, E1K_82546, "82546EB Copper, Quad Port" }, */ + { 0x1079, E1K_82546, "82546GB Copper, Dual Port" }, + { 0x107A, E1K_82546, "82546GB Fiber, Dual Port" }, + { 0x107B, E1K_82546, "82546GB SerDes, Dual Port" }, + { 0x100F, E1K_82545, "82545EM Copper" }, + { 0x1011, E1K_82545, "82545EM Fiber" }, + { 0x1026, E1K_82545, "82545GM Copper" }, + { 0x1027, E1K_82545, "82545GM Fiber" }, + { 0x1028, E1K_82545, "82545GM SerDes" }, + { 0x1107, E1K_82544, "82544EI Copper" }, + { 0x1112, E1K_82544, "82544GC Copper" }, + { 0x1013, E1K_82541, "82541EI Copper" }, + { 0x1018, E1K_82541, "82541EI Mobile" }, + { 0x1076, E1K_82541, "82541GI Copper" }, + { 0x1077, E1K_82541, "82541GI Mobile" }, + { 0x1078, E1K_82541, "82541ER Copper" }, + { 0x107C, E1K_82541, "82541PI" }, + { 0x1015, E1K_82540, "82540EM Mobile" }, + { 0x1016, E1K_82540, "82540EP Mobile" }, + { 0x1017, E1K_82540, "82540EP Desktop" }, + { 0x100E, E1K_82540, "82540EM Desktop" }, + { 0 , 0 } +}; + +/* + * local variables + ****************************************************************************** + */ +static e1k_st m_e1k __attribute__ ((aligned(16))); +static long dma_offset; + +/* + * global functions + ****************************************************************************** + */ +int +check_driver(uint16_t vendor_id, uint16_t device_id); + +static int e1k_init(net_driver_t *driver); +static int e1k_term(void); +static int e1k_xmit(char *f_buffer_pc, int f_len_i); +static int e1k_receive(char *f_buffer_pc, int f_len_i); + +/** + * Translate virtual to "physical" address, ie. an address + * which can be used for DMA transfers. + */ +static uint64_t +virt2dma(void *addr) +{ + return (uint64_t)addr + dma_offset; +} + +static void * +dma2virt(uint64_t addr) +{ + return (void *)(addr - dma_offset); +} + +/* + * local inline functions for e1k register access + ****************************************************************************** + */ +static uint32_t +e1k_rd32(uint16_t f_offs_u16) +{ // caution: shall only be used after initialization! + return bswap_32(rd32(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16)); +} + +/* not used so far +static uint16_t +e1k_rd16(uint16_t f_offs_u16) +{ // caution: shall only be used after initialization! + return bswap_16(rd16(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16)); +}*/ + +/* not used so far +static uint8_t +e1k_rd08(uint16_t f_offs_u16) +{ // caution: shall only be used after initialization! + return rd08(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16); +}*/ + +static void +e1k_wr32(uint16_t f_offs_u16, uint32_t f_val_u32) +{ // caution: shall only be used after initialization! + wr32(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, bswap_32(f_val_u32)); +} + +/* not used so far +static void +e1k_wr16(uint16_t f_offs_u16, uint16_t f_val_u16) +{ // caution: shall only be used after initialization! + wr16(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, bswap_16(f_val_u16)); +}*/ + +/* not used so far +static void +e1k_wr08(uint16_t f_offs_u16, uint8_t f_val_u08) +{ // caution: shall only be used after initialization! + wr08(m_e1k.m_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u08); +}*/ + +static void +e1k_setb32(uint16_t f_offs_u16, uint32_t f_mask_u32) +{ + uint32_t v; + + v = e1k_rd32(f_offs_u16); + v |= f_mask_u32; + e1k_wr32(f_offs_u16, v); +} + +/* not used so far +static void +e1k_setb16(uint16_t f_offs_u16, uint16_t f_mask_u16) +{ + uint16_t v; + v = e1k_rd16(f_offs_u16); + v |= f_mask_u16; + e1k_wr16(f_offs_u16, v); +}*/ + +/* not used so far +static void +e1k_setb08(uint16_t f_offs_u16, uint8_t f_mask_u08) +{ + uint8_t v; + v = e1k_rd08(f_offs_u16); + v |= f_mask_u08; + e1k_wr08(f_offs_u16, v); +}*/ + +static void +e1k_clrb32(uint16_t f_offs_u16, uint32_t f_mask_u32) +{ + uint32_t v; + + v = e1k_rd32(f_offs_u16); + v &= ~f_mask_u32; + e1k_wr32(f_offs_u16, v); +} + +/* not used so far +static void +e1k_clrb16(uint16_t f_offs_u16, uint16_t f_mask_u16) +{ + uint16_t v; + + v = e1k_rd16(f_offs_u16); + v &= ~f_mask_u16; + e1k_wr16(f_offs_u16, v); +}*/ + +/* not used so far +static void +e1k_clrb08(uint16_t f_offs_u16, uint8_t f_mask_u08) +{ + uint8_t v; + v = e1k_rd08(f_offs_u16); + v &= ~f_mask_u08; + e1k_wr08(f_offs_u16, v); +}*/ + +static int32_t +e1k_eep_rd16(uint8_t f_offs_u08, uint16_t *f_data_pu16) +{ + uint32_t i; + uint32_t v; + int32_t done_shft; + int32_t addr_shft; + + if(IS_82541 || IS_82547) { + addr_shft = 2; + done_shft = 1; + } else { + addr_shft = 8; + done_shft = 4; + } + + /* + * initiate eeprom read + */ + e1k_wr32(EERD, ((uint32_t) f_offs_u08 << addr_shft) | // address + BIT32(0)); // start read + + /* + * wait for read done bit to be set + */ + i = 1000; + v = e1k_rd32(EERD); + while ((--i) && + ((v & BIT32(done_shft)) == 0)) { + SLOF_msleep(1); + v = e1k_rd32(EERD); + } + + /* + * return on error + */ + if ((v & BIT32(done_shft)) == 0) { + return -1; + } + + /* + * return data + */ + *f_data_pu16 = (uint16_t) ((v >> 16) & 0xffff); + + return 0; +} + +/* + * ring initialization + */ +static void +e1k_init_receiver(void) +{ + uint32_t i; + uint64_t addr; + + /* + * disable receiver for initialization + */ + e1k_wr32(RCTL, 0); + + /* + * clear receive desciptors and setup buffer pointers + */ + for (i = 0; i < E1K_NUM_RX_DESC; i++) { + memset((uint8_t *) &m_e1k.m_rx_ring_pst[i], 0, + sizeof(e1k_rx_desc_st)); + mb(); + + m_e1k.m_rx_ring_pst[i].m_buffer_u64 = + bswap_64(virt2dma(&m_e1k.m_rx_buffer_pu08[i][0])); + } + + /* + * initialize previously received index + */ + m_e1k.m_rx_next_u32 = 0; + + /* + * setup the base address and the length of the rx descriptor ring + */ + addr = virt2dma(&m_e1k.m_rx_ring_pst[0]); + e1k_wr32(RDBAH, (uint32_t) ((uint64_t) addr >> 32)); + e1k_wr32(RDBAL, (uint32_t) ((uint64_t) addr & 0xffffffff)); + e1k_wr32(RDLEN, E1K_NUM_RX_DESC * sizeof(e1k_rx_desc_st)); + + /* + * setup the rx head and tail descriptor indices + */ + e1k_wr32(RDH, 0); + e1k_wr32(RDT, E1K_NUM_RX_DESC - 1); + + /* + * setup the receive delay timer register + */ + e1k_wr32(RDTR, 0); + + /* + * setup the receive control register + */ + e1k_wr32(RCTL, BIT32( 1) | // enable receiver + BIT32( 4) | // enable multicast reception + BIT32(15)); // broadcast accept mode + // packet size 2048 + // no buffer extension +} + +static void +e1k_init_transmitter(void) +{ + uint32_t i; + uint64_t addr; + + /* + * clear transmit desciptors and setup buffer pointers + */ + for (i = 0; i < E1K_NUM_TX_DESC; i++) { + memset((uint8_t *) &m_e1k.m_tx_ring_pst[i], 0, + sizeof(e1k_tx_desc_st)); + mb(); + + m_e1k.m_tx_ring_pst[i].m_buffer_u64 = + bswap_64(virt2dma(&m_e1k.m_tx_buffer_pu08[i][0])); + } + + /* + * setup the base address and the length of the tx descriptor ring + */ + addr = virt2dma(&m_e1k.m_tx_ring_pst[0]); + e1k_wr32(TDBAH, (uint32_t) ((uint64_t) addr >> 32)); + e1k_wr32(TDBAL, (uint32_t) ((uint64_t) addr & 0xffffffff)); + e1k_wr32(TDLEN, E1K_NUM_TX_DESC * sizeof(e1k_tx_desc_st)); + + /* + * setup the rx head and tail descriptor indices + */ + e1k_wr32(TDH, 0); + e1k_wr32(TDT, 0); + + /* + * initialize the transmit control register + */ + e1k_wr32(TCTL, BIT32(1) | // enable transmitter + BIT32(3) | // pad short packets + ((uint32_t) 0x0f << 4) | // collision threshhold + ((uint32_t) 0x40 << 12)); // collision distance +} + +static int32_t +e1k_mac_init(uint8_t *f_mac_pu08) +{ + uint32_t l_ah_u32; + uint32_t l_al_u32; + uint32_t i; + uint32_t v; + + /* + * Use MAC address from device tree if possible + */ + for (i = 0, v = 0; i < 6; i++) { + v += (uint32_t) f_mac_pu08[i]; + } + + if (v != 0) { + /* + * use passed mac address for transmission to nic + */ + l_al_u32 = ((uint32_t) f_mac_pu08[3] << 24); + l_al_u32 |= ((uint32_t) f_mac_pu08[2] << 16); + l_al_u32 |= ((uint32_t) f_mac_pu08[1] << 8); + l_al_u32 |= ((uint32_t) f_mac_pu08[0] << 0); + l_ah_u32 = ((uint32_t) f_mac_pu08[5] << 8); + l_ah_u32 |= ((uint32_t) f_mac_pu08[4] << 0); + } else { + /* + * read mac address from eeprom + */ + uint16_t w[3]; // 3 16 bit words from eeprom + + for (i = 0; i < 3; i++) { + if (e1k_eep_rd16(EEPROM_MAC_OFFS + i, &w[i]) != 0) { + printf("Failed to read MAC address from EEPROM!\n"); + return -1; + } + } + + /* + * invert the least significant bit for 82546 dual port + * if the second device is in use (remember word is byteswapped) + */ + if ((IS_82546) && + ((e1k_rd32(STATUS) & BIT32(2)) != 0)) { + w[2] ^= (uint16_t) 0x100; + } + + /* + * store mac address for transmission to nic + */ + l_ah_u32 = ((uint32_t) w[2] << 0); + l_al_u32 = ((uint32_t) w[1] << 16); + l_al_u32 |= ((uint32_t) w[0] << 0); + + /* + * return mac address + * mac address in eeprom is stored byteswapped + */ + f_mac_pu08[1] = (uint8_t) ((w[0] >> 8) & 0xff); + f_mac_pu08[0] = (uint8_t) ((w[0] >> 0) & 0xff); + f_mac_pu08[3] = (uint8_t) ((w[1] >> 8) & 0xff); + f_mac_pu08[2] = (uint8_t) ((w[1] >> 0) & 0xff); + f_mac_pu08[5] = (uint8_t) ((w[2] >> 8) & 0xff); + f_mac_pu08[4] = (uint8_t) ((w[2] >> 0) & 0xff); + } + + /* + * insert mac address in receive address register + * and set AV bit + */ + e1k_wr32(RAL0, l_al_u32); + e1k_wr32(RAH0, l_ah_u32 | BIT32(31)); + + /* + * clear remaining receive address registers + */ + for (i = 1; i < NUM_MAC_ADDR; i++) { + e1k_wr32(RAL0 + i * sizeof(uint64_t), 0); + e1k_wr32(RAH0 + i * sizeof(uint64_t), 0); + } + + return 0; +} + + +/* + * interface + ****************************************************************************** + */ + +/* + * e1k_receive + */ +static int +e1k_receive(char *f_buffer_pc, int f_len_i) +{ + uint32_t l_rdh_u32 = e1k_rd32(RDH); // this includes needed dummy read + e1k_rx_desc_st *rx; + int l_ret_i; + + #ifdef E1K_DEBUG + #ifdef E1K_SHOW_RCV_DATA + int i; + #endif + #endif + + /* + * check whether new packets have arrived + */ + if (m_e1k.m_rx_next_u32 == l_rdh_u32) { + return 0; + } + + /* + * get a pointer to the next rx descriptor for ease of use + */ + rx = &m_e1k.m_rx_ring_pst[m_e1k.m_rx_next_u32]; + + /* + * check whether the descriptor done bit is set + */ + if ((rx->m_sta_u08 & 0x1) == 0) { + return 0; + } + + /* + * get the length of the packet, throw away checksum + */ + l_ret_i = (int) bswap_16(rx->m_len_u16) - (int) 4; + + /* + * copy the data + */ + memcpy((uint8_t *) f_buffer_pc, dma2virt(bswap_64(rx->m_buffer_u64)), + (size_t) l_ret_i); + + #ifdef E1K_DEBUG + #if defined(E1K_SHOW_RCV) || defined(E1K_SHOW_RCV_DATA) + printf("e1k: %d bytes received\n", l_ret_i); + #endif + + #ifdef E1K_SHOW_RCV_DATA + for (i = 0; i < l_ret_i; i++) { + + if ((i & 0x1f) == 0) { + printf("\n "); + } + + printf("%02X ", f_buffer_pc[i]); + } + + printf("\n\n"); + #endif + #endif + + /* + * clear descriptor for reusage, but leave buffer pointer untouched + */ + memset((uint8_t *) &rx->m_len_u16, 0, + sizeof(e1k_rx_desc_st) - sizeof(uint64_t)); + mb(); + + /* + * write new tail pointer + */ + e1k_wr32(RDT, m_e1k.m_rx_next_u32); + + /* + * update next receive index + */ + m_e1k.m_rx_next_u32 = (m_e1k.m_rx_next_u32 + 1) & (E1K_NUM_RX_DESC - 1); + + return l_ret_i; +} + +static int +e1k_xmit(char *f_buffer_pc, int f_len_i) +{ + uint32_t l_tdh_u32 = e1k_rd32(TDH); + uint32_t l_tdt_u32 = e1k_rd32(TDT); + uint32_t l_pre_u32 = (l_tdh_u32 + (E1K_NUM_TX_DESC - 1)) & + (E1K_NUM_TX_DESC - 1); + e1k_tx_desc_st *tx; + #if defined(E1K_DEBUG) && defined(E1K_SHOW_XMIT_DATA) + int i; + #endif + + /* + * check for available buffers + */ + if (l_pre_u32 == l_tdt_u32) { + return 0; + } + + /* + * get a pointer to the next tx descriptor for ease of use + */ + tx = &m_e1k.m_tx_ring_pst[l_tdt_u32]; + + /* + * copy the data + */ + memcpy(dma2virt(bswap_64(tx->m_buffer_u64)), (uint8_t *) f_buffer_pc, + (size_t) f_len_i); + + /* + * insert length & command flags + */ + tx->m_len_u16 = bswap_16((uint16_t) f_len_i); + tx->m_cmd_u08 = (BIT08(0) | // EOP + BIT08(1)); // IFCS + tx->m_sta_u08 = 0; + mb(); + + /* + * update tail index + */ + l_tdt_u32 = (l_tdt_u32 + 1) & (E1K_NUM_TX_DESC - 1); + e1k_wr32(TDT, l_tdt_u32); + + #ifdef E1K_DEBUG + #if defined(E1K_SHOW_XMIT) || defined(E1K_SHOW_XMIT_DATA) + printf("e1k: %d bytes transmitted\n", bswap_16(tx->m_len_u16)); + #endif + + #ifdef E1K_SHOW_XMIT_DATA + for (i = 0; i < bswap_16(tx->m_len_u16); i++) { + + if ((i & 0x1f) == 0) { + printf("\n "); + } + + f_buffer_pc = dma2virt(bswap_64(tx->m_buffer_u64)); + printf("%02X ", f_buffer_pc[i]); + } + + printf("\n\n"); + #endif + #endif + + return f_len_i; +} + +int +check_driver(uint16_t vendor_id, uint16_t device_id) +{ + uint64_t i; + + /* + * checks whether the driver is handling this device + * by verifying vendor & device id + * vendor id 0x8086 == Intel + */ + if (vendor_id != 0x8086) { + #ifdef E1K_DEBUG + printf("e1k: netdevice with vendor id %04X not supported\n", + vendor_id); + #endif + return -1; + } + + for (i = 0; e1k_dev[i].m_dev_u32 != 0; i++) { + if (e1k_dev[i].m_dev_u32 == (uint32_t) device_id) { + break; + } + } + + if (e1k_dev[i].m_dev_u32 == 0) { + #ifdef E1K_DEBUG + printf("e1k: netdevice with device id %04X not supported\n", + device_id); + #endif + return -1; + } + + /* + * initialize static variables + */ + m_e1k.m_device_u64 = e1k_dev[i].m_devmsk_u64; + m_e1k.m_baseaddr_u64 = 0; + + // success + #ifdef E1K_DEBUG + printf("e1k: found device %s\n", e1k_dev[i].m_name); + #endif + + return 0; +} + +static int +e1k_init(net_driver_t *driver) +{ + uint32_t i; + uint32_t v; + + if (!driver) + return -1; + + #ifdef E1K_DEBUG + printf("\ne1k: initializing\n"); + #endif + + dma_offset = SLOF_dma_map_in(&m_e1k, sizeof(m_e1k), 0); + #ifdef E1K_DEBUG + printf("e1k: dma offset: %lx - %lx = %lx\n", dma_offset, (long)&m_e1k, + dma_offset - (long)&m_e1k); + #endif + dma_offset = dma_offset - (long)&m_e1k; + + /* + * setup register & memory base addresses of NIC + */ + //m_e1k.m_baseaddr_u64 = baseaddr; + #ifdef E1K_DEBUG + printf("e1k: base address register = 0x%llx\n", m_e1k.m_baseaddr_u64); + #endif + + /* + * e1k hardware initialization + */ + + /* + * at first disable all interrupts + */ + e1k_wr32(IMC, (uint32_t) ~0); + + /* + * check for link up + */ + #ifdef E1K_DEBUG + printf("e1k: checking link status..\n"); + #endif + + i = 50; + v = e1k_rd32(STATUS); + while ((--i) && + ((v & BIT32(1)) == 0)) { + SLOF_msleep(100); + v = e1k_rd32(STATUS); + } + + if ((v & BIT32(1)) == 0) { + #ifdef E1K_DEBUG + printf("e1k: link is down.\n"); + printf(" terminating.\n"); + #endif + + return -1; + } + + #ifdef E1K_DEBUG + printf("e1k: link is up\n"); + + switch ((v >> 6) & 0x3) { + case 0: { + printf(" 10 Mb/s\n"); + } break; + case 1: { + printf(" 100 Mb/s\n"); + } break; + case 2: + case 3: { + printf(" 1000 Mb/s\n"); + } break; + } + + if ((v & BIT32(0)) == 0) { + printf(" half-duplex\n"); + } else { + printf(" full-duplex\n"); + } + #endif + + /* + * initialize mac address + */ + #ifdef E1K_DEBUG + printf("e1k: initializing mac address.. "); + #endif + if (e1k_mac_init((uint8_t *)driver->mac_addr) != 0) { + #ifdef E1K_DEBUG + printf("failed.\n"); + printf(" terminating.\n"); + #endif + + return -1; + } + + #ifdef E1K_DEBUG + printf("done.\n"); + printf(" mac address = %02X:%02X:%02X:%02X:%02X:%02X\n", + driver->mac_addr[0], driver->mac_addr[1], driver->mac_addr[2], + driver->mac_addr[3], driver->mac_addr[4], driver->mac_addr[5]); + #endif + + /* + * initialize transmitter + */ + #ifdef E1K_DEBUG + printf("e1k: initializing transmitter.. "); + #endif + e1k_init_transmitter(); + #ifdef E1K_DEBUG + printf("done.\n"); + #endif + + /* + * initialize receiver + */ + #ifdef E1K_DEBUG + printf("e1k: initializing receiver.. "); + #endif + e1k_init_receiver(); + #ifdef E1K_DEBUG + printf("done.\n"); + printf("e1k: initialization complete\n"); + #endif + + driver->running = 1; + + return 0; +} + +static int +e1k_reset(void) +{ + /* + * reset the PHY + */ + e1k_setb32(CTRL, BIT32(31)); + SLOF_msleep(10); + + /* + * reset the MAC + */ + e1k_setb32(CTRL, BIT32(26)); + SLOF_msleep(10); + + return 0; +} + +static int +e1k_term(void) +{ + #ifdef E1K_DEBUG + printf("e1k: shutdown.. "); + #endif + + /* + * disable receiver & transmitter + */ + e1k_wr32(RCTL, 0); + e1k_wr32(TCTL, 0); + SLOF_msleep(10); + + /* + * reset the ring indices + */ + e1k_wr32(RDH, 0); + e1k_wr32(RDT, 0); + e1k_wr32(TDH, 0); + e1k_wr32(TDT, 0); + + /* + * disable receive address + */ + e1k_clrb32(RAH0, BIT32(31)); + + /* + * reset the mac/phy + */ + e1k_reset(); + + /* + * Disable DMA translation + */ + SLOF_dma_map_out((long)virt2dma(&m_e1k), (void *)&m_e1k, (long)sizeof(m_e1k)); + + #ifdef E1K_DEBUG + printf("done.\n"); + #endif + + return 0; +} + +net_driver_t *e1k_open(uint64_t baseaddr) +{ + net_driver_t *driver; + + m_e1k.m_baseaddr_u64 = baseaddr; + driver = SLOF_alloc_mem(sizeof(*driver)); + if (!driver) { + printf("Unable to allocate virtio-net driver\n"); + return NULL; + } + memset(driver, 0, sizeof(*driver)); + + if (e1k_init(driver)) + goto FAIL; + + return driver; + +FAIL: SLOF_free_mem(driver, sizeof(*driver)); + return NULL; + + return 0; +} + +void e1k_close(net_driver_t *driver) +{ + if (driver->running == 0) + return; + + e1k_term(); + driver->running = 0; + SLOF_free_mem(driver, sizeof(*driver)); +} + +int e1k_read(char *buf, int len) +{ + if (buf) + return e1k_receive(buf, len); + return -1; +} + +int e1k_write(char *buf, int len) +{ + if (buf) + return e1k_xmit(buf, len); + return -1; +} + +int e1k_mac_setup(uint16_t vendor_id, uint16_t device_id, + uint64_t baseaddr, char *mac_addr) +{ + if (check_driver(vendor_id, device_id)) + return -1; + + m_e1k.m_baseaddr_u64 = baseaddr; + memset(mac_addr, 0, 6); + + return e1k_mac_init((uint8_t *)mac_addr); +} diff --git a/qemu/roms/SLOF/lib/libe1k/e1k.code b/qemu/roms/SLOF/lib/libe1k/e1k.code new file mode 100644 index 000000000..225ed4e83 --- /dev/null +++ b/qemu/roms/SLOF/lib/libe1k/e1k.code @@ -0,0 +1,75 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libe1k Forth wrapper + */ + +#include <e1k.h> + +// : e1k-open ( baseaddr -- false | [ driver true ] ) +PRIM(E1K_X2d_OPEN) +{ + uint64_t baseaddr = TOS.u; POP; + net_driver_t *net_driver = e1k_open(baseaddr); + if (net_driver) { + PUSH; + TOS.u = (unsigned long)net_driver; PUSH; + TOS.n = -1; + } else { + PUSH; + TOS.n = 0; + } +} +MIRP + +// : e1k-close ( driver -- ) +PRIM(E1K_X2d_CLOSE) +{ + net_driver_t *driver = TOS.a; POP; + e1k_close(driver); +} +MIRP + + +// : e1k-read ( addr len -- actual ) +PRIM(E1K_X2d_READ) +{ + int len = TOS.u; POP; + TOS.n = e1k_read(TOS.a, len); +} +MIRP + +// : e1k-write ( addr len -- actual ) +PRIM(E1K_X2d_WRITE) +{ + int len = TOS.u; POP; + TOS.n = e1k_write(TOS.a, len); +} +MIRP + +// : e1k-mac-setup ( vendor-id device-id baseaddr addr -- false | [ mac-addr len true ] ) +PRIM(E1K_X2d_MAC_X2d_SETUP) +{ + char *mac_addr = TOS.a; POP; + uint64_t baseaddr = TOS.u; POP; + unsigned int device_id = TOS.u; POP; + + int ret = e1k_mac_setup(TOS.u, device_id, baseaddr, mac_addr); + if (!ret) { + TOS.a = mac_addr; PUSH; + TOS.n = 6; PUSH; + TOS.n = -1; + } else + TOS.n = 0; +} +MIRP diff --git a/qemu/roms/SLOF/lib/libe1k/e1k.h b/qemu/roms/SLOF/lib/libe1k/e1k.h new file mode 100644 index 000000000..c88b3e561 --- /dev/null +++ b/qemu/roms/SLOF/lib/libe1k/e1k.h @@ -0,0 +1,108 @@ +/****************************************************************************** + * Copyright (c) 2007, 2011, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * Definitions for the e1000 Gigabit Ethernet Driver for SLOF + */ + +#include <stdint.h> +#include <cache.h> + +// compiler switches + +// Debug switches +//#define E1K_DEBUG // main debug switch, w/o it the other ones don't work +//#define E1K_SHOW_RCV +//#define E1K_SHOW_RCV_DATA +//#define E1K_SHOW_XMIT +//#define E1K_SHOW_XMIT_DATA + +/* + * pci register offsets + */ +// PCI command register +#define PCI_COM_R ((uint16_t) 0x0004) +// PCI Cache Line Size register +#define PCI_CACHELS_R ((uint16_t) 0x000c) +// PCI bar1 register +#define PCI_BAR1_R ((uint16_t) 0x0010) +// PCI bar2 register +#define PCI_BAR2_R ((uint16_t) 0x0014) +// PCI bar1 register +#define PCI_SUBID_R ((uint16_t) 0x002e) + +/* + * e1000 register offsets + */ +// Device Control register +#define CTRL ((uint16_t) 0x0000) +// Device Status register +#define STATUS ((uint16_t) 0x0008) +// Eeprom Read register +#define EERD ((uint16_t) 0x0014) +// Interrupt Mask Clear register +#define IMC ((uint16_t) 0x00d8) +// Receive Control register +#define RCTL ((uint16_t) 0x0100) +// Receive Descriptor Base Address Low register +#define RDBAL ((uint16_t) 0x2800) +// Receive Descriptor Base Address High register +#define RDBAH ((uint16_t) 0x2804) +// Receive Descriptor Length register +#define RDLEN ((uint16_t) 0x2808) +// Receive Descriptor Head register +#define RDH ((uint16_t) 0x2810) +// Receive Descriptor Tail register +#define RDT ((uint16_t) 0x2818) +// Receive Delay Timer register +#define RDTR ((uint16_t) 0x2820) +// Transmit Control register +#define TCTL ((uint16_t) 0x0400) +// Transmit Descriptor Base Address Low register +#define TDBAL ((uint16_t) 0x3800) +// Transmit Descriptor Base Address High register +#define TDBAH ((uint16_t) 0x3804) +// Transmit Descriptor Length register +#define TDLEN ((uint16_t) 0x3808) +// Transmit Descriptor Head register +#define TDH ((uint16_t) 0x3810) +// Transmit Descriptor Tail register +#define TDT ((uint16_t) 0x3818) +// Receive Address Low register +#define RAL0 ((uint16_t) 0x5400) +// Receive Address High register +#define RAH0 ((uint16_t) 0x5404) + + +/* + * useful def's + */ +#define rd08(a) ci_read_8((uint32_t *)(a)) +#define rd16(a) ci_read_16((uint32_t *)(a)) +#define rd32(a) ci_read_32((uint32_t *)(a)) +#define wr08(a,v) ci_write_8((uint32_t *)(a), (v)) +#define wr16(a,v) ci_write_16((uint32_t *)(a), (v)) +#define wr32(a,v) ci_write_32((uint32_t *)(a), (v)) +//#define printk snk_kernel_interface->print +//#define ms_delay snk_kernel_interface->ms_delay + +#define BIT08(bit) ((uint8_t) 0x1 << (bit)) +#define BIT16(bit) ((uint16_t) 0x1 << (bit)) +#define BIT32(bit) ((uint32_t) 0x1 << (bit)) + +//#define mb() asm volatile("sync" ::: "memory"); + +extern net_driver_t *e1k_open(uint64_t baseaddr); +extern void e1k_close(net_driver_t *driver); +extern int e1k_read(char *buf, int len); +extern int e1k_write(char *buf, int len); +extern int e1k_mac_setup(uint16_t vendor_id, uint16_t device_id, + uint64_t baseaddr, char *mac_addr); diff --git a/qemu/roms/SLOF/lib/libe1k/e1k.in b/qemu/roms/SLOF/lib/libe1k/e1k.in new file mode 100644 index 000000000..a9cb13f83 --- /dev/null +++ b/qemu/roms/SLOF/lib/libe1k/e1k.in @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libe1k bindings for Forth - definitions + */ + +cod(E1K-OPEN) +cod(E1K-CLOSE) +cod(E1K-READ) +cod(E1K-WRITE) +cod(E1K-MAC-SETUP) diff --git a/qemu/roms/SLOF/lib/libelf/Makefile b/qemu/roms/SLOF/lib/libelf/Makefile new file mode 100644 index 000000000..34a8f20b6 --- /dev/null +++ b/qemu/roms/SLOF/lib/libelf/Makefile @@ -0,0 +1,47 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2011 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) +LDFLAGS= -nostdlib + +TARGET = ../libelf.a + +all: $(TARGET) + +SRCS = elf.c elf32.c elf64.c elf_claim.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/lib/libelf/elf.c b/qemu/roms/SLOF/lib/libelf/elf.c new file mode 100644 index 000000000..db2d2abc9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libelf/elf.c @@ -0,0 +1,190 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * ELF loader + */ + +#include <string.h> +#include <cache.h> +#include <libelf.h> +#include <byteorder.h> + +/** + * elf_check_file tests if the file at file_addr is + * a correct endian, ELF PPC executable + * @param file_addr pointer to the start of the ELF file + * @return the class (1 for 32 bit, 2 for 64 bit) + * -1 if it is not an ELF file + * -2 if it has the wrong endianness + * -3 if it is not an ELF executable + * -4 if it is not for PPC + */ +static int +elf_check_file(unsigned long *file_addr) +{ + struct ehdr *ehdr = (struct ehdr *) file_addr; + uint8_t native_endian; + + /* check if it is an ELF image at all */ + if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46) + return -1; + +#ifdef __BIG_ENDIAN__ + native_endian = ELFDATA2MSB; +#else + native_endian = ELFDATA2LSB; +#endif + + if (native_endian != ehdr->ei_data) { + switch (ehdr->ei_class) { + case 1: + elf_byteswap_header32(file_addr); + break; + case 2: + elf_byteswap_header64(file_addr); + break; + } + } + + /* check if it is an ELF executable ... and also + * allow DYN files, since this is specified by ePAPR */ + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) + return -3; + + /* check if it is a PPC ELF executable */ + if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15) + return -4; + + return ehdr->ei_class; +} + +/** + * load_elf_file tries to load the ELF file specified in file_addr + * + * it first checks if the file is a PPC ELF executable and then loads + * the segments depending if it is a 64bit or 32 bit ELF file + * + * @param file_addr pointer to the start of the elf file + * @param entry pointer where the ELF loader will store + * the entry point + * @param pre_load handler that is called before copying a segment + * @param post_load handler that is called after copying a segment + * @return 1 for a 32 bit file + * 2 for a 64 bit BE file + * 3 for a 64 bit LE ABIv1 file + * 4 for a 64 bit LE ABIv2 file + * 5 for a 32 bit LE ABIv1 file + * anything else means an error during load + */ +int +elf_load_file(void *file_addr, unsigned long *entry, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + int type = elf_check_file(file_addr); + struct ehdr *ehdr = (struct ehdr *) file_addr; + + switch (type) { + case 1: + *entry = elf_load_segments32(file_addr, 0, pre_load, post_load); + if (ehdr->ei_data != ELFDATA2MSB) { + type = 5; /* LE32 ABIv1 */ + } + break; + case 2: + *entry = elf_load_segments64(file_addr, 0, pre_load, post_load); + if (ehdr->ei_data != ELFDATA2MSB) { + uint32_t flags = elf_get_eflags_64(file_addr); + if ((flags & 0x3) == 2) + type = 4; /* LE64 ABIv2 */ + else + type = 3; /* LE64 ABIv1 */ + } + break; + } + if (*entry == 0) + type = 0; + + return type; +} + + +/** + * load_elf_file_to_addr loads an ELF file to given address. + * This is useful for 64-bit vmlinux images that use the virtual entry + * point address in their headers, and thereby need a special treatment. + * + * @param file_addr pointer to the start of the elf file + * @param entry pointer where the ELF loader will store + * the entry point + * @param pre_load handler that is called before copying a segment + * @param post_load handler that is called after copying a segment + * @return 1 for a 32 bit file + * 2 for a 64 bit file + * anything else means an error during load + */ +int +elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + int type; + long offset; + + type = elf_check_file(file_addr); + + switch (type) { + case 1: + /* Parse 32-bit image */ + offset = (long)addr - elf_get_base_addr32(file_addr); + *entry = elf_load_segments32(file_addr, offset, pre_load, + post_load) + offset; + // TODO: elf_relocate32(...) + break; + case 2: + /* Parse 64-bit image */ + offset = (long)addr - elf_get_base_addr64(file_addr); + *entry = elf_load_segments64(file_addr, offset, pre_load, + post_load) + offset; + elf_relocate64(file_addr, offset); + break; + } + + return type; +} + + +/** + * Get the base load address of the ELF image + * @return The base address or -1 for error + */ +long +elf_get_base_addr(void *file_addr) +{ + int type; + + type = elf_check_file(file_addr); + + switch (type) { + case 1: + /* Return 32-bit image base address */ + return elf_get_base_addr32(file_addr); + break; + case 2: + /* Return 64-bit image base address */ + return elf_get_base_addr64(file_addr); + break; + } + + return -1; +} diff --git a/qemu/roms/SLOF/lib/libelf/elf32.c b/qemu/roms/SLOF/lib/libelf/elf32.c new file mode 100644 index 000000000..fea5cf420 --- /dev/null +++ b/qemu/roms/SLOF/lib/libelf/elf32.c @@ -0,0 +1,193 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * 32-bit ELF loader + */ +#include <stdio.h> +#include <string.h> +#include <libelf.h> +#include <byteorder.h> + +struct ehdr32 { + uint32_t ei_ident; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_pad[9]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +struct phdr32 { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +}; + + +static struct phdr32* +get_phdr32(void *file_addr) +{ + return (struct phdr32 *) (((unsigned char *)file_addr) + + ((struct ehdr32 *)file_addr)->e_phoff); +} + +static void +load_segment(void *file_addr, struct phdr32 *phdr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + unsigned long src = phdr->p_offset + (unsigned long) file_addr; + unsigned long destaddr; + + destaddr = (unsigned long)phdr->p_paddr; + destaddr = destaddr + offset; + + /* check if we're allowed to copy */ + if (pre_load != NULL) { + if (pre_load((void*)destaddr, phdr->p_memsz) != 0) + return; + } + + /* copy into storage */ + memmove((void *)destaddr, (void *)src, phdr->p_filesz); + + /* clear bss */ + memset((void *)(destaddr + phdr->p_filesz), 0, + phdr->p_memsz - phdr->p_filesz); + + if (phdr->p_memsz && post_load) { + post_load((void*)destaddr, phdr->p_memsz); + } +} + +unsigned int +elf_load_segments32(void *file_addr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + struct ehdr32 *ehdr = (struct ehdr32 *) file_addr; + /* Calculate program header address */ + struct phdr32 *phdr = get_phdr32(file_addr); + int i; + + /* loop e_phnum times */ + for (i = 0; i <= ehdr->e_phnum; i++) { + /* PT_LOAD ? */ + if (phdr->p_type == 1) { + if (phdr->p_paddr != phdr->p_vaddr) { + printf("ELF32: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n", + (long)phdr->p_vaddr, (long)phdr->p_paddr); + return 0; + } + + /* copy segment */ + load_segment(file_addr, phdr, offset, pre_load, + post_load); + } + /* step to next header */ + phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } + + /* Entry point is always a virtual address, so translate it + * to physical before returning it */ + return ehdr->e_entry; +} + +/** + * Return the base address for loading (i.e. the address of the first PT_LOAD + * segment) + * @param file_addr pointer to the ELF file in memory + * @return the base address + */ +long +elf_get_base_addr32(void *file_addr) +{ + struct ehdr32 *ehdr = (struct ehdr32 *) file_addr; + struct phdr32 *phdr = get_phdr32(file_addr); + int i; + + /* loop e_phnum times */ + for (i = 0; i <= ehdr->e_phnum; i++) { + /* PT_LOAD ? */ + if (phdr->p_type == 1) { + return phdr->p_paddr; + } + /* step to next header */ + phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } + + return 0; +} + +uint32_t elf_get_eflags_32(void *file_addr) +{ + struct ehdr32 *ehdr = (struct ehdr32 *) file_addr; + + return ehdr->e_flags; +} + +void +elf_byteswap_header32(void *file_addr) +{ + struct ehdr32 *ehdr = (struct ehdr32 *) file_addr; + struct phdr32 *phdr; + int i; + + bswap_16p(&ehdr->e_type); + bswap_16p(&ehdr->e_machine); + bswap_32p(&ehdr->e_version); + bswap_32p(&ehdr->e_entry); + bswap_32p(&ehdr->e_phoff); + bswap_32p(&ehdr->e_shoff); + bswap_32p(&ehdr->e_flags); + bswap_16p(&ehdr->e_ehsize); + bswap_16p(&ehdr->e_phentsize); + bswap_16p(&ehdr->e_phnum); + bswap_16p(&ehdr->e_shentsize); + bswap_16p(&ehdr->e_shnum); + bswap_16p(&ehdr->e_shstrndx); + + phdr = get_phdr32(file_addr); + + /* loop e_phnum times */ + for (i = 0; i <= ehdr->e_phnum; i++) { + bswap_32p(&phdr->p_type); + bswap_32p(&phdr->p_offset); + bswap_32p(&phdr->p_vaddr); + bswap_32p(&phdr->p_paddr); + bswap_32p(&phdr->p_filesz); + bswap_32p(&phdr->p_memsz); + bswap_32p(&phdr->p_flags); + bswap_32p(&phdr->p_align); + + /* step to next header */ + phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } +} diff --git a/qemu/roms/SLOF/lib/libelf/elf64.c b/qemu/roms/SLOF/lib/libelf/elf64.c new file mode 100644 index 000000000..37e9c10a9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libelf/elf64.c @@ -0,0 +1,473 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * 64-bit ELF loader for PowerPC. + * See the "64-bit PowerPC ELF Application Binary Interface Supplement" and + * the "ELF-64 Object File Format" documentation for details. + */ + +#include <string.h> +#include <stdio.h> +#include <libelf.h> +#include <byteorder.h> + +struct ehdr64 +{ + uint32_t ei_ident; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_pad[9]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +struct phdr64 +{ + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +}; + +struct shdr64 +{ + uint32_t sh_name; /* Section name */ + uint32_t sh_type; /* Section type */ + uint64_t sh_flags; /* Section attributes */ + uint64_t sh_addr; /* Virtual address in memory */ + uint64_t sh_offset; /* Offset in file */ + uint64_t sh_size; /* Size of section */ + uint32_t sh_link; /* Link to other section */ + uint32_t sh_info; /* Miscellaneous information */ + uint64_t sh_addralign; /* Address alignment boundary */ + uint64_t sh_entsize; /* Size of entries, if section has table */ +}; + +struct rela /* RelA relocation table entry */ +{ + uint64_t r_offset; /* Address of reference */ + uint64_t r_info; /* Symbol index and type of relocation */ + int64_t r_addend; /* Constant part of expression */ +}; + +struct sym64 +{ + uint32_t st_name; /* Symbol name */ + uint8_t st_info; /* Type and Binding attributes */ + uint8_t st_other; /* Reserved */ + uint16_t st_shndx; /* Section table index */ + uint64_t st_value; /* Symbol value */ + uint64_t st_size; /* Size of object (e.g., common) */ +}; + + +/* For relocations */ +#define ELF_R_SYM(i) ((i)>>32) +#define ELF_R_TYPE(i) ((uint32_t)(i) & 0xFFFFFFFF) +#define ELF_R_INFO(s,t) ((((uint64_t) (s)) << 32) + (t)) + +/* + * Relocation types for PowerPC64. + */ +#define R_PPC64_NONE 0 +#define R_PPC64_ADDR32 1 +#define R_PPC64_ADDR24 2 +#define R_PPC64_ADDR16 3 +#define R_PPC64_ADDR16_LO 4 +#define R_PPC64_ADDR16_HI 5 +#define R_PPC64_ADDR16_HA 6 +#define R_PPC64_ADDR14 7 +#define R_PPC64_ADDR14_BRTAKEN 8 +#define R_PPC64_ADDR14_BRNTAKEN 9 +#define R_PPC64_REL24 10 +#define R_PPC64_REL14 11 +#define R_PPC64_REL14_BRTAKEN 12 +#define R_PPC64_REL14_BRNTAKEN 13 +#define R_PPC64_GOT16 14 +#define R_PPC64_GOT16_LO 15 +#define R_PPC64_GOT16_HI 16 +#define R_PPC64_GOT16_HA 17 +#define R_PPC64_COPY 19 +#define R_PPC64_GLOB_DAT 20 +#define R_PPC64_JMP_SLOT 21 +#define R_PPC64_RELATIVE 22 +#define R_PPC64_UADDR32 24 +#define R_PPC64_UADDR16 25 +#define R_PPC64_REL32 26 +#define R_PPC64_PLT32 27 +#define R_PPC64_PLTREL32 28 +#define R_PPC64_PLT16_LO 29 +#define R_PPC64_PLT16_HI 30 +#define R_PPC64_PLT16_HA 31 +#define R_PPC64_SECTOFF 33 +#define R_PPC64_SECTOFF_LO 34 +#define R_PPC64_SECTOFF_HI 35 +#define R_PPC64_SECTOFF_HA 36 +#define R_PPC64_ADDR30 37 +#define R_PPC64_ADDR64 38 +#define R_PPC64_ADDR16_HIGHER 39 +#define R_PPC64_ADDR16_HIGHERA 40 +#define R_PPC64_ADDR16_HIGHEST 41 +#define R_PPC64_ADDR16_HIGHESTA 42 +#define R_PPC64_UADDR64 43 +#define R_PPC64_REL64 44 +#define R_PPC64_PLT64 45 +#define R_PPC64_PLTREL64 46 +#define R_PPC64_TOC16 47 +#define R_PPC64_TOC16_LO 48 +#define R_PPC64_TOC16_HI 49 +#define R_PPC64_TOC16_HA 50 +#define R_PPC64_TOC 51 +#define R_PPC64_PLTGOT16 52 +#define R_PPC64_PLTGOT16_LO 53 +#define R_PPC64_PLTGOT16_HI 54 +#define R_PPC64_PLTGOT16_HA 55 +#define R_PPC64_ADDR16_DS 56 +#define R_PPC64_ADDR16_LO_DS 57 +#define R_PPC64_GOT16_DS 58 +#define R_PPC64_GOT16_LO_DS 59 +#define R_PPC64_PLT16_LO_DS 60 +#define R_PPC64_SECTOFF_DS 61 +#define R_PPC64_SECTOFF_LO_DS 62 +#define R_PPC64_TOC16_DS 63 +#define R_PPC64_TOC16_LO_DS 64 +#define R_PPC64_PLTGOT16_DS 65 +#define R_PPC64_PLTGOT16_LO_DS 66 +#define R_PPC64_TLS 67 +#define R_PPC64_DTPMOD64 68 +#define R_PPC64_TPREL16 69 +#define R_PPC64_TPREL16_LO 60 +#define R_PPC64_TPREL16_HI 71 +#define R_PPC64_TPREL16_HA 72 +#define R_PPC64_TPREL64 73 +#define R_PPC64_DTPREL16 74 +#define R_PPC64_DTPREL16_LO 75 +#define R_PPC64_DTPREL16_HI 76 +#define R_PPC64_DTPREL16_HA 77 +#define R_PPC64_DTPREL64 78 +#define R_PPC64_GOT_TLSGD16 79 +#define R_PPC64_GOT_TLSGD16_LO 80 +#define R_PPC64_GOT_TLSGD16_HI 81 +#define R_PPC64_GOT_TLSGD16_HA 82 +#define R_PPC64_GOT_TLSLD16 83 +#define R_PPC64_GOT_TLSLD16_LO 84 +#define R_PPC64_GOT_TLSLD16_HI 85 +#define R_PPC64_GOT_TLSLD16_HA 86 +#define R_PPC64_GOT_TPREL16_DS 87 +#define R_PPC64_GOT_TPREL16_LO_ DS 88 +#define R_PPC64_GOT_TPREL16_HI 89 +#define R_PPC64_GOT_TPREL16_HA 90 +#define R_PPC64_GOT_DTPREL16_DS 91 +#define R_PPC64_GOT_DTPREL16_LO_DS 92 +#define R_PPC64_GOT_DTPREL16_HI 93 +#define R_PPC64_GOT_DTPREL16_HA 94 +#define R_PPC64_TPREL16_DS 95 +#define R_PPC64_TPREL16_LO_DS 96 +#define R_PPC64_TPREL16_HIGHER 97 +#define R_PPC64_TPREL16_HIGHERA 98 +#define R_PPC64_TPREL16_HIGHEST 99 +#define R_PPC64_TPREL16_HIGHESTA 100 +#define R_PPC64_DTPREL16_DS 101 +#define R_PPC64_DTPREL16_LO_DS 102 +#define R_PPC64_DTPREL16_HIGHER 103 +#define R_PPC64_DTPREL16_HIGHERA 104 +#define R_PPC64_DTPREL16_HIGHEST 105 +#define R_PPC64_DTPREL16_HIGHESTA 106 + + +static struct phdr64* +get_phdr64(unsigned long *file_addr) +{ + return (struct phdr64 *) (((unsigned char *) file_addr) + + ((struct ehdr64 *)file_addr)->e_phoff); +} + +static void +load_segment64(unsigned long *file_addr, struct phdr64 *phdr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + unsigned long src = phdr->p_offset + (unsigned long) file_addr; + unsigned long destaddr; + + destaddr = phdr->p_paddr + offset; + + /* check if we're allowed to copy */ + if (pre_load != NULL) { + if (pre_load((void*)destaddr, phdr->p_memsz) != 0) + return; + } + + /* copy into storage */ + memmove((void*)destaddr, (void*)src, phdr->p_filesz); + + /* clear bss */ + memset((void*)(destaddr + phdr->p_filesz), 0, + phdr->p_memsz - phdr->p_filesz); + + if (phdr->p_memsz && post_load != NULL) { + post_load((void*)destaddr, phdr->p_memsz); + } +} + +unsigned long +elf_load_segments64(void *file_addr, signed long offset, + int (*pre_load)(void*, long), + void (*post_load)(void*, long)) +{ + struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; + /* Calculate program header address */ + struct phdr64 *phdr = get_phdr64(file_addr); + int i; + + /* loop e_phnum times */ + for (i = 0; i <= ehdr->e_phnum; i++) { + /* PT_LOAD ? */ + if (phdr->p_type == PT_LOAD) { + if (phdr->p_paddr != phdr->p_vaddr) { + printf("ELF64: VirtAddr(%lx) != PhysAddr(%lx) not supported, aborting\n", + (long)phdr->p_vaddr, (long)phdr->p_paddr); + return 0; + } + + /* copy segment */ + load_segment64(file_addr, phdr, offset, pre_load, post_load); + } + /* step to next header */ + phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } + + /* Entry point is always a virtual address, so translate it + * to physical before returning it */ + return ehdr->e_entry; +} + +/** + * Return the base address for loading (i.e. the address of the first PT_LOAD + * segment) + * @param file_addr pointer to the ELF file in memory + * @return the base address + */ +long +elf_get_base_addr64(void *file_addr) +{ + struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; + /* Calculate program header address */ + struct phdr64 *phdr = get_phdr64(file_addr); + int i; + + /* loop e_phnum times */ + for (i = 0; i <= ehdr->e_phnum; i++) { + /* PT_LOAD ? */ + if (phdr->p_type == PT_LOAD) { + /* Return base address */ + return phdr->p_paddr; + } + /* step to next header */ + phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } + + return 0; +} + + +/** + * Apply one relocation entry. + */ +static void +elf_apply_rela64(void *file_addr, signed long offset, struct rela *relaentry, + struct sym64 *symtabentry) +{ + void *addr; + unsigned long s_a; + unsigned long base_addr; + + base_addr = elf_get_base_addr64(file_addr); + + /* Sanity check */ + if (relaentry->r_offset < base_addr) { + printf("\nELF relocation out of bounds!\n"); + return; + } + + base_addr += offset; + + /* Actual address where the relocation will be applied at. */ + addr = (void*)(relaentry->r_offset + offset); + + /* Symbol value (S) + Addend (A) */ + s_a = symtabentry->st_value + offset + relaentry->r_addend; + + switch (ELF_R_TYPE(relaentry->r_info)) { + case R_PPC64_ADDR32: /* S + A */ + *(uint32_t *)addr = (uint32_t) s_a; + break; + case R_PPC64_ADDR64: /* S + A */ + *(uint64_t *)addr = (uint64_t) s_a; + break; + case R_PPC64_TOC: /* .TOC */ + *(uint64_t *)addr += offset; + break; + case R_PPC64_ADDR16_HIGHEST: /* #highest(S + A) */ + *(uint16_t *)addr = ((s_a >> 48) & 0xffff); + break; + case R_PPC64_ADDR16_HIGHER: /* #higher(S + A) */ + *(uint16_t *)addr = ((s_a >> 32) & 0xffff); + break; + case R_PPC64_ADDR16_HI: /* #hi(S + A) */ + *(uint16_t *)addr = ((s_a >> 16) & 0xffff); + break; + case R_PPC64_ADDR16_LO: /* #lo(S + A) */ + *(uint16_t *)addr = s_a & 0xffff; + break; + case R_PPC64_ADDR16_LO_DS: + *(uint16_t *)addr = (s_a & 0xfffc); + break; + case R_PPC64_ADDR16_HA: /* #ha(S + A) */ + *(uint16_t *)addr = (((s_a >> 16) + ((s_a & 0x8000) ? 1 : 0)) + & 0xffff); + break; + + case R_PPC64_TOC16: /* half16* S + A - .TOC. */ + case R_PPC64_TOC16_LO_DS: + case R_PPC64_TOC16_LO: /* #lo(S + A - .TOC.) */ + case R_PPC64_TOC16_HI: /* #hi(S + A - .TOC.) */ + case R_PPC64_TOC16_HA: + case R_PPC64_TOC16_DS: /* (S + A - .TOC) >> 2 */ + case R_PPC64_REL14: + case R_PPC64_REL24: /* (S + A - P) >> 2 */ + case R_PPC64_REL64: /* S + A - P */ + case R_PPC64_GOT16_DS: + case R_PPC64_GOT16_LO_DS: + // printf("\t\tignoring relocation type %i\n", + // ELF_R_TYPE(relaentry->r_info)); + break; + default: + printf("ERROR: Unhandled relocation (A) type %i\n", + ELF_R_TYPE(relaentry->r_info)); + } +} + + +/** + * Step through all relocation entries and apply them one by one. + */ +static void +elf_apply_all_rela64(void *file_addr, signed long offset, struct shdr64 *shdrs, int idx) +{ + struct shdr64 *rela_shdr = &shdrs[idx]; + struct shdr64 *dst_shdr = &shdrs[rela_shdr->sh_info]; + struct shdr64 *sym_shdr = &shdrs[rela_shdr->sh_link]; + struct rela *relaentry; + struct sym64 *symtabentry; + uint32_t symbolidx; + int i; + + /* If the referenced section has not been allocated, then it has + * not been loaded and thus does not need to be relocated. */ + if ((dst_shdr->sh_flags & SHF_ALLOC) != SHF_ALLOC) + return; + + for (i = 0; i < rela_shdr->sh_size; i += rela_shdr->sh_entsize) { + relaentry = (struct rela *)(file_addr + rela_shdr->sh_offset + i); + + symbolidx = ELF_R_SYM(relaentry->r_info); + symtabentry = (struct sym64*)(file_addr + sym_shdr->sh_offset) + symbolidx; + + elf_apply_rela64(file_addr, offset, relaentry, symtabentry); + } +} + + +/** + * Apply ELF relocations + */ +void +elf_relocate64(void *file_addr, signed long offset) +{ + struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; + /* Calculate section header address */ + struct shdr64 *shdrs = (struct shdr64 *) + (((unsigned char *) file_addr) + ehdr->e_shoff); + int i; + + /* loop over all segments */ + for (i = 0; i <= ehdr->e_shnum; i++) { + /* Skip if it is not a relocation segment */ + if (shdrs[i].sh_type == SHT_RELA) { + elf_apply_all_rela64(file_addr, offset, shdrs, i); + } + } +} + +void +elf_byteswap_header64(void *file_addr) +{ + struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; + struct phdr64 *phdr; + int i; + + bswap_16p(&ehdr->e_type); + bswap_16p(&ehdr->e_machine); + bswap_32p(&ehdr->e_version); + bswap_64p(&ehdr->e_entry); + bswap_64p(&ehdr->e_phoff); + bswap_64p(&ehdr->e_shoff); + bswap_32p(&ehdr->e_flags); + bswap_16p(&ehdr->e_ehsize); + bswap_16p(&ehdr->e_phentsize); + bswap_16p(&ehdr->e_phnum); + bswap_16p(&ehdr->e_shentsize); + bswap_16p(&ehdr->e_shnum); + bswap_16p(&ehdr->e_shstrndx); + + phdr = get_phdr64(file_addr); + + /* loop e_phnum times */ + for (i = 0; i <= ehdr->e_phnum; i++) { + bswap_32p(&phdr->p_type); + bswap_32p(&phdr->p_flags); + bswap_64p(&phdr->p_offset); + bswap_64p(&phdr->p_vaddr); + bswap_64p(&phdr->p_paddr); + bswap_64p(&phdr->p_filesz); + bswap_64p(&phdr->p_memsz); + bswap_64p(&phdr->p_align); + + /* step to next header */ + phdr = (struct phdr64 *)(((uint8_t *)phdr) + ehdr->e_phentsize); + } +} + +uint32_t elf_get_eflags_64(void *file_addr) +{ + struct ehdr64 *ehdr = (struct ehdr64 *) file_addr; + + return ehdr->e_flags; +} diff --git a/qemu/roms/SLOF/lib/libelf/elf_claim.c b/qemu/roms/SLOF/lib/libelf/elf_claim.c new file mode 100644 index 000000000..43540f9b6 --- /dev/null +++ b/qemu/roms/SLOF/lib/libelf/elf_claim.c @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2009, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <libelf.h> +#include "../../slof/paflof.h" + + +/** + * Call Forth code to try to claim the memory region + */ +int +elf_forth_claim(void *addr, long size) +{ + forth_push((long)addr); + forth_push(size); + forth_eval("elf-claim-segment"); + return forth_pop(); +} diff --git a/qemu/roms/SLOF/lib/libelf/libelf.code b/qemu/roms/SLOF/lib/libelf/libelf.code new file mode 100644 index 000000000..551468bdd --- /dev/null +++ b/qemu/roms/SLOF/lib/libelf/libelf.code @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libelf Forth wrapper + */ + +#include <libelf.h> + +// : elf-load-file ( fileaddr -- entry type ) +PRIM(ELF_X2d_LOAD_X2d_FILE) +{ + void *file_addr = TOS.a; + int type; + unsigned long entry; + type = elf_load_file(file_addr, &entry, elf_forth_claim, flush_cache); + TOS.u = entry; + PUSH; TOS.n = type; +} +MIRP + +// : elf-load-file-to-addr ( fileaddr destaddr -- entry type ) +PRIM(ELF_X2d_LOAD_X2d_FILE_X2d_TO_X2d_ADDR) +{ + void *dest_addr = TOS.a; POP; + void *file_addr = TOS.a; + int type; + unsigned long entry; + type = elf_load_file_to_addr(file_addr, dest_addr, &entry, + elf_forth_claim, flush_cache); + TOS.u = entry; + PUSH; TOS.n = type; +} +MIRP diff --git a/qemu/roms/SLOF/lib/libelf/libelf.in b/qemu/roms/SLOF/lib/libelf/libelf.in new file mode 100644 index 000000000..9c5f019ce --- /dev/null +++ b/qemu/roms/SLOF/lib/libelf/libelf.in @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libelf bindings for Forth - definitions + */ + +cod(ELF-LOAD-FILE) +cod(ELF-LOAD-FILE-TO-ADDR) diff --git a/qemu/roms/SLOF/lib/libhvcall/Makefile b/qemu/roms/SLOF/lib/libhvcall/Makefile new file mode 100644 index 000000000..2a9b2d7d1 --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/Makefile @@ -0,0 +1,57 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) +LDFLAGS = -nostdlib + +TARGET = ../libhvcall.a + + +all: $(TARGET) + +SRCS = brokensc1.c +SRCSS = hvcall.S + + +OBJS = $(SRCS:%.c=%.o) $(SRCSS:%.S=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +%.o: %.S + $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep + diff --git a/qemu/roms/SLOF/lib/libhvcall/brokensc1.c b/qemu/roms/SLOF/lib/libhvcall/brokensc1.c new file mode 100644 index 000000000..e6387e0ab --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/brokensc1.c @@ -0,0 +1,162 @@ +#include <stdint.h> +#include <stddef.h> +#include <cpu.h> +#include "libhvcall.h" +#include "byteorder.h" + +// #define DEBUG_PATCHERY + +#define H_SET_DABR 0x28 +#define INS_SC1 0x44000022 +#define INS_SC1_REPLACE 0x7c000268 + +extern volatile uint32_t sc1ins; + +static unsigned long hcall(uint32_t inst, unsigned long arg0, unsigned long arg1) +{ + register unsigned long r3 asm("r3") = arg0; + register unsigned long r4 asm("r4") = arg1; + register unsigned long r5 asm("r5") = inst; + asm volatile("bl 1f \n" + "1: \n" + "li 11, 2f - 1b \n" + "mflr 12 \n" + "add 11, 11, 12 \n" + "stw 5, 0(11) \n" + "dcbst 0, 11 \n" + "sync \n" + "icbi 0, 11 \n" + "isync \n" + "2: \n" + ".long 0 \n" + : "=r" (r3) + : "r" (r3), "r" (r4), "r" (r5) + : "ctr", "r0", "r6", "r7", "r8", "r9", "r10", "r11", + "r12", "r13", "r31", "lr", "cc"); + return r3; +} + +static int check_broken_sc1(void) +{ + long r; + + /* + * Check if we can do a simple hcall. If it works, we are running in + * a sane environment and everything's fine. If it doesn't, we need + * to patch the hypercall instruction to something that traps into + * supervisor mode. + */ + r = hcall(INS_SC1, H_SET_DABR, 0); + if (r == H_SUCCESS || r == H_HARDWARE) { + /* All is fine */ + return 0; + } + + /* We found a broken sc1 host! */ + return 1; +} + +int patch_broken_sc1(void *start, void *end, uint32_t *test_ins) +{ + uint32_t *p; + /* The sc 1 instruction */ + uint32_t sc1 = INS_SC1; + /* An illegal instruction that KVM interprets as sc 1 */ + uint32_t sc1_replacement = INS_SC1_REPLACE; + int is_le = (test_ins && *test_ins == 0x48000008); +#ifdef DEBUG_PATCHERY + int cnt = 0; +#endif + + /* The host is sane, get out of here */ + if (!check_broken_sc1()) + return 0; + + /* We only get here with a broken sc1 implementation */ + + /* Trim the range we scan to not cover the data section */ + if (test_ins) { + /* This is the cpu table matcher for 970FX */ + uint32_t end_bytes[] = { 0xffff0000, 0x3c0000 }; + /* + * The .__start symbol contains a trap instruction followed + * by lots of zeros. + */ + uint32_t start_bytes[] = { 0x7fe00008, 0, 0, 0, 0 }; + + if (is_le) { + end_bytes[0] = bswap_32(end_bytes[0]); + end_bytes[1] = bswap_32(end_bytes[1]); + start_bytes[1] = bswap_32(start_bytes[1]); + } + + /* Find the start of the text section */ + for (p = test_ins; (long)p > (long)start; p--) { + if (p[0] == start_bytes[0] && + p[1] == start_bytes[1] && + p[2] == start_bytes[2] && + p[3] == start_bytes[3] && + p[4] == start_bytes[4]) { + /* + * We found a match of the instruction sequence + * trap + * .long 0 + * .long 0 + * .long 0 + * .long 0 + * which marks the beginning of the .text + * section on all Linux kernels I've checked. + */ +#ifdef DEBUG_PATCHERY + printf("Shortened start from %p to %p\n", end, p); +#endif + start = p; + break; + } + } + + /* Find the end of the text section */ + for (p = start; (long)p < (long)end; p++) { + if (p[0] == end_bytes[0] && p[1] == end_bytes[1]) { + /* + * We found a match of the PPC970FX entry in the + * guest kernel's CPU table. That table is + * usually found early in the .data section and + * thus marks the end of the .text section for + * us which we need to patch. + */ +#ifdef DEBUG_PATCHERY + printf("Shortened end from %p to %p\n", end, p); +#endif + end = p; + break; + } + } + } + + if (is_le) { + /* + * The kernel was built for LE mode, so our sc1 and replacement + * opcodes are in the wrong byte order. Reverse them. + */ + sc1 = bswap_32(sc1); + sc1_replacement = bswap_32(sc1_replacement); + } + + /* Patch all sc 1 instructions to reserved instruction 31/308 */ + for (p = start; (long)p < (long)end; p++) { + if (*p == sc1) { + *p = sc1_replacement; + flush_cache(p, sizeof(*p)); +#ifdef DEBUG_PATCHERY + cnt++; +#endif + } + } + +#ifdef DEBUG_PATCHERY + printf("Patched %d instructions (%p - %p)\n", cnt, start, end); +#endif + + return 1; +} diff --git a/qemu/roms/SLOF/lib/libhvcall/hvcall.S b/qemu/roms/SLOF/lib/libhvcall/hvcall.S new file mode 100644 index 000000000..92cf22e4c --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/hvcall.S @@ -0,0 +1,134 @@ +#define _ASM +#define __ASSEMBLY__ +#include "macros.h" +#include "libhvcall.h" +#include <termctrl.h> +#include <product.h> + +#define HVCALL .long 0x44000022 + .text + .align 3 + +ENTRY(get_print_banner) + LOAD32(r4, print_version) + LOAD32(r5, print_version_end) + std r4,0(r3) + std r5,8(r3) + blr + +ENTRY(hv_generic) + HVCALL + blr + +/* r3 = char, r4 = hvtermno */ +ENTRY(hv_putchar) + sldi r6,r3,(24+32) + li r3,H_PUT_TERM_CHAR + li r5,1 + HVCALL + blr + +/* r3 = hvtermno */ +ENTRY(hv_getchar) + mflr r10 + bl .hv_haschar + mtlr r10 + cmpwi cr0,r3,0 + beqlr + lis r9,inbuf@h + ori r9,r9,inbuf@l + lwz r4,20(r9) + lbzx r3,r4,r9 + addi r4,r4,1 + stw r4,20(r9) + blr + +/* r3 = hvtermno */ +ENTRY(hv_haschar) + mr r4,r3 + li r3,-1 + lis r9,inbuf@h + ori r9,r9,inbuf@l + lwz r5,16(r9) + lwz r6,20(r9) + cmplw cr0,r5,r6 + bnelr + li r3,H_GET_TERM_CHAR + HVCALL + lis r9,inbuf@h + ori r9,r9,inbuf@l + stw r4,16(r9) + li r3,0 + stw r3,20(r9) + cmplwi cr0,r4,0 + beqlr + li r3,-1 + std r5,0(r9) + std r6,8(r9) + blr + +ENTRY(hv_send_crq) + ld r5,0(r4) + ld r6,8(r4) + mr r4,r3 + li r3,H_SEND_CRQ + HVCALL + blr + +ENTRY(hv_send_logical_lan) + li r11,0 /* no continue token for now */ + mr r10,r9 + mr r9,r8 + mr r8,r7 + mr r7,r6 + mr r6,r5 + mr r5,r4 + mr r4,r3 + li r3,H_SEND_LOGICAL_LAN + HVCALL + blr + +ENTRY(hv_logical_ci_load) + mr r5,r4 + mr r4,r3 + li r3,H_LOGICAL_CI_LOAD + HVCALL + cmpdi cr0,r3,0 + mr r3,r4 + beqlr + li r3,-1 + blr + +ENTRY(hv_logical_ci_store) + mr r6,r5 + mr r5,r4 + mr r4,r3 + li r3,H_LOGICAL_CI_STORE + HVCALL + blr + +ENTRY(hv_logical_memop) + mr r8,r7 + mr r7,r6 + mr r6,r5 + mr r5,r4 + mr r4,r3 + lis r3,KVMPPC_H_LOGICAL_MEMOP@h + ori r3,r3,KVMPPC_H_LOGICAL_MEMOP@l + HVCALL + blr + +ENTRY(hv_cas) + mr r6,r5 + mr r5,r4 + mr r4,r3 + lis r3,KVMPPC_H_CAS@h + ori r3,r3,KVMPPC_H_CAS@l + HVCALL + blr + + .section ".bss" +inbuf: .space 16 +inlen: .space 4 +inpos: .space 4 + .text diff --git a/qemu/roms/SLOF/lib/libhvcall/hvcall.code b/qemu/roms/SLOF/lib/libhvcall/hvcall.code new file mode 100644 index 000000000..0ff50f27e --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/hvcall.code @@ -0,0 +1,131 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <libhvcall.h> + +// : hv-putchar ( hvtermno char -- ) +PRIM(hv_X2d_putchar) + char c = TOS.n; POP; + int hvtermno = TOS.n; POP; + hv_putchar(c, hvtermno); +MIRP + +// : hv-getchar ( hvtermno -- char ) +PRIM(hv_X2d_getchar) + TOS.n = hv_getchar(TOS.n); +MIRP + +// : hv-haschar ( hvtermno -- res ) +PRIM(hv_X2d_haschar) + TOS.n = hv_haschar(TOS.n); +MIRP + +// : hv-reg-crq ( unit qaddr qsize -- res ) +PRIM(hv_X2d_reg_X2d_crq) + unsigned long qsize = TOS.u; POP; + unsigned long qaddr = TOS.u; POP; + unsigned int unit = TOS.u; + TOS.n = hv_reg_crq(unit, qaddr, qsize); +MIRP + +// : hv-free-crq ( unit -- ) +PRIM(hv_X2d_free_X2d_crq) + unsigned int unit = TOS.u; POP; + hv_free_crq(unit); +MIRP + +// : hv-send-crq ( unit msgaddr -- rc ) +PRIM(hv_X2d_send_X2d_crq) + uint64_t *msgaddr = (uint64_t *)TOS.u; POP; + unsigned int unit = TOS.u; + TOS.n = hv_send_crq(unit, msgaddr); +MIRP + +// : hv-put-tce ( liobn ioba tce -- rc ) +PRIM(hv_X2d_put_X2d_tce) + uint64_t tce = TOS.u; POP; + uint64_t ioba = TOS.u; POP; + uint32_t liobn = TOS.u; + TOS.u = hv_generic(H_PUT_TCE, liobn, ioba, tce); +MIRP + +PRIM(RB_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(1, qaddr); +MIRP +PRIM(RB_X21) + unsigned long qaddr = TOS.u; POP; + unsigned char val = TOS.u; POP; + hv_logical_ci_store(1, qaddr, val); +MIRP +PRIM(RW_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(2, qaddr); +MIRP +PRIM(RW_X21) + unsigned long qaddr = TOS.u; POP; + unsigned short val = TOS.u; POP; + hv_logical_ci_store(2, qaddr, val); +MIRP +PRIM(RL_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(4, qaddr); +MIRP +PRIM(RL_X21) + unsigned long qaddr = TOS.u; POP; + unsigned int val = TOS.u; POP; + hv_logical_ci_store(4, qaddr, val); +MIRP +PRIM(RX_X40) + unsigned long qaddr = TOS.u; + TOS.u = hv_logical_ci_load(8, qaddr); +MIRP +PRIM(RX_X21) + unsigned long qaddr = TOS.u; POP; + unsigned long val = TOS.u; POP; + hv_logical_ci_store(8, qaddr, val); +MIRP + +PRIM(hv_X2d_logical_X2d_memop) + unsigned long op = TOS.u; POP; + unsigned long count = TOS.u; POP; + unsigned long esize = TOS.u; POP; + unsigned long src = TOS.u; POP; + unsigned long dst = TOS.u; + TOS.u = hv_logical_memop(dst, src, esize, count, op); +MIRP + +PRIM(hv_X2d_cas) + unsigned long size = TOS.u; POP; + unsigned long buf = TOS.u; POP; + unsigned long vec = TOS.u; + TOS.u = hv_cas(vec, buf, size); +MIRP + +PRIM(hv_X2d_rtas_X2d_update) + unsigned long rtas_entry = TOS.u; POP; + unsigned long rtas_base = TOS.u; + TOS.u = hv_generic(KVMPPC_H_RTAS_UPDATE, rtas_base, rtas_entry); +MIRP + +PRIM(get_X2d_print_X2d_version) + unsigned long addr = TOS.u; POP; + get_print_banner(addr); +MIRP + +PRIM(check_X2d_and_X2d_patch_X2d_sc1) + unsigned long end = TOS.u; POP; + unsigned long start = TOS.u; POP; + unsigned long patch_ins = TOS.u; POP; + + patch_broken_sc1((void*)start, (void*)end, (void*)patch_ins); +MIRP diff --git a/qemu/roms/SLOF/lib/libhvcall/hvcall.in b/qemu/roms/SLOF/lib/libhvcall/hvcall.in new file mode 100644 index 000000000..4437b77f0 --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/hvcall.in @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +cod(hv-putchar) +cod(hv-getchar) +cod(hv-haschar) +cod(hv-reg-crq) +cod(hv-free-crq) +cod(hv-send-crq) +cod(hv-put-tce) +cod(check-and-patch-sc1) + +cod(RB@) +cod(RB!) +cod(RW@) +cod(RW!) +cod(RL@) +cod(RL!) +cod(RX@) +cod(RX!) + +cod(hv-logical-memop) +cod(hv-cas) +cod(hv-rtas-update) +cod(get-print-version) diff --git a/qemu/roms/SLOF/lib/libhvcall/libhvcall.h b/qemu/roms/SLOF/lib/libhvcall/libhvcall.h new file mode 100644 index 000000000..193b7383d --- /dev/null +++ b/qemu/roms/SLOF/lib/libhvcall/libhvcall.h @@ -0,0 +1,107 @@ +#ifndef __LIBHVCALL_H__ +#define __LIBHVCALL_H__ + +#define H_SUCCESS 0 +#define H_HARDWARE -1 + +#define H_GET_TCE 0x1C +#define H_PUT_TCE 0x20 +#define H_LOGICAL_CI_LOAD 0x3c +#define H_LOGICAL_CI_STORE 0x40 +#define H_GET_TERM_CHAR 0x54 +#define H_PUT_TERM_CHAR 0x58 +#define H_REG_CRQ 0xFC +#define H_FREE_CRQ 0x100 +#define H_SEND_CRQ 0x108 +#define H_REGISTER_LOGICAL_LAN 0x114 +#define H_FREE_LOGICAL_LAN 0x118 +#define H_ADD_LOGICAL_LAN_BUFFER 0x11C +#define H_SEND_LOGICAL_LAN 0x120 + +/* KVM specific ones */ +#define KVMPPC_HCALL_BASE 0xf000 +#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) +#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1) +/* Client Architecture support */ +#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2) +#define KVMPPC_H_RTAS_UPDATE (KVMPPC_HCALL_BASE + 0x3) +#define KVMPPC_H_REPORT_MC_ERR (KVMPPC_HCALL_BASE + 0x4) +#define KVMPPC_HCALL_MAX KVMPPC_H_NMI_MCE + +#ifndef __ASSEMBLY__ + +extern long hv_generic(unsigned long opcode, ...); + +extern void hv_putchar(char c, int hvtermno); +extern char hv_getchar(int hvtermno); +extern char hv_haschar(int hvtermno); +extern void get_print_banner(unsigned long addr); + +extern int hv_send_crq(unsigned int unit, uint64_t *msgaddr); + +static inline long hv_reg_crq(unsigned int unit, unsigned long qaddr, + unsigned long qsize) +{ + return hv_generic(H_REG_CRQ, unit, qaddr, qsize); +} + +static inline void hv_free_crq(unsigned int unit) +{ + hv_generic(H_FREE_CRQ, unit); +} + +extern long hv_send_logical_lan(unsigned long unit_address, + unsigned long desc1, unsigned long desc2, + unsigned long desc3, unsigned long desc4, + unsigned long desc5, unsigned long desc6); + +static inline long h_register_logical_lan(unsigned long unit_address, + unsigned long buf_list, + unsigned long rec_q, + unsigned long filter_list, + unsigned long mac_address) +{ + return hv_generic(H_REGISTER_LOGICAL_LAN, unit_address, + buf_list, rec_q, filter_list, mac_address); +} + +static inline long h_free_logical_lan(unsigned long unit_address) +{ + return hv_generic(H_FREE_LOGICAL_LAN, unit_address); +} + +static inline long h_add_logical_lan_buffer(unsigned long unit_address, + unsigned long buffer) +{ + return hv_generic(H_ADD_LOGICAL_LAN_BUFFER, unit_address, buffer); +} + +#define HV_RTAS_MAX_ARGRET 5 + +struct hv_rtas_call { + uint32_t token; + uint32_t nargs; + uint32_t nrets; + uint32_t argret[HV_RTAS_MAX_ARGRET]; +}; + +static inline unsigned long h_rtas(struct hv_rtas_call *rtas_buf) +{ + return hv_generic(KVMPPC_H_RTAS, (unsigned long)rtas_buf); +} + +extern unsigned long hv_logical_ci_load(unsigned long size, unsigned long addr); +extern unsigned long hv_logical_ci_store(unsigned long size, unsigned long addr, + unsigned long value); + +extern unsigned long hv_logical_memop(unsigned long dst, unsigned long src, + unsigned long esize, unsigned long count, + unsigned long op); +extern int patch_broken_sc1(void *start, void *end, uint32_t *test_ins); + +extern unsigned long hv_cas(unsigned long vec, unsigned long buf, + unsigned long size); + +#endif /* __ASSEMBLY__ */ + +#endif /* __LIBHVCALL_H__ */ diff --git a/qemu/roms/SLOF/lib/libipmi/Makefile b/qemu/roms/SLOF/lib/libipmi/Makefile new file mode 100644 index 000000000..4777f9edd --- /dev/null +++ b/qemu/roms/SLOF/lib/libipmi/Makefile @@ -0,0 +1,28 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2007 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +LIBIPMICMNDIR = $(shell pwd) + +include $(TOPCMNDIR)/make.rules + +TARGET = ../libipmi.a + +all: $(TARGET) + +$(TARGET): + cp libipmi.oco $@ + +clean: + +distclean: diff --git a/qemu/roms/SLOF/lib/libipmi/libipmi.code b/qemu/roms/SLOF/lib/libipmi/libipmi.code new file mode 100644 index 000000000..59c124418 --- /dev/null +++ b/qemu/roms/SLOF/lib/libipmi/libipmi.code @@ -0,0 +1,120 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <libipmi.h> + +// : ipmi-kcs-cmd ( in-buf in-len out-buf out-maxlen -- out-len errorcode ) +PRIM(IPMI_X2d_KCS_X2d_CMD) + cell maxlen = TOS; POP; + cell outbuf = TOS; POP; + int len = TOS.n; POP; + cell inbuf = TOS; + int retval; + retval = ipmi_kcs_cmd(inbuf.a, outbuf.a, maxlen.n, (uint32_t *) &len); + TOS.n = len; + PUSH; TOS.n = retval; +MIRP + + +PRIM(IPMI_X2d_SYSTEM_X2d_REBOOT) + ipmi_system_reboot(); +MIRP + + +PRIM(IPMI_X2d_POWER_X2d_OFF) + ipmi_power_off(); +MIRP + + +// : ipmi-oem-stop-bootwatchdog ( -- errorcode ) +PRIM(IPMI_X2d_OEM_X2d_STOP_X2d_BOOTWATCHDOG) + PUSH; + TOS.n = ipmi_oem_stop_bootwatchdog(); +MIRP + + +// : ipmi-oem-set-bootwatchdog ( seconds -- errorcode ) +PRIM(IPMI_X2d_OEM_X2d_SET_X2d_BOOTWATCHDOG) + int sec = TOS.n; + TOS.n = ipmi_oem_set_bootwatchdog(sec); +MIRP + + +// : ipmi-oem-reset-bootwatchdog ( -- errorcode ) +PRIM(IPMI_X2d_OEM_X2d_RESET_X2d_BOOTWATCHDOG) + PUSH; + TOS.n = ipmi_oem_reset_bootwatchdog(); +MIRP + + +// : ipmi-oem-led-set ( type instance state -- errorcode ) +PRIM(IPMI_X2d_OEM_X2d_LED_X2d_SET) + int state = TOS.n; POP; + int instance = TOS.n; POP; + int type = TOS.n; + TOS.n = ipmi_oem_led_set(type, instance, state); +MIRP + + +// : ipmi-oem-read-vpd ( offset length dst -- status ) +PRIM(IPMI_X2d_OEM_X2d_READ_X2d_VPD) + cell dest = TOS; POP; + int len = TOS.n; POP; + int offset = TOS.n; + TOS.n = ipmi_oem_read_vpd(dest.a, len, offset); +MIRP + +// : ipmi-oem-write-vpd ( offset length src -- status ) +PRIM(IPMI_X2d_OEM_X2d_WRITE_X2d_VPD) + cell src = TOS; POP; + int len = TOS.n; POP; + int offset = TOS.n; + TOS.n = ipmi_oem_write_vpd(src.a, len, offset); +MIRP + + +// : ipmi-oem-get-blade-descr ( buf maxlen -- len status ) +PRIM(IPMI_X2d_OEM_X2d_GET_X2d_BLADE_X2d_DESCR) + int maxlen = TOS.n; POP; + cell buf = TOS; + int len = 0; + int retval; + retval = ipmi_oem_get_blade_descr(buf.a, maxlen, (uint32_t *) &len); + TOS.n = len; + PUSH; TOS.n = retval; +MIRP + + +// : ipmi-oem-bios2sp ( str-ptr str-len swid type -- errorcode ) +PRIM(IPMI_X2d_OEM_X2d_BIOS2SP) + int type = TOS.n; POP; + int swid = TOS.n; POP; + int len = TOS.n; POP; + void* addr = TOS.a; + TOS.n = ipmi_oem_bios2sp(swid, type, addr, len); +MIRP + +// : ipmi-set-sensor ( param-1 ... param-n n command sensor - errorcode ) +PRIM(IPMI_X2d_SET_X2d_SENSOR) + int sensor = TOS.n; POP; + int cmd = TOS.n; POP; + int n = TOS.n; + int i = n; + uint8_t param[10]; + while (i>0) { + i--; + POP; param[i]=TOS.n; + }; + TOS.n = ipmi_set_sensor((cmd<<8)+sensor,n, + param[0],param[1],param[2],param[3],param[4], + param[5],param[6],param[7],param[8],param[9]); +MIRP diff --git a/qemu/roms/SLOF/lib/libipmi/libipmi.h b/qemu/roms/SLOF/lib/libipmi/libipmi.h new file mode 100644 index 000000000..9ac83087e --- /dev/null +++ b/qemu/roms/SLOF/lib/libipmi/libipmi.h @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __LIBIPMI_H +#define __LIBIPMI_H + +#include <stdint.h> + +extern int ipmi_kcs_cmd(uint8_t *, uint8_t *, uint32_t, uint32_t *); + +extern void ipmi_system_reboot(void); +extern void ipmi_power_off(void); +extern int ipmi_set_sensor(const int sensor, int number_of_args, ...); + +extern int ipmi_oem_stop_bootwatchdog(void); +extern int ipmi_oem_set_bootwatchdog(uint16_t seconds); +extern int ipmi_oem_reset_bootwatchdog(void); +extern int ipmi_oem_led_set(int type, int instance, int state); +extern uint32_t ipmi_oem_read_vpd(uint8_t *dst, uint32_t len, uint32_t offset); +extern uint32_t ipmi_oem_write_vpd(uint8_t *src, uint32_t len, uint32_t offset); +extern uint32_t ipmi_oem_get_blade_descr(uint8_t *dst, uint32_t maxlen, uint32_t *len); +extern int ipmi_oem_bios2sp(int swid, int type, char *data, int len); + +#endif diff --git a/qemu/roms/SLOF/lib/libipmi/libipmi.in b/qemu/roms/SLOF/lib/libipmi/libipmi.in new file mode 100644 index 000000000..5b0e0ec5e --- /dev/null +++ b/qemu/roms/SLOF/lib/libipmi/libipmi.in @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +cod(IPMI-KCS-CMD) +cod(IPMI-SYSTEM-REBOOT) +cod(IPMI-POWER-OFF) +cod(IPMI-OEM-STOP-BOOTWATCHDOG) +cod(IPMI-OEM-SET-BOOTWATCHDOG) +cod(IPMI-OEM-RESET-BOOTWATCHDOG) +cod(IPMI-OEM-LED-SET) +cod(IPMI-OEM-READ-VPD) +cod(IPMI-OEM-WRITE-VPD) +cod(IPMI-OEM-GET-BLADE-DESCR) +cod(IPMI-OEM-BIOS2SP) +cod(IPMI-SET-SENSOR) diff --git a/qemu/roms/SLOF/lib/libipmi/libipmi.oco b/qemu/roms/SLOF/lib/libipmi/libipmi.oco Binary files differnew file mode 100644 index 000000000..74af7249c --- /dev/null +++ b/qemu/roms/SLOF/lib/libipmi/libipmi.oco diff --git a/qemu/roms/SLOF/lib/libnativeio/nativeio.code b/qemu/roms/SLOF/lib/libnativeio/nativeio.code new file mode 100644 index 000000000..4887b115a --- /dev/null +++ b/qemu/roms/SLOF/lib/libnativeio/nativeio.code @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* There are 970 implementations. If we are ever to run native IOs + * on Power7 in hypervisor mode, these will have to change to use + * the new CI-load/store instructions + */ +PRIM(RB_X40) GET_CHAR1; SET_CI; GET_CHAR2; CLR_CI; GET_CHAR3; MIRP +PRIM(RB_X21) PUT_CHAR1; SET_CI; PUT_CHAR2; CLR_CI; MIRP +PRIM(RW_X40) GET_WORD1; SET_CI; GET_WORD2; CLR_CI; GET_WORD3; MIRP +PRIM(RW_X21) PUT_WORD1; SET_CI; PUT_WORD2; CLR_CI; MIRP +PRIM(RL_X40) GET_LONG1; SET_CI; GET_LONG2; CLR_CI; GET_LONG3; MIRP +PRIM(RL_X21) PUT_LONG1; SET_CI; PUT_LONG2; CLR_CI; MIRP +PRIM(RX_X40) GET_XONG1; SET_CI; GET_XONG2; CLR_CI; GET_XONG3; MIRP +PRIM(RX_X21) PUT_XONG1; SET_CI; PUT_XONG2; CLR_CI; MIRP + diff --git a/qemu/roms/SLOF/lib/libnativeio/nativeio.in b/qemu/roms/SLOF/lib/libnativeio/nativeio.in new file mode 100644 index 000000000..f5fb9d977 --- /dev/null +++ b/qemu/roms/SLOF/lib/libnativeio/nativeio.in @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +// I/O accesses. +cod(RB@) +cod(RB!) +cod(RW@) +cod(RW!) +cod(RL@) +cod(RL!) +cod(RX@) +cod(RX!) + diff --git a/qemu/roms/SLOF/lib/libnvram/Makefile b/qemu/roms/SLOF/lib/libnvram/Makefile new file mode 100644 index 000000000..d4e9a617e --- /dev/null +++ b/qemu/roms/SLOF/lib/libnvram/Makefile @@ -0,0 +1,53 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +SRCS = nvram.c envvar.c + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) $(FLAG) \ + -I$(INCLBRDDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I. -I../../include +LDFLAGS = -nostdlib + +TARGET = ../libnvram.a + +all: $(TARGET) + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(SRCS) > Makefile.dep + + +# Include dependency file if available: +-include Makefile.dep + diff --git a/qemu/roms/SLOF/lib/libnvram/envvar.c b/qemu/roms/SLOF/lib/libnvram/envvar.c new file mode 100644 index 000000000..87aaf27a0 --- /dev/null +++ b/qemu/roms/SLOF/lib/libnvram/envvar.c @@ -0,0 +1,243 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include "../libc/include/stdio.h" +#include "../libc/include/string.h" +#include "../libc/include/stdlib.h" +#include "nvram.h" + +/* returns the offset of the first byte after the searched envvar */ +static int get_past_env_pos(partition_t part, char *envvar) +{ + int offset, len; + static char temp[256]; + uint8_t data; + + offset=part.addr; + + memset(temp, 0, 256); + + do { + len=0; + while((data=nvram_read_byte(offset++)) && len < 256) { + temp[len++]=data; + } + if (!strncmp(envvar, temp, strlen(envvar))) { + return offset; + } + } while (len); + + return -1; +} + +/** + * @param partition name of the envvar partition + * @param envvar name of the environment variable + * @return pointer to temporary string containing the value of envvar + */ + +char *get_env(partition_t part, char *envvar) +{ + static char temp[256+1]; + int len, offset; + uint8_t data; + + DEBUG("get_env %s... ", envvar); + if(!part.addr) { + /* ERROR: No environment variable partition */ + DEBUG("invalid partition.\n"); + return NULL; + } + + offset=part.addr; + + do { + len=0; + while((data=nvram_read_byte(offset++)) && len < 256) { + temp[len++]=data; + } + temp[len]=0; + + if (!strncmp(envvar, temp, strlen(envvar))) { + int pos=0; + while (temp[pos]!='=' && pos < len) pos++; + // DEBUG("value='%s'\n", temp+pos+1); + return temp+pos+1; + } + } while (len); + + DEBUG("not found\n"); + return NULL; +} + +static int find_last_envvar(partition_t part) +{ + uint8_t last, current; + int offset; + + offset=part.addr; + + last=nvram_read_byte(part.addr); + + for (offset=part.addr; offset<(int)(part.addr+part.len); offset++) { + current=nvram_read_byte(offset); + if(!last && !current) + return offset; + + last=current; + } + + return -1; +} + +int add_env(partition_t part, char *envvar, char *value) +{ + int freespace, last, len, offset; + unsigned int i; + + /* Find offset where we can write */ + last = find_last_envvar(part); + + /* How much space do we have left? */ + freespace = part.addr+part.len-last; + + /* how long is the entry we want to write? */ + len = strlen(envvar) + strlen(value) + 2; + + if(freespace<len) { + // TODO try to increase partition size + return -1; + } + + offset=last; + + for(i=0; i<strlen(envvar); i++) + nvram_write_byte(offset++, envvar[i]); + + nvram_write_byte(offset++, '='); + + for(i=0; i<strlen(value); i++) + nvram_write_byte(offset++, value[i]); + + return 0; +} + +int del_env(partition_t part, char *envvar) +{ + int last, current, pos, i; + char *buffer; + + if(!part.addr) + return -1; + + last=find_last_envvar(part); + current = pos = get_past_env_pos(part, envvar); + + // TODO is this really required? + /* go back to non-0 value */ + current--; + + while (nvram_read_byte(current)) + current--; + + // TODO is this required? + current++; + + buffer=get_nvram_buffer(last-pos); + + for (i=0; i<last-pos; i++) + buffer[i]=nvram_read_byte(i+pos); + + for (i=0; i<last-pos; i++) + nvram_write_byte(i+current, buffer[i]); + + free_nvram_buffer(buffer); + + erase_nvram(last, current+last-pos); + + return 0; +} + +int set_env(partition_t part, char *envvar, char *value) +{ + char *oldvalue, *buffer; + int last, current, buffersize, i; + + DEBUG("set_env %lx[%lx]: %s=%s\n", part.addr, part.len, envvar, value); + + if(!part.addr) + return -1; + + /* Check whether the environment variable exists already */ + oldvalue = get_env(part, envvar); + + if(oldvalue==NULL) + return add_env(part, envvar, value); + + + /* The value did not change. So we succeeded! */ + if(!strncmp(oldvalue, value, strlen(value)+1)) + return 0; + + /* we need to overwrite environment variables, back them up first */ + + // DEBUG("overwriting existing environment variable\n"); + + /* allocate a buffer */ + last=find_last_envvar(part); + current=get_past_env_pos(part, envvar); + buffersize = last - current; + buffer=get_nvram_buffer(buffersize); + if(!buffer) + return -1; + + for (i=0; i<buffersize; i++) { + buffer[i] = nvram_read_byte(current+i); + } + + /* walk back until the = */ + while (nvram_read_byte(current)!='=') { + current--; + } + + /* Start at envvar= */ + current++; + + /* Write the new value */ + for(i=0; i<(int)strlen(value); i++) { + nvram_write_byte(current++, value[i]); + } + + /* Write end of string marker */ + nvram_write_byte(current++, 0); + + /* Copy back the buffer */ + for (i=0; i<buffersize; i++) { + nvram_write_byte(current++, buffer[i]); + } + + free_nvram_buffer(buffer); + + /* If the new environment variable content is shorter than the old one, + * we need to erase the rest of the bytes + */ + + if (current<last) { + for(i=current; i<last; i++) { + nvram_write_byte(i, 0); + } + } + + return 0; /* success */ +} + diff --git a/qemu/roms/SLOF/lib/libnvram/libnvram.code b/qemu/roms/SLOF/lib/libnvram/libnvram.code new file mode 100644 index 000000000..723941d3e --- /dev/null +++ b/qemu/roms/SLOF/lib/libnvram/libnvram.code @@ -0,0 +1,287 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <nvram.h> + +#define STRING_INIT(str) \ + char str[255]; \ + char * str##_address; \ + int str##_length; + +#define STRING_FROM_STACK(str) \ + str##_length = TOS.u; POP; \ + str##_address = TOS.a; POP; \ + memcpy(str, str##_address, str##_length); \ + memset(str + str##_length, 0, 255 - str##_length); + +PRIM(nvram_X2d_c_X40) + unsigned int offset = TOS.u; + TOS.u=nvram_read_byte(offset); +MIRP + +PRIM(nvram_X2d_w_X40) + unsigned int offset = TOS.u; + TOS.u=nvram_read_word(offset); +MIRP + +PRIM(nvram_X2d_l_X40) + unsigned int offset = TOS.u; + TOS.u=nvram_read_dword(offset); +MIRP + +PRIM(nvram_X2d_x_X40) + unsigned int offset = TOS.u; + TOS.u=nvram_read_qword(offset); +MIRP + +PRIM(nvram_X2d_c_X21) + nvram_write_byte(TOS.u, NOS.u); + POP; POP; +MIRP + +PRIM(nvram_X2d_w_X21) + nvram_write_word(TOS.u, NOS.u); + POP; POP; +MIRP + +PRIM(nvram_X2d_l_X21) + nvram_write_dword(TOS.u, NOS.u); + POP; POP; +MIRP + +PRIM(nvram_X2d_x_X21) + nvram_write_qword(TOS.u, NOS.u); + POP; POP; +MIRP + +/* get-nvram-partition ( type -- addr len FAILED? ) */ +PRIM(get_X2d_nvram_X2d_partition) + partition_t partition; + unsigned int ptype = TOS.u; + partition = get_partition(ptype, NULL); + if(partition.len && partition.len != -1) { + TOS.u = partition.addr; + PUSH; + TOS.u = partition.len; + PUSH; + TOS.u = 0; // FALSE + } else { + TOS.u = -1; // TRUE + } +MIRP + +/* get-named-nvram-partition ( name.addr name.len -- addr len FAILED? ) */ +PRIM(get_X2d_named_X2d_nvram_X2d_partition) + STRING_INIT(name) + partition_t partition; + + STRING_FROM_STACK(name) + partition = get_partition(-1, name); + + if(partition.len && partition.len != -1) { + PUSH; + TOS.u = partition.addr; + PUSH; + TOS.u = partition.len; + PUSH; + TOS.u = 0; // FALSE + } else { + PUSH; + TOS.u = -1; // TRUE + } +MIRP + + + +/* new-nvram-partition ( type name.addr name.len len -- part.offs part.len FALSE | TRUE) */ +PRIM(new_X2d_nvram_X2d_partition) + int type, len, i, slen; + char name[12], *addr; + partition_t partition; + + len = TOS.u; POP; + slen = TOS.u; POP; + addr = (char *)TOS.u; POP; + type = TOS.u; POP; + + for (i=0; i<12; i++) { + if(slen>i) + name[i]=addr[i]; + else + name[i]=0; + } + + partition=new_nvram_partition(type, name, len); + + if(!partition.len) { + PUSH; TOS.u = -1; // TRUE + } else { + PUSH; TOS.u = partition.addr; + PUSH; TOS.u = partition.len; + PUSH; TOS.u = 0; // FALSE + } +MIRP + +/* inrease-nvram-partition ( part.offs part.len new-len -- FALSE | TRUE ) */ +PRIM(increase_X2d_nvram_X2d_partition) + int len, ret; + partition_t partition; + + // FIXME + partition.addr = TOS.u; POP; + partition.len = TOS.u; POP; + len = TOS.u; POP; + + ret=increase_nvram_partition_size(partition, len); + + PUSH; + + if(!ret) + TOS.u=-1; // TRUE + else + TOS.u=0; // FALSE + +MIRP + +PRIM(internal_X2d_reset_X2d_nvram) + reset_nvram(); +MIRP + +PRIM(wipe_X2d_nvram) + wipe_nvram(); +MIRP + +PRIM(nvram_X2d_debug) + nvram_debug(); +MIRP + +// ( part.start part.len name.addr name.len -- var.addr var.len TRUE | false ) +PRIM(internal_X2d_get_X2d_env) + STRING_INIT(name) + partition_t part; + char *val; + + STRING_FROM_STACK(name) + part.len = TOS.u; POP; + part.addr = TOS.u; POP; + + val=get_env(part, name); + if(val) { + PUSH; TOS.a = val; + PUSH; TOS.u = strlen(val); + PUSH; TOS.u = -1; // TRUE + } else { + PUSH; TOS.u = 0; // FALSE + } +MIRP + +// ( part.start part.len name.addr name.len val.addr val.len -- FALSE|TRUE) +PRIM(internal_X2d_add_X2d_env) + STRING_INIT(name) + STRING_INIT(value) + partition_t part; + int ret; + + STRING_FROM_STACK(value) + STRING_FROM_STACK(name) + part.len = TOS.u; POP; + part.addr = TOS.u; POP; + + ret=add_env(part, name, value); + if(ret) { + PUSH; TOS.u = -1; // TRUE + } else { + PUSH; TOS.u = 0; // FALSE + } +MIRP + +// ( part.addr part.len name.addr name.len -- FALSE|TRUE) +PRIM(internal_X2d_del_X2d_env) + STRING_INIT(name) + partition_t part; + int ret; + + STRING_FROM_STACK(name); + part.len = TOS.u; POP; + part.addr = TOS.u; POP; + + ret=del_env(part, name); + if(ret) { + PUSH; TOS.u = -1; // TRUE + } else { + PUSH; TOS.u = 0; // FALSE + } + +MIRP + +// internal-set-env ( part.addr part.len name.addr name.len val.addr val.len -- FALSE|TRUE) +PRIM(internal_X2d_set_X2d_env) + STRING_INIT(name) + STRING_INIT(value) + partition_t part; + int ret; + + STRING_FROM_STACK(value) + STRING_FROM_STACK(name) + part.len = TOS.u; POP; + part.addr = TOS.u; POP; + + ret=set_env(part, name, value); + if(ret) { + PUSH; TOS.u = -1; // TRUE + } else { + PUSH; TOS.u = 0; // FALSE + } +MIRP + +// ( part.addr part.len -- FALSE|TRUE) +PRIM(erase_X2d_nvram_X2d_partition) + partition_t part; + int ret; + + part.len = TOS.u; POP; + part.addr = TOS.u; POP; + + ret=clear_nvram_partition(part); + if(ret) { + PUSH; TOS.u = -1; // TRUE + } else { + PUSH; TOS.u = 0; // FALSE + } + +MIRP + +// ( part.addr part.len -- FALSE|TRUE) +PRIM(delete_X2d_nvram_X2d_partition) + partition_t part; + int ret; + + part.len = TOS.u; POP; + part.addr = TOS.u; POP; + + ret=delete_nvram_partition(part); + if(ret) { + PUSH; TOS.u = -1; // TRUE + } else { + PUSH; TOS.u = 0; // FALSE + } + +MIRP + +// ( fetch_token store_token size nvram-addr -- ) +PRIM(internal_X2d_nvram_X2d_init) + void *nvram_addr = TOS.a; POP; + uint32_t nvram_size = TOS.u; POP; + uint32_t store_token = TOS.u; POP; + long fetch_token = TOS.u; POP; + + nvram_init(fetch_token, store_token, nvram_size, nvram_addr); +MIRP diff --git a/qemu/roms/SLOF/lib/libnvram/libnvram.in b/qemu/roms/SLOF/lib/libnvram/libnvram.in new file mode 100644 index 000000000..bbb20a889 --- /dev/null +++ b/qemu/roms/SLOF/lib/libnvram/libnvram.in @@ -0,0 +1,42 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* NVRAM access primitives */ +cod(nvram-c@) +cod(nvram-c!) +cod(nvram-w@) +cod(nvram-w!) +cod(nvram-l@) +cod(nvram-l!) +cod(nvram-x@) +cod(nvram-x!) + +/* Generic NVRAM helpers */ +cod(internal-reset-nvram) +cod(nvram-debug) +cod(wipe-nvram) + +/* NVRAM Partition Handling */ +cod(get-nvram-partition) +cod(get-named-nvram-partition) +cod(new-nvram-partition) +cod(increase-nvram-partition) +cod(erase-nvram-partition) +cod(delete-nvram-partition) + +/* NVRAM environment access words */ +cod(internal-get-env) +cod(internal-add-env) +cod(internal-del-env) +cod(internal-set-env) + +cod(internal-nvram-init) diff --git a/qemu/roms/SLOF/lib/libnvram/nvram.c b/qemu/roms/SLOF/lib/libnvram/nvram.c new file mode 100644 index 000000000..5c1137669 --- /dev/null +++ b/qemu/roms/SLOF/lib/libnvram/nvram.c @@ -0,0 +1,623 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "cache.h" +#include "nvram.h" +#include "../libhvcall/libhvcall.h" + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <southbridge.h> +#include <nvramlog.h> +#include <byteorder.h> + +#ifdef RTAS_NVRAM +static uint32_t fetch_token; +static uint32_t store_token; +static uint32_t NVRAM_LENGTH; +static char *nvram_buffer; /* use buffer allocated by SLOF code */ +#else +#ifndef NVRAM_LENGTH +#define NVRAM_LENGTH 0x10000 +#endif +/* + * This is extremely ugly, but still better than implementing + * another sbrk() around it. + */ +static char nvram_buffer[NVRAM_LENGTH]; +#endif + +static uint8_t nvram_buffer_locked=0x00; + +void nvram_init(uint32_t _fetch_token, uint32_t _store_token, + long _nvram_length, void* nvram_addr) +{ +#ifdef RTAS_NVRAM + fetch_token = _fetch_token; + store_token = _store_token; + NVRAM_LENGTH = _nvram_length; + nvram_buffer = nvram_addr; + + DEBUG("\nNVRAM: size=%d, fetch=%x, store=%x\n", + NVRAM_LENGTH, fetch_token, store_token); +#endif +} + + +void asm_cout(long Character,long UART,long NVRAM); + +#if defined(DISABLE_NVRAM) + +static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */ + +#define nvram_access(type,size,name) \ + type nvram_read_##name(unsigned int offset) \ + { \ + type *pos; \ + if (offset > (NVRAM_LENGTH - sizeof(type))) \ + return 0; \ + pos = (type *)(nvram+offset); \ + return *pos; \ + } \ + void nvram_write_##name(unsigned int offset, type data) \ + { \ + type *pos; \ + if (offset > (NVRAM_LENGTH - sizeof(type))) \ + return; \ + pos = (type *)(nvram+offset); \ + *pos = data; \ + } + +#elif defined(RTAS_NVRAM) + +static inline void nvram_fetch(unsigned int offset, void *buf, unsigned int len) +{ + struct hv_rtas_call rtas = { + .token = fetch_token, + .nargs = 3, + .nrets = 2, + .argret = { offset, (uint32_t)(unsigned long)buf, len }, + }; + h_rtas(&rtas); +} + +static inline void nvram_store(unsigned int offset, void *buf, unsigned int len) +{ + struct hv_rtas_call rtas = { + .token = store_token, + .nargs = 3, + .nrets = 2, + .argret = { offset, (uint32_t)(unsigned long)buf, len }, + }; + h_rtas(&rtas); +} + +#define nvram_access(type,size,name) \ + type nvram_read_##name(unsigned int offset) \ + { \ + type val; \ + if (offset > (NVRAM_LENGTH - sizeof(type))) \ + return 0; \ + nvram_fetch(offset, &val, size / 8); \ + return val; \ + } \ + void nvram_write_##name(unsigned int offset, type data) \ + { \ + if (offset > (NVRAM_LENGTH - sizeof(type))) \ + return; \ + nvram_store(offset, &data, size / 8); \ + } + +#else /* DISABLE_NVRAM */ + +static volatile uint8_t *nvram = (volatile uint8_t *)SB_NVRAM_adr; + +#define nvram_access(type,size,name) \ + type nvram_read_##name(unsigned int offset) \ + { \ + type *pos; \ + if (offset > (NVRAM_LENGTH - sizeof(type))) \ + return 0; \ + pos = (type *)(nvram+offset); \ + return ci_read_##size(pos); \ + } \ + void nvram_write_##name(unsigned int offset, type data) \ + { \ + type *pos; \ + if (offset > (NVRAM_LENGTH - sizeof(type))) \ + return; \ + pos = (type *)(nvram+offset); \ + ci_write_##size(pos, data); \ + } + +#endif + +/* + * producer for nvram access functions. Since these functions are + * basically all the same except for the used data types, produce + * them via the nvram_access macro to keep the code from bloating. + */ + +nvram_access(uint8_t, 8, byte) +nvram_access(uint16_t, 16, word) +nvram_access(uint32_t, 32, dword) +nvram_access(uint64_t, 64, qword) + + + +/** + * This function is a minimal abstraction for our temporary + * buffer. It should have been malloced, but since there is no + * usable malloc, we go this route. + * + * @return pointer to temporary buffer + */ + +char *get_nvram_buffer(int len) +{ + if(len>NVRAM_LENGTH) + return NULL; + + if(nvram_buffer_locked) + return NULL; + + nvram_buffer_locked = 0xff; + + return nvram_buffer; +} + +/** + * @param buffer pointer to the allocated buffer. This + * is unused, but nice in case we ever get a real malloc + */ + +void free_nvram_buffer(char *buffer __attribute__((unused))) +{ + nvram_buffer_locked = 0x00; +} + +/** + * @param fmt format string, like in printf + * @param ... variable number of arguments + */ + +int nvramlog_printf(const char* fmt, ...) +{ + char buff[256]; + int count, i; + va_list ap; + + va_start(ap, fmt); + count = vsprintf(buff, fmt, ap); + va_end(ap); + + for (i=0; i<count; i++) + asm_cout(buff[i], 0, 1); + + return count; +} + +/** + * @param offset start offset of the partition header + */ + +static uint8_t get_partition_type(int offset) +{ + return nvram_read_byte(offset); +} + +/** + * @param offset start offset of the partition header + */ + +static uint8_t get_partition_header_checksum(int offset) +{ + return nvram_read_byte(offset+1); +} + +/** + * @param offset start offset of the partition header + */ + +static uint16_t get_partition_len(int offset) +{ + return nvram_read_word(offset+2); +} + +/** + * @param offset start offset of the partition header + * @return static char array containing the partition name + * + * NOTE: If the partition name needs to be non-temporary, strdup + * and use the copy instead. + */ + +static char * get_partition_name(int offset) +{ + static char name[12]; + int i; + for (i=0; i<12; i++) + name[i]=nvram_read_byte(offset+4+i); + + DEBUG("name: \"%s\"\n", name); + return name; +} + +static uint8_t calc_partition_header_checksum(int offset) +{ + uint16_t plainsum; + uint8_t checksum; + int i; + + plainsum = nvram_read_byte(offset); + + for (i=2; i<PARTITION_HEADER_SIZE; i++) + plainsum+=nvram_read_byte(offset+i); + + checksum=(plainsum>>8)+(plainsum&0xff); + + return checksum; +} + +static int calc_used_nvram_space(void) +{ + int walk, len; + + for (walk=0; walk<NVRAM_LENGTH;) { + if(nvram_read_byte(walk) == 0 + || get_partition_header_checksum(walk) != + calc_partition_header_checksum(walk)) { + /* If there's no valid entry, bail out */ + break; + } + + len=get_partition_len(walk); + DEBUG("... part len=%x, %x\n", len, len*16); + + if(!len) { + /* If there's a partition type but no len, bail out. + * Don't bail out if type is 0. This can be used to + * find the offset of the first free byte. + */ + break; + } + + walk += len * 16; + } + DEBUG("used nvram space: %d\n", walk); + + return walk; +} + +/** + * + * @param type partition type. Set this to the partition type you are looking + * for. If there are several partitions with the same type, only + * the first partition with that type will be found. + * Set to -1 to ignore. Set to 0 to find free unpartitioned space. + * + * @param name partition name. Set this to the name of the partition you are + * looking for. If there are several partitions with the same name, + * only the first partition with that name will be found. + * Set to NULL to ignore. + * + * To disambiguate the partitions you should have a unique name if you plan to + * have several partitions of the same type. + * + */ + +partition_t get_partition(unsigned int type, char *name) +{ + partition_t ret={0,-1}; + int walk, len; + + DEBUG("get_partition(%i, '%s')\n", type, name); + + for (walk=0; walk<NVRAM_LENGTH;) { + // DEBUG("get_partition: walk=%x\n", walk); + if(get_partition_header_checksum(walk) != + calc_partition_header_checksum(walk)) { + /* If there's no valid entry, bail out */ + break; + } + + len=get_partition_len(walk); + if(type && !len) { + /* If there's a partition type but no len, bail out. + * Don't bail out if type is 0. This can be used to + * find the offset of the first free byte. + */ + break; + } + + /* Check if either type or name or both do not match. */ + if ( (type!=(unsigned int)-1 && type != get_partition_type(walk)) || + (name && strncmp(get_partition_name(walk), name, 12)) ) { + /* We hit another partition. Continue + * at the end of this partition + */ + walk += len*16; + continue; + } + + ret.addr=walk+PARTITION_HEADER_SIZE; + ret.len=(len*16)-PARTITION_HEADER_SIZE; + break; + } + + return ret; +} + +void erase_nvram(int offset, int len) +{ + int i; + + for (i=offset; i<offset+len; i++) + nvram_write_byte(i, 0); +} + +void wipe_nvram(void) +{ + erase_nvram(0, NVRAM_LENGTH); +} + +/** + * @param partition partition structure pointing to the partition to wipe. + * @param header_only if header_only is != 0 only the partition header is + * nulled out, not the whole partition. + */ + +int wipe_partition(partition_t partition, int header_only) +{ + int pstart, len; + + pstart=partition.addr-PARTITION_HEADER_SIZE; + + len=PARTITION_HEADER_SIZE; + + if(!header_only) + len += partition.len; + + erase_nvram(pstart, len); + + return 0; +} + + +static partition_t create_nvram_partition(int type, const char *name, int len) +{ + partition_t ret = { 0, 0 }; + int offset, plen; + unsigned int i; + + plen = ALIGN(len+PARTITION_HEADER_SIZE, 16); + + DEBUG("Creating partition type=%x, name=%s, len=%d plen=%d\n", + type, name, len, plen); + + offset = calc_used_nvram_space(); + + if (NVRAM_LENGTH-(calc_used_nvram_space())<plen) { + DEBUG("Not enough free space.\n"); + return ret; + } + + DEBUG("Writing header."); + + nvram_write_byte(offset, type); + nvram_write_word(offset+2, plen/16); + + for (i=0; i<strlen(name); i++) + nvram_write_byte(offset+4+i, name[i]); + + nvram_write_byte(offset+1, calc_partition_header_checksum(offset)); + + ret.addr = offset+PARTITION_HEADER_SIZE; + ret.len = len; + + DEBUG("partition created: addr=%lx len=%lx\n", ret.addr, ret.len); + + return ret; +} + +static int create_free_partition(void) +{ + int free_space; + partition_t free_part; + + free_space = NVRAM_LENGTH - calc_used_nvram_space() - PARTITION_HEADER_SIZE; + free_part = create_nvram_partition(0x7f, "free space", free_space); + + return (free_part.addr != 0); +} + +partition_t new_nvram_partition(int type, char *name, int len) +{ + partition_t free_part, new_part = { 0, 0 }; + + /* NOTE: Assume all free space is consumed by the "free space" + * partition. This means a partition can not be increased in the middle + * of reset_nvram, which is obviously not a big loss. + */ + + free_part=get_partition(0x7f, NULL); + if( free_part.len && free_part.len != -1) + wipe_partition(free_part, 1); + + new_part = create_nvram_partition(type, name, len); + + if(new_part.len != len) { + new_part.len = 0; + new_part.addr = 0; + } + + create_free_partition(); + + return new_part; +} + +/** + * @param partition partition structure pointing to the partition to wipe. + */ + +int delete_nvram_partition(partition_t partition) +{ + int i; + partition_t free_part; + + if(!partition.len || partition.len == -1) + return 0; + + for (i=partition.addr+partition.len; i< NVRAM_LENGTH; i++) + nvram_write_byte(i - partition.len - PARTITION_HEADER_SIZE, nvram_read_byte(i)); + + erase_nvram(NVRAM_LENGTH-partition.len-PARTITION_HEADER_SIZE, + partition.len-PARTITION_HEADER_SIZE); + + free_part=get_partition(0x7f, NULL); + wipe_partition(free_part, 0); + create_free_partition(); + + return 1; +} + +int clear_nvram_partition(partition_t part) +{ + if(!part.addr) + return 0; + + erase_nvram(part.addr, part.len); + + return 1; +} + + +int increase_nvram_partition_size(partition_t partition, int newsize) +{ + partition_t free_part; + int free_offset, end_offset, i; + + /* We don't support shrinking partitions (yet) */ + if (newsize < partition.len) { + return 0; + } + + /* NOTE: Assume all free space is consumed by the "free space" + * partition. This means a partition can not be increased in the middle + * of reset_nvram, which is obviously not a big loss. + */ + + free_part=get_partition(0x7f, NULL); + + // FIXME: It could be 16 byte more. Also handle empty "free" partition. + if (free_part.len == -1 || free_part.len < newsize - partition.len ) { + return 0; + } + + free_offset=free_part.addr - PARTITION_HEADER_SIZE; // first unused byte + end_offset=partition.addr + partition.len; // last used byte of partition + 1 + + if(free_offset > end_offset) { + int j, bufferlen; + char *overlap_buffer; + + bufferlen=free_offset - end_offset; + + overlap_buffer=get_nvram_buffer(bufferlen); + if(!overlap_buffer) { + return 0; + } + + for (i=end_offset, j=0; i<free_offset; i++, j++) + overlap_buffer[j]=nvram_read_byte(i); + + /* Only wipe the header. The free space partition is empty per + * definition + */ + + wipe_partition(free_part, 1); + + for (i=partition.addr+newsize, j=0; i<(int)(partition.addr+newsize+bufferlen); i++, j++) + nvram_write_byte(i, overlap_buffer[j]); + + free_nvram_buffer(overlap_buffer); + } else { + /* Only wipe the header. */ + wipe_partition(free_part, 1); + } + + /* Clear the new partition space */ + erase_nvram(partition.addr+partition.len, newsize-partition.len); + + nvram_write_word(partition.addr - 16 + 2, newsize); + + create_free_partition(); + + return 1; +} + +static void init_cpulog_partition(partition_t cpulog) +{ + unsigned int offset=cpulog.addr; + + /* see board-xxx/include/nvramlog.h for information */ + nvram_write_word(offset+0, 0x40); // offset + nvram_write_word(offset+2, 0x00); // flags + nvram_write_dword(offset+4, 0x01); // pointer + +} + +void reset_nvram(void) +{ + partition_t cpulog0, cpulog1; + struct { + uint32_t prefix; + uint64_t name; + } __attribute__((packed)) header; + + DEBUG("Erasing NVRAM\n"); + erase_nvram(0, NVRAM_LENGTH); + + DEBUG("Creating CPU log partitions\n"); + header.prefix = be32_to_cpu(LLFW_LOG_BE0_NAME_PREFIX); + header.name = be64_to_cpu(LLFW_LOG_BE0_NAME); + cpulog0=create_nvram_partition(LLFW_LOG_BE0_SIGNATURE, (char *)&header, + (LLFW_LOG_BE0_LENGTH*16)-PARTITION_HEADER_SIZE); + + header.prefix = be32_to_cpu(LLFW_LOG_BE1_NAME_PREFIX); + header.name = be64_to_cpu(LLFW_LOG_BE1_NAME); + cpulog1=create_nvram_partition(LLFW_LOG_BE1_SIGNATURE, (char *)&header, + (LLFW_LOG_BE1_LENGTH*16)-PARTITION_HEADER_SIZE); + + DEBUG("Initializing CPU log partitions\n"); + init_cpulog_partition(cpulog0); + init_cpulog_partition(cpulog1); + + nvramlog_printf("Creating common NVRAM partition\r\n"); + create_nvram_partition(0x70, "common", 0x01000-PARTITION_HEADER_SIZE); + + create_free_partition(); +} + +void nvram_debug(void) +{ +#ifndef RTAS_NVRAM + printf("\nNVRAM_BASE: %p\n", nvram); + printf("NVRAM_LEN: 0x%x\n", NVRAM_LENGTH); +#endif +} + +unsigned int get_nvram_size(void) +{ + return NVRAM_LENGTH; +} diff --git a/qemu/roms/SLOF/lib/libnvram/nvram.h b/qemu/roms/SLOF/lib/libnvram/nvram.h new file mode 100644 index 000000000..fa6bdd425 --- /dev/null +++ b/qemu/roms/SLOF/lib/libnvram/nvram.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __NVRAM_H +#define __NVRAM_H 1 + +/* data structures */ + +typedef struct { + unsigned long addr; + long len; +} partition_t; + +/* macros */ + +#define DEBUG(x...) +// #define DEBUG(x...) printf(x); + +#ifndef ALIGN +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) +#endif + +#define NULL ((void *)0) + +#define PARTITION_HEADER_SIZE 16 + + +/* exported functions */ + +#define nvram_access_proto(type,name) \ + type nvram_read_##name(unsigned int offset); \ + void nvram_write_##name(unsigned int offset, type data); + +nvram_access_proto(uint8_t, byte) +nvram_access_proto(uint16_t, word) +nvram_access_proto(uint32_t, dword) +nvram_access_proto(uint64_t, qword) + +/* nvram.c */ + +char *get_nvram_buffer(int len); +void free_nvram_buffer(char *buffer); +int nvramlog_printf(const char* fmt, ...); +partition_t get_partition(unsigned int type, char *name); +void erase_nvram(int offset, int len); +int wipe_partition(partition_t partition, int header_only); +partition_t new_nvram_partition(int type, char *name, int len); +int increase_nvram_partition_size(partition_t partition, int newsize); +int clear_nvram_partition(partition_t part); +int delete_nvram_partition(partition_t part); +void reset_nvram(void); +void wipe_nvram(void); +void nvram_debug(void); +void nvram_init(uint32_t store_token, uint32_t fetch_token, + long nv_size, void* nvram_addr); +unsigned int get_nvram_size(void); + +/* envvar.c */ +char *get_env(partition_t part, char *envvar); +int add_env(partition_t part, char *envvar, char *value); +int del_env(partition_t part, char *envvar); +int set_env(partition_t part, char *envvar, char *value); + +#endif diff --git a/qemu/roms/SLOF/lib/libusb/Makefile b/qemu/roms/SLOF/lib/libusb/Makefile new file mode 100644 index 000000000..0780489ea --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/Makefile @@ -0,0 +1,52 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) -I$(SLOFCMNDIR) +LDFLAGS = -nostdlib + +TARGET = ../libusb.a + + +all: $(TARGET) + +SRCS = usb-core.c usb-ohci.c usb-ehci.c usb-slof.c usb-key.c usb-hid.c \ + usb-hub.c usb-xhci.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/lib/libusb/tools.h b/qemu/roms/SLOF/lib/libusb/tools.h new file mode 100644 index 000000000..f531175c1 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/tools.h @@ -0,0 +1,77 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __TOOLS_H +#define __TOOLS_H + +#include <stdint.h> +#include <byteorder.h> +#include <cache.h> + +#define PTR_U32(x) ((uint32_t) (uint64_t) (x)) + +static inline uint32_t read_reg32(uint32_t *reg) +{ + return bswap_32(ci_read_32(reg)); +} + +static inline void write_reg32(uint32_t *reg, uint32_t value) +{ + mb(); + ci_write_32(reg, bswap_32(value)); +} + +static inline uint8_t read_reg8(uint8_t *reg) +{ + return ci_read_8(reg); +} + +static inline void write_reg8(uint8_t *reg, uint8_t value) +{ + mb(); + ci_write_8(reg, value); +} + +static inline uint16_t read_reg16(uint16_t *reg) +{ + return bswap_16(ci_read_16(reg)); +} + +static inline void write_reg16(uint16_t *reg, uint16_t value) +{ + mb(); + ci_write_16(reg, bswap_16(value)); +} + +static inline uint64_t read_reg64(uint64_t *reg) +{ + return bswap_64(ci_read_64(reg)); +} + +static inline void write_reg64(uint64_t *reg, uint64_t value) +{ + mb(); + ci_write_64(reg, bswap_64(value)); +} + +static inline uint32_t ci_read_reg(uint32_t *reg) +{ + return bswap_32(ci_read_32(reg)); +} + +static inline void ci_write_reg(uint32_t *reg, uint32_t value) +{ + mb(); + ci_write_32(reg, bswap_32(value)); +} + +#endif diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.c b/qemu/roms/SLOF/lib/libusb/usb-core.c new file mode 100644 index 000000000..6719c5726 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-core.c @@ -0,0 +1,590 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include "usb-core.h" + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +#define dprintf(_x ...) do { printf(_x); } while(0) +#else +#define dprintf(_x ...) +#endif + +#define __unused __attribute__((unused)) + +struct usb_hcd_ops *head; +struct usb_dev *devpool; +#define USB_DEVPOOL_SIZE 4096 + +static struct usb_dev *usb_alloc_devpool(void) +{ + struct usb_dev *head, *curr, *prev; + unsigned int dev_count = 0, i; + + head = SLOF_alloc_mem(USB_DEVPOOL_SIZE); + if (!head) + return NULL; + + dev_count = USB_DEVPOOL_SIZE/sizeof(struct usb_dev); + dprintf("%s: %d number of devices\n", __func__, dev_count); + /* Although an array, link them*/ + for (i = 0, curr = head, prev = NULL; i < dev_count; i++, curr++) { + if (prev) + prev->next = curr; + curr->next = NULL; + prev = curr; + } + +#ifdef DEBUG + for (i = 0, curr = head; curr; curr = curr->next) + printf("%s: %d dev %p\n", __func__, i++, curr); +#endif + + return head; +} + +struct usb_dev *usb_devpool_get(void) +{ + struct usb_dev *new; + + if (!devpool) { + devpool = usb_alloc_devpool(); + if (!devpool) + return NULL; + } + + new = devpool; + devpool = devpool->next; + memset(new, 0, sizeof(*new)); + new->next = NULL; + return new; +} + +void usb_devpool_put(struct usb_dev *dev) +{ + struct usb_dev *curr; + if (!dev && !devpool) + return; + + curr = devpool; + while (curr->next) + curr = curr->next; + curr->next = dev; + dev->next = NULL; +} + +#ifndef DEBUG +#define validate_hcd_ops(dev) (dev && dev->hcidev && dev->hcidev->ops) +#else +int validate_hcd_ops(struct usb_dev *dev) +{ + int ret = true; + + if (!dev) { + printf("dev is NULL\n"); + ret = false; + } else if (!dev->hcidev) { + printf("hcidev is NULL\n"); + ret = false; + } else if (!dev->hcidev->ops) { + printf("ops is NULL\n"); + ret = false; + } + return ret; +} +#endif + +struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, + char *buf, size_t len) +{ + if (validate_hcd_ops(dev) && dev->hcidev->ops->get_pipe) + return dev->hcidev->ops->get_pipe(dev, ep, buf, len); + else { + printf("%s: Failed\n", __func__); + return NULL; + } +} + +void usb_put_pipe(struct usb_pipe *pipe) +{ + struct usb_dev *dev = NULL; + if (pipe && pipe->dev) { + dev = pipe->dev; + if (validate_hcd_ops(dev) && dev->hcidev->ops->put_pipe) + dev->hcidev->ops->put_pipe(pipe); + } +} + +int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf) +{ + struct usb_dev *dev = NULL; + if (pipe && pipe->dev) { + dev = pipe->dev; + if (validate_hcd_ops(dev) && dev->hcidev->ops->poll_intr) + return dev->hcidev->ops->poll_intr(pipe, buf); + } + return 0; +} + +void usb_hcd_register(struct usb_hcd_ops *ops) +{ + struct usb_hcd_ops *list; + + if (!ops) + printf("Error"); + dprintf("Registering %s %d\n", ops->name, ops->usb_type); + + if (head) { + list = head; + while (list->next) + list = list->next; + list->next = ops; + } else + head = ops; +} + +void usb_hcd_init(void *hcidev) +{ + struct usb_hcd_dev *dev = hcidev; + struct usb_hcd_ops *list = head; + + if (!dev) { + printf("Device Error"); + return; + } + + while (list) { + if (list->usb_type == dev->type) { + dprintf("usb_ops(%p) for the controller found\n", list); + dev->ops = list; + dev->ops->init(dev); + return; + } + list = list->next; + } + + dprintf("usb_ops for the controller not found\n"); +} + +void usb_hcd_exit(void *_hcidev) +{ + struct usb_hcd_dev *hcidev = _hcidev; + + dprintf("%s: enter \n", __func__); + if (!hcidev) { + printf("Device Error"); + return; + } + + if (hcidev->ops->exit) + hcidev->ops->exit(hcidev); +} + +int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data) +{ + struct usb_dev *dev = NULL; + if (!pipe) + return false; + dev = pipe->dev; + if (validate_hcd_ops(dev) && dev->hcidev->ops->send_ctrl) + return dev->hcidev->ops->send_ctrl(pipe, req, data); + else { + printf("%s: Failed\n", __func__); + return false; + } +} + +int usb_transfer_ctrl(void *dev, void *req, void *data) +{ + struct usb_pipe *pipe = NULL; + struct usb_dev *usbdev; + + if (!dev) + return false; + usbdev = (struct usb_dev *)dev; + pipe = usbdev->control; + return usb_send_ctrl(pipe, req, data); +} + +int usb_transfer_bulk(void *dev, int dir, void *td, void *td_phys, void *data, int size) +{ + struct usb_pipe *pipe = NULL; + struct usb_dev *usbdev; + + if (!dev) + return false; + usbdev = (struct usb_dev *)dev; + pipe = (dir == USB_PIPE_OUT) ? usbdev->bulk_out : usbdev->bulk_in; + if (!pipe) + return false; + if (validate_hcd_ops(usbdev) && usbdev->hcidev->ops->transfer_bulk) + return usbdev->hcidev->ops->transfer_bulk(pipe, td, td_phys, data, size); + else { + printf("%s: Failed\n", __func__); + return false; + } +} + +/* + * USB Specification 1.1 + * 9.3 USB Device Requests + * 9.4 Standard Device Requests + */ +static int usb_set_address(struct usb_dev *dev, uint32_t port) +{ + struct usb_dev_req req; + struct usb_hcd_dev *hcidev; + + if (!dev) + return false; + + hcidev = dev->hcidev; + req.bmRequestType = 0; + req.bRequest = REQ_SET_ADDRESS; + req.wIndex = 0; + req.wLength = 0; + req.wValue = cpu_to_le16((uint16_t)(hcidev->nextaddr)); + if (usb_send_ctrl(dev->control, &req, NULL)) { + dev->addr = hcidev->nextaddr++; + return true; + } else + return false; +} + +static int usb_get_device_descr(struct usb_dev *dev, void *data, size_t size) +{ + struct usb_dev_req req; + + if (!dev) + return false; + + req.bmRequestType = 0x80; + req.bRequest = REQ_GET_DESCRIPTOR; + req.wIndex = 0; + req.wLength = cpu_to_le16((uint16_t) size); + req.wValue = cpu_to_le16(DESCR_TYPE_DEVICE << 8); + return usb_send_ctrl(dev->control, &req, data); +} + +static int usb_get_config_descr(struct usb_dev *dev, void *data, size_t size) +{ + struct usb_dev_req req; + + if (!dev) + return false; + + req.bmRequestType = 0x80; + req.bRequest = REQ_GET_DESCRIPTOR; + req.wIndex = 0; + req.wLength = cpu_to_le16((uint16_t) size); + req.wValue = cpu_to_le16(DESCR_TYPE_CONFIGURATION << 8); + return usb_send_ctrl(dev->control, &req, data); + +} + +static int usb_set_config(struct usb_dev *dev, uint8_t cfg_value) +{ + struct usb_dev_req req; + + if (!dev) + return false; + + req.bmRequestType = 0x00; + req.bRequest = REQ_SET_CONFIGURATION; + req.wIndex = 0; + req.wLength = 0; + req.wValue = cpu_to_le16(0x00FF & cfg_value); + return usb_send_ctrl(dev->control, &req, NULL); +} + +static int usb_clear_halt(struct usb_pipe *pipe) +{ + struct usb_dev_req req; + struct usb_dev *dev; + + if (pipe && pipe->dev) { + dev = pipe->dev; + dprintf("Clearing port %d dir %d type %d\n", + pipe->epno, pipe->dir, pipe->type); + req.bmRequestType = REQT_DIR_OUT | REQT_REC_EP; + req.bRequest = REQ_CLEAR_FEATURE; + req.wValue = FEATURE_ENDPOINT_HALT; + req.wIndex = cpu_to_le16(pipe->epno | pipe->dir); + req.wLength = 0; + return usb_send_ctrl(dev->control, &req, NULL); + } + return false; +} + +int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, + void *buf, size_t len) +{ + uint8_t dir, type; + + dir = (ep->bEndpointAddress & 0x80) >> 7; + type = ep->bmAttributes & USB_EP_TYPE_MASK; + + dprintf("EP: %s: %d size %d type %d\n", dir ? "IN " : "OUT", + ep->bEndpointAddress & 0xF, le16_to_cpu(ep->wMaxPacketSize), + type); + if (type == USB_EP_TYPE_BULK) { + if (dir) + dev->bulk_in = usb_get_pipe(dev, ep, buf, len); + else + dev->bulk_out = usb_get_pipe(dev, ep, buf, len); + } else if (type == USB_EP_TYPE_INTR) + dev->intr = usb_get_pipe(dev, ep, buf, len); + + return true; +} + +static void usb_dev_copy_epdesc(struct usb_dev *dev, struct usb_ep_descr *ep) +{ + uint32_t ep_cnt; + + ep_cnt = dev->ep_cnt; + if (ep_cnt < USB_DEV_EP_MAX) + memcpy((void *)&dev->ep[ep_cnt], ep, sizeof(*ep)); + else + dprintf("usb-core: only %d EPs supported\n", USB_DEV_EP_MAX); + dev->ep_cnt++; +} + +int usb_hid_init(void *vdev) +{ + struct usb_dev *dev; + dev = (struct usb_dev *) vdev; + if (!dev) + return false; + if (dev->class == DEV_HID_KEYB) + usb_hid_kbd_init(dev); + return true; +} + +int usb_hid_exit(void *vdev) +{ + struct usb_dev *dev; + dev = (struct usb_dev *) vdev; + if (!dev) + return false; + if (dev->class == DEV_HID_KEYB) + usb_hid_kbd_exit(dev); + return true; +} + +#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16) + +int usb_msc_init(void *vdev) +{ + struct usb_dev *dev; + int i; + + dev = (struct usb_dev *) vdev; + dprintf("%s: enter %x\n", __func__, dev->class); + if (!dev) + return false; + if (usb_get_intf_class(dev->class) == 8) { + for (i = 0; i < dev->ep_cnt; i++) { + if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK) + == USB_EP_TYPE_BULK) + usb_dev_populate_pipe(dev, &dev->ep[i], NULL, 0); + } + } + return true; +} + +int usb_msc_exit(void *vdev) +{ + struct usb_dev *dev; + dev = (struct usb_dev *) vdev; + dprintf("%s: enter %x\n", __func__, dev->class); + if (!dev) + return false; + if (usb_get_intf_class(dev->class) == 8) { + if (dev->bulk_in) + usb_put_pipe(dev->bulk_in); + if (dev->bulk_out) + usb_put_pipe(dev->bulk_out); + } + return true; +} + +static int usb_msc_reset(struct usb_dev *dev) +{ + struct usb_dev_req req; + + if (!dev) + return false; + + req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT; + req.bRequest = 0xFF; + req.wLength = 0; + req.wValue = 0; + req.wIndex = cpu_to_le16(dev->intf_num); + return usb_send_ctrl(dev->control, &req, NULL); +} + +void usb_msc_resetrecovery(struct usb_dev *dev) +{ + // usb_msc_reset(dev); + usb_clear_halt(dev->bulk_in); + usb_clear_halt(dev->bulk_out); + SLOF_msleep(2); +} + +static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *cfg, + uint8_t *ptr, uint16_t len) +{ + struct usb_dev_intf_descr *intf = NULL; + struct usb_ep_descr *ep = NULL; + struct usb_dev_hid_descr *hid __unused = NULL; + uint8_t desc_len, desc_type; + + len -= sizeof(struct usb_dev_config_descr); + ptr = (uint8_t *)(ptr + sizeof(struct usb_dev_config_descr)); + + while (len > 0) { + desc_len = *ptr; + desc_type = *(ptr + 1); + switch (desc_type) { + case DESCR_TYPE_INTERFACE: + intf = (struct usb_dev_intf_descr *)ptr; + dev->class = intf->bInterfaceClass << 16 | + intf->bInterfaceSubClass << 8 | + intf->bInterfaceProtocol; + break; + case DESCR_TYPE_ENDPOINT: + ep = (struct usb_ep_descr *)ptr; + dev->intf_num = intf->bInterfaceNumber; + usb_dev_copy_epdesc(dev, ep); + break; + case DESCR_TYPE_HID: + hid = (struct usb_dev_hid_descr *)ptr; + dprintf("hid-report %d size %d\n", + hid->bReportType, le16_to_cpu(hid->wReportLength)); + break; + case DESCR_TYPE_HUB: + break; + default: + printf("ptr %p desc_type %d\n", ptr, desc_type); + } + ptr += desc_len; + len -= desc_len; + } + return true; +} + +int setup_new_device(struct usb_dev *dev, unsigned int port) +{ + struct usb_dev_descr descr; + struct usb_dev_config_descr cfg; + struct usb_ep_descr ep; + uint16_t len; + void *data = NULL; + + dprintf("usb: %s - port %d\n", __func__, port); + + dev->addr = 0; + dev->port = port; + ep.bEndpointAddress = 0; + ep.bmAttributes = USB_EP_TYPE_CONTROL; + ep.wMaxPacketSize = cpu_to_le16(8); + dev->control = usb_get_pipe(dev, &ep, NULL, 0); + + if (!usb_get_device_descr(dev, &descr, 8)) + goto fail; + dev->control->mps = descr.bMaxPacketSize0; + + /* + * For USB3.0 ADDRESS-SLOT command takes care of setting + * address, skip this during generic device setup for USB3.0 + * devices + */ + if (dev->speed != USB_SUPER_SPEED) { + /* + * Qemu starts the port number from 1 which was + * revealed in bootindex and resulted in mismatch for + * storage devices names. Adjusting this here for + * compatibility. + */ + dev->port = port + 1; + if(!usb_set_address(dev, dev->port)) + goto fail; + } + mb(); + SLOF_msleep(100); + + if (!usb_get_device_descr(dev, &descr, sizeof(struct usb_dev_descr))) + goto fail; + + if (!usb_get_config_descr(dev, &cfg, sizeof(struct usb_dev_config_descr))) + goto fail; + + len = le16_to_cpu(cfg.wTotalLength); + /* No device config descriptor present */ + if (len == sizeof(struct usb_dev_config_descr)) + goto fail; + + data = SLOF_dma_alloc(len); + if (!data) { + printf("%s: alloc failed %d\n", __func__, port); + goto fail; + } + + if (!usb_get_config_descr(dev, data, len)) + goto fail_mem_free; + if (!usb_set_config(dev, cfg.bConfigurationValue)) + goto fail_mem_free; + mb(); + SLOF_msleep(100); + + if (!usb_handle_device(dev, &cfg, data, len)) + goto fail_mem_free; + + switch (usb_get_intf_class(dev->class)) { + case 3: + dprintf("HID found %06X\n", dev->class); + slof_usb_handle(dev); + break; + case 8: + dprintf("MASS STORAGE found %d %06X\n", dev->intf_num, + dev->class); + if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */ + printf("Device not supported %06X\n", dev->class); + goto fail_mem_free; + } + + if (!usb_msc_reset(dev)) { + printf("%s: bulk reset failed\n", __func__); + goto fail_mem_free; + } + SLOF_msleep(100); + slof_usb_handle(dev); + break; + case 9: + dprintf("HUB found\n"); + slof_usb_handle(dev); + break; + default: + printf("USB Interface class -%x- Not supported\n", dev->class); + break; + } + + SLOF_dma_free(data, len); + return true; +fail_mem_free: + SLOF_dma_free(data, len); +fail: + return false; +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.h b/qemu/roms/SLOF/lib/libusb/usb-core.h new file mode 100644 index 000000000..7441979e9 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-core.h @@ -0,0 +1,279 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef __USB_CORE_H +#define __USB_CORE_H + +#include <stdio.h> +#include <stdbool.h> +#include "helpers.h" +#include "usb.h" +#include "tools.h" + +enum usb_hcd_type { + USB_OHCI = 1, + USB_EHCI = 2, + USB_XHCI = 3, +}; + +struct usb_hcd_dev; + +struct usb_hcd_dev { + void *base; + long type; + long num; + struct usb_hcd_ops *ops; + void *priv; /* hcd owned structure */ + long nextaddr; /* address for devices */ +}; + +struct usb_pipe; + +/*******************************************/ +/* Standard Endpoint Descriptor */ +/*******************************************/ +/* bmAttributes */ +#define USB_EP_TYPE_MASK 0x03 +#define USB_EP_TYPE_CONTROL 0 +#define USB_EP_TYPE_ISOC 1 +#define USB_EP_TYPE_BULK 2 +#define USB_EP_TYPE_INTR 3 + +struct usb_ep_descr { + uint8_t bLength; /* size of descriptor */ + uint8_t bDescriptorType; /* Type = 5 */ + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} __attribute__((packed)); + +#define DEV_HID_KEYB 0x030101 /* class=HIB, protocol=Keyboard */ +#define DEV_HID_MOUSE 0x030102 /* class=HIB, protocol=Mouse */ +#define DEV_HUB 0x090000 /* class=HUB, subclass, protocol */ +#define DEV_MASS_RBC 0x080150 /* MassStorage, RBC, Bulk */ +#define DEV_CDROM_ATAPI 0x080250 /* MassStorage, SFF-8020i , Bulk */ +#define DEV_MASS_FLOPPY 0x080450 /* MassStorage, UFI, Bulk */ +#define DEV_MASS_ATAPI 0x080550 /* MassStorage, SFF-8070i , Bulk */ +#define DEV_MASS_SCSI 0x080650 /* MassStorage, SCSI, Bulk */ + +enum USB_SPEED_TYPE { + USB_LOW_SPEED = 0, + USB_FULL_SPEED = 1, + USB_HIGH_SPEED = 2, + USB_SUPER_SPEED = 3, +}; + +/* Max number of endpoints supported in a device */ +#define USB_DEV_EP_MAX 4 +#define USB_TIMEOUT 5000 /* 5 sec usb timeout */ + +struct usb_dev { + struct usb_dev *next; + struct usb_hcd_dev *hcidev; + struct usb_pipe *intr; + struct usb_pipe *control; + struct usb_pipe *bulk_in; + struct usb_pipe *bulk_out; + struct usb_ep_descr ep[USB_DEV_EP_MAX]; + void *priv; + uint32_t ep_cnt; + uint32_t class; + uint32_t speed; + uint32_t addr; + uint32_t mps0; + uint32_t port; + uint16_t intf_num; +}; + +#define DEVICE_KEYBOARD 1 +#define DEVICE_MOUSE 2 +#define DEVICE_DISK 3 +#define DEVICE_HUB 4 + +/* Structure in sync with FORTH code */ +struct slof_usb_dev { + void *udev; + uint32_t port; + uint32_t addr; + uint32_t hcitype; + uint32_t num; + uint32_t devtype; +} __attribute__((packed)); + +enum USB_PIPE_DIR { + USB_PIPE_OUT = 0, + USB_PIPE_IN, +}; + +struct usb_pipe { + struct usb_dev *dev; + struct usb_pipe *next; + uint32_t type; + uint32_t speed; + uint32_t dir; + uint16_t epno; + uint16_t mps; +} __attribute__((packed)); + +#define REQ_GET_STATUS 0 /* see Table 9-4 */ +#define REQ_CLEAR_FEATURE 1 +#define REQ_GET_STATE 2 /* HUB specific */ +#define REQ_SET_FEATURE 3 +#define REQ_SET_ADDRESS 5 +#define REQ_GET_DESCRIPTOR 6 +#define REQ_SET_DESCRIPTOR 7 +#define REQ_GET_CONFIGURATION 8 +#define REQ_SET_CONFIGURATION 9 +#define REQ_GET_INTERFACE 10 +#define REQ_SET_INTERFACE 11 +#define REQ_SYNCH_FRAME 12 + +#define FEATURE_DEVICE_REMOTE_WAKEUP 1 +#define FEATURE_ENDPOINT_HALT 0 + +#define REQT_REC_DEVICE 0 +#define REQT_REC_INTERFACE 1 +#define REQT_REC_EP 2 +#define REQT_REC_OTHER 3 +#define REQT_TYPE_STANDARD (0 << 5) +#define REQT_TYPE_CLASS (1 << 5) +#define REQT_TYPE_VENDOR (2 << 5) +#define REQT_TYPE_RSRVD (3 << 5) +#define REQT_DIR_OUT (0 << 7) /* host -> device */ +#define REQT_DIR_IN (1 << 7) /* device -> host */ + +#define DESCR_TYPE_DEVICE 1 /* see Table 9-5 */ +#define DESCR_TYPE_CONFIGURATION 2 +#define DESCR_TYPE_STRING 3 +#define DESCR_TYPE_INTERFACE 4 +#define DESCR_TYPE_ENDPOINT 5 +#define DESCR_TYPE_HUB 0x29 /* Class Descriptor HUB */ +#define DESCR_TYPE_HID 0x21 /* Class Descriptor HID */ +#define DESCR_TYPE_REPORT 0x22 /* Class Descriptor HID */ +#define DESCR_TYPE_PHYSICAL 0x23 /* Class Descriptor HID */ + +struct usb_dev_req { + uint8_t bmRequestType; /* direction, recipient */ + uint8_t bRequest; /* see spec: Table 9-3 */ + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; /* number of bytes to transfer */ +} __attribute__((packed)); + +/* Standard Device Descriptor (18 Bytes) */ +/*******************************************/ +struct usb_dev_descr { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} __attribute__((packed)); + +/*******************************************/ +/* Standard Configuration Descriptor */ +/*******************************************/ +struct usb_dev_config_descr { + uint8_t bLength; /* size of descriptor */ + uint8_t bDescriptorType; /* Type = 2 */ + uint16_t wTotalLength; /* total returned data */ + uint8_t bNumInterfaces; /* interfaces supported by this config */ + uint8_t bConfigurationValue; /* Configuration-ID for SetConfiguration */ + uint8_t iConfiguration; /* index of string descriptor */ + uint8_t bmAttributes; /* configuration characteristics */ + uint8_t bMaxPower; /* in 2mA units */ +} __attribute__((packed)); + +/*******************************************/ +/* Standard Interface Descriptor */ +/*******************************************/ +struct usb_dev_intf_descr { + uint8_t bLength; /* size of descriptor */ + uint8_t bDescriptorType; /* Type = 4 */ + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; /* protocol code */ + uint8_t iInterface; /* index to string descriptor */ +} __attribute__((packed)); + +/*******************************************/ +/* HUB-Class Descriptor */ +/*******************************************/ +struct usb_dev_hub_descr { + uint8_t bLength; /* size of complete descriptor */ + uint8_t bDescriptorType; /* type = 0x29 for HUB */ + uint8_t bNbrPorts; /* number of downstream ports */ + uint8_t wHubCharacteristics; /* mode bits 7..0 */ + uint8_t reserved; /* mode bits 15..8 */ + uint8_t bPwrOn2PwrGood; /* in 2ms units */ + uint8_t bHubContrCurrent; /* current requirement in mA */ + uint8_t DeviceTable; /* length depends on number of ports */ +} __attribute__((packed)); + +/*******************************************/ +/* HID-Class Descriptor */ +/*******************************************/ +struct usb_dev_hid_descr { + uint8_t bLength; /* size of this descriptor */ + uint8_t bDescriptorType; /* type = 0x21 for HID */ + uint16_t bcdHID; /* Sample: 0x0102 for 2.01 */ + uint8_t bCountryCode; /* Hardware target country */ + uint8_t bNumDescriptors; /* Number of HID class descr. */ + uint8_t bReportType; /* Report Descriptor Type */ + uint16_t wReportLength; /* Total Length of Report Descr. */ +} __attribute__((packed)); + +struct usb_hcd_ops { + const char *name; + void (*init)(struct usb_hcd_dev *); + void (*exit)(struct usb_hcd_dev *); + void (*detect)(void); + void (*disconnect)(void); + int (*send_ctrl)(struct usb_pipe *pipe, struct usb_dev_req *req, void *data); + struct usb_pipe* (*get_pipe)(struct usb_dev *dev, struct usb_ep_descr *ep, + char *buf, size_t len); + int (*transfer_bulk)(struct usb_pipe *pipe, void *td, void *td_phys, void *data, int size); + void (*put_pipe)(struct usb_pipe *); + int (*poll_intr)(struct usb_pipe *, uint8_t *); + struct usb_hcd_ops *next; + unsigned int usb_type; +}; + +extern void usb_hcd_register(struct usb_hcd_ops *ops); +extern struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, + char *buf, size_t len); +extern void usb_put_pipe(struct usb_pipe *pipe); +extern int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf); +extern int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data); +extern struct usb_dev *usb_devpool_get(void); +extern void usb_devpool_put(struct usb_dev *); +extern int setup_new_device(struct usb_dev *dev, unsigned int port); +extern int slof_usb_handle(struct usb_dev *dev); +extern int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, + void *buf, size_t len); +extern int usb_hid_kbd_init(struct usb_dev *dev); +extern int usb_hid_kbd_exit(struct usb_dev *dev); +extern void usb_msc_resetrecovery(struct usb_dev *dev); +#endif diff --git a/qemu/roms/SLOF/lib/libusb/usb-ehci.c b/qemu/roms/SLOF/lib/libusb/usb-ehci.c new file mode 100644 index 000000000..4cca0da15 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-ehci.c @@ -0,0 +1,609 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include "usb.h" +#include "usb-core.h" +#include "usb-ehci.h" +#include "tools.h" +#include "paflof.h" + +#undef EHCI_DEBUG +//#define EHCI_DEBUG +#ifdef EHCI_DEBUG +#define dprintf(_x ...) do { printf(_x); } while(0) +#else +#define dprintf(_x ...) +#endif + +#ifdef EHCI_DEBUG +static void dump_ehci_regs(struct ehci_hcd *ehcd) +{ + struct ehci_cap_regs *cap_regs; + struct ehci_op_regs *op_regs; + + cap_regs = ehcd->cap_regs; + op_regs = ehcd->op_regs; + + dprintf("\n - CAPLENGTH %02X", read_reg8(&cap_regs->caplength)); + dprintf("\n - HCIVERSION %04X", read_reg16(&cap_regs->hciversion)); + dprintf("\n - HCSPARAMS %08X", read_reg32(&cap_regs->hcsparams)); + dprintf("\n - HCCPARAMS %08X", read_reg32(&cap_regs->hccparams)); + dprintf("\n - HCSP_PORTROUTE %016llX", read_reg64(&cap_regs->portroute)); + dprintf("\n"); + + dprintf("\n - USBCMD %08X", read_reg32(&op_regs->usbcmd)); + dprintf("\n - USBSTS %08X", read_reg32(&op_regs->usbsts)); + dprintf("\n - USBINTR %08X", read_reg32(&op_regs->usbintr)); + dprintf("\n - FRINDEX %08X", read_reg32(&op_regs->frindex)); + dprintf("\n - CTRLDSSEGMENT %08X", read_reg32(&op_regs->ctrldssegment)); + dprintf("\n - PERIODICLISTBASE %08X", read_reg32(&op_regs->periodiclistbase)); + dprintf("\n - ASYNCLISTADDR %08X", read_reg32(&op_regs->asynclistaddr)); + dprintf("\n - CONFIGFLAG %08X", read_reg32(&op_regs->configflag)); + dprintf("\n - PORTSC %08X", read_reg32(&op_regs->portsc[0])); + dprintf("\n"); +} +#endif + +static int ehci_hub_check_ports(struct ehci_hcd *ehcd) +{ + uint32_t num_ports, portsc, i; + struct usb_dev *dev; + + dprintf("%s: enter\n", __func__); + num_ports = read_reg32(&ehcd->cap_regs->hcsparams) & HCS_NPORTS_MASK; + for (i = 0; i < num_ports; i++) { + dprintf("%s: device %d\n", __func__, i); + portsc = read_reg32(&ehcd->op_regs->portsc[i]); + if (portsc & PORT_CONNECT) { /* Device present */ + dprintf("usb-ehci: Device present on port %d\n", i); + /* Reset the port */ + portsc = read_reg32(&ehcd->op_regs->portsc[i]); + portsc = (portsc & ~PORT_PE) | PORT_RESET; + write_reg32(&ehcd->op_regs->portsc[i], portsc); + SLOF_msleep(20); + portsc = read_reg32(&ehcd->op_regs->portsc[i]); + portsc &= ~PORT_RESET; + write_reg32(&ehcd->op_regs->portsc[i], portsc); + SLOF_msleep(20); + dev = usb_devpool_get(); + dprintf("usb-ehci: allocated device %p\n", dev); + dev->hcidev = ehcd->hcidev; + dev->speed = USB_HIGH_SPEED; /* TODO: Check for Low/Full speed device */ + if (!setup_new_device(dev, i)) + printf("usb-ehci: unable to setup device on port %d\n", i); + } + } + dprintf("%s: exit\n", __func__); + return 0; +} + +static int ehci_hcd_init(struct ehci_hcd *ehcd) +{ + uint32_t usbcmd; + uint32_t time; + struct ehci_framelist *fl; + struct ehci_qh *qh_intr, *qh_async; + int i; + long fl_phys = 0, qh_intr_phys = 0, qh_async_phys; + + /* Reset the host controller */ + time = SLOF_GetTimer() + 250; + usbcmd = read_reg32(&ehcd->op_regs->usbcmd); + write_reg32(&ehcd->op_regs->usbcmd, (usbcmd & ~(CMD_PSE | CMD_ASE)) | CMD_HCRESET); + while (time > SLOF_GetTimer()) + cpu_relax(); + usbcmd = read_reg32(&ehcd->op_regs->usbcmd); + if (usbcmd & CMD_HCRESET) { + printf("usb-ehci: reset failed\n"); + return -1; + } + + /* Initialize periodic list */ + fl = SLOF_dma_alloc(sizeof(*fl)); + if (!fl) { + printf("usb-ehci: Unable to allocate frame list\n"); + goto fail; + } + fl_phys = SLOF_dma_map_in(fl, sizeof(*fl), true); + dprintf("fl %p, fl_phys %lx\n", fl, fl_phys); + + /* TODO: allocate qh pool */ + qh_intr = SLOF_dma_alloc(sizeof(*qh_intr)); + if (!qh_intr) { + printf("usb-ehci: Unable to allocate interrupt queue head\n"); + goto fail_qh_intr; + } + qh_intr_phys = SLOF_dma_map_in(qh_intr, sizeof(*qh_intr), true); + dprintf("qh_intr %p, qh_intr_phys %lx\n", qh_intr, qh_intr_phys); + + memset(qh_intr, 0, sizeof(*qh_intr)); + qh_intr->qh_ptr = QH_PTR_TERM; + qh_intr->ep_cap2 = cpu_to_le32(0x01 << QH_SMASK_SHIFT); + qh_intr->next_qtd = qh_intr->alt_next_qtd = QH_PTR_TERM; + qh_intr->token = cpu_to_le32(QH_STS_HALTED); + for (i = 0; i < FL_SIZE; i++) + fl->fl_ptr[i] = cpu_to_le32(qh_intr_phys | EHCI_TYP_QH); + write_reg32(&ehcd->op_regs->periodiclistbase, fl_phys); + + /* Initialize async list */ + qh_async = SLOF_dma_alloc(sizeof(*qh_async)); + if (!qh_async) { + printf("usb-ehci: Unable to allocate async queue head\n"); + goto fail_qh_async; + } + qh_async_phys = SLOF_dma_map_in(qh_async, sizeof(*qh_async), true); + dprintf("qh_async %p, qh_async_phys %lx\n", qh_async, qh_async_phys); + + memset(qh_async, 0, sizeof(*qh_async)); + qh_async->qh_ptr = cpu_to_le32(qh_async_phys | EHCI_TYP_QH); + qh_async->ep_cap1 = cpu_to_le32(QH_CAP_H); + qh_async->next_qtd = qh_async->alt_next_qtd = QH_PTR_TERM; + qh_async->token = cpu_to_le32(QH_STS_HALTED); + write_reg32(&ehcd->op_regs->asynclistaddr, qh_async_phys); + ehcd->qh_async = qh_async; + ehcd->qh_async_phys = qh_async_phys; + ehcd->qh_intr = qh_intr; + ehcd->qh_intr_phys = qh_intr_phys; + ehcd->fl = fl; + ehcd->fl_phys = fl_phys; + + write_reg32(&ehcd->op_regs->usbcmd, usbcmd | CMD_ASE | CMD_RUN); + write_reg32(&ehcd->op_regs->configflag, 1); + + return 0; + +fail_qh_async: + SLOF_dma_map_out(qh_intr_phys, qh_intr, sizeof(*qh_intr)); + SLOF_dma_free(qh_intr, sizeof(*qh_intr)); +fail_qh_intr: + SLOF_dma_map_out(fl_phys, fl, sizeof(*fl)); + SLOF_dma_free(fl, sizeof(*fl)); +fail: + return -1; +} + +static int ehci_hcd_exit(struct ehci_hcd *ehcd) +{ + uint32_t usbcmd; + + if (!ehcd) { + dprintf("NULL pointer\n"); + return false; + } + + usbcmd = read_reg32(&ehcd->op_regs->usbcmd); + write_reg32(&ehcd->op_regs->usbcmd, usbcmd | ~CMD_RUN); + write_reg32(&ehcd->op_regs->periodiclistbase, 0); + + if (ehcd->pool) { + SLOF_dma_map_out(ehcd->pool_phys, ehcd->pool, EHCI_PIPE_POOL_SIZE); + SLOF_dma_free(ehcd->pool, EHCI_PIPE_POOL_SIZE); + } + if (ehcd->qh_intr) { + SLOF_dma_map_out(ehcd->qh_intr_phys, ehcd->qh_intr, sizeof(struct ehci_qh)); + SLOF_dma_free(ehcd->qh_intr, sizeof(struct ehci_qh)); + } + if (ehcd->qh_async) { + SLOF_dma_map_out(ehcd->qh_async_phys, ehcd->qh_async, sizeof(struct ehci_qh)); + SLOF_dma_free(ehcd->qh_async, sizeof(struct ehci_qh)); + } + if (ehcd->fl) { + SLOF_dma_map_out(ehcd->fl_phys, ehcd->fl, sizeof(struct ehci_framelist)); + SLOF_dma_free(ehcd->fl, sizeof(struct ehci_framelist)); + } + return true; +} + +static int ehci_alloc_pipe_pool(struct ehci_hcd *ehcd) +{ + struct ehci_pipe *epipe, *curr, *prev; + unsigned int i, count; + long epipe_phys = 0; + + count = EHCI_PIPE_POOL_SIZE/sizeof(*epipe); + ehcd->pool = epipe = SLOF_dma_alloc(EHCI_PIPE_POOL_SIZE); + if (!epipe) + return -1; + ehcd->pool_phys = epipe_phys = SLOF_dma_map_in(epipe, EHCI_PIPE_POOL_SIZE, true); + dprintf("%s: epipe %p, epipe_phys %lx\n", __func__, epipe, epipe_phys); + + /* Although an array, link them */ + for (i = 0, curr = epipe, prev = NULL; i < count; i++, curr++) { + if (prev) + prev->pipe.next = &curr->pipe; + curr->pipe.next = NULL; + prev = curr; + curr->qh_phys = epipe_phys + (curr - epipe) * sizeof(*curr) + + offset_of(struct ehci_pipe, qh); + dprintf("%s - %d: qh %p, qh_phys %lx\n", __func__, + i, &curr->qh, curr->qh_phys); + } + + if (!ehcd->freelist) + ehcd->freelist = &epipe->pipe; + else + ehcd->end->next = &epipe->pipe; + ehcd->end = &prev->pipe; + + return 0; +} + +static void ehci_init(struct usb_hcd_dev *hcidev) +{ + struct ehci_hcd *ehcd; + + printf(" EHCI: Initializing\n"); + dprintf("%s: device base address %p\n", __func__, hcidev->base); + + ehcd = SLOF_alloc_mem(sizeof(*ehcd)); + if (!ehcd) { + printf("usb-ehci: Unable to allocate memory\n"); + return; + } + memset(ehcd, 0, sizeof(*ehcd)); + + hcidev->nextaddr = 1; + hcidev->priv = ehcd; + ehcd->hcidev = hcidev; + ehcd->cap_regs = (struct ehci_cap_regs *)(hcidev->base); + ehcd->op_regs = (struct ehci_op_regs *)(hcidev->base + + read_reg8(&ehcd->cap_regs->caplength)); +#ifdef EHCI_DEBUG + dump_ehci_regs(ehcd); +#endif + ehci_hcd_init(ehcd); + ehci_hub_check_ports(ehcd); +} + +static void ehci_exit(struct usb_hcd_dev *hcidev) +{ + struct ehci_hcd *ehcd; + static int count = 0; + + dprintf("%s: enter \n", __func__); + + if (!hcidev && !hcidev->priv) { + return; + } + count++; + if (count > 1) { + printf("%s: already called once \n", __func__); + return; + } + ehcd = hcidev->priv; + ehci_hcd_exit(ehcd); + SLOF_free_mem(ehcd, sizeof(*ehcd)); + hcidev->priv = NULL; +} + +static void ehci_detect(void) +{ + +} + +static void ehci_disconnect(void) +{ + +} + +static int ehci_handshake(struct ehci_hcd *ehcd, uint32_t timeout) +{ + uint32_t usbsts = 0, time; + uint32_t usbcmd; + mb(); + usbcmd = read_reg32(&ehcd->op_regs->usbcmd); + /* Ring a doorbell */ + write_reg32(&ehcd->op_regs->usbcmd, usbcmd | CMD_IAAD); + mb(); + time = SLOF_GetTimer() + timeout; + while ((time > SLOF_GetTimer())) { + /* Wait for controller to confirm */ + usbsts = read_reg32(&ehcd->op_regs->usbsts); + if (usbsts & STS_IAA) { + /* Acknowledge it, for next doorbell to work */ + write_reg32(&ehcd->op_regs->usbsts, STS_IAA); + return true; + } + cpu_relax(); + } + return false; +} + +static int fill_qtd_buff(struct ehci_qtd *qtd, long data, uint32_t size) +{ + long i, rem; + long pos = (data + 0x1000) & ~0xfff; + + qtd->buffer[0] = cpu_to_le32(PTR_U32(data)); + for (i = 1; i < 5; i++) { + if ((data + size - 1) >= pos) { + //dprintf("data spans page boundary: %d, %p\n", i, pos); + qtd->buffer[i] = cpu_to_le32(pos); + pos += 0x1000; + } else + break; + } + if ((data + size) > pos) + rem = data + size - pos; + else + rem = 0; + return rem; +} + +static int ehci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data) +{ + struct ehci_hcd *ehcd; + struct ehci_qtd *qtd, *qtds, *qtds_phys; + struct ehci_pipe *epipe; + uint32_t transfer_size = sizeof(*req); + uint32_t datalen, pid; + uint32_t time; + long req_phys = 0, data_phys = 0; + int ret = true; + + if (pipe->type != USB_EP_TYPE_CONTROL) { + printf("usb-ehci: Not a control pipe.\n"); + return false; + } + + ehcd = pipe->dev->hcidev->priv; + qtds = qtd = SLOF_dma_alloc(sizeof(*qtds) * 3); + if (!qtds) { + printf("Error allocating qTDs.\n"); + return false; + } + qtds_phys = (struct ehci_qtd *)SLOF_dma_map_in(qtds, sizeof(*qtds) * 3, true); + memset(qtds, 0, sizeof(*qtds) * 3); + req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true); + qtd->next_qtd = cpu_to_le32(PTR_U32(&qtds_phys[1])); + qtd->alt_next_qtd = QH_PTR_TERM; + qtd->token = cpu_to_le32((transfer_size << TOKEN_TBTT_SHIFT) | + (3 << TOKEN_CERR_SHIFT) | + (PID_SETUP << TOKEN_PID_SHIFT) | + (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)); + fill_qtd_buff(qtd, req_phys, sizeof(*req)); + + qtd++; + datalen = cpu_to_le16(req->wLength); + pid = (req->bmRequestType & REQT_DIR_IN) ? PID_IN : PID_OUT; + if (datalen) { + data_phys = SLOF_dma_map_in(data, datalen, true); + qtd->next_qtd = cpu_to_le32(PTR_U32(&qtds_phys[2])); + qtd->alt_next_qtd = QH_PTR_TERM; + qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) | + (datalen << TOKEN_TBTT_SHIFT) | + (3 << TOKEN_CERR_SHIFT) | + (pid << TOKEN_PID_SHIFT) | + (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)); + fill_qtd_buff(qtd, data_phys, datalen); + qtd++; + } + + if (pid == PID_IN) + pid = PID_OUT; + else + pid = PID_IN; + qtd->next_qtd = QH_PTR_TERM; + qtd->alt_next_qtd = QH_PTR_TERM; + qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) | + (3 << TOKEN_CERR_SHIFT) | + (pid << TOKEN_PID_SHIFT) | + (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)); + + /* link qtd to qh and attach to ehcd */ + mb(); + epipe = container_of(pipe, struct ehci_pipe, pipe); + epipe->qh.next_qtd = cpu_to_le32(PTR_U32(qtds_phys)); + epipe->qh.qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH); + epipe->qh.ep_cap1 = cpu_to_le32((pipe->mps << QH_MPS_SHIFT) | + (pipe->speed << QH_EPS_SHIFT) | + (pipe->epno << QH_EP_SHIFT) | + (pipe->dev->addr << QH_DEV_ADDR_SHIFT)); + mb(); + + ehcd->qh_async->qh_ptr = cpu_to_le32(epipe->qh_phys | EHCI_TYP_QH); + + /* transfer data */ + mb(); + qtd = &qtds[0]; + time = SLOF_GetTimer() + USB_TIMEOUT; + do { + if (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)) + mb(); + else + qtd++; + + if (time < SLOF_GetTimer()) { /* timed out */ + printf("usb-ehci: control transfer timed out_\n"); + ret = false; + break; + } + } while (qtd->next_qtd != QH_PTR_TERM); + + ehcd->qh_async->qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH); + mb(); + if (!ehci_handshake(ehcd, USB_TIMEOUT)) { + printf("%s: handshake failed\n", __func__); + ret = false; + } + + SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req)); + SLOF_dma_map_out(data_phys, data, datalen); + SLOF_dma_map_out(PTR_U32(qtds_phys), qtds, sizeof(*qtds) * 3); + SLOF_dma_free(qtds, sizeof(*qtds) * 3); + + return ret; +} + +static int ehci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys, + void *data_phys, int size) +{ + struct ehci_hcd *ehcd; + struct ehci_qtd *qtd, *qtd_phys; + struct ehci_pipe *epipe; + uint32_t pid; + int i, rem, ret = true; + uint32_t time; + long ptr; + + dprintf("usb-ehci: bulk transfer: data %p, size %d, td %p, td_phys %p\n", + data_phys, size, td, td_phys); + + if (pipe->type != USB_EP_TYPE_BULK) { + printf("usb-ehci: Not a bulk pipe.\n"); + return false; + } + + if (size > QTD_MAX_TRANSFER_LEN) { + printf("usb-ehci: bulk transfer size too big\n"); + return false; + } + + ehcd = pipe->dev->hcidev->priv; + pid = (pipe->dir == USB_PIPE_OUT) ? PID_OUT : PID_IN; + qtd = (struct ehci_qtd *)td; + qtd_phys = (struct ehci_qtd *)td_phys; + ptr = (long)data_phys; + for (i = 0; i < NUM_BULK_QTDS; i++) { + memset(qtd, 0, sizeof(*qtd)); + rem = fill_qtd_buff(qtd, ptr, size); + qtd->token = cpu_to_le32((1 << TOKEN_DT_SHIFT) | + ((size - rem) << TOKEN_TBTT_SHIFT) | + (3 << TOKEN_CERR_SHIFT) | + (pid << TOKEN_PID_SHIFT) | + (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)); + if (rem) { + qtd->next_qtd = cpu_to_le32(PTR_U32(&qtd_phys[i+1])); + qtd->alt_next_qtd = QH_PTR_TERM; + ptr += size - rem; + size = rem; + qtd++; + } else { + qtd->next_qtd = qtd->alt_next_qtd = QH_PTR_TERM; + break; /* no more data */ + } + } + + /* link qtd to qh and attach to ehcd */ + mb(); + epipe = container_of(pipe, struct ehci_pipe, pipe); + epipe->qh.next_qtd = cpu_to_le32(PTR_U32(qtd_phys)); + epipe->qh.qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH); + epipe->qh.ep_cap1 = cpu_to_le32((pipe->mps << QH_MPS_SHIFT) | + (pipe->speed << QH_EPS_SHIFT) | + (pipe->epno << QH_EP_SHIFT) | + (pipe->dev->addr << QH_DEV_ADDR_SHIFT)); + mb(); + + ehcd->qh_async->qh_ptr = cpu_to_le32(epipe->qh_phys | EHCI_TYP_QH); + + /* transfer data */ + mb(); + qtd = (struct ehci_qtd *)td; + for (i = 0; i < NUM_BULK_QTDS; i++) { + time = SLOF_GetTimer() + USB_TIMEOUT; + while ((time > SLOF_GetTimer()) && + (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT))) + cpu_relax(); + mb(); + if (qtd->next_qtd == QH_PTR_TERM) + break; + + if (le32_to_cpu(qtd->token) & (QH_STS_ACTIVE << TOKEN_STATUS_SHIFT)) { + printf("usb-ehci: bulk transfer timed out_\n"); + ret = false; + break; + } + qtd++; + } + + ehcd->qh_async->qh_ptr = cpu_to_le32(ehcd->qh_async_phys | EHCI_TYP_QH); + mb(); + if (!ehci_handshake(ehcd, USB_TIMEOUT)) { + printf("%s: handshake failed\n", __func__); + ret = false; + } + return ret; +} + +static struct usb_pipe *ehci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, + char *buf, size_t len) +{ + struct ehci_hcd *ehcd; + struct usb_pipe *new = NULL; + + if (!dev) + return NULL; + + ehcd = (struct ehci_hcd *)dev->hcidev->priv; + if (!ehcd->freelist) { + dprintf("usb-ehci: %s allocating pool\n", __func__); + if (ehci_alloc_pipe_pool(ehcd)) + return NULL; + } + + new = ehcd->freelist; + ehcd->freelist = ehcd->freelist->next; + if (!ehcd->freelist) + ehcd->end = NULL; + + memset(new, 0, sizeof(*new)); + new->dev = dev; + new->next = NULL; + new->type = ep->bmAttributes & USB_EP_TYPE_MASK; + new->speed = dev->speed; + new->mps = ep->wMaxPacketSize; + new->dir = (ep->bEndpointAddress & 0x80) >> 7; + new->epno = ep->bEndpointAddress & 0x0f; + + return new; +} + +static void ehci_put_pipe(struct usb_pipe *pipe) +{ + struct ehci_hcd *ehcd; + + dprintf("usb-ehci: %s enter - %p\n", __func__, pipe); + if (!pipe || !pipe->dev) + return; + ehcd = pipe->dev->hcidev->priv; + if (ehcd->end) + ehcd->end->next = pipe; + else + ehcd->freelist = pipe; + + ehcd->end = pipe; + pipe->next = NULL; + pipe->dev = NULL; + memset(pipe, 0, sizeof(*pipe)); + dprintf("usb-ehci: %s exit\n", __func__); +} + +struct usb_hcd_ops ehci_ops = { + .name = "ehci-hcd", + .init = ehci_init, + .exit = ehci_exit, + .detect = ehci_detect, + .disconnect = ehci_disconnect, + .get_pipe = ehci_get_pipe, + .put_pipe = ehci_put_pipe, + .send_ctrl = ehci_send_ctrl, + .transfer_bulk = ehci_transfer_bulk, + .usb_type = USB_EHCI, + .next = NULL, +}; + +void usb_ehci_register(void) +{ + usb_hcd_register(&ehci_ops); +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-ehci.h b/qemu/roms/SLOF/lib/libusb/usb-ehci.h new file mode 100644 index 000000000..2955a9cb8 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-ehci.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * Copyright (c) 2007, 2012, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * Definitions for EHCI Controller + * + */ + +#ifndef USB_EHCI_H +#define USB_EHCI_H + +#include <stdint.h> +#include "usb-core.h" + +#define FL_SIZE 1024 + +struct ehci_cap_regs { + uint8_t caplength; + uint8_t reserved; + uint16_t hciversion; + uint32_t hcsparams; + uint32_t hccparams; + uint64_t portroute; +} __attribute__ ((packed)); + +struct ehci_op_regs { + uint32_t usbcmd; + uint32_t usbsts; + uint32_t usbintr; + uint32_t frindex; + uint32_t ctrldssegment; + uint32_t periodiclistbase; + uint32_t asynclistaddr; + uint32_t reserved[9]; + uint32_t configflag; + uint32_t portsc[0]; +} __attribute__ ((packed)); + +struct ehci_framelist { + uint32_t fl_ptr[FL_SIZE]; +} __attribute__ ((packed)); + +struct ehci_hcd { + struct ehci_cap_regs *cap_regs; + struct ehci_op_regs *op_regs; + struct usb_hcd_dev *hcidev; + struct ehci_qh *qh_async; + struct ehci_qh *qh_intr; + struct usb_pipe *freelist; + struct usb_pipe *end; + struct ehci_framelist *fl; + long qh_async_phys; + long qh_intr_phys; + long fl_phys; + void *pool; + long pool_phys; +}; + +struct ehci_qtd { + uint32_t next_qtd; + uint32_t alt_next_qtd; + uint32_t token; + uint32_t buffer[5]; +} __attribute__ ((packed)); + +struct ehci_qh { + uint32_t qh_ptr; + uint32_t ep_cap1; + uint32_t ep_cap2; + uint32_t curr_qtd; + uint32_t next_qtd; + uint32_t alt_next_qtd; + uint32_t token; + uint32_t buffer[5]; +} __attribute__ ((packed)) __attribute__((aligned(32))); + +struct ehci_pipe { + struct ehci_qh qh; + struct usb_pipe pipe; + long qh_phys; +}; + +#define EHCI_PIPE_POOL_SIZE 4096 + +#define EHCI_TYP_ITD 0x00 +#define EHCI_TYP_QH 0x02 +#define EHCI_TYP_SITD 0x04 +#define EHCI_TYP_FSTN 0x06 + +#define PID_OUT 0x00 +#define PID_IN 0x01 +#define PID_SETUP 0x02 + +#define HCS_NPORTS_MASK 0x000f + +#define CMD_IAAD (1 << 6) +#define CMD_ASE (1 << 5) +#define CMD_PSE (1 << 4) +#define CMD_FLS_MASK (3 << 2) +#define CMD_HCRESET (1 << 1) +#define CMD_RUN (1 << 0) + +#define STS_IAA (1 << 5) + +#define PORT_RESET (1 << 8) +#define PORT_PE (1 << 2) +#define PORT_CSC (1 << 1) +#define PORT_CONNECT (1 << 0) + +#define QH_LOW_SPEED 0 +#define QH_FULL_SPEED 1 +#define QH_HIGH_SPEED 2 + +#define QH_RL_SHIFT 28 +#define QH_CAP_C (1 << 27) +#define QH_MPS_SHIFT 16 +#define QH_CAP_H (1 << 15) +#define QH_CAP_DTC (1 << 14) +#define QH_EPS_SHIFT 12 +#define QH_EP_SHIFT 8 +#define QH_CAP_I (1 << 7) +#define QH_DEV_ADDR_SHIFT 0 + +#define QH_PTR_TERM __builtin_bswap32(1) +#define QH_SMASK_SHIFT 0 +#define QH_STS_ACTIVE (1 << 7) +#define QH_STS_HALTED (1 << 6) +#define QH_STS_DBE (1 << 5) +#define QH_STS_BABBLE (1 << 4) +#define QH_STS_XACTERR (1 << 3) +#define QH_STS_MMF (1 << 2) +#define QH_STS_SXS (1 << 1) +#define QH_STS_PING (1 << 0) + +#define NUM_BULK_QTDS 4 +#define MAX_XFER_PER_QTD (20 * 1024) +#define QTD_MAX_TRANSFER_LEN (NUM_BULK_QTDS * MAX_XFER_PER_QTD) + +#define TOKEN_DT_SHIFT 31 +#define TOKEN_TBTT_SHIFT 16 +#define TOKEN_IOC_SHIFT 15 +#define TOKEN_CPAGE_SHIFT 12 +#define TOKEN_CERR_SHIFT 10 +#define TOKEN_PID_SHIFT 8 +#define TOKEN_STATUS_SHIFT 0 + +#endif /* USB_EHCI_H */ diff --git a/qemu/roms/SLOF/lib/libusb/usb-hid.c b/qemu/roms/SLOF/lib/libusb/usb-hid.c new file mode 100644 index 000000000..f0cab8a69 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-hid.c @@ -0,0 +1,453 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <termctrl.h> + +#include "usb-core.h" +#include "usb-key.h" + +/* + * HID Spec Version 1.11 + */ + +#define HID_REQ_GET_REPORT 0x01 +#define HID_REQ_GET_IDLE 0x02 +#define HID_REQ_GET_PROTOCOL 0x03 +#define HID_REQ_SET_REPORT 0x09 +#define HID_REQ_SET_IDLE 0x0A +#define HID_REQ_SET_PROTOCOL 0x0B + +//#define KEY_DEBUG + +/* HID SPEC - 7.2.6 Set_Protocol Request */ +static int usb_hid_set_protocol(struct usb_dev *dev, uint16_t value) +{ + struct usb_dev_req req; + if (!dev) + return false; + req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT; + req.bRequest = HID_REQ_SET_PROTOCOL; + req.wValue = cpu_to_le16(value); + req.wIndex = cpu_to_le16(dev->intf_num); + req.wLength = 0; + return usb_send_ctrl(dev->control, &req, NULL); +} + +/* HID SPEC - 7.2.4 Set_Idle Request */ +static int usb_hid_set_idle(struct usb_dev *dev, uint16_t ms_delay) +{ + struct usb_dev_req req; + if (!dev) + return false; + req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_OUT; + req.bRequest = HID_REQ_SET_IDLE; + req.wValue = cpu_to_le16((ms_delay/4) << 8); + req.wIndex = cpu_to_le16(dev->intf_num); + req.wLength = 0; + return usb_send_ctrl(dev->control, &req, NULL); +} + +/* HID SPEC - 7.2.1 Get Report Request */ +static int usb_hid_get_report(struct usb_dev *dev, void *data, size_t size) +{ + struct usb_dev_req req; + if (!dev) + return false; + req.bmRequestType = REQT_TYPE_CLASS | REQT_REC_INTERFACE | REQT_DIR_IN; + req.bRequest = HID_REQ_GET_REPORT; + req.wIndex = cpu_to_le16(dev->intf_num); + + req.wLength = cpu_to_le16((uint16_t)size); + req.wValue = cpu_to_le16(1 << 8); + return usb_send_ctrl(dev->control, &req, data); +} + +/* ring buffer with RD/WR indices for key buffering */ +static uint8_t keybuf[256]; /* size fixed to byte range ! */ +uint8_t r_ptr = 0; /* RD-index for Keyboard-Buffer */ +uint8_t w_ptr = 0; /* WR-index for Keyboard-Buffer */ + +/* variables for LED status */ +uint8_t set_leds; +const uint8_t *key_std = NULL; +const uint8_t *key_std_shift = NULL; + +/** + * read character from Keyboard-Buffer + * + * @param - + * @return > 0 Keycode + * = 0 if no key available + */ +static int read_key(void) +{ + if (r_ptr != w_ptr) + return (int)keybuf[r_ptr++]; + else + return false; +} + +/** + * Store character into Keyboard-Buffer + * + * @param Key = detected ASCII-Key (> 0) + * @return - + */ +static void write_key(uint8_t key) +{ + if ((w_ptr + 1) != r_ptr) + keybuf[w_ptr++] = key; +} + +/** + * Convert keyboard usage-ID to ANSI-Code + * + * @param Ctrl=Modifier Byte + * Key =Usage ID from USB Keyboard + * @return - + */ +static void get_char(uint8_t ctrl, uint8_t keypos) +{ + uint8_t ch; + +#ifdef KEY_DEBUG + printf("pos %02X\n", keypos); +#endif + + if (set_leds & LED_CAPS_LOCK) /* is CAPS Lock set ? */ + ctrl |= MODIFIER_SHIFT; /* simulate shift */ + + if (ctrl == 0) { + ch = key_std[keypos]; + if (ch != 0) + write_key(ch); + return; + } + + if (ctrl & MODIFIER_SHIFT) { + ch = key_std_shift[keypos]; + if (ch != 0) + write_key(ch); + return; + } + + if (ctrl & MODIFIER_CTRL) { + ch = keycodes_ctrl[keypos]; + if (ch != 0) + write_key(ch); + return; + } + + if (ctrl == MODIFIER_ALT_GR) { + ch = keycodes_alt_GR[keypos]; + if (ch != 0) + write_key(ch); + return; + } +} + +static void check_key_code(uint8_t *buf) +{ + static uint8_t key_last[6]; /* list of processed keys */ + uint8_t i, j, key_pos; + + /* set translation table to defaults */ + if ((key_std == NULL) || (key_std_shift == NULL)) { + key_std = keycodes_std_US; + key_std_shift = keycodes_shift_US; + } + + if (buf[0] & MODIFIER_SHIFT) /* any shift key pressed ? */ + set_leds &= ~LED_CAPS_LOCK; /* CAPS-LOCK-LED always off */ + + i = 2; /* skip modifier byte and reserved byte */ + while (i < 8) { + key_pos = buf[i]; + if ((key_pos != 0) && (key_pos <= 100)) { /* support for 101 keys */ + j = 0; + /* search if already processed */ + while ((j < 6) && (key_pos != key_last[j])) + j++; + + if (j >= 6) { /* not found (= not processed) */ + switch (key_pos) { + case 0x39: /* caps-lock key ? */ + case 0x32: /* caps-lock key ? */ + set_leds ^= LED_CAPS_LOCK; + break; + + case 0x3a: /* F1 */ + write_key(0x1b); + write_key(0x5b); + write_key(0x31); + write_key(0x31); + write_key(0x7e); + break; + + case 0x3b: /* F2 */ + write_key(0x1b); + write_key(0x5b); + write_key(0x31); + write_key(0x32); + write_key(0x7e); + break; + + case 0x3c: + write_key(0x1b); /* F3 */ + write_key(0x5b); + write_key(0x31); + write_key(0x33); + write_key(0x7e); + break; + + case 0x3d: + write_key(0x1b); /* F4 */ + write_key(0x5b); + write_key(0x31); + write_key(0x34); + write_key(0x7e); + break; + + case 0x3e: + write_key(0x1b); /* F5 */ + write_key(0x5b); + write_key(0x31); + write_key(0x35); + write_key(0x7e); + break; + + case 0x3f: + write_key(0x1b); /* F6 */ + write_key(0x5b); + write_key(0x31); + write_key(0x37); + write_key(0x7e); + break; + + case 0x40: + write_key(0x1b); /* F7 */ + write_key(0x5b); + write_key(0x31); + write_key(0x38); + write_key(0x7e); + break; + + case 0x41: + write_key(0x1b); /* F8 */ + write_key(0x5b); + write_key(0x31); + write_key(0x39); + write_key(0x7e); + break; + + case 0x42: + write_key(0x1b); /* F9 */ + write_key(0x5b); + write_key(0x31); + write_key(0x30); + write_key(0x7e); + break; + + case 0x43: + write_key(0x1b); /* F10 */ + write_key(0x5b); + write_key(0x31); + write_key(0x31); + write_key(0x7e); + break; + + case 0x44: + write_key(0x1b); /* F11 */ + write_key(0x5b); + write_key(0x31); + write_key(0x33); + write_key(0x7e); + break; + + case 0x45: + write_key(0x1b); /* F12 */ + write_key(0x5b); + write_key(0x31); + write_key(0x34); + write_key(0x7e); + break; + + case 0x47: /* scroll-lock key ? */ + set_leds ^= LED_SCROLL_LOCK; + break; + + case 0x49: + write_key(0x1b); /* INS */ + write_key(0x5b); + write_key(0x31); + write_key(0x7e); + break; + + case 0x4a: + write_key(0x1b); /* HOME */ + write_key(0x5b); + write_key(0x32); + write_key(0x7e); + break; + + case 0x4b: + write_key(0x1b); /* PgUp */ + write_key(0x5b); + write_key(0x33); + write_key(0x7e); + break; + + case 0x4c: + write_key(0x1b); /* DEL */ + write_key(0x5b); + write_key(0x34); + write_key(0x7e); + break; + + case 0x4d: + write_key(0x1b); /* END */ + write_key(0x5b); + write_key(0x35); + write_key(0x7e); + break; + + case 0x4e: + write_key(0x1b); /* PgDn */ + write_key(0x5b); + write_key(0x36); + write_key(0x7e); + break; + + case 0x4f: + write_key(0x1b); /* R-Arrow */ + write_key(0x5b); + write_key(0x43); + break; + + case 0x50: + write_key(0x1b); /* L-Arrow */ + write_key(0x5b); + write_key(0x44); + break; + + case 0x51: + write_key(0x1b); /* D-Arrow */ + write_key(0x5b); + write_key(0x42); + break; + + case 0x52: + write_key(0x1b); /* U-Arrow */ + write_key(0x5b); + write_key(0x41); + break; + + case 0x53: /* num-lock key ? */ + set_leds ^= LED_NUM_LOCK; + break; + + default: + /* convert key position to ASCII code */ + get_char(buf[0], key_pos); + break; + } + } + } + i++; + } + /*****************************************/ + /* all keys are processed, create a copy */ + /* to flag them as processed */ + /*****************************************/ + for (i = 2, j = 0; j < 6; i++, j++) + key_last[j] = buf[i]; /* copy all actual keys to last */ +} + +#define USB_HID_SIZE 128 +uint32_t *kbd_buffer; + +int usb_hid_kbd_init(struct usb_dev *dev) +{ + int i; + uint8_t key[8]; + + usb_hid_set_protocol(dev, 0); + usb_hid_set_idle(dev, 500); + + memset(key, 0, 8); + if (usb_hid_get_report(dev, key, 8)) + check_key_code(key); + + kbd_buffer = SLOF_dma_alloc(USB_HID_SIZE); + if (!kbd_buffer) { + printf("%s: unable to allocate keyboard buffer\n", __func__); + return false; + } + +#ifdef KEY_DEBUG + printf("HID kbd init %d\n", dev->ep_cnt); +#endif + for (i = 0; i < dev->ep_cnt; i++) { + if ((dev->ep[i].bmAttributes & USB_EP_TYPE_MASK) + == USB_EP_TYPE_INTR) + usb_dev_populate_pipe(dev, &dev->ep[i], kbd_buffer, USB_HID_SIZE); + } + return true; +} + +int usb_hid_kbd_exit(struct usb_dev *dev) +{ + if (dev->intr) { + usb_put_pipe(dev->intr); + dev->intr = NULL; + } + SLOF_dma_free(kbd_buffer, USB_HID_SIZE); + return true; +} + +static int usb_poll_key(void *vdev) +{ + struct usb_dev *dev = vdev; + uint8_t key[8]; + int rc; + + memset(key, 0, 8); + rc = usb_poll_intr(dev->intr, key); + if (rc) + check_key_code(key); + return rc; +} + +unsigned char usb_key_available(void *dev) +{ + if (!dev) + return false; + + usb_poll_key(dev); + if (r_ptr != w_ptr) + return true; + else + return false; +} + +unsigned char usb_read_keyb(void *vdev) +{ + if (!vdev) + return false; + + while (usb_poll_key(vdev)) { + /* loop for all pending keys */ + } + return read_key(); +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-hub.c b/qemu/roms/SLOF/lib/libusb/usb-hub.c new file mode 100644 index 000000000..7059cd019 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-hub.c @@ -0,0 +1,183 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include "usb-core.h" + +#undef HUB_DEBUG +//#define HUB_DEBUG +#ifdef HUB_DEBUG +#define dprintf(_x ...) do { printf(_x); } while(0) +#else +#define dprintf(_x ...) +#endif + +/* + * USB Spec 1.1 + * 11.16.2 Class-specific Requests + */ +struct usb_hub_ps { + uint16_t wPortStatus; + uint16_t wPortChange; +} __attribute__((packed)); + +#define HUB_PS_CONNECTION (1 << 0) +#define HUB_PS_ENABLE (1 << 1) +#define HUB_PS_SUSPEND (1 << 2) +#define HUB_PS_OVER_CURRENT (1 << 3) +#define HUB_PS_RESET (1 << 4) +#define HUB_PS_POWER (1 << 8) +#define HUB_PS_LOW_SPEED (1 << 9) + +#define HUB_PF_CONNECTION 0 +#define HUB_PF_ENABLE 1 +#define HUB_PF_SUSPEND 2 +#define HUB_PF_OVER_CURRENT 3 +#define HUB_PF_RESET 4 +#define HUB_PF_POWER 8 +#define HUB_PF_LOWSPEED 9 +#define HUB_PF_C_CONNECTION 16 +#define HUB_PF_C_ENABLE 17 +#define HUB_PF_C_SUSPEND 18 +#define HUB_PF_C_OVER_CURRENT 19 +#define HUB_PF_C_RESET 20 + +static int usb_get_hub_desc(struct usb_dev *dev, void *data, size_t size) +{ + struct usb_dev_req req; + if (!dev) + return false; + req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_DEVICE; + req.bRequest = REQ_GET_DESCRIPTOR; + req.wIndex = 0; + req.wLength = cpu_to_le16((uint16_t) size); + req.wValue = cpu_to_le16(DESCR_TYPE_HUB << 8); + return usb_send_ctrl(dev->control, &req, data); +} + +static int hub_get_port_status(struct usb_dev *dev, int port, void *data, size_t size) +{ + struct usb_dev_req req; + if (!dev) + return false; + req.bmRequestType = REQT_DIR_IN | REQT_TYPE_CLASS | REQT_REC_OTHER; + req.bRequest = REQ_GET_STATUS; + req.wValue = 0; + req.wIndex = cpu_to_le16((uint16_t)(port + 1)); + req.wLength = cpu_to_le16((uint16_t)size); + return usb_send_ctrl(dev->control, &req, data); +} + +static int hub_set_port_feature(struct usb_dev *dev, int port, int feature) +{ + struct usb_dev_req req; + if (!dev) + return false; + req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER; + req.bRequest = REQ_SET_FEATURE; + req.wLength = 0; + req.wValue = cpu_to_le16((uint16_t)feature); + req.wIndex = cpu_to_le16((uint16_t)(port + 1)); + return usb_send_ctrl(dev->control, &req, NULL); +} + +#if 0 +static int hub_clear_port_feature(struct usb_dev *dev, int port, int feature) +{ + struct usb_dev_req req; + if (!dev) + return false; + req.bmRequestType = REQT_DIR_OUT | REQT_TYPE_CLASS | REQT_REC_OTHER; + req.bRequest = REQ_CLEAR_FEATURE; + req.wLength = 0; + req.wValue = cpu_to_le16((uint16_t)feature); + req.wIndex = cpu_to_le16((uint16_t)(port + 1)); + return usb_send_ctrl(dev->control, &req, NULL); +} +#endif + +static int hub_check_port(struct usb_dev *dev, int port) +{ + struct usb_hub_ps ps; + uint32_t time; + + if (!hub_get_port_status(dev, port, &ps, sizeof(ps))) + return false; + dprintf("Port Status %04X Port Change %04X\n", + le16_to_cpu(ps.wPortStatus), + le16_to_cpu(ps.wPortChange)); + + if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_POWER)) { + hub_set_port_feature(dev, port, HUB_PF_POWER); + SLOF_msleep(100); + time = SLOF_GetTimer() + USB_TIMEOUT; + while (time > SLOF_GetTimer()) { + cpu_relax(); + hub_get_port_status(dev, port, &ps, sizeof(ps)); + if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) { + dprintf("power on Port Status %04X Port Change %04X\n", + le16_to_cpu(ps.wPortStatus), + le16_to_cpu(ps.wPortChange)); + break; + } + } + } + + if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) { + hub_set_port_feature(dev, port, HUB_PF_RESET); + SLOF_msleep(100); + time = SLOF_GetTimer() + USB_TIMEOUT; + while (time > SLOF_GetTimer()) { + cpu_relax(); + hub_get_port_status(dev, port, &ps, sizeof(ps)); + if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_RESET)) { + dprintf("reset Port Status %04X Port Change %04X\n", + le16_to_cpu(ps.wPortStatus), + le16_to_cpu(ps.wPortChange)); + return true; + } + } + } + return false; +} + +unsigned int usb_hub_init(void *hubdev) +{ + struct usb_dev *dev = hubdev; + struct usb_dev_hub_descr hub; + struct usb_dev *newdev; + int i; + + dprintf("%s: enter %p\n", __func__, dev); + if (!dev) { + printf("usb-hub: NULL\n"); + return false; + } + memset(&hub, 0, sizeof(hub)); + usb_get_hub_desc(dev, &hub, sizeof(hub)); + dprintf("usb-hub: ports connected %d\n", hub.bNbrPorts); + for (i = 0; i < hub.bNbrPorts; i++) { + dprintf("usb-hub: ports scanning %d\n", i); + if (hub_check_port(dev, i)) { + dprintf("***********************************************\n"); + dprintf("\t\tusb-hub: device found %d\n", i); + dprintf("***********************************************\n"); + newdev = usb_devpool_get(); + dprintf("usb-hub: allocated device %p\n", newdev); + newdev->hcidev = dev->hcidev; + if (!setup_new_device(newdev, i)) + printf("usb-hub: unable to setup device on port %d\n", i); + } + } + return true; +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-key.c b/qemu/roms/SLOF/lib/libusb/usb-key.c new file mode 100644 index 000000000..7fb45da2c --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-key.c @@ -0,0 +1,446 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> + +/***********************************/ +/* Keycodes for US Keyboard */ +/* - no control keys pressed - */ +/***********************************/ +const uint8_t keycodes_std_US[] = { + 0, /* 0 00 Reserved (no event indicated) */ + 0, /* 1 01 Keyboard ErrorRollOver */ + 0, /* 2 02 Keyboard POSTFail */ + 0, /* 3 03 Keyboard ErrorUndefined */ + 'a', /* 4 04 Keyboard a and A 31 */ + 'b', /* 5 05 Keyboard b and B 50 */ + 'c', /* 6 06 Keyboard c and C 48 */ + 'd', /* 7 07 Keyboard d and D 33 */ + 'e', /* 8 08 Keyboard e and E 19 */ + 'f', /* 9 09 Keyboard f and F 34 */ + 'g', /* 10 0A Keyboard g and G 35 */ + 'h', /* 11 0B Keyboard h and H 36 */ + 'i', /* 12 0C Keyboard i and I 24 */ + 'j', /* 13 0D Keyboard j and J 37 */ + 'k', /* 14 0E Keyboard k and K 38 */ + 'l', /* 15 0F Keyboard l and L 39 */ + 'm', /* 16 10 Keyboard m and M 52 */ + 'n', /* 17 11 Keyboard n and N 51 */ + 'o', /* 18 12 Keyboard o and O 25 */ + 'p', /* 19 13 Keyboard p and P 26 */ + 'q', /* 20 14 Keyboard q and Q 17 */ + 'r', /* 21 15 Keyboard r and R 20 */ + 's', /* 22 16 Keyboard s and S 32 */ + 't', /* 23 17 Keyboard t and T 21 */ + 'u', /* 24 18 Keyboard u and U 23 */ + 'v', /* 25 19 Keyboard v and V 49 */ + 'w', /* 26 1A Keyboard w and W 18 */ + 'x', /* 27 1B Keyboard x and X 47 */ + 'y', /* 28 1C Keyboard y and Y 22 */ + 'z', /* 29 1D Keyboard z and Z 46 */ + '1', /* 30 1E Keyboard 1 and ! 2 */ + '2', /* 31 1F Keyboard 2 and @ 3 */ + '3', /* 32 20 Keyboard 3 and # 4 */ + '4', /* 33 21 Keyboard 4 and $ 5 */ + '5', /* 34 22 Keyboard 5 and % 6 */ + '6', /* 35 23 Keyboard 6 and ^ 7 */ + '7', /* 36 24 Keyboard 7 and & 8 */ + '8', /* 37 25 Keyboard 8 and * 9 */ + '9', /* 38 26 Keyboard 9 and ( 10 */ + '0', /* 39 27 Keyboard 0 and ) 11 */ + 13, /* 40 28 Keyboard Return (ENTER) 43 */ + 27, /* 41 29 Keyboard ESCAPE 110 */ + 8, /* 42 2A Keyboard DELETE (BS) 15 */ + 9, /* 43 2B Keyboard Tab 16 */ + ' ', /* 44 2C Keyboard Spacebar 61 */ + '-', /* 45 2D Keyboard - and (underscore) 12 */ + '=', /* 46 2E Keyboard = and + 13 */ + '[', /* 47 2F Keyboard [ and { 27 */ + ']', /* 48 30 Keyboard ] and } 28 */ + '\\', /* 49 31 Keyboard \ and | 29 */ + '\\', /* 50 32 Keyboard \ and | 42 */ + ';', /* 51 33 Keyboard ; and : 40 */ + 39, /* 52 34 Keyboard ' and " 41 */ + 96, /* 53 35 Keyboard Grave Accent and Tilde 1 */ + ',', /* 54 36 Keyboard , and < 53 */ + '.', /* 55 37 Keyboard . and > 54 */ + '/', /* 56 38 Keyboard / and ? 55 */ + 0, /* 57 39 Keyboard Caps Lock 30 */ + 0, /* 58 3A Keyboard F1 112 */ + 0, /* 59 3B Keyboard F2 113 */ + 0, /* 60 3C Keyboard F3 114 */ + 0, /* 61 3D Keyboard F4 115 */ + 0, /* 62 3E Keyboard F5 116 */ + 0, /* 63 3F Keyboard F6 117 */ + 0, /* 64 40 Keyboard F7 118 */ + 0, /* 65 41 Keyboard F8 119 */ + 0, /* 66 42 Keyboard F9 120 */ + 0, /* 67 43 Keyboard F10 121 */ + 0, /* 68 44 Keyboard F11 122 */ + 0, /* 69 45 Keyboard F12 123 */ + 0, /* 70 46 Keyboard PrintScreen 124 */ + 0, /* 71 47 Keyboard Scroll Lock 125 */ + 0, /* 72 48 Keyboard Pause 126 */ + 0, /* 73 49 Keyboard Insert 75 */ + 0, /* 74 4A Keyboard Home 80 */ + 0, /* 75 4B Keyboard PageUp 85 */ + 0, /* 76 4C Keyboard Delete Forward 76 */ + 0, /* 77 4D Keyboard End 81 */ + 0, /* 78 4E Keyboard PageDown 86 */ + 0, /* 79 4F Keyboard RightArrow 89 */ + 0, /* 80 50 Keyboard LeftArrow 79 */ + 0, /* 81 51 Keyboard DownArrow 84 */ + 0, /* 82 52 Keyboard UpArrow 83 */ + 0, /* 83 53 Keypad Num Lock and Clear 90 */ + '/', /* 84 54 Keypad / 95 */ + '*', /* 85 55 Keypad * 100 */ + '-', /* 86 56 Keypad - 105 */ + '+', /* 87 57 Keypad + 106 */ + 13, /* 88 58 Keypad ENTER 108 */ + '1', /* 89 59 Keypad 1 and End 93 */ + '2', /* 90 5A Keypad 2 and Down Arrow 98 */ + '3', /* 91 5B Keypad 3 and PageDn 103 */ + '4', /* 92 5C Keypad 4 and Left Arrow 92 */ + '5', /* 93 5D Keypad 5 97 */ + '6', /* 94 5E Keypad 6 and Right Arrow 102 */ + '7', /* 95 5F Keypad 7 and Home 91 */ + '8', /* 96 60 Keypad 8 and Up Arrow 96 */ + '9', /* 97 61 Keypad 9 and PageUp 101 */ + '0', /* 98 62 Keypad 0 and Insert 99 */ + '.', /* 99 63 Keypad . and Delete 104 */ + '\\' /* 100 64 Keyboard Non-US \ and | 45 */ +}; + +/***********************************/ +/* Keycodes for US Keyboard */ +/* - SHIFT-KEY pressed - */ +/***********************************/ +const uint8_t keycodes_shift_US[] = { + 0, /* 0 00 Reserved (no event indicated) */ + 0, /* 1 01 Keyboard ErrorRollOver */ + 0, /* 2 02 Keyboard POSTFail */ + 0, /* 3 03 Keyboard ErrorUndefined */ + 'A', /* 4 04 Keyboard a and A 31 */ + 'B', /* 5 05 Keyboard b and B 50 */ + 'C', /* 6 06 Keyboard c and C 48 */ + 'D', /* 7 07 Keyboard d and D 33 */ + 'E', /* 8 08 Keyboard e and E 19 */ + 'F', /* 9 09 Keyboard f and F 34 */ + 'G', /* 10 0A Keyboard g and G 35 */ + 'H', /* 11 0B Keyboard h and H 36 */ + 'I', /* 12 0C Keyboard i and I 24 */ + 'J', /* 13 0D Keyboard j and J 37 */ + 'K', /* 14 0E Keyboard k and K 38 */ + 'L', /* 15 0F Keyboard l and L 39 */ + 'M', /* 16 10 Keyboard m and M 52 */ + 'N', /* 17 11 Keyboard n and N 51 */ + 'O', /* 18 12 Keyboard o and O 25 */ + 'P', /* 19 13 Keyboard p and P 26 */ + 'Q', /* 20 14 Keyboard q and Q 17 */ + 'R', /* 21 15 Keyboard r and R 20 */ + 'S', /* 22 16 Keyboard s and S 32 */ + 'T', /* 23 17 Keyboard t and T 21 */ + 'U', /* 24 18 Keyboard u and U 23 */ + 'V', /* 25 19 Keyboard v and V 49 */ + 'W', /* 26 1A Keyboard w and W 18 */ + 'X', /* 27 1B Keyboard x and X 47 */ + 'Y', /* 28 1C Keyboard y and Y 22 */ + 'Z', /* 29 1D Keyboard z and Z 46 */ + '!', /* 30 1E Keyboard 1 and ! 2 */ + '@', /* 31 1F Keyboard 2 and @ 3 */ + '#', /* 32 20 Keyboard 3 and # 4 */ + '$', /* 33 21 Keyboard 4 and $ 5 */ + '%', /* 34 22 Keyboard 5 and % 6 */ + '^', /* 35 23 Keyboard 6 and ^ 7 */ + '&', /* 36 24 Keyboard 7 and & 8 */ + '*', /* 37 25 Keyboard 8 and * 9 */ + '(', /* 38 26 Keyboard 9 and ( 10 */ + ')', /* 39 27 Keyboard 0 and ) 11 */ + 13, /* 40 28 Keyboard Return (ENTER) 43 */ + 27, /* 41 29 Keyboard ESCAPE 110 */ + 8, /* 42 2A Keyboard DELETE (BS) 15 */ + 9, /* 43 2B Keyboard Tab 16 */ + ' ', /* 44 2C Keyboard Spacebar 61 */ + '_', /* 45 2D Keyboard - and (underscore) 12 */ + '+', /* 46 2E Keyboard = and + 13 */ + '{', /* 47 2F Keyboard [ and { 27 */ + '}', /* 48 30 Keyboard ] and } 28 */ + '|', /* 49 31 Keyboard \ and | 29 */ + '|', /* 50 32 Keyboard \ and | 42 */ + ':', /* 51 33 Keyboard ; and : 40 */ + '"', /* 52 34 Keyboard ' and " 41 */ + '~', /* 53 35 Keyboard Grave Accent and Tilde 1 */ + '<', /* 54 36 Keyboard , and < 53 */ + '>', /* 55 37 Keyboard . and > 54 */ + '?', /* 56 38 Keyboard / and ? 55 */ + 0, /* 57 39 Keyboard Caps Lock 30 */ + 0, /* 58 3A Keyboard F1 112 */ + 0, /* 59 3B Keyboard F2 113 */ + 0, /* 60 3C Keyboard F3 114 */ + 0, /* 61 3D Keyboard F4 115 */ + 0, /* 62 3E Keyboard F5 116 */ + 0, /* 63 3F Keyboard F6 117 */ + 0, /* 64 40 Keyboard F7 118 */ + 0, /* 65 41 Keyboard F8 119 */ + 0, /* 66 42 Keyboard F9 120 */ + 0, /* 67 43 Keyboard F10 121 */ + 0, /* 68 44 Keyboard F11 122 */ + 0, /* 69 45 Keyboard F12 123 */ + 0, /* 70 46 Keyboard PrintScreen 124 */ + 0, /* 71 47 Keyboard Scroll Lock 125 */ + 0, /* 72 48 Keyboard Pause 126 */ + 48, /* 73 49 Keyboard Insert 75 */ + 55, /* 74 4A Keyboard Home 80 */ + 57, /* 75 4B Keyboard PageUp 85 */ + 46, /* 76 4C Keyboard Delete Forward 76 */ + 49, /* 77 4D Keyboard End 81 */ + 51, /* 78 4E Keyboard PageDown 86 */ + 54, /* 79 4F Keyboard RightArrow 89 */ + 52, /* 80 50 Keyboard LeftArrow 79 */ + 50, /* 81 51 Keyboard DownArrow 84 */ + 56, /* 82 52 Keyboard UpArrow 83 */ + 0, /* 83 53 Keypad Num Lock and Clear 90 */ + '/', /* 84 54 Keypad / 95 */ + '*', /* 85 55 Keypad * 100 */ + '-', /* 86 56 Keypad - 105 */ + '+', /* 87 57 Keypad + 106 */ + 13, /* 88 58 Keypad ENTER 108 */ + '1', /* 89 59 Keypad 1 and End 93 */ + '2', /* 90 5A Keypad 2 and Down Arrow 98 */ + '3', /* 91 5B Keypad 3 and PageDn 103 */ + '4', /* 92 5C Keypad 4 and Left Arrow 92 */ + '5', /* 93 5D Keypad 5 97 */ + '6', /* 94 5E Keypad 6 and Right Arrow 102 */ + '7', /* 95 5F Keypad 7 and Home 91 */ + '8', /* 96 60 Keypad 8 and Up Arrow 96 */ + '9', /* 97 61 Keypad 9 and PageUp 101 */ + '0', /* 98 62 Keypad 0 and Insert 99 */ + '.', /* 99 63 Keypad . and Delete 104 */ + '|' /* 100 64 Keyboard Non-US \ and | 45 */ +}; + +/***********************************/ +/* Keycodes for 1 byte translation */ +/* - CONTROL-KEY pressed - */ +/***********************************/ +const uint8_t keycodes_alt_GR[] = { + 0, /* 0 00 Reserved (no event indicated) */ + 0, /* 1 01 Keyboard ErrorRollOver */ + 0, /* 2 02 Keyboard POSTFail */ + 0, /* 3 03 Keyboard ErrorUndefined */ + 0, /* 4 04 Keyboard a and A 31 */ + 0, /* 5 05 Keyboard b and B 50 */ + 0, /* 6 06 Keyboard c and C 48 */ + 0, /* 7 07 Keyboard d and D 33 */ + 0, /* 8 08 Keyboard e and E 19 */ + 0, /* 9 09 Keyboard f and F 34 */ + 0, /* 10 0A Keyboard g and G 35 */ + 0, /* 11 0B Keyboard h and H 36 */ + 0, /* 12 0C Keyboard i and I 24 */ + 0, /* 13 0D Keyboard j and J 37 */ + 0, /* 14 0E Keyboard k and K 38 */ + 0, /* 15 0F Keyboard l and L 39 */ + 0, /* 16 10 Keyboard m and M 52 */ + 0, /* 17 11 Keyboard n and N 51 */ + 0, /* 18 12 Keyboard o and O 25 */ + 0, /* 19 13 Keyboard p and P 26 */ + '@', /* 20 14 Keyboard q and Q 17 */ + 0, /* 21 15 Keyboard r and R 20 */ + 0, /* 22 16 Keyboard s and S 32 */ + 0, /* 23 17 Keyboard t and T 21 */ + 0, /* 24 18 Keyboard u and U 23 */ + 0, /* 25 19 Keyboard v and V 49 */ + 0, /* 26 1A Keyboard w and W 18 */ + 0, /* 27 1B Keyboard x and X 47 */ + 0, /* 28 1C Keyboard y and Y 22 */ + 0, /* 29 1D Keyboard z and Z 46 */ + 0, /* 30 1E Keyboard 1 and ! 2 */ + 0, /* 31 1F Keyboard 2 and @ 3 */ + 0, /* 32 20 Keyboard 3 and # 4 */ + 0, /* 33 21 Keyboard 4 and $ 5 */ + 0, /* 34 22 Keyboard 5 and % 6 */ + 0, /* 35 23 Keyboard 6 and ^ 7 */ + '{', /* 36 24 Keyboard 7 and & 8 */ + '[', /* 37 25 Keyboard 8 and * 9 */ + ']', /* 38 26 Keyboard 9 and ( 10 */ + '}', /* 39 27 Keyboard 0 and ) 11 */ + 0, /* 40 28 Keyboard Return (ENTER) 43 */ + 0, /* 41 29 Keyboard ESCAPE 110 */ + 0, /* 42 2A Keyboard DELETE (BS) 15 */ + 0, /* 43 2B Keyboard Tab 16 */ + 0, /* 44 2C Keyboard Spacebar 61 */ + '\\', /* 45 2D Keyboard - and (underscore) 12 */ + 0, /* 46 2E Keyboard = and + 13 */ + 0, /* 47 2F Keyboard [ and { 27 */ + '~', /* 48 30 Keyboard ] and } 28 */ + 0, /* 49 31 Keyboard \ and | 29 */ + 0, /* 50 32 Keyboard Non-US # and ~ 42 */ + 0, /* 51 33 Keyboard ; and : 40 */ + 0, /* 52 34 Keyboard ' and " 41 */ + 0, /* 53 35 Keyboard Grave Accent and Tilde 1 */ + 0, /* 54 36 Keyboard , and < 53 */ + 0, /* 55 37 Keyboard . and > 54 */ + 0, /* 56 38 Keyboard / and ? 55 */ + 0, /* 57 39 Keyboard Caps Lock 30 */ + 0, /* 58 3A Keyboard F1 112 */ + 0, /* 59 3B Keyboard F2 113 */ + 0, /* 60 3C Keyboard F3 114 */ + 0, /* 61 3D Keyboard F4 115 */ + 0, /* 62 3E Keyboard F5 116 */ + 0, /* 63 3F Keyboard F6 117 */ + 0, /* 64 40 Keyboard F7 118 */ + 0, /* 65 41 Keyboard F8 119 */ + 0, /* 66 42 Keyboard F9 120 */ + 0, /* 67 43 Keyboard F10 121 */ + 0, /* 68 44 Keyboard F11 122 */ + 0, /* 69 45 Keyboard F12 123 */ + 0, /* 70 46 Keyboard PrintScreen 124 */ + 0, /* 71 47 Keyboard Scroll Lock 125 */ + 0, /* 72 48 Keyboard Pause 126 */ + 0, /* 73 49 Keyboard Insert 75 */ + 0, /* 74 4A Keyboard Home 80 */ + 0, /* 75 4B Keyboard PageUp 85 */ + 0, /* 76 4C Keyboard Delete Forward 76 */ + 0, /* 77 4D Keyboard End 81 */ + 0, /* 78 4E Keyboard PageDown 86 */ + 0, /* 79 4F Keyboard RightArrow 89 */ + 0, /* 80 50 Keyboard LeftArrow 79 */ + 0, /* 81 51 Keyboard DownArrow 84 */ + 0, /* 82 52 Keyboard UpArrow 83 */ + 0, /* 83 53 Keypad Num Lock and Clear 90 */ + 0, /* 84 54 Keypad / 95 */ + 0, /* 85 55 Keypad * 100 */ + 0, /* 86 56 Keypad - 105 */ + 0, /* 87 57 Keypad + 106 */ + 0, /* 88 58 Keypad ENTER 108 */ + 0, /* 89 59 Keypad 1 and End 93 */ + 0, /* 90 5A Keypad 2 and Down Arrow 98 */ + 0, /* 91 5B Keypad 3 and PageDn 103 */ + 0, /* 92 5C Keypad 4 and Left Arrow 92 */ + 0, /* 93 5D Keypad 5 97 */ + 0, /* 94 5E Keypad 6 and Right Arrow 102 */ + 0, /* 95 5F Keypad 7 and Home 91 */ + 0, /* 96 60 Keypad 8 and Up Arrow 96 */ + 0, /* 97 61 Keypad 9 and PageUp 101 */ + 0, /* 98 62 Keypad 0 and Insert 99 */ + 0, /* 99 63 Keypad . and Delete 104 */ + '|' /* 100 64 Keyboard Non-US \ and | 45 */ +}; + + +/***********************************/ +/* Keycodes for 1 byte translation */ +/* - CONTROL-KEY pressed - */ +/***********************************/ +const uint8_t keycodes_ctrl[] = { + 0, /* 0 00 Reserved (no event indicated) */ + 0, /* 1 01 Keyboard ErrorRollOver */ + 0, /* 2 02 Keyboard POSTFail */ + 0, /* 3 03 Keyboard ErrorUndefined */ + 1, /* 4 04 Keyboard a and A 31 */ + 2, /* 5 05 Keyboard b and B 50 */ + 3, /* 6 06 Keyboard c and C 48 */ + 4, /* 7 07 Keyboard d and D 33 */ + 5, /* 8 08 Keyboard e and E 19 */ + 6, /* 9 09 Keyboard f and F 34 */ + 7, /* 10 0A Keyboard g and G 35 */ + 8, /* 11 0B Keyboard h and H 36 */ + 9, /* 12 0C Keyboard i and I 24 */ + 10, /* 13 0D Keyboard j and J 37 */ + 11, /* 14 0E Keyboard k and K 38 */ + 12, /* 15 0F Keyboard l and L 39 */ + 13, /* 16 10 Keyboard m and M 52 */ + 14, /* 17 11 Keyboard n and N 51 */ + 15, /* 18 12 Keyboard o and O 25 */ + 16, /* 19 13 Keyboard p and P 26 */ + 17, /* 20 14 Keyboard q and Q 17 */ + 18, /* 21 15 Keyboard r and R 20 */ + 19, /* 22 16 Keyboard s and S 32 */ + 20, /* 23 17 Keyboard t and T 21 */ + 21, /* 24 18 Keyboard u and U 23 */ + 22, /* 25 19 Keyboard v and V 49 */ + 23, /* 26 1A Keyboard w and W 18 */ + 24, /* 27 1B Keyboard x and X 47 */ + 25, /* 28 1C Keyboard y and Y 22 */ + 26, /* 29 1D Keyboard z and Z 46 */ + 0, /* 30 1E Keyboard 1 and ! 2 */ + 0, /* 31 1F Keyboard 2 and @ 3 */ + 0, /* 32 20 Keyboard 3 and # 4 */ + 0, /* 33 21 Keyboard 4 and $ 5 */ + 0, /* 34 22 Keyboard 5 and % 6 */ + 0, /* 35 23 Keyboard 6 and ^ 7 */ + 0, /* 36 24 Keyboard 7 and & 8 */ + 0, /* 37 25 Keyboard 8 and * 9 */ + 0, /* 38 26 Keyboard 9 and ( 10 */ + 0, /* 39 27 Keyboard 0 and ) 11 */ + 0, /* 40 28 Keyboard Return (ENTER) 43 */ + 0, /* 41 29 Keyboard ESCAPE 110 */ + 0, /* 42 2A Keyboard DELETE (BS) 15 */ + 0, /* 43 2B Keyboard Tab 16 */ + 0, /* 44 2C Keyboard Spacebar 61 */ + 0, /* 45 2D Keyboard - and (underscore) 12 */ + 0, /* 46 2E Keyboard = and + 13 */ + 0, /* 47 2F Keyboard [ and { 27 */ + 0, /* 48 30 Keyboard ] and } 28 */ + 0, /* 49 31 Keyboard \ and | 29 */ + 0, /* 50 32 Keyboard Non-US # and ~ 42 */ + 0, /* 51 33 Keyboard ; and : 40 */ + 0, /* 52 34 Keyboard ' and " 41 */ + 0, /* 53 35 Keyboard Grave Accent and Tilde 1 */ + 0, /* 54 36 Keyboard , and < 53 */ + 0, /* 55 37 Keyboard . and > 54 */ + 0, /* 56 38 Keyboard / and ? 55 */ + 0, /* 57 39 Keyboard Caps Lock 30 */ + 0, /* 58 3A Keyboard F1 112 */ + 0, /* 59 3B Keyboard F2 113 */ + 0, /* 60 3C Keyboard F3 114 */ + 0, /* 61 3D Keyboard F4 115 */ + 0, /* 62 3E Keyboard F5 116 */ + 0, /* 63 3F Keyboard F6 117 */ + 0, /* 64 40 Keyboard F7 118 */ + 0, /* 65 41 Keyboard F8 119 */ + 0, /* 66 42 Keyboard F9 120 */ + 0, /* 67 43 Keyboard F10 121 */ + 0, /* 68 44 Keyboard F11 122 */ + 0, /* 69 45 Keyboard F12 123 */ + 0, /* 70 46 Keyboard PrintScreen 124 */ + 0, /* 71 47 Keyboard Scroll Lock 125 */ + 0, /* 72 48 Keyboard Pause 126 */ + 0, /* 73 49 Keyboard Insert 75 */ + 0, /* 74 4A Keyboard Home 80 */ + 0, /* 75 4B Keyboard PageUp 85 */ + 0, /* 76 4C Keyboard Delete Forward 76 */ + 0, /* 77 4D Keyboard End 81 */ + 0, /* 78 4E Keyboard PageDown 86 */ + 0, /* 79 4F Keyboard RightArrow 89 */ + 0, /* 80 50 Keyboard LeftArrow 79 */ + 0, /* 81 51 Keyboard DownArrow 84 */ + 0, /* 82 52 Keyboard UpArrow 83 */ + 0, /* 83 53 Keypad Num Lock and Clear 90 */ + 0, /* 84 54 Keypad / 95 */ + 0, /* 85 55 Keypad * 100 */ + 0, /* 86 56 Keypad - 105 */ + 0, /* 87 57 Keypad + 106 */ + 0, /* 88 58 Keypad ENTER 108 */ + 0, /* 89 59 Keypad 1 and End 93 */ + 0, /* 90 5A Keypad 2 and Down Arrow 98 */ + 0, /* 91 5B Keypad 3 and PageDn 103 */ + 0, /* 92 5C Keypad 4 and Left Arrow 92 */ + 0, /* 93 5D Keypad 5 97 */ + 0, /* 94 5E Keypad 6 and Right Arrow 102 */ + 0, /* 95 5F Keypad 7 and Home 91 */ + 0, /* 96 60 Keypad 8 and Up Arrow 96 */ + 0, /* 97 61 Keypad 9 and PageUp 101 */ + 0, /* 98 62 Keypad 0 and Insert 99 */ + 0, /* 99 63 Keypad . and Delete 104 */ + 0 /* 100 64 Keyboard Non-US \ and | 45 */ +}; diff --git a/qemu/roms/SLOF/lib/libusb/usb-key.h b/qemu/roms/SLOF/lib/libusb/usb-key.h new file mode 100644 index 000000000..1871a9956 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-key.h @@ -0,0 +1,42 @@ +#ifndef _USB_KEYB_H +#define _USB_KEYB_H + +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#define BIT_0 1 +#define BIT_1 (BIT_0 << 1) +#define BIT_2 (BIT_0 << 2) +#define BIT_3 (BIT_0 << 3) +#define BIT_4 (BIT_0 << 4) +#define BIT_5 (BIT_0 << 5) +#define BIT_6 (BIT_0 << 6) +#define BIT_7 (BIT_0 << 7) + +/* bits from modifier input */ +#define MODIFIER_CTRL (BIT_0 | BIT_4) +#define MODIFIER_SHIFT (BIT_1 | BIT_5) +#define MODIFIER_ALT (BIT_2 | BIT_6) +#define MODIFIER_GUI (BIT_3 | BIT_7) +#define MODIFIER_ALT_GR BIT_6 + +/* bits representing Keyboard-LEDs */ +#define LED_NUM_LOCK BIT_0 +#define LED_CAPS_LOCK BIT_1 +#define LED_SCROLL_LOCK BIT_2 + +extern const uint8_t keycodes_std_US[]; +extern const uint8_t keycodes_shift_US[]; +extern const uint8_t keycodes_alt_GR[]; +extern const uint8_t keycodes_ctrl[]; + +#endif diff --git a/qemu/roms/SLOF/lib/libusb/usb-ohci.c b/qemu/roms/SLOF/lib/libusb/usb-ohci.c new file mode 100644 index 000000000..0e8400481 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-ohci.c @@ -0,0 +1,1055 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include <byteorder.h> +#include "usb.h" +#include "usb-core.h" +#include "usb-ohci.h" + +#undef OHCI_DEBUG +//#define OHCI_DEBUG +#ifdef OHCI_DEBUG +#define dprintf(_x ...) do { printf(_x); } while(0) +#else +#define dprintf(_x ...) +#endif + +#undef OHCI_DEBUG_PACKET +//#define OHCI_DEBUG_PACKET +#ifdef OHCI_DEBUG_PACKET +#define dpprintf(_x ...) do { printf(_x); } while(0) +#else +#define dpprintf(_x ...) +#endif + + +/* + * Dump OHCI register + * + * @param - ohci_hcd + * @return - + */ +static void ohci_dump_regs(struct ohci_regs *regs) +{ + dprintf("\n - HcRevision %08X", read_reg32(®s->rev)); + dprintf(" - HcControl %08X", read_reg32(®s->control)); + dprintf("\n - HcCommandStatus %08X", read_reg32(®s->cmd_status)); + dprintf(" - HcInterruptStatus %08X", read_reg32(®s->intr_status)); + dprintf("\n - HcInterruptEnable %08X", read_reg32(®s->intr_enable)); + dprintf(" - HcInterruptDisable %08X", read_reg32(®s->intr_disable)); + dprintf("\n - HcHCCA %08X", read_reg32(®s->hcca)); + dprintf(" - HcPeriodCurrentED %08X", read_reg32(®s->period_curr_ed)); + dprintf("\n - HcControlHeadED %08X", read_reg32(®s->cntl_head_ed)); + dprintf(" - HcControlCurrentED %08X", read_reg32(®s->cntl_curr_ed)); + dprintf("\n - HcBulkHeadED %08X", read_reg32(®s->bulk_head_ed)); + dprintf(" - HcBulkCurrentED %08X", read_reg32(®s->bulk_curr_ed)); + dprintf("\n - HcDoneHead %08X", read_reg32(®s->done_head)); + dprintf(" - HcFmInterval %08X", read_reg32(®s->fm_interval)); + dprintf("\n - HcFmRemaining %08X", read_reg32(®s->fm_remaining)); + dprintf(" - HcFmNumber %08X", read_reg32(®s->fm_num)); + dprintf("\n - HcPeriodicStart %08X", read_reg32(®s->period_start)); + dprintf(" - HcLSThreshold %08X", read_reg32(®s->ls_threshold)); + dprintf("\n - HcRhDescriptorA %08X", read_reg32(®s->rh_desc_a)); + dprintf(" - HcRhDescriptorB %08X", read_reg32(®s->rh_desc_b)); + dprintf("\n - HcRhStatus %08X", read_reg32(®s->rh_status)); + dprintf("\n"); +} + +/* + * OHCI Spec 5.1.1 + * OHCI Spec 7.4 Root Hub Partition + */ +static int ohci_hcd_reset(struct ohci_regs *regs) +{ + uint32_t time; + + /* USBRESET - 1sec */ + write_reg32(®s->control, 0); + SLOF_msleep(100); + + write_reg32(®s->intr_disable, ~0); + write_reg32(®s->cmd_status, OHCI_CMD_STATUS_HCR); + mb(); + + time = 30; /* wait for not more than 30usec */ + while ((read_reg32(®s->cmd_status) & OHCI_CMD_STATUS_HCR) != 0) { + time--; + if (!time) { + printf(" ** HCD Reset failed..."); + return -1; + } + SLOF_usleep(1); + } + return 0; +} + +static int ohci_hcd_init(struct ohci_hcd *ohcd) +{ + struct ohci_regs *regs; + struct ohci_ed *ed; + long ed_phys = 0; + unsigned int i; + uint32_t oldrwc; + struct usb_dev *rhdev = NULL; + struct usb_ep_descr ep; + uint32_t reg; + + if (!ohcd) + return -1; + + regs = ohcd->regs; + rhdev = &ohcd->rhdev; + dprintf("%s: HCCA memory %p\n", __func__, ohcd->hcca); + dprintf("%s: OHCI Regs %p\n", __func__, regs); + + rhdev->hcidev = ohcd->hcidev; + ep.bmAttributes = USB_EP_TYPE_INTR; + ep.wMaxPacketSize = 8; + rhdev->intr = usb_get_pipe(rhdev, &ep, NULL, 0); + if (!rhdev->intr) { + printf("usb-ohci: oops could not allocate intr_pipe\n"); + return -1; + } + + /* + * OHCI Spec 4.4: Host Controller Communications Area + */ + ed = ohci_pipe_get_ed(rhdev->intr); + ed_phys = ohci_pipe_get_ed_phys(rhdev->intr); + memset(ohcd->hcca, 0, HCCA_SIZE); + memset(ed, 0, sizeof(struct ohci_ed)); + ed->attr = cpu_to_le32(EDA_SKIP); + for (i = 0; i < HCCA_INTR_NUM; i++) + ohcd->hcca->intr_table[i] = cpu_to_le32(ed_phys); + + write_reg32(®s->hcca, ohcd->hcca_phys); + write_reg32(®s->cntl_head_ed, 0); + write_reg32(®s->bulk_head_ed, 0); + + /* OHCI Spec 7.1.2 HcControl Register */ + oldrwc = read_reg32(®s->control) & OHCI_CTRL_RWC; + write_reg32(®s->control, (OHCI_CTRL_CBSR | OHCI_CTRL_CLE | + OHCI_CTRL_BLE | OHCI_CTRL_PLE | + OHCI_USB_OPER | oldrwc)); + SLOF_msleep(100); + /* + * For JS20/21 need to rewrite it after setting it to + * operational state + */ + write_reg32(®s->fm_interval, FRAME_INTERVAL); + write_reg32(®s->period_start, PERIODIC_START); + reg = read_reg32(®s->rh_desc_a); + reg &= ~( RHDA_PSM_INDIVIDUAL | RHDA_OCPM_PERPORT ); + reg |= RHDA_NPS_ENABLE; + write_reg32(®s->rh_desc_a, reg); + write_reg32(®s->rh_desc_b, 0); + mb(); + SLOF_msleep(100); + ohci_dump_regs(regs); + return 0; +} + +/* + * OHCI Spec 7.4 Root Hub Partition + */ +static void ohci_hub_check_ports(struct ohci_hcd *ohcd) +{ + struct ohci_regs *regs; + struct usb_dev *dev; + unsigned int ports, i, port_status, port_clear = 0; + + regs = ohcd->regs; + ports = read_reg32(®s->rh_desc_a) & RHDA_NDP; + write_reg32(®s->rh_status, RH_STATUS_LPSC); + SLOF_msleep(100); + dprintf("usb-ohci: ports connected %d\n", ports); + for (i = 0; i < ports; i++) { + dprintf("usb-ohci: ports scanning %d\n", i); + port_status = read_reg32(®s->rh_ps[i]); + if (port_status & RH_PS_CSC) { + if (port_status & RH_PS_CCS) { + write_reg32(®s->rh_ps[i], RH_PS_PRS); + mb(); + port_clear |= RH_PS_CSC; + dprintf("Start enumerating device\n"); + SLOF_msleep(100); + } else + printf("Start removing device\n"); + } + port_status = read_reg32(®s->rh_ps[i]); + if (port_status & RH_PS_PRSC) { + port_clear |= RH_PS_PRSC; + dev = usb_devpool_get(); + dprintf("usb-ohci: Device reset, setting up %p\n", dev); + dev->hcidev = ohcd->hcidev; + if (!setup_new_device(dev, i)) + printf("usb-ohci: unable to setup device on port %d\n", i); + } + if (port_status & RH_PS_PESC) { + port_clear |= RH_PS_PESC; + if (port_status & RH_PS_PES) + dprintf("enabled\n"); + else + dprintf("disabled\n"); + } + if (port_status & RH_PS_PSSC) { + port_clear |= RH_PS_PESC; + dprintf("suspended\n"); + } + port_clear &= 0xFFFF0000; + if (port_clear) + write_reg32(®s->rh_ps[i], port_clear); + } +} + +static inline struct ohci_ed *ohci_pipe_get_ed(struct usb_pipe *pipe) +{ + struct ohci_pipe *opipe; + opipe = container_of(pipe, struct ohci_pipe, pipe); + dpprintf("%s: ed is %p\n", __func__, &opipe->ed); + return &opipe->ed; +} + +static inline long ohci_pipe_get_ed_phys(struct usb_pipe *pipe) +{ + struct ohci_pipe *opipe; + opipe = container_of(pipe, struct ohci_pipe, pipe); + dpprintf("%s: ed_phys is %x\n", __func__, opipe->ed_phys); + return opipe->ed_phys; +} + +static inline struct ohci_pipe *ohci_pipe_get_opipe(struct usb_pipe *pipe) +{ + struct ohci_pipe *opipe; + opipe = container_of(pipe, struct ohci_pipe, pipe); + dpprintf("%s: opipe is %p\n", __func__, opipe); + return opipe; +} + +static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd) +{ + struct ohci_pipe *opipe, *curr, *prev; + long opipe_phys = 0; + unsigned int i, count; +#ifdef OHCI_DEBUG_PACKET + struct usb_pipe *pipe; +#endif + + dprintf("usb-ohci: %s enter\n", __func__); + count = OHCI_PIPE_POOL_SIZE/sizeof(*opipe); + ohcd->pool = opipe = SLOF_dma_alloc(OHCI_PIPE_POOL_SIZE); + if (!opipe) + return false; + + ohcd->pool_phys = opipe_phys = SLOF_dma_map_in(opipe, OHCI_PIPE_POOL_SIZE, true); + dprintf("usb-ohci: %s opipe %x, opipe_phys %x size %d count %d\n", + __func__, opipe, opipe_phys, sizeof(*opipe), count); + /* Although an array, link them*/ + for (i = 0, curr = opipe, prev = NULL; i < count; i++, curr++) { + if (prev) + prev->pipe.next = &curr->pipe; + curr->pipe.next = NULL; + prev = curr; + + if (((uint64_t)&curr->ed) % 16) + printf("usb-ohci: Warning ED not aligned to 16byte boundary"); + curr->ed_phys = opipe_phys + (curr - opipe) * sizeof(*curr) + + offset_of(struct ohci_pipe, ed); + } + + if (!ohcd->freelist) + ohcd->freelist = &opipe->pipe; + else + ohcd->end->next = &opipe->pipe; + ohcd->end = &prev->pipe; + +#ifdef OHCI_DEBUG_PACKET + for (i = 0, pipe = ohcd->freelist; pipe; pipe = pipe->next) + dprintf("usb-ohci: %d: pipe cur %p ed %p ed_phys %x\n", + i++, pipe, ohci_pipe_get_ed(pipe), + ohci_pipe_get_ed_phys(pipe)); +#endif + + dprintf("usb-ohci: %s exit\n", __func__); + return true; +} + +static void ohci_init(struct usb_hcd_dev *hcidev) +{ + struct ohci_hcd *ohcd; + + printf(" OHCI: initializing\n"); + dprintf("%s: device base address %p\n", __func__, hcidev->base); + + ohcd = SLOF_alloc_mem(sizeof(struct ohci_hcd)); + if (!ohcd) { + printf("usb-ohci: Unable to allocate memory\n"); + goto out; + } + + hcidev->nextaddr = 1; + hcidev->priv = ohcd; + memset(ohcd, 0, sizeof(*ohcd)); + ohcd->hcidev = hcidev; + ohcd->freelist = NULL; + ohcd->end = NULL; + ohcd->regs = (struct ohci_regs *)(hcidev->base); + ohcd->hcca = SLOF_dma_alloc(sizeof(struct ohci_hcca)); + if (!ohcd->hcca || PTR_U32(ohcd->hcca) & HCCA_ALIGN) { + printf("usb-ohci: Unable to allocate/unaligned HCCA memory %p\n", + ohcd->hcca); + goto out_free_hcd; + } + ohcd->hcca_phys = SLOF_dma_map_in(ohcd->hcca, + sizeof(struct ohci_hcca), true); + dprintf("usb-ohci: HCCA memory %p HCCA-dev memory %08lx\n", + ohcd->hcca, ohcd->hcca_phys); + + ohci_hcd_reset(ohcd->regs); + ohci_hcd_init(ohcd); + ohci_hub_check_ports(ohcd); + return; + +out_free_hcd: + SLOF_dma_free(ohcd->hcca, sizeof(struct ohci_hcca)); + SLOF_free_mem(ohcd, sizeof(struct ohci_hcd)); +out: + return; +} + +static void ohci_exit(struct usb_hcd_dev *hcidev) +{ + struct ohci_hcd *ohcd = NULL; + + dprintf("%s: enter \n", __func__); + if (!hcidev && !hcidev->priv) + return; + + ohcd = hcidev->priv; + write_reg32(&ohcd->regs->control, (OHCI_CTRL_CBSR | OHCI_USB_SUSPEND)); + SLOF_msleep(20); + write_reg32(&ohcd->regs->hcca, cpu_to_le32(0)); + + if (ohcd->pool) { + SLOF_dma_map_out(ohcd->pool_phys, ohcd->pool, OHCI_PIPE_POOL_SIZE); + SLOF_dma_free(ohcd->pool, OHCI_PIPE_POOL_SIZE); + } + if (ohcd->hcca) { + SLOF_dma_map_out(ohcd->hcca_phys, ohcd->hcca, sizeof(struct ohci_hcca)); + SLOF_dma_free(ohcd->hcca, sizeof(struct ohci_hcca)); + } + SLOF_free_mem(ohcd, sizeof(struct ohci_hcd)); + return; +} + +static void ohci_detect(void) +{ + +} + +static void ohci_disconnect(void) +{ + +} + +#define OHCI_CTRL_TDS 3 + +static void ohci_fill_td(struct ohci_td *td, long next, + long req, size_t size, unsigned int attr) +{ + if (size && req) { + td->cbp = cpu_to_le32(req); + td->be = cpu_to_le32(req + size - 1); + } else { + td->cbp = 0; + td->be = 0; + } + td->attr = cpu_to_le32(attr); + td->next_td = cpu_to_le32(next); + + dpprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n", __func__, + le32_to_cpu(td->cbp), le32_to_cpu(td->attr), + le32_to_cpu(td->next_td), le32_to_cpu(td->be)); +} + +static void ohci_fill_ed(struct ohci_ed *ed, long headp, long tailp, + unsigned int attr, long next_ed) +{ + ed->attr = cpu_to_le32(attr); + ed->headp = cpu_to_le32(headp) | (ed->headp & ~EDA_HEADP_MASK_LE); + ed->tailp = cpu_to_le32(tailp); + ed->next_ed = cpu_to_le32(next_ed); + dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__, + le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp), + le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr)); + +} + +static long ohci_get_td_phys(struct ohci_td *curr, struct ohci_td *start, long td_phys) +{ + dpprintf("position %d\n", curr - start); + return td_phys + (curr - start) * sizeof(*start); +} + +static long ohci_get_td_virt(struct ohci_td *curr, struct ohci_td *start, long td_virt, long total_count) +{ + dpprintf("position %d\n", curr - start); + if ( (curr - start) >= total_count) { + /* busted position, should ignore this */ + return 0; + } + return td_virt + (curr - start) * sizeof(*start); +} + +/* OHCI Spec: 4.4.2.3 HccaDoneHead*/ +static int ohci_process_done_head(struct ohci_hcd *ohcd, + struct ohci_td *td_start, + long __td_start_phys, long total_count) +{ + struct ohci_hcca *hcca; + struct ohci_td *td_phys = NULL, *td_start_phys; + struct ohci_td *td, *prev_td = NULL; + uint32_t reg = 0, time = 0; + int ret = true; + long count; + + count = total_count; + td_start_phys = (struct ohci_td *) __td_start_phys; + hcca = ohcd->hcca; + time = SLOF_GetTimer() + USB_TIMEOUT; + dpprintf("Claiming %ld\n", count); + +again: + mb(); + /* Check if there is an interrupt */ + reg = read_reg32(&ohcd->regs->intr_status); + while(!(reg & OHCI_INTR_STATUS_WD)) + { + if (time < SLOF_GetTimer()) { + printf("Timed out waiting for interrupt %x\n", reg); + return false; + } + mb(); + reg = read_reg32(&ohcd->regs->intr_status); + } + + /* Interrupt is there, read from done_head pointer */ + td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(hcca->done_head); + if (!td_phys) { + dprintf("Again td_phys null %ld\n"); + goto again; + } + hcca->done_head = 0; + mb(); + + while (td_phys && (count > 0)) { + td = (struct ohci_td *)(uint64_t) ohci_get_td_virt(td_phys, + td_start_phys, + PTR_U32(td_start), + total_count); + + if (!td) { + printf("USB: Error TD null %p\n", td_phys); + break; + } + count--; + dprintf("Claimed %p(%p) td_start %p count %ld\n", + td, td_phys, td_start_phys, count); + dpprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n", + __func__, + le32_to_cpu(td->cbp), le32_to_cpu(td->attr), + le32_to_cpu(td->next_td), le32_to_cpu(td->be)); + mb(); + reg = (le32_to_cpu(td->attr) & TDA_CC) >> 28; + if (reg) { + dprintf("%s: cbp %08X attr %08X next_td %08X be %08X\n", + __func__, + le32_to_cpu(td->cbp), le32_to_cpu(td->attr), + le32_to_cpu(td->next_td), le32_to_cpu(td->be)); + printf("USB: Error %s %p\n", tda_cc_error[reg], td); + if (reg > 3) /* Return negative error code */ + ret = reg * -1; + } + prev_td = td; + td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(td->next_td); + prev_td->attr |= cpu_to_le32(TDA_DONE); + prev_td->next_td = 0; + mb(); + } + /* clear the WD interrupt status */ + write_reg32(&ohcd->regs->intr_status, OHCI_INTR_STATUS_WD); + mb(); + read_reg32(&ohcd->regs->intr_status); + + if (count > 0) { + dpprintf("Pending count %d\n", count); + goto again; + } + dprintf("TD claims done\n"); + return ret; +} + +/* + * OHCI Spec: + * 4.2 Endpoint Descriptor + * 4.3.1 General Transfer Descriptor + * 5.2.8 Transfer Descriptor Queues + */ +static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data) +{ + struct ohci_ed *ed; + struct ohci_td *tds, *td, *td_phys; + struct ohci_regs *regs; + struct ohci_hcd *ohcd; + uint32_t datalen; + uint32_t dir, attr = 0; + uint32_t time; + int ret = true, i; + long req_phys = 0, data_phys = 0, td_next = 0, td_count = 0; + unsigned char *dbuf; + + datalen = le16_to_cpu(req->wLength); + dir = (req->bmRequestType & REQT_DIR_IN) ? 1 : 0; + + dprintf("usb-ohci: %s len %d DIR_IN %d\n", __func__, datalen, dir); + + tds = td = (struct ohci_td *) SLOF_dma_alloc(sizeof(*td) * OHCI_CTRL_TDS); + td_phys = (struct ohci_td *) SLOF_dma_map_in(td, sizeof(*td) * OHCI_CTRL_TDS, true); + memset(td, 0, sizeof(*td) * OHCI_CTRL_TDS); + + req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true); + attr = TDA_DP_SETUP | TDA_CC | TDA_TOGGLE_DATA0; + td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys)); + ohci_fill_td(td, td_next, req_phys, sizeof(*req), attr); + td++; td_count++; + + if (datalen) { + data_phys = SLOF_dma_map_in(data, datalen, true); + attr = 0; + attr = (dir ? TDA_DP_IN : TDA_DP_OUT) | TDA_TOGGLE_DATA1 | TDA_CC; + td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys)); + ohci_fill_td(td, td_next, data_phys, datalen, attr); + td++; td_count++; + } + + attr = 0; + attr = (dir ? TDA_DP_OUT : TDA_DP_IN) | TDA_CC | TDA_TOGGLE_DATA1; + td_next = ohci_get_td_phys(td + 1, tds, PTR_U32(td_phys)); + ohci_fill_td(td, 0, 0, 0, attr); + td_count++; + + ed = ohci_pipe_get_ed(pipe); + attr = 0; + attr = EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) | EDA_SKIP; + ohci_fill_ed(ed, PTR_U32(td_phys), td_next, attr, 0); + ed->tailp = 0; /* HACK */ + dprintf("usb-ohci: %s - td_start %x td_end %x req %x\n", __func__, + td_phys, td_next, req_phys); + mb(); + ed->attr &= cpu_to_le32(~EDA_SKIP); + + ohcd = pipe->dev->hcidev->priv; + regs = ohcd->regs; + write_reg32(®s->cntl_head_ed, ohci_pipe_get_ed_phys(pipe)); + mb(); + write_reg32(®s->cmd_status, OHCI_CMD_STATUS_CLF); + + time = SLOF_GetTimer() + USB_TIMEOUT; + while ((time > SLOF_GetTimer()) && + ((ed->headp & EDA_HEADP_MASK_LE) != ed->tailp)) + cpu_relax(); + + if ((ed->headp & EDA_HEADP_MASK_LE) == ed->tailp) { + dprintf("%s: packet sent\n", __func__); +#ifdef OHCI_DEBUG_PACKET + dpprintf("Request: "); + dbuf = (unsigned char *)req; + for(i = 0; i < 8; i++) + printf("%02X ", dbuf[i]); + dpprintf("\n"); + if (datalen) { + dbuf = (unsigned char *)data; + dpprintf("Reply: "); + for(i = 0; i < datalen; i++) + printf("%02X ", dbuf[i]); + dpprintf("\n"); + } +#endif + } + else { + printf("%s: timed out - failed\n", __func__); + dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", + __func__, + le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp), + le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr)); + printf("Request: "); + dbuf = (unsigned char *)req; + for(i = 0; i < 8; i++) + printf("%02X ", dbuf[i]); + printf("\n"); + } + ret = ohci_process_done_head(ohcd, tds, (long)td_phys, td_count); + mb(); + ed->attr |= cpu_to_le32(EDA_SKIP); + mb(); + write_reg32(®s->cntl_head_ed, 0); + write_reg32(®s->cntl_curr_ed, 0); + + SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req)); + if (datalen) + SLOF_dma_map_out(data_phys, data, datalen); + SLOF_dma_map_out(PTR_U32(td_phys), tds, sizeof(*td) * OHCI_CTRL_TDS); + SLOF_dma_free(tds, sizeof(*td) * OHCI_CTRL_TDS); + return (ret > 0) ? true : false; +} + +static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr, + void *td_phys_ptr, void *data_phys, int datalen) +{ + struct ohci_ed *ed; + struct ohci_td *td, *tds; + struct ohci_regs *regs; + struct ohci_hcd *ohcd; + long td_phys = 0, td_next, ed_phys, ptr, td_count = 0; + uint32_t dir, attr = 0, count; + size_t len, packet_len; + uint32_t time; + int ret = true; + + if (pipe->type != USB_EP_TYPE_BULK) { + printf("usb-ohci: Not a bulk pipe.\n"); + ret = false; + goto end; + } + + dir = (pipe->dir == USB_PIPE_OUT) ? 0 : 1; + count = datalen / OHCI_MAX_BULK_SIZE; + if (count > OHCI_MAX_TDS) { + printf("usb-ohci: buffer size not supported - %d\n", datalen); + ret = false; + goto end; + } + + td = tds = (struct ohci_td *) td_ptr; + td_phys = (long)td_phys_ptr; + dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %p\n", + __func__, pipe, data_phys, datalen, dir, td, td_phys); + + if (!tds) { + printf("%s: tds NULL recieved\n", __func__); + ret = false; + goto end; + } + memset(td, 0, sizeof(*td) * OHCI_MAX_TDS); + + len = datalen; + ptr = (long)data_phys; + attr = 0; + attr = (dir ? TDA_DP_IN : TDA_DP_OUT) | TDA_CC | TDA_ROUNDING; + while (len) { + packet_len = (OHCI_MAX_BULK_SIZE < len)? OHCI_MAX_BULK_SIZE : len; + td_next = ohci_get_td_phys((td + 1), tds, td_phys); + ohci_fill_td(td, td_next, ptr, packet_len, attr); + ptr = ptr + packet_len; + len = len - packet_len; + td++; td_count++; + } + + ed = ohci_pipe_get_ed(pipe); + attr = 0; + dir = pipe->dir ? EDA_DIR_IN : EDA_DIR_OUT; + attr = dir | EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) + | EDA_SKIP | pipe->dev->speed | EDA_EP(pipe->epno); + td_next = ohci_get_td_phys(td, tds, td_phys); + ohci_fill_ed(ed, td_phys, td_next, attr, 0); + dprintf("usb-ohci: %s - tds %p td %p\n", __func__, td_phys, td_next); + mb(); + ed->attr &= cpu_to_le32(~EDA_SKIP); + + ohcd = pipe->dev->hcidev->priv; + regs = ohcd->regs; + ed_phys = ohci_pipe_get_ed_phys(pipe); + write_reg32(®s->bulk_head_ed, ed_phys); + mb(); + write_reg32(®s->cmd_status, 0x4); + + time = SLOF_GetTimer() + USB_TIMEOUT; + while ((time > SLOF_GetTimer()) && + ((ed->headp & EDA_HEADP_MASK_LE) != ed->tailp)) + cpu_relax(); + + if ((ed->headp & EDA_HEADP_MASK_LE) == ed->tailp) + dprintf("%s: packet sent\n", __func__); + else { + dpprintf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__, + le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp), + le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr)); + } + mb(); + ret = ohci_process_done_head(ohcd, tds, td_phys, td_count); + mb(); + ed->attr |= cpu_to_le32(EDA_SKIP); + mb(); + write_reg32(®s->bulk_head_ed, 0); + write_reg32(®s->bulk_curr_ed, 0); + + if (le32_to_cpu(ed->headp) & EDA_HEADP_HALTED) { + printf("ED Halted\n"); + printf("%s: headp %08X tailp %08X next_td %08X attr %08X\n", __func__, + le32_to_cpu(ed->headp), le32_to_cpu(ed->tailp), + le32_to_cpu(ed->next_ed), le32_to_cpu(ed->attr)); + ed->headp &= ~cpu_to_le32(EDA_HEADP_HALTED); + mb(); + if (ret == USB_STALL) /* Call reset recovery */ + usb_msc_resetrecovery(pipe->dev); + } + +end: + return (ret > 0) ? true : false; +} + +/* Populate the hcca intr region with periodic intr */ +static int ohci_get_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd, + char *buf, size_t buflen) +{ + struct ohci_hcca *hcca; + struct ohci_pipe *opipe; + struct ohci_ed *ed; + struct usb_dev *dev; + struct ohci_td *tds, *td; + int32_t count = 0, i; + uint8_t *ptr; + uint16_t mps; + long ed_phys, td_phys, td_next, buf_phys; + + if (!pipe || !ohcd) + return false; + + hcca = ohcd->hcca; + dev = pipe->dev; + if (dev->class != DEV_HID_KEYB && dev->class != DEV_HUB) + return false; + + opipe = ohci_pipe_get_opipe(pipe); + ed = &(opipe->ed); + ed_phys = opipe->ed_phys; + mps = pipe->mps; + ed->attr = cpu_to_le32(EDA_DIR_IN | + EDA_FADDR(dev->addr) | + dev->speed | + EDA_MPS(pipe->mps) | + EDA_SKIP | + EDA_EP(pipe->epno)); + dprintf("%s: pipe %p ed %p dev %p opipe %p\n", __func__, + pipe, ed, dev, opipe); + count = (buflen/mps) + 1; + tds = td = SLOF_dma_alloc(sizeof(*td) * count); + if (!tds) { + printf("%s: alloc failed\n", __func__); + return false; + } + td_phys = SLOF_dma_map_in(td, sizeof(*td) * count, false); + + memset(tds, 0, sizeof(*tds) * count); + memset(buf, 0, buflen); + buf_phys = SLOF_dma_map_in(buf, buflen, false); + opipe->td = td; + opipe->td_phys = td_phys; + opipe->count = count; + opipe->buf = buf; + opipe->buflen = buflen; + opipe->buf_phys = buf_phys; + + ptr = (uint8_t *)buf_phys; + for (i = 0; i < count - 1; i++, ptr += mps) { + td = &tds[i]; + td_next = ohci_get_td_phys(td + 1, &tds[0], td_phys); + td->cbp = cpu_to_le32(PTR_U32(ptr)); + td->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC); + td->next_td = cpu_to_le32(td_next); + td->be = cpu_to_le32(PTR_U32(ptr) + mps - 1); + dprintf("td %x td++ %x ptr %x be %x\n", + td, le32_to_cpu(td->next_td), + ptr, (PTR_U32(ptr) + mps - 1)); + } + td->next_td = 0; + td_next = ohci_get_td_phys(td, &tds[0], td_phys); + ed->headp = cpu_to_le32(td_phys); + ed->tailp = cpu_to_le32(td_next); + + dprintf("%s: head %08X tail %08X, count %d, mps %d\n", __func__, + le32_to_cpu(ed->headp), + le32_to_cpu(ed->tailp), + count, mps); + ed->next_ed = 0; + + + switch (dev->class) { + case DEV_HID_KEYB: + dprintf("%s: Keyboard class %d\n", __func__, dev->class); + hcca->intr_table[0] = cpu_to_le32(ed_phys); + hcca->intr_table[8] = cpu_to_le32(ed_phys); + hcca->intr_table[16] = cpu_to_le32(ed_phys); + hcca->intr_table[24] = cpu_to_le32(ed_phys); + ed->attr &= cpu_to_le32(~EDA_SKIP); + break; + + case DEV_HUB: + dprintf("%s: HUB class %x\n", __func__, dev->class); + hcca->intr_table[1] = cpu_to_le32(ed_phys); + ed->attr &= cpu_to_le32(~EDA_SKIP); + break; + + default: + dprintf("%s: unhandled class %d\n", __func__, dev->class); + } + return true; +} + +static int ohci_put_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd) +{ + struct ohci_hcca *hcca; + struct ohci_pipe *opipe; + struct ohci_ed *ed; + struct usb_dev *dev; + struct ohci_td *td; + long ed_phys; + + if (!pipe || !ohcd) + return false; + + hcca = ohcd->hcca; + dev = pipe->dev; + + if (dev->class != DEV_HID_KEYB && dev->class != DEV_HUB) + return false; + + opipe = ohci_pipe_get_opipe(pipe); + ed = &(opipe->ed); + ed_phys = opipe->ed_phys; + dprintf("%s: td %p td_phys %08lx buf %p buf_phys %08lx\n", __func__, + opipe->td, opipe->td_phys, opipe->buf, opipe->buf_phys); + + ed->attr |= cpu_to_le32(EDA_SKIP); + mb(); + ed->headp = 0; + ed->tailp = 0; + ed->next_ed = 0; + SLOF_dma_map_out(opipe->buf_phys, opipe->buf, opipe->buflen); + SLOF_dma_map_out(opipe->td_phys, opipe->td, sizeof(*td) * opipe->count); + SLOF_dma_free(opipe->td, sizeof(*td) * opipe->count); + + switch (dev->class) { + case DEV_HID_KEYB: + dprintf("%s: Keyboard class %d\n", __func__, dev->class); + hcca->intr_table[0] = cpu_to_le32(ed_phys); + hcca->intr_table[8] = cpu_to_le32(ed_phys); + hcca->intr_table[16] = cpu_to_le32(ed_phys); + hcca->intr_table[24] = cpu_to_le32(ed_phys); + break; + + case DEV_HUB: + dprintf("%s: HUB class %d\n", __func__, dev->class); + hcca->intr_table[1] = cpu_to_le32(ed_phys); + break; + + default: + dprintf("%s: unhandled class %d\n", __func__, dev->class); + } + return true; +} + +static int ohci_init_bulk_ed(struct usb_dev *dev, struct usb_pipe *pipe) +{ + struct ohci_pipe *opipe; + struct ohci_ed *ed; + uint32_t dir; + + if (!pipe || !dev) + return false; + + opipe = ohci_pipe_get_opipe(pipe); + ed = &(opipe->ed); + dir = pipe->dir ? EDA_DIR_IN : EDA_DIR_OUT; + + ed->attr = cpu_to_le32(dir | + EDA_FADDR(dev->addr) | + dev->speed | + EDA_MPS(pipe->mps) | + EDA_SKIP | + EDA_EP(pipe->epno)); + + dprintf("%s: pipe %p attr %x\n", __func__, pipe, + le32_to_cpu(ed->attr)); + return true; +} + +static struct usb_pipe *ohci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, + char *buf, size_t buflen) +{ + struct ohci_hcd *ohcd; + struct usb_pipe *new = NULL; + + dprintf("usb-ohci: %s enter %p\n", __func__, dev); + if (!dev) + return NULL; + + ohcd = (struct ohci_hcd *)dev->hcidev->priv; + if (!ohcd->freelist) { + dprintf("usb-ohci: %s allocating pool\n", __func__); + if (!ohci_alloc_pipe_pool(ohcd)) + return NULL; + } + + new = ohcd->freelist; + ohcd->freelist = ohcd->freelist->next; + if (!ohcd->freelist) + ohcd->end = NULL; + + memset(new, 0, sizeof(*new)); + new->dev = dev; + new->next = NULL; + new->type = ep->bmAttributes & USB_EP_TYPE_MASK; + new->speed = dev->speed; + new->mps = le16_to_cpu(ep->wMaxPacketSize); + new->epno = ep->bEndpointAddress & 0xF; + new->dir = ep->bEndpointAddress & 0x80; + if (new->type == USB_EP_TYPE_INTR) + if (!ohci_get_pipe_intr(new, ohcd, buf, buflen)) + dprintf("usb-ohci: %s alloc_intr failed %p\n", + __func__, new); + if (new->type == USB_EP_TYPE_BULK) + ohci_init_bulk_ed(dev, new); + + dprintf("usb-ohci: %s exit %p\n", __func__, new); + return new; +} + +static void ohci_put_pipe(struct usb_pipe *pipe) +{ + struct ohci_hcd *ohcd; + + dprintf("usb-ohci: %s enter - %p\n", __func__, pipe); + if (!pipe || !pipe->dev) + return; + ohcd = pipe->dev->hcidev->priv; + if (ohcd->end) + ohcd->end->next = pipe; + else + ohcd->freelist = pipe; + + if (pipe->type == USB_EP_TYPE_INTR) + if (!ohci_put_pipe_intr(pipe, ohcd)) + dprintf("usb-ohci: %s alloc_intr failed %p\n", + __func__, pipe); + + ohcd->end = pipe; + pipe->next = NULL; + pipe->dev = NULL; + memset(pipe, 0, sizeof(*pipe)); + dprintf("usb-ohci: %s exit\n", __func__); +} + +static uint16_t ohci_get_last_frame(struct usb_dev *dev) +{ + struct ohci_hcd *ohcd; + struct ohci_regs *regs; + + ohcd = dev->hcidev->priv; + regs = ohcd->regs; + return read_reg32(®s->fm_num); +} + +static int ohci_poll_intr(struct usb_pipe *pipe, uint8_t *data) +{ + struct ohci_pipe *opipe; + struct ohci_ed *ed; + struct ohci_td *head, *tail, *curr, *next; + struct ohci_td *head_phys, *tail_phys, *curr_phys; + uint8_t *ptr = NULL; + unsigned int i, pos; + static uint16_t last_frame; + long ptr_phys = 0; + long td_next; + + if (!pipe || last_frame == ohci_get_last_frame(pipe->dev)) + return 0; + + dprintf("%s: enter\n", __func__); + + last_frame = ohci_get_last_frame(pipe->dev); + opipe = ohci_pipe_get_opipe(pipe); + ed = &opipe->ed; + + head_phys = (struct ohci_td *)(long)(le32_to_cpu(ed->headp) & EDA_HEADP_MASK); + tail_phys = (struct ohci_td *)(long)le32_to_cpu(ed->tailp); + curr_phys = (struct ohci_td *) opipe->td_phys; + pos = (tail_phys - curr_phys + 1) % (opipe->count - 1); + dprintf("pos %d %ld -- %d\n", pos, (tail_phys - curr_phys + 1), + opipe->count); + curr = opipe->td + pos; + head = opipe->td + (head_phys - (struct ohci_td *) opipe->td_phys); + tail = opipe->td + (tail_phys - (struct ohci_td *) opipe->td_phys); + + /* dprintf("%08X %08X %08X %08X\n", + opipe->td_phys, head_phys, tail_phys, curr_phys); + dprintf("%08X %08X %08X %08X\n", opipe->td, head, tail, curr); */ + + if (curr != head) { + ptr = (uint8_t *) ((long)opipe->buf + pipe->mps * pos); + ptr_phys = opipe->buf_phys + pipe->mps * pos; + if (le32_to_cpu(*(uint32_t *)ptr) != 0) { + for (i = 0; i < 8; i++) + data[i] = *(ptr + i); + } + + next = curr + 1; + if (next == (opipe->td + opipe->count - 1)) + next = opipe->td; + + curr->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC); + curr->next_td = cpu_to_le32(0); + curr->cbp = cpu_to_le32(PTR_U32(ptr_phys)); + curr->be = cpu_to_le32(PTR_U32(ptr_phys + pipe->mps - 1)); + td_next = ohci_get_td_phys(curr, opipe->td, opipe->td_phys); + dprintf("Connecting %p to %p(phys %08lx) ptr %p, " + "ptr_phys %08lx\n", tail, curr, td_next, ptr, ptr_phys); + tail->next_td = cpu_to_le32(td_next); + mb(); + ed->tailp = cpu_to_le32(td_next); + } else + return 0; + + dprintf("%s: exit\n", __func__); + return 1; +} + +struct usb_hcd_ops ohci_ops = { + .name = "ohci-hcd", + .init = ohci_init, + .exit = ohci_exit, + .detect = ohci_detect, + .disconnect = ohci_disconnect, + .get_pipe = ohci_get_pipe, + .put_pipe = ohci_put_pipe, + .send_ctrl = ohci_send_ctrl, + .transfer_bulk = ohci_transfer_bulk, + .poll_intr = ohci_poll_intr, + .usb_type = USB_OHCI, + .next = NULL, +}; + +void usb_ohci_register(void) +{ + usb_hcd_register(&ohci_ops); +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-ohci.h b/qemu/roms/SLOF/lib/libusb/usb-ohci.h new file mode 100644 index 000000000..f4535fddd --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-ohci.h @@ -0,0 +1,217 @@ +/****************************************************************************** + * Copyright (c) 2007, 2012, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * Definitions for OHCI Controller + * + * USB on the PowerStation: + * ohci0 - port 0 -> not connected + * ohci0 - port 1 - 2 -> Internal connector (J60_USBINT) + * ohci1 - port 0 -> not connected + * ohci1 - port 1 - 2 -> External connector (J10_USBEXT) + */ + +#ifndef USB_OHCI_H +#define USB_OHCI_H + +#include <stdint.h> + +struct ohci_regs { + uint32_t rev; + uint32_t control; + uint32_t cmd_status; + uint32_t intr_status; + uint32_t intr_enable; + uint32_t intr_disable; + uint32_t hcca; + uint32_t period_curr_ed; + uint32_t cntl_head_ed; + uint32_t cntl_curr_ed; + uint32_t bulk_head_ed; + uint32_t bulk_curr_ed; + uint32_t done_head; + uint32_t fm_interval; + uint32_t fm_remaining; + uint32_t fm_num; + uint32_t period_start; + uint32_t ls_threshold; + uint32_t rh_desc_a; + uint32_t rh_desc_b; + uint32_t rh_status; + uint32_t rh_ps[5]; +} __attribute__((packed)); + +#define EDA_FADDR(x) ((x & 0x7F)) +#define EDA_EP(x) ((x & 0x0F) << 7) +#define EDA_DIR_OUT (1 << 11) +#define EDA_DIR_IN (1 << 12) +#define EDA_LOW_SPEED (1 << 13) +#define EDA_SKIP (1 << 14) +#define EDA_SKIP_LE (0x400000) /* avoiding conversions */ +#define EDA_FORMAT_ISO (1 << 15) +#define EDA_MPS(x) ((x & 0x7FF) << 16) + +#define EDA_HEADP_MASK (0xFFFFFFFC) +#define EDA_HEADP_MASK_LE (cpu_to_le32(EDA_HEADP_MASK)) +#define EDA_HEADP_HALTED (0x1) +#define EDA_HEADP_CARRY (0x2) + +struct ohci_ed { + uint32_t attr; + uint32_t tailp; + uint32_t headp; + uint32_t next_ed; +} __attribute__((packed)); + +#define TDA_DONE (1 << 17) +#define TDA_ROUNDING (1 << 18) +#define TDA_DP_SETUP (0 << 19) +#define TDA_DP_OUT (1 << 19) +#define TDA_DP_IN (1 << 20) +#define TDA_DI_NO (0x7 << 21) +#define TDA_TOGGLE_DATA0 (0x02000000) +#define TDA_TOGGLE_DATA1 (0x03000000) +#define TDA_CC (0xF << 28) + +#define TDA_ERROR(x) ((x) * -1) + +/* Table 4-7: Completion Codes */ +const char *tda_cc_error[] = { +#define USB_NOERROR TDA_ERROR(0) + "NOERROR", + "CRC", + "BITSTUFFING", + "DATATOGGLEMISMATCH", +#define USB_STALL TDA_ERROR(4) + "STALL", + "DEVICENOTRESPONDING", + "PIDCHECKFAILURE", + "UNEXPECTEDPID", + "DATAOVERRUN", + "DATAUNDERRUN", + "reserved", + "reserved", + "BUFFEROVERRUN", + "BUFFERUNDERRUN", + "NOT ACCESSED", + "NOT ACCESSED", +}; + +struct ohci_td { + uint32_t attr; + uint32_t cbp; + uint32_t next_td; + uint32_t be; +} __attribute__((packed)); + +#define HCCA_SIZE 256 +#define HCCA_ALIGN (HCCA_SIZE - 1) +#define HCCA_INTR_NUM 32 +struct ohci_hcca { + uint32_t intr_table[HCCA_INTR_NUM]; + uint16_t frame_num; + uint16_t pad1; + uint32_t done_head; + uint32_t reserved[120]; +} __attribute__((packed)); + +struct ohci_pipe { + struct ohci_ed ed; /* has to be aligned at 16 byte address*/ + struct usb_pipe pipe; + struct ohci_td *td; + void *buf; + long ed_phys; + long td_phys; + long buf_phys; + uint32_t buflen; + uint32_t count; + uint8_t pad[0]; +}__attribute__((packed)); + +#define OHCI_PIPE_POOL_SIZE 4096 +#define OHCI_MAX_TDS 256 /* supports 16k buffers, i.e. 64 * 256 */ +#define OHCI_MAX_BULK_SIZE 4096 + +struct ohci_hcd { + struct ohci_hcca *hcca; + struct ohci_regs *regs; + struct usb_hcd_dev *hcidev; + struct usb_pipe *freelist; + struct usb_pipe *end; + struct usb_dev rhdev; + long hcca_phys; + void *pool; + long pool_phys; +}; + +#define OHCI_CTRL_CBSR (3 << 0) +#define OHCI_CTRL_PLE (1 << 2) +#define OHCI_CTRL_CLE (1 << 4) +#define OHCI_CTRL_BLE (1 << 5) +#define OHCI_CTRL_HCFS (3 << 6) +#define OHCI_USB_RESET (0 << 6) +#define OHCI_USB_OPER (2 << 6) +#define OHCI_USB_SUSPEND (3 << 6) +#define OHCI_CTRL_RWC (1 << 9) + +/* OHCI Command Status */ +#define OHCI_CMD_STATUS_HCR (1 << 0) +#define OHCI_CMD_STATUS_CLF (1 << 1) +#define OHCI_CMD_STATUS_BLF (1 << 2) + +/* OHCI Interrupt status */ +#define OHCI_INTR_STATUS_WD (1 << 1) + +/* Root Hub Descriptor A bits */ +#define RHDA_NDP (0xFF) +#define RHDA_PSM_INDIVIDUAL (1 << 8) +#define RHDA_NPS_ENABLE (1 << 9) +#define RHDA_DT (1 << 10) +#define RHDA_OCPM_PERPORT (1 << 11) +#define RHDA_NOCP_ENABLE (1 << 12) + +/* Root Hub Descriptor B bits */ +#define RHDB_PPCM_PORT_POWER (0xFFFE) +#define RHDB_PPCM_GLOBAL_POWER (0x0000) + +#define RH_STATUS_LPSC (1 << 16) +#define RH_STATUS_OCIC (1 << 17) +#define RH_STATUS_CREW (1 << 31) + +#define RH_PS_CCS (1 << 0) +#define RH_PS_PES (1 << 1) +#define RH_PS_PSS (1 << 2) +#define RH_PS_POCI (1 << 3) +#define RH_PS_PRS (1 << 4) +#define RH_PS_PPS (1 << 8) +#define RH_PS_LSDA (1 << 9) + +#define RH_PS_CSC (1 << 16) +#define RH_PS_PESC (1 << 17) +#define RH_PS_PSSC (1 << 18) +#define RH_PS_OCIC (1 << 19) +#define RH_PS_PRSC (1 << 20) + +/*********************************************************************/ +/* Values for USB Frame Timing */ +/* One USB frame (1ms) consists of 12000 bit-times as clock is 12MHz */ +/* controller can be adjusted for performance optimization */ +/* We use standard values (OHCI spec 6.3.1, 5.1.1.4, 5.4, 7.3.4) */ +/*********************************************************************/ +#define FRAME_INTERVAL (((((11999 - 210) * 6) / 7) << 16) | 11999) +#define PERIODIC_START ((11999 * 9) / 10) + + +static inline struct ohci_ed *ohci_pipe_get_ed(struct usb_pipe *pipe); +static inline long ohci_pipe_get_ed_phys(struct usb_pipe *pipe); +static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd); + +#endif /* USB_OHCI_H */ diff --git a/qemu/roms/SLOF/lib/libusb/usb-slof.c b/qemu/roms/SLOF/lib/libusb/usb-slof.c new file mode 100644 index 000000000..de841f0fb --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-slof.c @@ -0,0 +1,61 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * All functions concerning interface to slof + */ + +#include <string.h> +#include "helpers.h" +#include "usb-core.h" +#include "paflof.h" + +#undef SLOF_DEBUG +//#define SLOF_DEBUG +#ifdef SLOF_DEBUG +#define dprintf(_x ...) do { printf(_x); } while(0) +#else +#define dprintf(_x ...) +#endif + +int slof_usb_handle(struct usb_dev *dev) +{ + struct slof_usb_dev sdev; + sdev.port = dev->port; + sdev.addr = dev->addr; + sdev.hcitype = dev->hcidev->type; + sdev.num = dev->hcidev->num; + sdev.udev = dev; + + if (dev->class == DEV_HID_KEYB) { + dprintf("Keyboard %ld %ld\n", dev->hcidev->type, dev->hcidev->num); + sdev.devtype = DEVICE_KEYBOARD; + forth_push((long)&sdev); + forth_eval("s\" dev-keyb.fs\" INCLUDED"); + } else if (dev->class == DEV_HID_MOUSE) { + dprintf("Mouse %ld %ld\n", dev->hcidev->type, dev->hcidev->num); + sdev.devtype = DEVICE_MOUSE; + forth_push((long)&sdev); + forth_eval("s\" dev-mouse.fs\" INCLUDED"); + } else if ((dev->class >> 16 & 0xFF) == 8) { + dprintf("MASS Storage device %ld %ld\n", dev->hcidev->type, dev->hcidev->num); + sdev.devtype = DEVICE_DISK; + forth_push((long)&sdev); + forth_eval("s\" dev-storage.fs\" INCLUDED"); + } else if (dev->class == DEV_HUB) { + dprintf("Generic hub device %ld %ld\n", dev->hcidev->type, + dev->hcidev->num); + sdev.devtype = DEVICE_HUB; + forth_push((long)&sdev); + forth_eval("s\" dev-hub.fs\" INCLUDED"); + } + return true; +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.c b/qemu/roms/SLOF/lib/libusb/usb-xhci.c new file mode 100644 index 000000000..0c3d6e47f --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.c @@ -0,0 +1,1316 @@ +/***************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <string.h> +#include "usb.h" +#include "usb-core.h" +#include "usb-xhci.h" +#include "tools.h" +#include "paflof.h" + +#undef XHCI_DEBUG +//#define XHCI_DEBUG +#ifdef XHCI_DEBUG +#define dprintf(_x ...) do { printf("%s: ", __func__); printf(_x); } while (0) +#else +#define dprintf(_x ...) +#endif + +static void dump_xhci_regs(struct xhci_hcd *xhcd) +{ +#ifdef XHCI_DEBUG + struct xhci_cap_regs *cap; + struct xhci_op_regs *op; + struct xhci_run_regs *run; + + cap = xhcd->cap_regs; + op = xhcd->op_regs; + run = xhcd->run_regs; + + dprintf("\n"); + dprintf(" - CAPLENGTH %02X\n", read_reg8 (&cap->caplength)); + dprintf(" - HCIVERSION %04X\n", read_reg16(&cap->hciversion)); + dprintf(" - HCSPARAMS1 %08X\n", read_reg32(&cap->hcsparams1)); + dprintf(" - HCSPARAMS2 %08X\n", read_reg32(&cap->hcsparams2)); + dprintf(" - HCSPARAMS3 %08X\n", read_reg32(&cap->hcsparams3)); + dprintf(" - HCCPARAMS %08X\n", read_reg32(&cap->hccparams)); + dprintf(" - DBOFF %08X\n", read_reg32(&cap->dboff)); + dprintf(" - RTSOFF %08X\n", read_reg32(&cap->rtsoff)); + dprintf("\n"); + + dprintf(" - USBCMD %08X\n", read_reg32(&op->usbcmd)); + dprintf(" - USBSTS %08X\n", read_reg32(&op->usbsts)); + dprintf(" - PAGESIZE %08X\n", read_reg32(&op->pagesize)); + dprintf(" - DNCTRL %08X\n", read_reg32(&op->dnctrl)); + dprintf(" - CRCR %016llX\n", read_reg64(&op->crcr)); + dprintf(" - DCBAAP %016llX\n", read_reg64(&op->dcbaap)); + dprintf(" - CONFIG %08X\n", read_reg32(&op->config)); + dprintf("\n"); + + dprintf(" - MFINDEX %08X\n", read_reg32(&run->mfindex)); + dprintf("\n"); +#endif +} + +static void print_port_status(struct xhci_port_regs *prs) +{ +#ifdef XHCI_DEBUG + uint32_t portsc; + uint32_t CCS, PED, PP, PLS, i, PR = 0; + + portsc = read_reg32(&prs->portsc); + dprintf("portsc %08x portpmsc %08x portli %08x\n", + portsc, + read_reg32(&prs->portpmsc), + read_reg32(&prs->portli)); + + if (portsc & PORTSC_CCS) { + printf("CCS "); + CCS = 1; + } + if (portsc & PORTSC_PED) { + printf("PED "); + PED = 1; + } + if (portsc & PORTSC_OCA) + printf("OCA "); + if (portsc & PORTSC_PR) + printf("OCA "); + PLS = (portsc & PORTSC_PLS_MASK) >> 5; + printf("PLS:%d ", PLS); + if (portsc & PORTSC_PP) { + printf("PP "); + PP = 1; + } + printf("PS:%d ", (portsc & PORTSC_PS_MASK) >> 10); + printf("PIC:%d ", (portsc & PORTSC_PIC_MASK) >> 14); + if (portsc & PORTSC_LWS) + printf("LWS "); + if (portsc & PORTSC_CSC) + printf("CSC "); + if (portsc & PORTSC_PEC) + printf("PEC "); + if (portsc & PORTSC_WRC) + printf("WRC "); + if (portsc & PORTSC_OCC) + printf("OCC "); + if (portsc & PORTSC_PRC) + printf("PRC "); + if (portsc & PORTSC_PLC) + printf("PLC "); + if (portsc & PORTSC_CEC) + printf("CEC "); + if (portsc & PORTSC_CAS) + printf("CAS "); + if (portsc & PORTSC_WCE) + printf("WCE "); + if (portsc & PORTSC_WDE) + printf("WDE "); + if (portsc & PORTSC_WOE) + printf("WOE "); + if (portsc & PORTSC_DR) + printf("DR "); + if (portsc & PORTSC_WPR) + printf("WPR "); + printf("\n"); + + for (i = 0 ; i < (sizeof(ps_array_usb3)/sizeof(struct port_state)); i++) { + if (PP == ps_array_usb3[i].PP) { + if (CCS == ps_array_usb3[i].CCS) { + if (PED == ps_array_usb3[i].PED) { + if (PR == ps_array_usb3[i].PR) { + dprintf("%s - PLS %d\n", ps_array_usb3[i].state, PLS); + break; + } + } + } + } + } +#endif + +} + +static inline bool xhci_is_hc_ready(uint32_t *usbsts) +{ + return !(read_reg32(usbsts) & XHCI_USBSTS_CNR); +} + +static inline bool xhci_wait_for_cnr(uint32_t *usbsts) +{ + /* Standard: + * Note: The xHC should halt within 16 ms. of software clearing the + * R/S bit to ‘0’. + * Give some more time... 32ms + */ + int count = 320; + dprintf("Waiting for Controller ready .."); + while (!xhci_is_hc_ready(usbsts)) { + dprintf("."); + count--; + if (!count) { + dprintf(" failed %08X\n", read_reg32(usbsts)); + return false; + } + SLOF_usleep(100); + } + dprintf(" done\n"); + return true; +} + +static bool xhci_hcd_set_runstop(struct xhci_op_regs *op, bool run_req) +{ + uint32_t reg; + + dprintf("Request %s\n", run_req ? "RUN" : "STOP"); + if (!xhci_is_hc_ready(&op->usbsts)) { + dprintf("Controller not ready\n"); + return false; + } + + reg = read_reg32(&op->usbcmd); + if (run_req) + reg |= run_req; + else + reg &= (uint32_t)~1; + dprintf("writing %08X\n", reg); + write_reg32(&op->usbcmd, reg); + mb(); + xhci_wait_for_cnr(&op->usbsts); + return true; +} + +static bool xhci_hcd_reset(struct xhci_op_regs *op) +{ + uint32_t reg; + + /* Check if the controller is halted, else halt it */ + if (!(read_reg32(&op->usbsts) & XHCI_USBSTS_HCH)) { + dprintf("HCHalted not set\n"); + if (!xhci_hcd_set_runstop(op, false)) + return false; + } + + if (read_reg32(&op->usbsts) & XHCI_USBSTS_CNR) { + dprintf("Controller not ready\n"); + return false; + } + + reg = read_reg32(&op->usbcmd) | XHCI_USBCMD_HCRST; + /* Ready to Reset the controller now */ + write_reg32(&op->usbcmd, reg); + xhci_wait_for_cnr(&op->usbsts); + return true; +} + +static void xhci_handle_cmd_completion(struct xhci_hcd *xhcd, + struct xhci_event_trb *event) +{ + uint32_t flags, slot_id, status; + + status = le32_to_cpu(event->status); + flags = le32_to_cpu(event->flags); + slot_id = TRB_SLOT_ID(flags); + if (TRB_STATUS(status) == COMP_SUCCESS) + xhcd->slot_id = slot_id; + else + xhcd->slot_id = 0; +} + +static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd, + uint32_t event_type) +{ + struct xhci_event_trb *event; + uint64_t val; + uint32_t flags, time; + int index; + + mb(); + event = (struct xhci_event_trb *)xhcd->ering.deq; + flags = le32_to_cpu(event->flags); + + dprintf("Reading from event ptr %p %08x\n", event, flags); + time = SLOF_GetTimer() + USB_TIMEOUT; + + while ((flags & TRB_CYCLE_STATE) != xhcd->ering.cycle_state) { + mb(); + flags = le32_to_cpu(event->flags); + if (time < SLOF_GetTimer()) + return NULL; + } + + mb(); + flags = le32_to_cpu(event->flags); + switch(TRB_TYPE(flags)) + { + case TRB_CMD_COMPLETION: + dprintf("CMD Completion\n"); + xhci_handle_cmd_completion(xhcd, event); + break; + case TRB_PORT_STATUS: + dprintf("Port status event\n"); + break; + case TRB_TRANSFER_EVENT: + dprintf("XFER event addr %16lx, status %08x, flags %08x\n", + le64_to_cpu(event->addr), + le32_to_cpu(event->status), + le32_to_cpu(event->flags)); + break; + default: + printf("TRB_TYPE %d\n", TRB_TYPE(flags)); + dprintf("Event addr %16lx, status %08x, flags %08x state %d\n", + le64_to_cpu(event->addr), + le32_to_cpu(event->status), + flags, xhcd->ering.cycle_state); + break; + } + xhcd->ering.deq = (uint64_t) (event + 1); + + event->addr = 0; + event->status = 0; + event->flags = cpu_to_le32(xhcd->ering.cycle_state); + + index = xhcd->ering.deq - (uint64_t)xhcd->ering.trbs; + val = xhcd->ering.trbs_dma; + val += (index % XHCI_EVENT_TRBS_SIZE); + if (!(index % XHCI_EVENT_TRBS_SIZE)) { + xhcd->ering.deq = (uint64_t)xhcd->ering.trbs; + xhcd->ering.cycle_state = xhcd->ering.cycle_state ? 0 : 1; + dprintf("Rounding %d\n", xhcd->ering.cycle_state); + } + dprintf("Update start %x deq %x index %d\n", + xhcd->ering.trbs_dma, val, index/sizeof(*event)); + write_reg64(&xhcd->run_regs->irs[0].erdp, val); + return event; +} + +static void xhci_send_cmd(struct xhci_hcd *xhcd, uint32_t field1, + uint32_t field2, uint32_t field3, uint32_t field4) +{ + struct xhci_db_regs *dbr; + struct xhci_command_trb *cmd; + uint32_t val, cycle_state; + + dbr = xhcd->db_regs; + cmd = (struct xhci_command_trb *)xhcd->crseg.enq; + + cmd->field[0] = cpu_to_le32(field1); + cmd->field[1] = cpu_to_le32(field2); + cmd->field[2] = cpu_to_le32(field3); + + val = le32_to_cpu(cmd->field[3]); + cycle_state = (val & 0x1) ? 0 : 1; + val = field4 | cycle_state; + cmd->field[3] = cpu_to_le32(val); + + dprintf("CMD %016lx val %08x cycle_state %d field1 %08x, field2 %08x, field3 %08x field4 %08x\n", + cmd, val, cycle_state, + le32_to_cpu(cmd->field[0]), + le32_to_cpu(cmd->field[1]), + le32_to_cpu(cmd->field[2]), + le32_to_cpu(cmd->field[3]) + ); + + /* Ring the doorbell */ + write_reg32(&dbr->db[0], 0); + xhci_poll_event(xhcd, 0); + cmd++; + xhcd->crseg.enq = (uint64_t)cmd; + return; +} + +static void xhci_send_enable_slot(struct xhci_hcd *xhcd, uint32_t port) +{ + uint32_t field1, field2, field3, field4; + + field1 = 0; + field2 = 0; + field3 = 0; + field4 = TRB_CMD_TYPE(TRB_ENABLE_SLOT); + xhci_send_cmd(xhcd, field1, field2, field3, field4); +} + +static void xhci_send_addr_device(struct xhci_hcd *xhcd, uint32_t slot_id, + uint64_t dma_in_ctx) +{ + uint32_t field1, field2, field3, field4; + + dprintf("Address device %lx, low %x, high %x\n", dma_in_ctx, + TRB_ADDR_LOW(dma_in_ctx), + TRB_ADDR_HIGH(dma_in_ctx)); + field1 = TRB_ADDR_LOW(dma_in_ctx) & ~0xF; + field2 = TRB_ADDR_HIGH(dma_in_ctx); + field3 = 0; + field4 = TRB_CMD_TYPE(TRB_ADDRESS_DEV) | TRB_CMD_SLOT_ID(slot_id); + xhci_send_cmd(xhcd, field1, field2, field3, field4); +} + +static uint32_t xhci_get_epno(struct usb_pipe *pipe) +{ + uint32_t x_epno; + x_epno = pipe->dir | 2 * pipe->epno; + dprintf("EPno %d:%d DIR %d\n", pipe->epno, x_epno, pipe->dir); + return x_epno; +} + +static void xhci_configure_ep(struct xhci_hcd *xhcd, uint32_t slot_id, + uint64_t dma_in_ctx) +{ + uint32_t field1, field2, field3, field4; + + dprintf("Configure EP %lx, low %x, high %x\n", dma_in_ctx, + TRB_ADDR_LOW(dma_in_ctx), + TRB_ADDR_HIGH(dma_in_ctx)); + field1 = TRB_ADDR_LOW(dma_in_ctx) & ~0xF; + field2 = TRB_ADDR_HIGH(dma_in_ctx); + field3 = 0; + field4 = TRB_CMD_TYPE(TRB_CONFIG_EP) | TRB_CMD_SLOT_ID(slot_id); + xhci_send_cmd(xhcd, field1, field2, field3, field4); +} + +static void xhci_init_seg(struct xhci_seg *seg, uint32_t size, uint32_t type) +{ + struct xhci_link_trb *link; + + seg->size = size / XHCI_TRB_SIZE; + seg->next = NULL; + seg->type = type; + seg->cycle_state = 1; + seg->enq = (uint64_t)seg->trbs; + seg->deq = (uint64_t)seg->trbs; + memset((void *)seg->trbs, 0, size); + + link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1); + link->addr = cpu_to_le64(seg->trbs_dma); + link->field2 = 0; + link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK)); + return; +} + +static bool xhci_alloc_seg(struct xhci_seg *seg, uint32_t size, uint32_t type) +{ + seg->trbs = (union xhci_trb *)SLOF_dma_alloc(size); + if (!seg->trbs) { + dprintf("Alloc failed\n"); + return false; + } + xhci_init_seg(seg, size, type); + seg->trbs_dma = SLOF_dma_map_in((void *)seg->trbs, size, false); + + dprintf(" TRBs %016lX TRBS-DMA %016lX\n", seg->trbs, seg->trbs_dma); + return true; +} + +static void xhci_free_seg(struct xhci_seg *seg, uint32_t size) +{ + if (seg->trbs) { + dprintf(" TRBs %016lX TRBS-DMA %016lX size %x\n", seg->trbs, seg->trbs_dma, size); + SLOF_dma_map_out(seg->trbs_dma, (void *)seg->trbs, size); + SLOF_dma_free((void *)seg->trbs, size); + } + memset(seg, 0, sizeof(*seg)); +} + +#define CTX_SIZE(x) ( (x) ? 64 : 32 ) + +static bool xhci_alloc_ctx(struct xhci_ctx *ctx, uint32_t size, uint32_t type) +{ + ctx->addr = (uint8_t *)SLOF_dma_alloc(size); + if (!ctx->addr) { + dprintf("Alloc failed\n"); + return false; + } + ctx->size = size; + ctx->type = type; + memset((void *)ctx->addr, 0, size); + ctx->dma_addr = SLOF_dma_map_in((void *)ctx->addr, size, false); + dprintf("ctx %llx, ctx_dma %llx\n", ctx->addr, ctx->dma_addr); + return true; +} + +static struct xhci_control_ctx *xhci_get_control_ctx(struct xhci_ctx *ctx) +{ + if (ctx->type == XHCI_CTX_TYPE_INPUT) + return (struct xhci_control_ctx *) ctx->addr; + return NULL; +} + +static struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_ctx *ctx, uint32_t ctx_size) +{ + uint32_t offset = 0; + + if (ctx->type == XHCI_CTX_TYPE_INPUT) + offset += ctx_size; + return (struct xhci_slot_ctx *)(ctx->addr + offset); +} + +static struct xhci_ep_ctx *xhci_get_ep0_ctx(struct xhci_ctx *ctx, uint32_t ctx_size) +{ + uint32_t offset = 0; + + offset = ctx_size; + if (ctx->type == XHCI_CTX_TYPE_INPUT) + offset += ctx_size; + return (struct xhci_ep_ctx *)(ctx->addr + offset); +} + +static struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_ctx *ctx, uint32_t ctx_size, + uint32_t epno) +{ + uint32_t offset = 0; + + offset = ctx_size * epno; + if (ctx->type == XHCI_CTX_TYPE_INPUT) + offset += ctx_size; + return (struct xhci_ep_ctx *)(ctx->addr + offset); +} + +static void xhci_free_ctx(struct xhci_ctx *ctx, uint32_t size) +{ + SLOF_dma_map_out(ctx->dma_addr, (void *)ctx->addr, size); + SLOF_dma_free((void *)ctx->addr, size); +} + +static uint32_t usb_control_max_packet(uint32_t speed) +{ + uint32_t max_packet = 0; + + switch(speed) + { + case USB_LOW_SPEED: + max_packet = 8; + break; + case USB_FULL_SPEED: + max_packet = 8; + break; + case USB_HIGH_SPEED: + max_packet = 64; + break; + case USB_SUPER_SPEED: + max_packet = 512; + break; + default: + /* should not reach here */ + dprintf("Unknown speed\n"); + } + return max_packet; +} + +static bool xhci_alloc_dev(struct xhci_hcd *xhcd, uint32_t slot_id, uint32_t port) +{ + struct usb_dev *dev; + struct xhci_dev *xdev; + struct xhci_slot_ctx *slot; + struct xhci_control_ctx *ctrl; + struct xhci_ep_ctx *ep0; + uint32_t ctx_size, val; + uint16_t max_packet; + uint32_t newport; + + ctx_size = CTX_SIZE(xhcd->hcc_csz_64); + xdev = &xhcd->xdevs[slot_id]; + xdev->slot_id = slot_id; + xdev->ctx_size = ctx_size; + + /* 4.3.3 Device Slot initialization */ + /* Step 1 */ + if (!xhci_alloc_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE, XHCI_CTX_TYPE_INPUT)) { + dprintf("Failed allocating in_ctx\n"); + return false; + } + + /* Step 2 */ + ctrl = xhci_get_control_ctx(&xdev->in_ctx); + ctrl->a_flags = cpu_to_le32(0x3); /* A0, A1 */ + ctrl->d_flags = 0; + + /* Step 3 */ + slot = xhci_get_slot_ctx(&xdev->in_ctx, ctx_size); + newport = port + 1; + val = LAST_CONTEXT(1) | SLOT_SPEED_SS | (newport << 16); /* FIXME speed, read from PS */ + slot->field1 = cpu_to_le32(val); + slot->field2 = cpu_to_le32(ROOT_HUB_PORT(newport)); /* FIXME how to get port no */ + + /* Step 4 */ + if (!xhci_alloc_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE, TYPE_CTRL)) { + dprintf("Failed allocating control\n"); + goto fail_in_ctx; + } + + /* Step 5 */ + ep0 = xhci_get_ep0_ctx(&xdev->in_ctx, ctx_size); + val = 0; + max_packet = usb_control_max_packet(USB_SUPER_SPEED); + max_packet = 64; + val = EP_TYPE(EP_CTRL) | MAX_BURST(0) | ERROR_COUNT(3) | + MAX_PACKET_SIZE(max_packet); + ep0->field2 = cpu_to_le32(val);; + ep0->deq_addr = cpu_to_le64(xdev->control.trbs_dma | xdev->control.cycle_state); + ep0->field4 = cpu_to_le32(8); + + /* Step 6 */ + if (!xhci_alloc_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE, XHCI_CTX_TYPE_DEVICE)) { + dprintf("Failed allocating out_ctx\n"); + goto fail_control_seg; + } + + /* Step 7 */ + xhcd->dcbaap[slot_id] = cpu_to_le64(xdev->out_ctx.dma_addr); + + /* Step 8 */ + slot = xhci_get_slot_ctx(&xdev->out_ctx, ctx_size); + ep0 = xhci_get_ep0_ctx(&xdev->out_ctx, ctx_size); + + dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4))); + xhci_send_addr_device(xhcd, slot_id, xdev->in_ctx.dma_addr); + mb(); + dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4))); + + dprintf("EP0 f0 %08X f1 %08X %016lX %08X\n", + le32_to_cpu(ep0->field1), + le32_to_cpu(ep0->field2), + le64_to_cpu(ep0->deq_addr), + le32_to_cpu(ep0->field4)); + + /* Step 9 - configure ep */ + ctrl->a_flags = cpu_to_le32(0x1); /* A0 */ + ctrl->d_flags = 0; + xhci_configure_ep(xhcd, slot_id, xdev->in_ctx.dma_addr); + mb(); + dprintf("Slot State %x \n", SLOT_STATE(le32_to_cpu(slot->field4))); + dprintf("USB Device address %d \n", USB_DEV_ADDRESS(le32_to_cpu(slot->field4))); + dprintf("EP0 f0 %08X f1 %08X %016lX %08X\n", + le32_to_cpu(ep0->field1), + le32_to_cpu(ep0->field2), + le64_to_cpu(ep0->deq_addr), + le32_to_cpu(ep0->field4)); + + dev = usb_devpool_get(); + dprintf("allocated device %p\n", dev); + dev->hcidev = xhcd->hcidev; + dev->speed = USB_SUPER_SPEED; + dev->addr = USB_DEV_ADDRESS(slot->field4); + dev->port = newport; + dev->priv = xdev; + xdev->dev = dev; + if (setup_new_device(dev, newport)) + return true; + + xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE); +fail_control_seg: + xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE); +fail_in_ctx: + xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE); + return false; +} + +static void xhci_free_dev(struct xhci_dev *xdev) +{ + xhci_free_seg(&xdev->bulk_in, XHCI_DATA_TRBS_SIZE); + xhci_free_seg(&xdev->bulk_out, XHCI_DATA_TRBS_SIZE); + xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE); + xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE); + xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE); +} + +static bool usb3_dev_init(struct xhci_hcd *xhcd, uint32_t port) +{ + /* Device enable slot */ + xhci_send_enable_slot(xhcd, port); + if (!xhcd->slot_id) { + dprintf("Unable to get slot id\n"); + return false; + } + dprintf("SLOT ID: %d\n", xhcd->slot_id); + if (!xhci_alloc_dev(xhcd, xhcd->slot_id, port)) { + dprintf("Unable to allocate device\n"); + return false; + } + return true; +} + +static int xhci_hub_check_ports(struct xhci_hcd *xhcd) +{ + uint32_t num_ports, portsc, i; + struct xhci_op_regs *op; + struct xhci_port_regs *prs; + struct xhci_cap_regs *cap; + uint32_t xecp_off; + uint32_t *xecp_addr, *base; + uint32_t port_off = 1, port_cnt; + + dprintf("enter\n"); + + op = xhcd->op_regs; + cap = xhcd->cap_regs; + port_cnt = num_ports = read_reg32(&cap->hcsparams1) >> 24; + + /* Read the xHCI extented capability to find usb3 ports and offset*/ + xecp_off = XHCI_HCCPARAMS_XECP(read_reg32(&cap->hccparams)); + base = (uint32_t *)cap; + while (xecp_off > 0) { + xecp_addr = base + xecp_off; + dprintf(stderr, "xecp_off %d %p %p \n", xecp_off, base, xecp_addr); + + if (XHCI_XECP_CAP_ID(read_reg32(xecp_addr)) == XHCI_XECP_CAP_SP && + XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == 3 && + XHCI_XECP_CAP_SP_MN(read_reg32(xecp_addr)) == 0) { + port_cnt = XHCI_XECP_CAP_SP_PC(read_reg32(xecp_addr + 2)); + port_off = XHCI_XECP_CAP_SP_PO(read_reg32(xecp_addr + 2)); + dprintf(stderr, "PortCount %d Portoffset %d\n", port_cnt, port_off); + } + base = xecp_addr; + xecp_off = XHCI_XECP_NEXT_PTR(read_reg32(xecp_addr)); + } + if (port_off == 0) /* port_off should always start from 1 */ + return false; + for (i = (port_off - 1); i < (port_off + port_cnt - 1); i++) { + prs = &op->prs[i]; + portsc = read_reg32(&prs->portsc); + if ((portsc & PORTSC_CCS) && + (portsc & PORTSC_PP) && + (portsc & PORTSC_PED)) { + /* Device present and enabled */ + dprintf("Device present on port %d\n", i); + /* Reset the port */ + portsc = read_reg32(&prs->portsc); + portsc = portsc | PORTSC_PR; + write_reg32(&prs->portsc, portsc); + /* FIXME poll for port event */ + SLOF_msleep(20); + xhci_poll_event(xhcd, 0); + portsc = read_reg32(&prs->portsc); + if (portsc & ~PORTSC_PRC) { + dprintf("Port reset complete %d\n", i); + } + print_port_status(prs); + if (!usb3_dev_init(xhcd, (i - (port_off - 1)))) { + dprintf("USB device initialization failed\n"); + } + } + } + dprintf("exit\n"); + return true; +} + +static bool xhci_hcd_init(struct xhci_hcd *xhcd) +{ + struct xhci_op_regs *op; + struct xhci_int_regs *irs; + uint64_t val; + uint32_t reg; + + if (!xhcd) { + dprintf("NULL pointer\n"); + goto fail; + } + + op = xhcd->op_regs; + irs = &xhcd->run_regs->irs[0]; + if (!xhci_hcd_reset(op)) { + dprintf("Reset failed\n"); + goto fail; + } + + write_reg32(&op->config, XHCI_CONFIG_MAX_SLOT); + reg = read_reg32(&xhcd->cap_regs->hccparams); + /* 64byte context !! */ + xhcd->hcc_csz_64 = (reg & XHCI_HCCPARAMS_CSZ) ? 1 : 0; + + if (xhcd->hcc_csz_64) { + printf("usb-xhci: 64 Byte context not supported\n"); + goto fail; + } + /* + * 6.1 Device Context Base Address Array + * + * Allocate memory and initialize + */ + xhcd->dcbaap = (uint64_t *)SLOF_dma_alloc(XHCI_DCBAAP_MAX_SIZE); + if (!xhcd->dcbaap) { + dprintf("Alloc failed\n"); + goto fail; + } + memset((void *)xhcd->dcbaap, 0, XHCI_DCBAAP_MAX_SIZE); + xhcd->dcbaap_dma = SLOF_dma_map_in((void *)xhcd->dcbaap, + XHCI_DCBAAP_MAX_SIZE, false); + dprintf("dcbaap %llx, dcbaap_phys %llx\n", xhcd->dcbaap, xhcd->dcbaap_dma); + write_reg64(&op->dcbaap, xhcd->dcbaap_dma); + + /* + * Command Ring Control - TRB + * FIXME - better way to allocate it... + */ + if (!xhci_alloc_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE, TYPE_COMMAND)) + goto fail_dcbaap; + + val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK; + val = val | (xhcd->crseg.trbs_dma & XHCI_CRCR_CRP_MASK); + write_reg64(&op->crcr, val); + + /* + * Event Ring Control - TRB + * Allocate event TRBS + */ + if (!xhci_alloc_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE, TYPE_EVENT)) + goto fail_crseg; + + /* + * Populate event ring segment table. + * Note: only using one segment. + */ + xhcd->erst.entries = SLOF_dma_alloc(XHCI_EVENT_TRBS_SIZE); + if (!xhcd->erst.entries) + goto fail_ering; + xhcd->erst.dma = SLOF_dma_map_in((void *)xhcd->erst.entries, + XHCI_EVENT_TRBS_SIZE, false); + xhcd->erst.num_segs = XHCI_ERST_NUM_SEGS; + + /* populate entries[0] */ + write_reg64(&xhcd->erst.entries->addr, xhcd->ering.trbs_dma); + write_reg32(&xhcd->erst.entries->size, xhcd->ering.size); + write_reg32(&xhcd->erst.entries->reserved, 0); + + /* populate erdp */ + val = read_reg64(&irs->erdp) & ~XHCI_ERDP_MASK; + val = val | (xhcd->ering.trbs_dma & XHCI_ERDP_MASK); + write_reg64(&irs->erdp, val); + + /* populate erstsz */ + val = read_reg32(&irs->erstsz) & ~XHCI_ERST_SIZE_MASK; + val = val | xhcd->erst.num_segs; + write_reg32(&irs->erstsz, val); + + /* Now write the erstba */ + val = read_reg64(&irs->erstba) & ~XHCI_ERST_ADDR_MASK; + val = val | (xhcd->erst.dma & XHCI_ERST_ADDR_MASK); + write_reg64(&irs->erstba, val); + + dprintf("ERDP %llx TRB-DMA %llx\n", read_reg64(&irs->erdp), + xhcd->ering.trbs_dma); + dprintf("ERST %llx, ERST DMA %llx, size %d\n", + (uint64_t)xhcd->erst.entries, xhcd->erst.dma, + xhcd->erst.num_segs); + + mb(); + if (!xhci_hcd_set_runstop(op, true)) + goto fail_erst_entries; + + if (!xhci_hub_check_ports(xhcd)) + goto fail_erst_entries; + + return true; +fail_erst_entries: + write_reg64(&irs->erstba, 0); + mb(); + SLOF_dma_map_out(xhcd->erst.dma, (void *)xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE); + SLOF_dma_free((void *)xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE); +fail_ering: + xhci_free_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE); +fail_crseg: + val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK; + write_reg64(&op->crcr, val); + mb(); + xhci_free_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE); +fail_dcbaap: + write_reg64(&op->dcbaap, 0); + mb(); + SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE); + SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE); +fail: + return false; +} + +static bool xhci_hcd_exit(struct xhci_hcd *xhcd) +{ + struct xhci_op_regs *op; + struct xhci_int_regs *irs; + uint64_t val; + int i; + + if (!xhcd) { + dprintf("NULL pointer\n"); + return false; + } + op = xhcd->op_regs; + + if (!xhci_hcd_set_runstop(op, false)) { + dprintf("NULL pointer\n"); + } + + for (i = 1; i < XHCI_CONFIG_MAX_SLOT; i++) { + if (xhcd->xdevs[i].dev) + xhci_free_dev(&xhcd->xdevs[i]); + } + + irs = &xhcd->run_regs->irs[0]; + write_reg64(&irs->erstba, 0); + mb(); + if (xhcd->erst.entries) { + SLOF_dma_map_out(xhcd->erst.dma, xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE); + SLOF_dma_free(xhcd->erst.entries, XHCI_EVENT_TRBS_SIZE); + } + xhci_free_seg(&xhcd->ering, XHCI_EVENT_TRBS_SIZE); + + val = read_reg64(&op->crcr) & ~XHCI_CRCR_CRP_MASK; + write_reg64(&op->crcr, val); + xhci_free_seg(&xhcd->crseg, XHCI_CRCR_CRP_SIZE); + write_reg64(&op->dcbaap, 0); + if (xhcd->dcbaap) { + SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE); + SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE); + } + return true; +} + +static void xhci_init(struct usb_hcd_dev *hcidev) +{ + struct xhci_hcd *xhcd; + + printf(" XHCI: Initializing\n"); + dprintf("device base address %p\n", hcidev->base); + + hcidev->base = (void *)((uint64_t)hcidev->base & ~7); + xhcd = SLOF_alloc_mem(sizeof(*xhcd)); + if (!xhcd) { + printf("usb-xhci: Unable to allocate memory\n"); + return; + } + memset(xhcd, 0, sizeof(*xhcd)); + + hcidev->nextaddr = 1; + hcidev->priv = xhcd; + xhcd->hcidev = hcidev; + xhcd->cap_regs = (struct xhci_cap_regs *)(hcidev->base); + xhcd->op_regs = (struct xhci_op_regs *)(hcidev->base + + read_reg8(&xhcd->cap_regs->caplength)); + xhcd->run_regs = (struct xhci_run_regs *)(hcidev->base + + read_reg32(&xhcd->cap_regs->rtsoff)); + xhcd->db_regs = (struct xhci_db_regs *)(hcidev->base + + read_reg32(&xhcd->cap_regs->dboff)); + dump_xhci_regs(xhcd); + if (!xhci_hcd_init(xhcd)) + printf("usb-xhci: failed to initialize XHCI controller.\n"); + dump_xhci_regs(xhcd); +} + +static void xhci_exit(struct usb_hcd_dev *hcidev) +{ + struct xhci_hcd *xhcd; + + dprintf("%s: enter \n", __func__); + if (!hcidev && !hcidev->priv) { + return; + } + + xhcd = hcidev->priv; + xhci_hcd_exit(xhcd); + SLOF_free_mem(xhcd, sizeof(*xhcd)); + hcidev->priv = NULL; +} + +static void fill_trb_buff(struct xhci_command_trb *cmd, uint32_t field1, + uint32_t field2, uint32_t field3, uint32_t field4) +{ + uint32_t val, cycle_state; + + cmd->field[0] = cpu_to_le32(field1); + cmd->field[1] = cpu_to_le32(field2); + cmd->field[2] = cpu_to_le32(field3); + + val = le32_to_cpu(cmd->field[3]); + cycle_state = (val & 0x1) ? 0 : 1; + val = cycle_state | (field4 & ~0x1); + cmd->field[3] = cpu_to_le32(val); + + dprintf("CMD %016lx val %08x cycle_state %d field1 %08x, field2 %08x, field3 %08x field4 %08x\n", + cmd, val, cycle_state, + le32_to_cpu(cmd->field[0]), + le32_to_cpu(cmd->field[1]), + le32_to_cpu(cmd->field[2]), + le32_to_cpu(cmd->field[3]) + ); + + return; +} + +static void fill_setup_trb(struct xhci_command_trb *cmd, struct usb_dev_req *req, + uint32_t size) +{ + uint32_t field1, field2, field3, field4 = 0; + uint64_t req_raw; + uint32_t datalen = 0, pid = 0; + + req_raw = *((uint64_t *)req); + dprintf("%lx %lx \n", *((uint64_t *)req), req_raw); + /* req_raw is already in right byte order... */ + field1 = cpu_to_le32(TRB_ADDR_HIGH(req_raw)); + field2 = cpu_to_le32(TRB_ADDR_LOW(req_raw)); + field3 = 8; /* ALWAYS 8 */ + + datalen = cpu_to_le16(req->wLength); + if (datalen) { + pid = (req->bmRequestType & REQT_DIR_IN) ? 3 : 2; + field4 = TRB_TRT(pid); + } + field4 |= TRB_CMD_TYPE(TRB_SETUP_STAGE) | TRB_IDT; + fill_trb_buff(cmd, field1, field2, field3, field4); +} + +static void fill_setup_data(struct xhci_command_trb *cmd, void *data, + uint32_t size, uint32_t dir) +{ + uint32_t field1, field2, field3, field4; + + field1 = TRB_ADDR_LOW(data); + field2 = TRB_ADDR_HIGH(data); + field3 = size; + if (dir) + field4 = TRB_DIR_IN; + field4 |= TRB_CMD_TYPE(TRB_DATA_STAGE); + fill_trb_buff(cmd, field1, field2, field3, field4); +} + +static void fill_status_trb(struct xhci_command_trb *cmd, uint32_t dir) +{ + uint32_t field1, field2, field3, field4; + + field1 = 0; + field2 = 0; + field3 = 0; + if (dir) + field4 = TRB_DIR_IN; + + field4 |= TRB_CMD_TYPE(TRB_STATUS_STAGE) | TRB_IOC; + fill_trb_buff(cmd, field1, field2, field3, field4); +} + +static void fill_normal_trb(struct xhci_transfer_trb *trb, void *data, + uint32_t size) +{ + uint32_t field1, field2, field3, field4; + + field1 = TRB_ADDR_LOW(data); + field2 = TRB_ADDR_HIGH(data); + field3 = size; + field4 = TRB_CMD_TYPE(TRB_NORMAL) | TRB_IOC; + fill_trb_buff((struct xhci_command_trb *)trb, field1, field2, field3, field4); +} + +static int xhci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data) +{ + struct xhci_dev *xdev; + struct xhci_seg *ctrl; + struct xhci_hcd *xhcd; + struct xhci_command_trb *cmd; + struct xhci_db_regs *dbr; + long req_phys = 0, data_phys = 0; + int ret = true; + uint32_t slot_id, pid = 0, datalen = 0; + + if (!pipe->dev || !pipe->dev->hcidev) { + dprintf(" NULL pointer\n"); + return false; + } + + xdev = pipe->dev->priv; + slot_id = xdev->slot_id; + ctrl = &xdev->control; + xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv; + dbr = xhcd->db_regs; + if (!ctrl || !xdev || !xhcd) { + dprintf(" NULL pointer\n"); + return false; + } + + cmd = (struct xhci_command_trb *)ctrl->enq; + req_phys = SLOF_dma_map_in(req, sizeof(struct usb_dev_req), true); + fill_setup_trb(cmd, req, sizeof(*req)); + + cmd++; + datalen = cpu_to_le16(req->wLength); + if (datalen) + pid = 1; + if (datalen) { + data_phys = SLOF_dma_map_in(data, datalen, true); + fill_setup_data(cmd, (void *) data_phys, datalen, pid); + cmd++; + } + + fill_status_trb(cmd, pid); + cmd++; + + /* Ring the doorbell - ep0 */ + write_reg32(&dbr->db[slot_id], 1); + if (!xhci_poll_event(xhcd, 0)) { + dprintf("Command failed\n"); + ret = false; + } + ctrl->enq = (uint64_t) cmd; + SLOF_dma_map_out(req_phys, req, sizeof(struct usb_dev_req)); + if (datalen) + SLOF_dma_map_out(data_phys, data, datalen); + return ret; +} + +static inline struct xhci_pipe *xhci_pipe_get_xpipe(struct usb_pipe *pipe) +{ + struct xhci_pipe *xpipe; + xpipe = container_of(pipe, struct xhci_pipe, pipe); + dprintf("%s: xpipe is %p\n", __func__, xpipe); + return xpipe; +} + +static inline struct xhci_seg *xhci_pipe_get_seg(struct usb_pipe *pipe) +{ + struct xhci_pipe *xpipe; + xpipe = xhci_pipe_get_xpipe(pipe); + return xpipe->seg; +} + +static inline void *xhci_get_trb(struct xhci_seg *seg) +{ + uint64_t val, enq; + uint32_t size; + struct xhci_link_trb *link; + + enq = val = seg->enq; + val = val + XHCI_TRB_SIZE; + size = seg->size * XHCI_TRB_SIZE; + /* TRBs being a cyclic buffer, here we cycle back to beginning. */ + if ((val % size) == 0) { + seg->enq = (uint64_t)seg->trbs; + enq = seg->enq; + seg->enq = seg->enq + XHCI_TRB_SIZE; + val = 0; + seg->cycle_state ^= seg->cycle_state; + link = (struct xhci_link_trb *) (seg->trbs + seg->size - 1); + link->addr = cpu_to_le64(seg->trbs_dma); + link->field2 = 0; + link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK)); + mb(); + } + else { + seg->enq = seg->enq + XHCI_TRB_SIZE; + } + + return (void *)enq; +} + +static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys, + void *data, int datalen) +{ + struct xhci_dev *xdev; + struct xhci_seg *seg; + struct xhci_hcd *xhcd; + struct xhci_transfer_trb *trb; + struct xhci_db_regs *dbr; + int ret = true; + uint32_t slot_id, epno; + + if (!pipe->dev || !pipe->dev->hcidev) { + dprintf(" NULL pointer\n"); + dprintf(" pipe dev %p hcidev %p\n", pipe->dev, pipe->dev->hcidev); + return false; + } + + xdev = pipe->dev->priv; + slot_id = xdev->slot_id; + seg = xhci_pipe_get_seg(pipe); + xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv; + dbr = xhcd->db_regs; + if (!seg || !xdev || !xhcd) { + dprintf(" NULL pointer\n"); + dprintf(" seg %p xdev %p xhcd %p\n", seg, xdev, xhcd); + return false; + } + + if (datalen > XHCI_MAX_BULK_SIZE) { + printf("usb-xhci: bulk transfer size too big\n"); + return false; + } + + trb = xhci_get_trb(seg); + fill_normal_trb(trb, (void *)data, datalen); + + epno = xhci_get_epno(pipe); + write_reg32(&dbr->db[slot_id], epno); + if (!xhci_poll_event(xhcd, 0)) { + dprintf("Bulk failed\n"); + ret = false; + } + trb->addr = 0; + trb->len = 0; + trb->flags = 0; + mb(); + + return ret; +} + +static int xhci_alloc_pipe_pool(struct xhci_hcd *xhcd) +{ + struct xhci_pipe *xpipe, *curr, *prev; + unsigned int i, count; + long xpipe_phys = 0; + + count = XHCI_PIPE_POOL_SIZE/sizeof(*xpipe); + xhcd->pool = xpipe = SLOF_dma_alloc(XHCI_PIPE_POOL_SIZE); + if (!xpipe) + return -1; + xhcd->pool_phys = xpipe_phys = SLOF_dma_map_in(xpipe, XHCI_PIPE_POOL_SIZE, true); + dprintf("%s: xpipe %p, xpipe_phys %lx\n", __func__, xpipe, xpipe_phys); + + /* Although an array, link them */ + for (i = 0, curr = xpipe, prev = NULL; i < count; i++, curr++) { + if (prev) + prev->pipe.next = &curr->pipe; + curr->pipe.next = NULL; + prev = curr; + } + + if (!xhcd->freelist) + xhcd->freelist = &xpipe->pipe; + else + xhcd->end->next = &xpipe->pipe; + xhcd->end = &prev->pipe; + + return 0; +} + +static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe) +{ + struct xhci_hcd *xhcd; + struct xhci_dev *xdev; + struct xhci_seg *seg; + struct xhci_pipe *xpipe; + struct xhci_control_ctx *ctrl; + struct xhci_ep_ctx *ep; + uint32_t x_epno, val, type; + + if (!pipe || !dev || !dev->priv) + return; + + xdev = dev->priv; + xhcd = dev->hcidev->priv; + dprintf("dir %d\n", pipe->dir); + seg = xhci_pipe_get_seg(pipe); + xpipe = xhci_pipe_get_xpipe(pipe); + if (pipe->dir) { + type = EP_BULK_IN; + seg = &xdev->bulk_in; + } + else { + type = EP_BULK_OUT; + seg = &xdev->bulk_out; + } + + if (!seg->trbs) { + if (!xhci_alloc_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK)) { + dprintf("Failed allocating seg\n"); + } + } else { + xhci_init_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK); + } + + pipe->mps = XHCI_MAX_BULK_SIZE; + ctrl = xhci_get_control_ctx(&xdev->in_ctx); + x_epno = xhci_get_epno(pipe); + ep = xhci_get_ep_ctx(&xdev->in_ctx, xdev->ctx_size, x_epno); + val = EP_TYPE(type) | MAX_BURST(0) | ERROR_COUNT(3) | + MAX_PACKET_SIZE(pipe->mps); + ep->field2 = cpu_to_le32(val);; + ep->deq_addr = cpu_to_le64(seg->trbs_dma | seg->cycle_state); + ep->field4 = cpu_to_le32(8); + ctrl->a_flags = cpu_to_le32(BIT(x_epno) | 0x1); + ctrl->d_flags = 0; + xhci_configure_ep(xhcd, xdev->slot_id, xdev->in_ctx.dma_addr); + xpipe->seg = seg; +} + +static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len) +{ + struct xhci_hcd *xhcd; + struct usb_pipe *new = NULL; + + if (!dev) + return NULL; + + xhcd = (struct xhci_hcd *)dev->hcidev->priv; + if (!xhcd->freelist) { + dprintf("usb-xhci: %s allocating pool\n", __func__); + if (xhci_alloc_pipe_pool(xhcd)) + return NULL; + } + + new = xhcd->freelist; + xhcd->freelist = xhcd->freelist->next; + if (!xhcd->freelist) + xhcd->end = NULL; + + memset(new, 0, sizeof(*new)); + new->dev = dev; + new->next = NULL; + new->type = ep->bmAttributes & USB_EP_TYPE_MASK; + new->speed = dev->speed; + new->mps = ep->wMaxPacketSize; + new->dir = (ep->bEndpointAddress & 0x80) >> 7; + new->epno = ep->bEndpointAddress & 0x0f; + + if (new->type == USB_EP_TYPE_BULK) + xhci_init_bulk_ep(dev, new); + + return new; +} + +static void xhci_put_pipe(struct usb_pipe *pipe) +{ + struct xhci_hcd *xhcd; + struct xhci_pipe *xpipe; + + dprintf("usb-xhci: %s enter - %p\n", __func__, pipe); + if (!pipe || !pipe->dev) + return; + xhcd = pipe->dev->hcidev->priv; + + dprintf("dir %d\n", pipe->dir); + if (pipe->type == USB_EP_TYPE_BULK) { + xpipe = xhci_pipe_get_xpipe(pipe); + xpipe->seg = NULL; + } + if (xhcd->end) + xhcd->end->next = pipe; + else + xhcd->freelist = pipe; + + xhcd->end = pipe; + pipe->next = NULL; + pipe->dev = NULL; + memset(pipe, 0, sizeof(*pipe)); + + dprintf("usb-xhci: %s exit\n", __func__); +} + +struct usb_hcd_ops xhci_ops = { + .name = "xhci-hcd", + .init = xhci_init, + .exit = xhci_exit, + .usb_type = USB_XHCI, + .get_pipe = xhci_get_pipe, + .put_pipe = xhci_put_pipe, + .send_ctrl = xhci_send_ctrl, + .transfer_bulk = xhci_transfer_bulk, + .next = NULL, +}; + +void usb_xhci_register(void) +{ + usb_hcd_register(&xhci_ops); +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.h b/qemu/roms/SLOF/lib/libusb/usb-xhci.h new file mode 100644 index 000000000..faeb07ead --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.h @@ -0,0 +1,386 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * Definitions for XHCI Controller - Revision 1.0 (5/21/10) + * + */ + +#ifndef USB_XHCI_H +#define USB_XHCI_H + +#include <stdint.h> +#include "usb-core.h" + +#define BIT(x) (1 << x) + +/* 5.3 Host Controller Capability Registers + * Table 19 + */ +struct xhci_cap_regs { + uint8_t caplength; + uint8_t reserved; + uint16_t hciversion; + uint32_t hcsparams1; + uint32_t hcsparams2; + uint32_t hcsparams3; + uint32_t hccparams; +#define XHCI_HCCPARAMS_CSZ BIT(2) +#define XHCI_HCCPARAMS_XECP(x) ((x & 0xFFFF0000) >> 16) + uint32_t dboff; + uint32_t rtsoff; +} __attribute__ ((packed)); + +/* USB 3.0: Section 7 and 7.2 */ +#define XHCI_XECP_CAP_ID(x) ((x & 0xF)) +#define XHCI_XECP_CAP_SP 2 +#define XHCI_XECP_CAP_SP_MN(x) ((x & 0xFF0000) >> 16) +#define XHCI_XECP_CAP_SP_MJ(x) ((x & 0xFF000000) >> 24) +#define XHCI_XECP_CAP_SP_PC(x) ((x & 0xFF00) >> 8) +#define XHCI_XECP_CAP_SP_PO(x) (x & 0xFF) +#define XHCI_XECP_NEXT_PTR(x) ((x & 0xFF00) >> 8) + +/* Table 27: Host Controller USB Port Register Set */ +struct xhci_port_regs { + uint32_t portsc; +#define PORTSC_CCS BIT(0) +#define PORTSC_PED BIT(1) +#define PORTSC_OCA BIT(3) +#define PORTSC_PR BIT(4) +#define PORTSC_PLS_MASK (0xF << 5) +#define PORTSC_PLS_U0 0 +#define PORTSC_PLS_U1 1 +#define PORTSC_PLS_U2 2 +#define PORTSC_PLS_U3 3 +#define PORTSC_PLS_DISABLED 4 +#define PORTSC_PLS_RXDETECT 5 +#define PORTSC_PLS_INACTIVE 6 +#define PORTSC_PLS_POLLING 7 +#define PORTSC_PLS_RECOVERY 8 +#define PORTSC_PLS_HOTRESET 9 +#define PORTSC_PLS_COMP_MODE 10 +#define PORTSC_PLS_TEST_MODE 11 +#define PORTSC_PLS_RESUME 15 +#define PORTSC_PP BIT(9) +#define PORTSC_PS_MASK (0xF << 10) +#define PORTSC_PIC_MASK (0x3 << 14) +#define PORTSC_LWS BIT(16) +#define PORTSC_CSC BIT(17) +#define PORTSC_PEC BIT(18) +#define PORTSC_WRC BIT(19) +#define PORTSC_OCC BIT(20) +#define PORTSC_PRC BIT(21) +#define PORTSC_PLC BIT(22) +#define PORTSC_CEC BIT(23) +#define PORTSC_CAS BIT(24) +#define PORTSC_WCE BIT(25) +#define PORTSC_WDE BIT(26) +#define PORTSC_WOE BIT(27) +#define PORTSC_DR BIT(30) +#define PORTSC_WPR BIT(31) + + uint32_t portpmsc; + uint32_t portli; + uint32_t reserved; +} __attribute__ ((packed)); + +struct port_state { + bool PP; + bool CCS; + bool PED; + bool PR; + uint8_t PLS; + char *state; +}; + + +struct port_state ps_array_usb2[] = { + {1, 0, 0, 0, PORTSC_PLS_U0, "ERROR"} +}; + +struct port_state ps_array_usb3[] = { + {0, 0, 0, 0, PORTSC_PLS_DISABLED, "Powered-OFF"}, + {1, 0, 0, 0, PORTSC_PLS_POLLING, "Polling"}, + {1, 0, 0, 0, PORTSC_PLS_U0, "Polling"}, + {1, 0, 0, 0, PORTSC_PLS_RXDETECT, "*** Disconnected ***"}, + {1, 0, 0, 0, PORTSC_PLS_DISABLED, "Disabled"}, + {1, 0, 0, 0, PORTSC_PLS_INACTIVE, "Error"}, + {1, 0, 0, 0, PORTSC_PLS_TEST_MODE,"Loopback"}, + {1, 0, 0, 0, PORTSC_PLS_COMP_MODE,"Compliancek"}, + {1, 1, 0, 1, PORTSC_PLS_U0, "****** Reset ******"}, + {1, 1, 1, 0, PORTSC_PLS_U0, "****** Enabled ******"}, +}; + +/* 5.4 Host Controller Operational Registers + * Table 26 + */ +struct xhci_op_regs { + uint32_t usbcmd; +#define XHCI_USBCMD_RS BIT(0) +#define XHCI_USBCMD_HCRST BIT(1) + + uint32_t usbsts; +#define XHCI_USBSTS_HCH BIT(0) +#define XHCI_USBSTS_CNR BIT(11) + + uint32_t pagesize; + uint8_t reserved[8]; /* 0C - 13 */ + uint32_t dnctrl; /* Device notification control */ + uint64_t crcr; /* Command ring control */ +#define XHCI_CRCR_CRP_MASK 0xFFFFFFFFFFFFFFC0 +#define XHCI_CRCR_CRR BIT(3) +#define XHCI_CRCR_CRP_SIZE 4096 + + uint8_t reserved1[16]; /* 20 - 2F */ + uint64_t dcbaap; /* Device Context Base Address Array Pointer */ +#define XHCI_DCBAAP_MAX_SIZE 2048 + + uint32_t config; /* Configure */ +#define XHCI_CONFIG_MAX_SLOT 4 + + uint8_t reserved2[964]; /* 3C - 3FF */ + /* USB Port register set */ +#define XHCI_PORT_MAX 256 + struct xhci_port_regs prs[XHCI_PORT_MAX]; +} __attribute__ ((packed)); + +/* + * 5.5.2 Interrupter Register Set + * Table 42: Interrupter Registers + */ +struct xhci_int_regs { + uint32_t iman; + uint32_t imod; + uint32_t erstsz; +#define XHCI_ERST_SIZE_MASK 0xFFFF + uint32_t reserved; + uint64_t erstba; +#define XHCI_ERST_ADDR_MASK (~(0x3FUL)) + uint64_t erdp; +#define XHCI_ERDP_MASK (~(0xFUL)) +} __attribute__ ((packed)); + +/* 5.5 Host Controller Runtime Registers */ +struct xhci_run_regs { + uint32_t mfindex; /* microframe index */ + uint8_t reserved[28]; +#define XHCI_IRS_MAX 1024 + struct xhci_int_regs irs[XHCI_IRS_MAX]; +} __attribute__ ((packed)); + +/* 5.6 Doorbell Registers*/ +struct xhci_db_regs { + uint32_t db[256]; +} __attribute__ ((packed)); + +#define COMP_SUCCESS 1 + +#define TRB_SLOT_ID(x) (((x) & (0xFF << 24)) >> 24) +#define TRB_CMD_SLOT_ID(x) ((x & 0xFF) << 24) +#define TRB_TYPE(x) (((x) & (0x3F << 10)) >> 10) +#define TRB_CMD_TYPE(x) ((x & 0x3F) << 10) +#define TRB_STATUS(x) (((x) & (0xFF << 24)) >> 24) +#define TRB_ADDR_LOW(x) ((uint32_t)((uint64_t)(x))) +#define TRB_ADDR_HIGH(x) ((uint32_t)((uint64_t)(x) >> 32)) +#define TRB_TRT(x) (((x) & 0x3) << 16 ) +#define TRB_DIR_IN BIT(16) +#define TRB_IOC BIT(5) +#define TRB_IDT BIT(6) + +#define TRB_CYCLE_STATE BIT(0) + +struct xhci_transfer_trb { + uint64_t addr; + uint32_t len; + uint32_t flags; +} __attribute__ ((packed)); + +struct xhci_link_trb { + uint64_t addr; + uint32_t field2; + uint32_t field3; +} __attribute__ ((packed)); + +/* Event TRB */ +struct xhci_event_trb { + uint64_t addr; + uint32_t status; + uint32_t flags; +} __attribute__ ((packed)); + +#define TRB_NORMAL 1 +#define TRB_SETUP_STAGE 2 +#define TRB_DATA_STAGE 3 +#define TRB_STATUS_STAGE 4 +#define TRB_ISOCH 5 +#define TRB_LINK 6 +#define TRB_EVENT_DATA 7 +#define TRB_NOOP 8 +#define TRB_ENABLE_SLOT 9 +#define TRB_DISABLE_SLOT 10 +#define TRB_ADDRESS_DEV 11 +#define TRB_CONFIG_EP 12 +#define TRB_EVAL_CNTX 13 +#define TRB_TRANSFER_EVENT 32 +#define TRB_CMD_COMPLETION 33 +#define TRB_PORT_STATUS 34 + +struct xhci_command_trb { + uint32_t field[4]; +}__attribute__ ((packed)); + +union xhci_trb { + struct xhci_event_trb event; + struct xhci_transfer_trb xfer; + struct xhci_command_trb cmd; + struct xhci_link_trb link; +}; + +enum xhci_seg_type { + TYPE_CTRL = 0, + TYPE_BULK, + TYPE_COMMAND, + TYPE_EVENT, +}; + +struct xhci_seg { + union xhci_trb *trbs; + struct xhci_seg *next; + uint64_t enq; + uint64_t deq; + uint64_t trbs_dma; + uint32_t size; + uint32_t cycle_state; + enum xhci_seg_type type; +}; + +#define XHCI_TRB_SIZE 16 +#define XHCI_EVENT_TRBS_SIZE 4096 +#define XHCI_CONTROL_TRBS_SIZE 4096 +#define XHCI_DATA_TRBS_SIZE 4096 +#define XHCI_ERST_NUM_SEGS 1 + +#define XHCI_MAX_BULK_SIZE 0xF000 + +struct xhci_erst_entry { + uint64_t addr; + uint32_t size; + uint32_t reserved; +} __attribute__ ((packed)); + +struct xhci_erst { + struct xhci_erst_entry *entries; + uint64_t dma; + uint32_t num_segs; /* number of segments */ +}; + +struct xhci_control_ctx { + uint32_t d_flags; + uint32_t a_flags; + uint32_t reserved[6]; +} __attribute__ ((packed)); + +struct xhci_slot_ctx { + uint32_t field1; +#define SLOT_SPEED_FS BIT(20) +#define SLOT_SPEED_LS BIT(21) +#define SLOT_SPEED_HS BIT(22) +#define SLOT_SPEED_SS BIT(23) +#define LAST_CONTEXT(x) (x << 27) + + uint32_t field2; +#define ROOT_HUB_PORT(x) ((x & 0xff) << 16) + + uint32_t field3; + uint32_t field4; +#define USB_DEV_ADDRESS(x) (x & 0xFFU) +#define SLOT_STATE(x) ((x >> 27) & 0x1FU) +#define SLOT_STATE_DIS_ENA 0 +#define SLOT_STATE_DEFAULT 1 +#define SLOT_STATE_ADDRESSED 2 +#define SLOT_STATE_CONFIGURED 3 + + + uint32_t reserved[4]; +} __attribute__ ((packed)); + +struct xhci_ep_ctx { + uint32_t field1; + uint32_t field2; +#define MAX_PACKET_SIZE(x) (((x) & 0xFFFF) << 16) +#define MAX_BURST(x) (((x) & 0xFF) << 8) +#define EP_TYPE(x) (((x) & 0x07) << 3) +#define EP_ISOC_OUT 1 +#define EP_BULK_OUT 2 +#define EP_INT_OUT 3 +#define EP_CTRL 4 +#define EP_ISOC_IN 5 +#define EP_BULK_IN 6 +#define EP_INT_IN 7 + +#define ERROR_COUNT(x) (((x) & 0x03) << 1) + + uint64_t deq_addr; + uint32_t field4; + uint32_t reserved[3]; +} __attribute__ ((packed)); + +struct xhci_ctx { + uint8_t type; +#define XHCI_CTX_TYPE_DEVICE 0x1 +#define XHCI_CTX_TYPE_INPUT 0x2 + uint32_t size; + uint8_t *addr; +#define XHCI_CTX_BUF_SIZE 4096 + uint64_t dma_addr; +}; + +struct xhci_dev { + struct usb_dev *dev; + uint32_t slot_id; + struct xhci_ctx in_ctx; + struct xhci_ctx out_ctx; + struct xhci_seg control; + struct xhci_seg bulk_in; + struct xhci_seg bulk_out; + uint32_t ctx_size; +}; + +struct xhci_hcd { + struct xhci_cap_regs *cap_regs; + struct xhci_op_regs *op_regs; + struct xhci_run_regs *run_regs; + struct xhci_db_regs *db_regs; + struct usb_hcd_dev *hcidev; + struct xhci_dev xdevs[XHCI_CONFIG_MAX_SLOT + 1]; + struct usb_pipe *freelist; + struct usb_pipe *end; + uint64_t *dcbaap; + uint64_t dcbaap_dma; + struct xhci_seg ering; + struct xhci_seg crseg; + struct xhci_erst erst; + uint64_t erds_dma; + uint32_t erds_size; + uint32_t slot_id; + uint32_t hcc_csz_64; + void *pool; +#define XHCI_PIPE_POOL_SIZE 4096 + + long pool_phys; +}; + +struct xhci_pipe { + struct usb_pipe pipe; + struct xhci_seg *seg; +}; + +#endif /* USB_XHCI_H */ diff --git a/qemu/roms/SLOF/lib/libusb/usb.code b/qemu/roms/SLOF/lib/libusb/usb.code new file mode 100644 index 000000000..fd92d9e78 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb.code @@ -0,0 +1,162 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * libusb bindings for SLOF - implementation + */ + +#include <usb.h> + + +/************************************************/ +/* Register with the usb-core */ +/* SLOF: USB-OHCI-REGISTER ( -- ) */ +/* LIBNEWUSB: usb_ohci_register(void) */ +/************************************************/ +PRIM(USB_X2d_OHCI_X2d_REGISTER) + usb_ohci_register(); +MIRP + +/************************************************/ +/* Register with the usb-core */ +/* SLOF: USB-EHCI-REGISTER ( -- ) */ +/* LIBNEWUSB: usb_ehci_register(void) */ +/************************************************/ +PRIM(USB_X2d_EHCI_X2d_REGISTER) + usb_ehci_register(); +MIRP + +/************************************************/ +/* Register with the usb-core */ +/* SLOF: USB-XHCI-REGISTER ( -- ) */ +/* LIBNEWUSB: usb_xhci_register(void) */ +/************************************************/ +PRIM(USB_X2d_XHCI_X2d_REGISTER) + usb_xhci_register(); +MIRP + +/************************************************/ +/* Initialize hcidev with the usb-core */ +/* SLOF: USB-HCD-INIT ( hcidev -- ) */ +/* LIBNEWUSB: usb_hcd_init(hcidev) */ +/************************************************/ +PRIM(USB_X2d_HCD_X2d_INIT) + void *hcidev = TOS.a; POP; + usb_hcd_init(hcidev); +MIRP + +/************************************************/ +/* Remove hcidev with the usb-core */ +/* SLOF: USB-HCD-EXIT ( hcidev -- ) */ +/* LIBNEWUSB: usb_hcd_exit(hcidev) */ +/************************************************/ +PRIM(USB_X2d_HCD_X2d_EXIT) + void *hcidev = TOS.a; POP; + usb_hcd_exit(hcidev); +MIRP + +/************************************************/ +/* Initialize hid */ +/* SLOF: USB-HID-INIT ( dev -- true | false )*/ +/* LIBNEWUSB: usb_hid_init(hcidev) */ +/************************************************/ +PRIM(USB_X2d_HID_X2d_INIT) + void *dev = TOS.a; + TOS.n = usb_hid_init(dev); +MIRP + +/************************************************/ +/* Exit hid */ +/* SLOF: USB-HID-EXIT ( dev -- true | false )*/ +/* LIBNEWUSB: usb_hid_exit(hcidev) */ +/************************************************/ +PRIM(USB_X2d_HID_X2d_EXIT) + void *dev = TOS.a; + TOS.n = usb_hid_exit(dev); +MIRP + +/************************************************/ +/* Read usb keyboard for key */ +/* SLOF: USB-READ-KEYB ( dev -- */ +/* ( key | false )) */ +/* LIBNEWUSB: usb_read_keyb */ +/************************************************/ +PRIM(USB_X2d_READ_X2d_KEYB) + void *dev = TOS.a; + TOS.n = usb_read_keyb(dev); +MIRP + +/************************************************/ +/* Is USB KEY available */ +/* SLOF: USB-KEY-AVAILABLE ( dev -- ( true | */ +/* false ))*/ +/* LIBNEWUSB: usb_key_available */ +/************************************************/ +PRIM(USB_X2d_KEY_X2d_AVAILABLE) + void *dev = TOS.a; + TOS.n = usb_key_available(dev); +MIRP + +/************************************************/ +/* Initialize and enumerate generic hub */ +/* SLOF: USB-HUB-INIT ( dev -- true | false ) */ +/* LIBNEWUSB: usb_hub_init */ +/************************************************/ +PRIM(USB_X2d_HUB_X2d_INIT) + void *dev = TOS.a; + TOS.n = usb_hub_init(dev); +MIRP + +/************************************************/ +/* Initialize msc */ +/* SLOF: USB-MSC-INIT ( dev -- true | false )*/ +/* LIBNEWUSB: usb_msc_init(hcidev) */ +/************************************************/ +PRIM(USB_X2d_MSC_X2d_INIT) + void *dev = TOS.a; + TOS.n = usb_msc_init(dev); +MIRP + +/************************************************/ +/* Exit msc */ +/* SLOF: USB-MSC-EXIT ( dev -- true | false )*/ +/* LIBNEWUSB: usb_msc_exit(hcidev) */ +/************************************************/ +PRIM(USB_X2d_MSC_X2d_EXIT) + void *dev = TOS.a; + TOS.n = usb_msc_exit(dev); +MIRP + +/*****************************************************************************/ +/* Transfer data through control endpoint */ +/* SLOF: USB-TRANSFER_CTRL ( dev req data -- true | false ) */ +/* LIBNEWUSB: int usb_transfer_ctrl(void *dev, void *req, void *data) */ +/*****************************************************************************/ +PRIM(USB_X2d_TRANSFER_X2d_CTRL) + void *data = TOS.a; POP; + void *req = TOS.a; POP; + TOS.n = usb_transfer_ctrl(TOS.a, req, data); +MIRP + +/*****************************************************************************/ +/* Transfer data through bulk endpoint */ +/* SLOF: USB-TRANSFER_BULK ( dev dir td td-phys data size -- true | false ) */ +/* LIBNEWUSB: int usb_transfer_bulk(void *dev, int dir, void *td, */ +/* void *td_phys, void *data, int size) */ +/*****************************************************************************/ +PRIM(USB_X2d_TRANSFER_X2d_BULK) + int size = TOS.u; POP; + void *data = TOS.a; POP; + void *td_phys = TOS.a; POP; + void *td = TOS.a; POP; + int dir = TOS.u; POP; + TOS.n = usb_transfer_bulk(TOS.a, dir, td, td_phys, data, size); +MIRP diff --git a/qemu/roms/SLOF/lib/libusb/usb.h b/qemu/roms/SLOF/lib/libusb/usb.h new file mode 100644 index 000000000..fba19d2a1 --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * Copyright (c) 2006, 2012, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * prototypes for libusb implementation used in libusb.code + */ + +#ifndef __LIBUSB_H +#define __LIBUSB_H + +/*******************************************/ +/* SLOF: USB-OHCI-REGISTER */ +/*******************************************/ +extern void usb_ohci_register(void); +/*******************************************/ +/* SLOF: USB-EHCI-REGISTER */ +/*******************************************/ +extern void usb_ehci_register(void); +/*******************************************/ +/* SLOF: USB-XHCI-REGISTER */ +/*******************************************/ +extern void usb_xhci_register(void); +/*******************************************/ +/* SLOF: USB-HCD-INIT */ +/*******************************************/ +extern void usb_hcd_init(void *hcidev); +/*******************************************/ +/* SLOF: USB-HCD-EXIT */ +/*******************************************/ +extern void usb_hcd_exit(void *hcidev); +/*******************************************/ +/* SLOF: USB-HID-INIT */ +/*******************************************/ +extern int usb_hid_init(void *dev); +/*******************************************/ +/* SLOF: USB-HID-EXIT */ +/*******************************************/ +extern int usb_hid_exit(void *dev); +/*******************************************/ +/* SLOF: USB-READ-KEYB */ +/*******************************************/ +extern unsigned char usb_read_keyb(void *dev); +/*******************************************/ +/* SLOF: USB-KEY-AVAILABLE */ +/*******************************************/ +extern unsigned char usb_key_available(void *dev); +/*******************************************/ +/* SLOF: USB-HUB-INIT */ +/*******************************************/ +extern unsigned int usb_hub_init(void *dev); +/*******************************************/ +/* SLOF: USB-MSC-INIT */ +/*******************************************/ +extern int usb_msc_init(void *dev); +/*******************************************/ +/* SLOF: USB-MSC-EXIT */ +/*******************************************/ +extern int usb_msc_exit(void *dev); +/*******************************************/ +/* SLOF: USB-TRANSFER-CTRL */ +/*******************************************/ +extern int usb_transfer_ctrl(void *dev, void *req, void *data); +/*******************************************/ +/* SLOF: USB-TRANSFER-BULK */ +/*******************************************/ +extern int usb_transfer_bulk(void *dev, int dir, void *td, + void *td_phys, void *data, int size); + +#endif diff --git a/qemu/roms/SLOF/lib/libusb/usb.in b/qemu/roms/SLOF/lib/libusb/usb.in new file mode 100644 index 000000000..7ceba7d2d --- /dev/null +++ b/qemu/roms/SLOF/lib/libusb/usb.in @@ -0,0 +1,29 @@ +/****************************************************************************** + * Copyright (c) 2007, 2012, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * libusb bindings for SLOF - definitions + */ + +cod(USB-OHCI-REGISTER) +cod(USB-EHCI-REGISTER) +cod(USB-XHCI-REGISTER) +cod(USB-HCD-INIT) +cod(USB-HCD-EXIT) +cod(USB-HID-INIT) +cod(USB-HID-EXIT) +cod(USB-READ-KEYB) +cod(USB-KEY-AVAILABLE) +cod(USB-HUB-INIT) +cod(USB-MSC-INIT) +cod(USB-MSC-EXIT) +cod(USB-TRANSFER-CTRL) +cod(USB-TRANSFER-BULK) diff --git a/qemu/roms/SLOF/lib/libveth/Makefile b/qemu/roms/SLOF/lib/libveth/Makefile new file mode 100644 index 000000000..dd1234af1 --- /dev/null +++ b/qemu/roms/SLOF/lib/libveth/Makefile @@ -0,0 +1,52 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) +CPPFLAGS += -I../libhvcall + +LDFLAGS = -nostdlib + +TARGET = ../libveth.a + + +all: $(TARGET) + +SRCS = veth.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/lib/libveth/veth.c b/qemu/roms/SLOF/lib/libveth/veth.c new file mode 100644 index 000000000..748730854 --- /dev/null +++ b/qemu/roms/SLOF/lib/libveth/veth.c @@ -0,0 +1,273 @@ +/****************************************************************************** + * Copyright (c) 2011, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <helpers.h> +#include "veth.h" +#include "libhvcall.h" + +#undef VETH_DEBUG +//#define VETH_DEBUG +#ifdef VETH_DEBUG +#define dprintf(_x ...) do { printf(_x); } while(0) +#else +#define dprintf(_x ...) +#endif + +/* *** WARNING: We pass our addresses as-is as DMA addresses, + * we -do- rely on the forth code to have enabled TCE bypass + * on our device ! + */ +#define vaddr_to_dma(vaddr) ((uint64_t)vaddr) + +struct ibmveth_buf_desc_fields { + uint32_t flags_len; +#define IBMVETH_BUF_VALID 0x80000000 +#define IBMVETH_BUF_TOGGLE 0x40000000 +#define IBMVETH_BUF_NO_CSUM 0x02000000 +#define IBMVETH_BUF_CSUM_GOOD 0x01000000 +#define IBMVETH_BUF_LEN_MASK 0x00FFFFFF + uint32_t address; +}; + +union ibmveth_buf_desc { + uint64_t desc; + struct ibmveth_buf_desc_fields fields; +}; + +struct ibmveth_rx_q_entry { + uint32_t flags_off; +#define IBMVETH_RXQ_TOGGLE 0x80000000 +#define IBMVETH_RXQ_TOGGLE_SHIFT 31 +#define IBMVETH_RXQ_VALID 0x40000000 +#define IBMVETH_RXQ_NO_CSUM 0x02000000 +#define IBMVETH_RXQ_CSUM_GOOD 0x01000000 +#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF + + uint32_t length; + uint64_t correlator; +}; + +static void *buffer_list; +static void *filter_list; +static uint64_t *rx_bufs; +static uint64_t *rx_bufs_aligned; +static uint32_t cur_rx_toggle; +static uint32_t cur_rx_index; + +#define RX_QUEUE_SIZE 256 +#define RX_BUF_SIZE 2048 +#define RX_BUF_MULT (RX_BUF_SIZE >> 3) + +static struct ibmveth_rx_q_entry *rx_queue; + +static inline uint64_t *veth_get_rx_buf(unsigned int i) +{ + return &rx_bufs_aligned[i * RX_BUF_MULT]; +} + +static int veth_init(net_driver_t *driver) +{ + char *mac_addr; + union ibmveth_buf_desc rxq_desc; + unsigned long rx_queue_len = sizeof(struct ibmveth_rx_q_entry) * + RX_QUEUE_SIZE; + unsigned int i; + long rc; + + if (!driver) + return -1; + + dprintf("veth_init(%02x:%02x:%02x:%02x:%02x:%02x)\n", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + + if (driver->running != 0) + return 0; + + mac_addr = (char *)driver->mac_addr; + cur_rx_toggle = IBMVETH_RXQ_TOGGLE; + cur_rx_index = 0; + buffer_list = SLOF_alloc_mem_aligned(8192, 4096); + filter_list = buffer_list + 4096; + rx_queue = SLOF_alloc_mem_aligned(rx_queue_len, 16); + rx_bufs = SLOF_alloc_mem(2048 * RX_QUEUE_SIZE + 4); + if (!buffer_list || !filter_list || !rx_queue || !rx_bufs) { + printf("veth: Failed to allocate memory !\n"); + goto fail; + } + rx_bufs_aligned = (uint64_t *)(((uint64_t)rx_bufs | 3) + 1); + rxq_desc.fields.address = vaddr_to_dma(rx_queue); + rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | rx_queue_len; + + rc = h_register_logical_lan(driver->reg, + vaddr_to_dma(buffer_list), + rxq_desc.desc, + vaddr_to_dma(filter_list), + (*(uint64_t *)mac_addr) >> 16); + if (rc != H_SUCCESS) { + printf("veth: Error %ld registering interface !\n", rc); + goto fail; + } + for (i = 0; i < RX_QUEUE_SIZE; i++) { + uint64_t *buf = veth_get_rx_buf(i); + union ibmveth_buf_desc desc; + *buf = (uint64_t)buf; + desc.fields.address = vaddr_to_dma(buf); + desc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE; + h_add_logical_lan_buffer(driver->reg, desc.desc); + } + + driver->running = 1; + + return 0; + fail: + if (buffer_list) + SLOF_free_mem(buffer_list, 8192); + if (rx_queue) + SLOF_free_mem(rx_queue, rx_queue_len); + if (rx_bufs) + SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4); + return -1; +} + +static int veth_term(net_driver_t *driver) +{ + dprintf("veth_term()\n"); + + if (driver->running == 0) + return 0; + + h_free_logical_lan(driver->reg); + + if (buffer_list) + SLOF_free_mem(buffer_list, 8192); + if (rx_queue) + SLOF_free_mem(rx_queue, sizeof(struct ibmveth_rx_q_entry) * RX_QUEUE_SIZE); + if (rx_bufs) + SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4); + + driver->running = 0; + + return 0; +} + +static int veth_receive(char *f_buffer_pc, int f_len_i, net_driver_t *driver) +{ + int packet = 0; + + dprintf("veth_receive()\n"); + + while(!packet) { + struct ibmveth_rx_q_entry *desc = &rx_queue[cur_rx_index]; + union ibmveth_buf_desc bdesc; + void *buf; + + buf = (void *)desc->correlator; + + if ((desc->flags_off & IBMVETH_RXQ_TOGGLE) != cur_rx_toggle) + break; + + if (!(desc->flags_off & IBMVETH_RXQ_VALID)) + goto recycle; + if (desc->length > f_len_i) { + printf("veth: Dropping too big packet [%d bytes]\n", + desc->length); + goto recycle; + } + + packet = desc->length; + memcpy(f_buffer_pc, + buf + (desc->flags_off & IBMVETH_RXQ_OFF_MASK), packet); + recycle: + bdesc.fields.address = vaddr_to_dma(buf); + bdesc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE; + h_add_logical_lan_buffer(driver->reg, bdesc.desc); + + cur_rx_index = (cur_rx_index + 1) % RX_QUEUE_SIZE; + if (cur_rx_index == 0) + cur_rx_toggle ^= IBMVETH_RXQ_TOGGLE; + } + + return packet; +} + +static int veth_xmit(char *f_buffer_pc, int f_len_i, net_driver_t *driver) +{ + union ibmveth_buf_desc tx_desc; + long rc; + + dprintf("veth_xmit(packet at %p, %d bytes)\n", f_buffer_pc, f_len_i); + + tx_desc.fields.address = vaddr_to_dma(f_buffer_pc); + tx_desc.fields.flags_len = IBMVETH_BUF_VALID | f_len_i; + + rc = hv_send_logical_lan(driver->reg, tx_desc.desc, 0, 0, 0, 0, 0); + if (rc != H_SUCCESS) { + printf("veth: Error %ld sending packet !\n", rc); + return -1; + } + + return f_len_i; +} + +net_driver_t *libveth_open(char *mac_addr, int mac_len, char *reg, int reg_len) +{ + net_driver_t *driver; + + driver = SLOF_alloc_mem(sizeof(*driver)); + if (!driver) { + printf("Unable to allocate veth driver\n"); + return NULL; + } + + /* veth uses a 8-byte wide property instead of 6-byte wide MACs */ + if ((mac_len == 8) && (mac_addr[0] == 0) && mac_addr[1] == 0) + mac_addr += 2; + memcpy(driver->mac_addr, mac_addr, 6); + driver->reg = *(uint32_t *)reg; + driver->running = 0; + + if (veth_init(driver)) { + SLOF_free_mem(driver, sizeof(*driver)); + return NULL; + } + + return driver; +} + +void libveth_close(net_driver_t *driver) +{ + if (driver) { + veth_term(driver); + SLOF_free_mem(driver, sizeof(*driver)); + } +} + +int libveth_read(char *buf, int len, net_driver_t *driver) +{ + if (buf) + return veth_receive(buf, len, driver); + + return -1; +} + +int libveth_write(char *buf, int len, net_driver_t *driver) +{ + if (buf) + return veth_xmit(buf, len, driver); + + return -1; +} diff --git a/qemu/roms/SLOF/lib/libveth/veth.code b/qemu/roms/SLOF/lib/libveth/veth.code new file mode 100644 index 000000000..76d14a968 --- /dev/null +++ b/qemu/roms/SLOF/lib/libveth/veth.code @@ -0,0 +1,61 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libveth Forth wrapper + */ + +#include <veth.h> + +// : libveth-open ( mac-addr-str len reg-str len -- false | [ driver true ] ) +PRIM(LIBVETH_X2d_OPEN) +{ + int reg_len = TOS.u; POP; + char *reg = TOS.a; POP; + int len = TOS.u; POP; + char *mac_addr = TOS.a; + + net_driver_t *net_driver = libveth_open(mac_addr, len, reg, reg_len); + if (net_driver) { + TOS.u = (unsigned long)net_driver; PUSH; + TOS.n = -1; + } else + TOS.n = 0; +} +MIRP + +// : libveth-close ( driver -- ) +PRIM(LIBVETH_X2d_CLOSE) +{ + net_driver_t *driver = TOS.a; POP; + libveth_close(driver); +} +MIRP + + +// : libveth-read ( addr len driver -- actual ) +PRIM(LIBVETH_X2d_READ) +{ + net_driver_t *driver = TOS.a; POP; + int len = TOS.u; POP; + TOS.n = libveth_read(TOS.a, len, driver); +} +MIRP + +// : libveth-write ( addr len driver -- actual ) +PRIM(LIBVETH_X2d_WRITE) +{ + net_driver_t *driver = TOS.a; POP; + int len = TOS.u; POP; + TOS.n = libveth_write(TOS.a, len, driver); +} +MIRP diff --git a/qemu/roms/SLOF/lib/libveth/veth.h b/qemu/roms/SLOF/lib/libveth/veth.h new file mode 100644 index 000000000..23af0eab6 --- /dev/null +++ b/qemu/roms/SLOF/lib/libveth/veth.h @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + ******************************************************************************/ + +#ifndef _VETH_H +#define _VETH_H + +#include <stdint.h> +#include <netdriver.h> + +extern net_driver_t *libveth_open(char *mac_addr, int mac_len, char *reg, int reg_len); +extern void libveth_close(net_driver_t *driver); +extern int libveth_read(char *buf, int len, net_driver_t *driver); +extern int libveth_write(char *buf, int len, net_driver_t *driver); + +#endif diff --git a/qemu/roms/SLOF/lib/libveth/veth.in b/qemu/roms/SLOF/lib/libveth/veth.in new file mode 100644 index 000000000..dc684fe9c --- /dev/null +++ b/qemu/roms/SLOF/lib/libveth/veth.in @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * libveth bindings for Forth - definitions + */ + +cod(LIBVETH-OPEN) +cod(LIBVETH-CLOSE) +cod(LIBVETH-READ) +cod(LIBVETH-WRITE) diff --git a/qemu/roms/SLOF/lib/libvirtio/Makefile b/qemu/roms/SLOF/lib/libvirtio/Makefile new file mode 100644 index 000000000..bd6a1fae4 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/Makefile @@ -0,0 +1,55 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +include $(TOPCMNDIR)/make.rules + +ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) +LDFLAGS = -nostdlib + +TARGET = ../libvirtio.a + + +all: $(TARGET) + +SRCS = virtio.c virtio-blk.c p9.c virtio-9p.c virtio-scsi.c virtio-net.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +%.o: %.S + $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep + diff --git a/qemu/roms/SLOF/lib/libvirtio/p9.c b/qemu/roms/SLOF/lib/libvirtio/p9.c new file mode 100644 index 000000000..a55662994 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/p9.c @@ -0,0 +1,575 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <byteorder.h> +#include "p9.h" + + +/* Protocol stack marshaling. */ +uint8_t *sp; + +#define GET_08(s,i) (s)[(i)] +#define GET_16(s,i) le16_to_cpu(*(uint16_t*)(&(s)[(i)])) +#define GET_32(s,i) le32_to_cpu(*(uint32_t*)(&(s)[(i)])) +#define GET_64(s,i) le64_to_cpu(*(uint64_t*)(&(s)[(i)])) + +#define SET_08(s,i,v) (s)[(i)] = (v) +#define SET_16(s,i,v) *(uint16_t*)(&(s)[(i)]) = cpu_to_le16(v) +#define SET_32(s,i,v) *(uint32_t*)(&(s)[(i)]) = cpu_to_le32(v) +#define SET_64(s,i,v) *(uint64_t*)(&(s)[(i)]) = cpu_to_le64(v) + +#define PUT_08(v) sp[0] = (v);sp+=1 +#define PUT_16(v) *(uint16_t*)(&sp[0]) = cpu_to_le16(v);sp+=2 +#define PUT_32(v) *(uint32_t*)(&sp[0]) = cpu_to_le32(v);sp+=4 +#define PUT_64(v) *(uint64_t*)(&sp[0]) = cpu_to_le64(v);sp+=8 + +#define PUT_HD(m,t) PUT_32(0);PUT_08(m);PUT_16(t) +#define PUT_SN(v,n) PUT_16(n);memcpy(sp,(v),(n));sp+=n +#define PUT_ST(v) PUT_16(strlen(v));memcpy(sp,(v),strlen(v));\ + sp+=strlen(v) + +#define GET_SIZE (sp - tx) + + +/* General defines. */ +#define MIN(a,b) ((a)>(b)?(b):(a)) + +#define NOTAG ((uint16_t)~0) +#define NOFID ((uint32_t)~0) +#define TAG 1 +#define BUF_SIZE (8*1024) + +#define VERSION "9P2000.u" +#define UNKNOWN_VER "unknown" + +#define MSG_SIZE 0 +#define MSG_ID 4 +#define MSG_ERR 0x6b +#define MSG_ERR_STR 9 +#define MSG_ERR_STR_LEN 7 +#define MSG_TAG 5 +#define MSG_VER_MSIZE 7 +#define MSG_VER_STR_LEN 11 +#define MSG_VER_STR 13 +#define MSG_WALK_TX_ELMT 15 +#define MSG_WALK_RX_ELMT 7 +#define MSG_SIZE 0 +#define MSG_WALK_MAX_ELMT 16 +#define MSG_QID_SIZE 13 +#define MSG_WALK_RX_HDR_SIZE 9 +#define MSG_OPEN_IOUNIT 20 +#define MSG_OPEN_MODE_MASK 0x5f +#define MSG_READ_COUNT 7 +#define MSG_READ_DATA 11 +#define MSG_STAT_LEN 42 +#define MSG_STAT_TYPE 17 + +#define T_VERSION 100 +#define R_VERSION (T_VERSION + 1) +#define T_ATTACH 104 +#define R_ATTACH (T_ATTACH + 1) +#define T_ERROR 106 +#define R_ERROR (T_ERROR + 1) +#define T_WALK 110 +#define R_WALK (T_WALK + 1) +#define T_OPEN 112 +#define R_OPEN (T_OPEN + 1) +#define T_READ 116 +#define R_READ (T_READ + 1) +#define T_CLUNK 120 +#define R_CLUNK (T_CLUNK + 1) +#define T_STAT 124 +#define R_STAT (T_STAT + 1) + +static p9_transact_t transact; +static void *transact_opaque; +static uint8_t *tx; +static uint8_t *rx; + + +/** + * p9_reg_transport + * + * Registers a transport function for use by the P9 protocol. The transport + * connects the P9 Client (this library) to a server instance. + * + * @param transact_func[in] Function pointer to type p9_transact_t. + * @param tx_buffer[in] TX buffer, must be 8k in size. + * @param rx_buffer[in] RX buffer, must be 8k in size. + */ +void p9_reg_transport(p9_transact_t transact_func, void *opaque, + uint8_t *tx_buffer, uint8_t *rx_buffer) +{ + transact = transact_func; + transact_opaque = opaque; + tx = tx_buffer; + rx = rx_buffer; +} + +/** + * reset_buffers + * + * Reset the RX and TX buffers to BUF_SIZE (8k) and reset the Stack Pointer + * for the TX buffer, which is referenced by the PUT_* macro's. + */ +void reset_buffers(void) +{ + memset(tx, 0, BUF_SIZE); + memset(rx, 0, BUF_SIZE); + sp = tx; +} + +/** + * p9_transaction + * + * Perform a transaction (send/recv) over the registered transport. + * + * @param connection[in|out] Connection object. + * @return 0 = success, -ve = error. + */ +int p9_transaction(p9_connection_t *connection) +{ + int rc; + int tx_size = GET_SIZE; + int rx_size = connection->message_size; + + if (transact == NULL) { + return P9_NO_TRANSPORT; + } + if (tx == NULL || rx == NULL) { + return P9_NO_BUFFER; + } + if (connection->message_size > BUF_SIZE) { + return P9_MSG_SIZE_TOO_BIG; + } + if (tx_size > connection->message_size) { + return P9_MSG_TOO_LONG; + } + + SET_32(tx, MSG_SIZE, tx_size); + rc = transact(transact_opaque, tx, tx_size, rx, &rx_size); + + if (rc != 0) { + return P9_TRANSPORT_ERROR; + } + if (GET_16(tx, MSG_TAG) != GET_16(rx, MSG_TAG)) { + return P9_UNEXPECTED_TAG; + } + if (GET_08(rx, MSG_ID) == MSG_ERR) { + char error_string[200]; + + memset(error_string, 0, 200); + strncpy(error_string, (char *)&rx[MSG_ERR_STR], + MIN(200 - 1, GET_16(rx, MSG_ERR_STR_LEN))); +#ifndef TEST + printf("\nError: %s\n", error_string); +#endif + return P9_R_ERROR; + } + if ((GET_08(tx, MSG_ID) + 1) != GET_08(rx, MSG_ID)) { + return P9_UNEXPECTED_MSG; + } + + return 0; +} + +/** + * p9_version + * + * Called to start a session. Negotiates the maximum message size for the + * P9 protocol. + * + * @param connection[in|out] Connection object, contains message_size. + * @return 0 = success, -ve = error. + * + * @remark + * size[4] Tversion tag[2] msize[4] version[s] + * size[4] Rversion tag[2] msize[4] version[s] + */ +int p9_version(p9_connection_t *connection) +{ + int rc; + char *ver_str; + int ver_len; + + reset_buffers(); + + /* Build message. */ + PUT_HD(T_VERSION, NOTAG); + PUT_32(connection->message_size); + PUT_ST(VERSION); + + /* Send message. */ + rc = p9_transaction(connection); + if (rc != 0) { + return rc; + } + + /* Handle response. */ + connection->message_size = MIN(connection->message_size, + GET_32(rx, MSG_VER_MSIZE)); + + ver_str = (char *)&rx[MSG_VER_STR]; + ver_len = GET_16(rx, MSG_VER_STR_LEN); + if (strncmp(UNKNOWN_VER, ver_str, ver_len) == 0) { + return P9_UNKNOWN_VERSION; + } + + + return 0; +} + +/** + * p9_attach + * + * Called to open a connection for a user to a file tree on the server. There + * is no authorisation undertaken (NOFID). + * + * @param connection[in|out] Connection object, contains uname and aname as + * well as the connection fid and returned qid. + * @return 0 = success, -ve = error. + * + * @remark + * size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] + * size[4] Rattach tag[2] qid[13] + */ +int p9_attach(p9_connection_t *connection) +{ + int rc; + int length = 19 + strlen(connection->uname) + strlen(connection->aname); + + if (length > connection->message_size) { + return P9_MSG_TOO_LONG; + } + + reset_buffers(); + + /* Build message. */ + PUT_HD(T_ATTACH, TAG); + PUT_32(connection->fid); + PUT_32(NOFID); + PUT_ST(connection->uname); + PUT_ST(connection->aname); + PUT_32(~0); /* ??? */ + + /* Send message. */ + rc = p9_transaction(connection); + if (rc != 0) { + return rc; + } + + + return 0; +} + +/** + * p9_clunk + * + * Called when closing a file or connection (or after failed opens). Tells the + * server that the supplied fid is no longer needed by this client. + * + * @param connection[in|out] Connection object. + * @param fid[in] Fid to be clunked (released) on the server. + * @return 0 = success, -ve = error. + * + * @remark + * size[4] Tclunk tag[2] fid[4] + * size[4] Rclunk tag[2] + */ +int p9_clunk(p9_connection_t *connection, uint32_t fid) +{ + int rc; + + reset_buffers(); + + /* Build message. */ + PUT_HD(T_CLUNK, TAG); + PUT_32(fid); + + /* Send message. */ + rc = p9_transaction(connection); + if (rc != 0) { + return rc; + } + + + return 0; +} + +/** + * p9_walk + * + * Walk the provided path to a file (or directory) starting at the directory + * indicated by fid and assigning new_fid to the last successfully walked + * element. If not all elements of the path can be walked then the pos + * pointer is set to the part of the path following the last successful + * walked element. The function can be called again to walk the remainder + * of the path (or produce an error). + * + * @param connection[in] Connection object. + * @param fid[in] Fid to start walk from, must be directory or root (from + * call to p9_attach). + * @param new_fid[in] Fid to be used for the last walked element. + * @param pos[in|out] Position in path that remains to be walked. If the + * path was completely walked without error this will point to the NULL + * at the end of path. + * @return 1 = partial walk, 0 = success, -ve = error. + * + * @remark + * size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) + * size[4] Rwalk tag[2] nwqid[2] nwqid*(qid[13]) + */ +int p9_walk(p9_connection_t *connection, uint32_t fid, uint32_t new_fid, + uint8_t **pos) +{ + int rc; + const char *path = (const char *)*pos; + uint8_t *s_tok; + uint8_t *e_tok; + int element_count = 0; + + if (path == NULL) { + *pos = NULL; + return P9_NULL_PATH; + } + + reset_buffers(); + + /* Build message. */ + PUT_HD(T_WALK, TAG); /* Length to 0, set later. */ + PUT_32(fid); + PUT_32(new_fid); + PUT_16(0); /* Element count to 0, set later. */ + + /* Get elements from path, and append to message. */ + s_tok = (uint8_t *)path; + e_tok = s_tok; + + while (*s_tok != 0) { + while (*s_tok == '/') { + s_tok++; + } + e_tok = s_tok; + while ((*e_tok != '/') && (*e_tok != 0)) { + e_tok++; + } + + /* Check the element is OK. */ + if (strncmp(".", (const char *)s_tok, (e_tok - s_tok)) == 0) { + /* Don't send ".", continue to next. */ + s_tok = e_tok; + continue; + } + int tx_size = (e_tok - s_tok + 2 + GET_SIZE); + int rx_size = ((element_count + 1) * MSG_QID_SIZE + + MSG_WALK_RX_HDR_SIZE); + if ((tx_size > connection->message_size) + || (rx_size > connection->message_size)) { + /* + * Element makes TX msg too long OR expected RX msg + * too long. Move pos to previous element and do + * partial walk. + */ + e_tok = s_tok; + if (*(e_tok - 1) == '/') { + e_tok--; + } + break; + } + + /* Add the element to the message. */ + PUT_SN(s_tok, e_tok - s_tok); + element_count++; + + /* Server supports no more than 16 elements, partial walk. */ + if (element_count == MSG_WALK_MAX_ELMT) { + break; + } + + /* Ready to find the next element. */ + s_tok = e_tok; + } + + if ((element_count == 0) && (strlen(path) > 0)) { + return P9_PATH_ELEMENT_TOO_LONG; + } + + *pos = e_tok; + + /* Update counts and then send message. */ + SET_16(tx, MSG_WALK_TX_ELMT, element_count); + rc = p9_transaction(connection); + if (rc != 0) { + return rc; + } + + /* Check for special return conditions. */ + if (element_count != GET_16(rx, MSG_WALK_RX_ELMT)) { + /* Find the last element successfully walked */ + s_tok = (uint8_t *)path; + e_tok = s_tok; + element_count = GET_16(rx, MSG_WALK_RX_ELMT); + + while (element_count--) { + while (*s_tok == '/') { + s_tok++; + } + + e_tok = s_tok; + + while ((*e_tok != '/') && (*e_tok != 0)) { + e_tok++; + } + + s_tok = e_tok; + } + + *pos = e_tok; + } + if (**pos != 0) { + rc = P9_PARTIAL_WALK; + } + + + return rc; +} + +/** + * p9_open + * + * Opens the file represented by fid with associated mode bit mask. The iounit + * size returned from the server is written to the connection object. + * + * @param file[in|out] File object, contains fid for file. + * @param mode[in] Mode to open with. Bit's 0=R, 1=W, 2=RW, 3=EX, 4=Trunc + * and 6=Delete on Close. + * @return 0 = success, -ve = error. + * + * @remark + * size[4] Topen tag[2] fid[4] mode[1] + * size[4] Ropen tag[2] qid[13] iounit[4] + */ +int p9_open(p9_file_t *file, uint8_t mode) +{ + int rc; + p9_connection_t *connection = file->connection; + + reset_buffers(); + file->iounit = 0; + + /* Build message. */ + PUT_HD(T_OPEN, TAG); + PUT_32(file->fid); + PUT_08(mode & MSG_OPEN_MODE_MASK); + + /* Send message. */ + rc = p9_transaction(connection); + if (rc != 0) { + return rc; + } + + /* Handle response. */ + file->iounit = GET_32(rx, MSG_OPEN_IOUNIT); + + + return 0; +} + +/** + * p9_read + * + * Reads the file in to buffer. + * + * @param file[in] File object, contains fid for file. + * @param buffer[out] Buffer for data. + * @param count[in] Number of bytes to read (less bytes than requested + * may be read). + * @param offset[in] Offset in file to read from. + * @return Bytes read, -ve = error. + * + * @remark + * size[4] Tread tag[2] fid[4] offset[8] count[4] + * size[4] Rread tag[2] count[4] data[count] + */ +int p9_read(p9_file_t *file, uint8_t *buffer, + uint32_t count, uint64_t offset) +{ + int rc; + p9_connection_t *connection = file->connection; + uint32_t got; + + reset_buffers(); + count = MIN((connection->message_size - MSG_READ_DATA), count); + + /* Build message. */ + PUT_HD(T_READ, TAG); + PUT_32(file->fid); + PUT_64(offset); + PUT_32(count); + + /* Send message. */ + rc = p9_transaction(connection); + if (rc != 0) { + return rc; + } + got = GET_32(rx, MSG_READ_COUNT); + if (got > count) { + return P9_READ_UNEXPECTED_DATA; + } + + /* Handle response. */ + memcpy(buffer, &rx[MSG_READ_DATA], got); + + return got; +} + +/** + * p9_stat + * + * Stat's the fid and writes the type and length to the file object. + * + * @param file[in|out] File object, contains fid for file. + * @return 0 = success, -ve = error. + * + * @remark + * size[4] Tstat tag[2] fid[4] + * size[4] Rstat tag[2] size[2] stat[n] + */ +int p9_stat(p9_file_t *file) +{ + int rc; + p9_connection_t *connection = file->connection; + + reset_buffers(); + file->length = 0; + file->type = 0; + + /* Build message. */ + PUT_HD(T_STAT, TAG); + PUT_32(file->fid); + + /* Send message. */ + rc = p9_transaction(connection); + if (rc != 0) { + return rc; + } + + /* Handle response. */ + file->length = GET_64(rx, MSG_STAT_LEN); + file->type = GET_08(rx, MSG_STAT_TYPE); + + + return 0; +} diff --git a/qemu/roms/SLOF/lib/libvirtio/p9.h b/qemu/roms/SLOF/lib/libvirtio/p9.h new file mode 100644 index 000000000..7df9ef441 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/p9.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef P9_H +#define P9_H + +#include <stdint.h> + + +#define P9_ERROR -1 +#define P9_UNKNOWN_VERSION -2 +#define P9_R_ERROR -3 +#define P9_MSG_TOO_LONG -4 +#define P9_UNEXPECTED_MSG -5 +#define P9_UNEXPECTED_TAG -6 +#define P9_TRANSPORT_ERROR -7 +#define P9_NO_TRANSPORT -8 +#define P9_NULL_PATH -9 +#define P9_PATH_ELEMENT_TOO_LONG -10 +#define P9_READ_UNEXPECTED_DATA -11 +#define P9_NO_BUFFER -12 +#define P9_MSG_SIZE_TOO_BIG -13 + +#define P9_PARTIAL_WALK 1 + +typedef int (*p9_transact_t)(void *opaque, uint8_t *tx, int tx_size, + uint8_t *rx, int *rx_size); + +typedef struct { + uint32_t message_size; + char *uname; /* User name. */ + char *aname; /* Tree/mount name/path. */ + uint32_t fid; /* Represents mount point. */ +} p9_connection_t; + +typedef struct { + uint32_t fid; /* Identifies the file to P9 server. */ + uint32_t iounit; /* Maximum read size in bytes. */ + uint8_t type; /* Type of file. */ + uint64_t length; /* Length of file. */ + p9_connection_t *connection; +} p9_file_t; + + +void reset_buffers(void); +void p9_reg_transport(p9_transact_t transact_func, void *opaque, + uint8_t *tx_buffer, uint8_t *rx_buffer); +int p9_transaction(p9_connection_t *connection); +int p9_version(p9_connection_t *connection); +int p9_attach(p9_connection_t *connection); +int p9_clunk(p9_connection_t *connection, uint32_t fid); +int p9_walk(p9_connection_t *connection, uint32_t fid, uint32_t new_fid, + uint8_t **pos); +int p9_open(p9_file_t *file, uint8_t mode); +int p9_read(p9_file_t *file, uint8_t *buffer, + uint32_t count, uint64_t offset); +int p9_stat(p9_file_t *file); + +#endif diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c new file mode 100644 index 000000000..5a5fd01da --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c @@ -0,0 +1,336 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <byteorder.h> +#include <cpu.h> + +#include "virtio-9p.h" +#include "p9.h" + + +/** + * Notes for 9P Server config: + * + * make distclean; cm make qemu + * sudo cp boot_rom.bin /opt/qemu/share/qemu/slof.bin + * /opt/qemu/bin/qemu-system-ppc64 -M pseries -m 512 -boot d -nographic -fsdev + * local,id=trule,path=/home/trule/virtfs,security_model=none -device + * virtio-9p-spapr,fsdev=trule,mount_tag=trule + * load virtfs:\some\file + */ + +/* We support only one instance due to the (ab)use of globals. We + * use the buffer size as an open marker as well. + */ +static int __buf_size; + + +#define ROOT_FID 1 +#define FILE_FID 2 +#define TAG_SIZE 128 +#define MIN(a,b) ((a)>(b)?(b):(a)) + + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +#define dprintf(_x ...) do { printf(_x); } while(0) +#else +#define dprintf(_x ...) +#endif + +#ifdef DEBUG +static void dprint_buffer(const char *name, uint8_t *buffer, int length) +{ + int i; + + printf("*** %s ***", name); + + for (i = 0; i < length; i++) { + if (i % 16 == 0) { + printf("\n %04x:", i); + } + + printf(" %02x", buffer[i]); + } + + printf("\n"); +} +#else +#define dprint_buffer(n, b, l) +#endif + +/** + * virtio_9p_transact + * + * Perform a 9P transaction over the VIRTIO queue interface. This function is + * registered with the p9.c library via p9_reg_transport() to provide + * connectivity to the 9P server. + * + * @param tx[in] Data to send, mapped to first queue item. + * @param tx_size[in] Size of data to send. + * @param rx[out] Data to receive, mappend to second queue item. + * @param rx_size[out] Size of data received. + * @return 0 = success, -ve = error. + */ +static int virtio_9p_transact(void *opaque, uint8_t *tx, int tx_size, uint8_t *rx, + int *rx_size) +{ + struct virtio_device *dev = opaque; + struct vring_desc *desc; + int id, i; + uint32_t vq_size; + struct vring_desc *vq_desc; + struct vring_avail *vq_avail; + struct vring_used *vq_used; + volatile uint16_t *current_used_idx; + uint16_t last_used_idx; + + + /* Virt IO queues. */ + vq_size = virtio_get_qsize(dev, 0); + vq_desc = virtio_get_vring_desc(dev, 0); + vq_avail = virtio_get_vring_avail(dev, 0); + vq_used = virtio_get_vring_used(dev, 0); + + last_used_idx = vq_used->idx; + current_used_idx = &vq_used->idx; + + /* Determine descriptor index */ + id = (vq_avail->idx * 3) % vq_size; + + /* TX in first queue item. */ + dprint_buffer("TX", tx, tx_size); + + desc = &vq_desc[id]; + desc->addr = (uint64_t)tx; + desc->len = tx_size; + desc->flags = VRING_DESC_F_NEXT; + desc->next = (id + 1) % vq_size; + + /* RX in the second queue item. */ + desc = &vq_desc[(id + 1) % vq_size]; + desc->addr = (uint64_t)rx; + desc->len = *rx_size; + desc->flags = VRING_DESC_F_WRITE; + desc->next = 0; + + /* Tell HV that the queue is ready */ + vq_avail->ring[vq_avail->idx % vq_size] = id; + mb(); + vq_avail->idx += 1; + virtio_queue_notify(dev, 0); + + /* Receive the response. */ + i = 10000000; + while (*current_used_idx == last_used_idx && i-- > 0) { + // do something better + mb(); + } + if (i == 0) { + return -1; + } + + *rx_size = MIN(*rx_size, le32_to_cpu(*(uint32_t*)(&rx[0]))); + dprint_buffer("RX", rx, *rx_size); + + return 0; +} + +/** + * virtio_9p_init + * + * Establish the VIRTIO connection for use with the 9P server. Setup queues + * and negotiate capabilities. Setup the 9P (Client) library. + * + * @param reg[in] Pointer to device tree node for VIRTIO/9P interface. + * @param tx_buf[in] TX buffer for use by 9P Client lib - 8K in size. + * @param rx_buf[in] TX buffer for use by 9P Client lib - 8K in size. + * @param buf_size Somewhat redundant, buffer size expected to be 8k. + * @return 0 = success, -ve = error. + */ +int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf, + int buf_size) +{ + struct vring_avail *vq_avail; + + /* Check for double open */ + if (__buf_size) + return -1; + __buf_size = buf_size; + + dprintf("%s : device at %p\n", __func__, dev->base); + dprintf("%s : type is %04x\n", __func__, dev->type); + + /* Reset device */ + // XXX That will clear the virtq base. We need to move + // initializing it to here anyway + // + // virtio_reset_device(dev); + + /* Acknowledge device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); + + /* Tell HV that we know how to drive the device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER); + + /* Device specific setup - we do not support special features */ + virtio_set_guest_features(dev, 0); + + vq_avail = virtio_get_vring_avail(dev, 0); + vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; + vq_avail->idx = 0; + + /* Tell HV that setup succeeded */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER + |VIRTIO_STAT_DRIVER_OK); + + /* Setup 9P library. */ + p9_reg_transport(virtio_9p_transact, dev,(uint8_t *)tx_buf, + (uint8_t *)rx_buf); + + dprintf("%s : complete\n", __func__); + return 0; +} + +/** + * virtio_9p_shutdown + */ +void virtio_9p_shutdown(struct virtio_device *dev) +{ + /* Quiesce device */ + virtio_set_status(dev, VIRTIO_STAT_FAILED); + + /* Reset device */ + virtio_reset_device(dev); + + __buf_size = 0; +} + +/** + * virtio_9p_load + * + * Read a file from the 9P Server on the VIRTIO interface. + * + * @param file_name[in] File to read, use Linux style paths. + * @param buffer[out] Where to read the file to. + * @return +ve = amount of data read, -ve = error. + */ +int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer) +{ + int rc; + uint16_t tag_len; + char tag_name[TAG_SIZE]; + uint64_t offset = 0; + uint8_t *pos = (uint8_t *)file_name; + int start_fid = ROOT_FID; + p9_connection_t connection = { + .message_size = __buf_size, + .fid = ROOT_FID, + .uname = "slof" + }; + p9_file_t file = { + .connection = &connection, + .fid = FILE_FID, + }; + + + /* Get the share name from 9P config space. */ + tag_len = virtio_get_config(dev, 0, sizeof(tag_len)); + if (tag_len >= TAG_SIZE) + tag_len = TAG_SIZE - 1; + __virtio_read_config(dev, tag_name, 2, tag_len); + connection.aname = tag_name; + + /* Connect to the 9P server. */ + dprintf("%s : connecting, tag = %s, user = %s, msgsize = %d\n", + __func__, connection.aname, connection.uname, + connection.message_size); + rc = p9_version(&connection); + if (rc != 0) { + printf("Version check failed, rc = %d\n", rc); + goto cleanup_connection; + } + rc = p9_attach(&connection); + if (rc != 0) { + printf("Attach failed, rc = %d\n", rc); + goto cleanup_connection; + } + dprintf("%s : connected, msgsize = %d\n", __func__, + connection.message_size); + + /* Walk to the file. */ + do { + dprintf("%s : walk path %s\n", __func__, pos); + rc = p9_walk(&connection, start_fid, FILE_FID, &pos); + + if (rc < 0) { /* Some error. */ + printf("Walk failed, rc = %d\n", rc); + goto cleanup_connection; + } + + /* + * If partial walk (*pos != 0) then continue the walk from + * mid point with start_fid updated to current position + * FILE_FID. FILE_FID will then be reused for the result of + * the next call to walk. + */ + start_fid = FILE_FID; + } while (*pos != 0); + + /* Open the file. */ + dprintf("%s : stat and open\n", __func__); + rc = p9_stat(&file); + if (rc != 0) { + printf("Stat failed, rc = %d\n", rc); + goto cleanup_file; + } + rc = p9_open(&file, 0x00); /* TODO find include for "read mode" */ + if (rc != 0) { + printf("Open failed, rc = %d\n", rc); + goto cleanup_file; + } + dprintf("%s : file opened, size %lld\n", __func__, file.length); + + /* Read the file contents to buffer. */ + while (offset < file.length) { + dprintf("%s : read from offset %llu\n", __func__, offset); + rc = p9_read(&file, buffer + offset, + file.length - offset, offset); + dprintf("%s : read done, length was %d\n", __func__, rc); + if (rc < 0) { + printf("Read failed, rc = %d\n", rc); + goto cleanup_file; + } + if (rc == 0) { + break; + } + offset += rc; + rc = 0; + } + + /* Cleanup and disconnect. */ +cleanup_file: + dprintf("%s : clunking file\n", __func__); + p9_clunk(&connection, file.fid); + +cleanup_connection: + dprintf("%s : clunking connection\n", __func__); + p9_clunk(&connection, connection.fid); + + + dprintf("%s : complete, read %llu bytes\n", __func__, offset); + return rc == 0 ? offset : rc; +} diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h new file mode 100644 index 000000000..4bf47d078 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef VIRTIO_9P_H_ +#define VIRTIO_9P_H_ + +#include <stdint.h> + +#include "virtio.h" + +#if 0 +typedef struct { + uint16_t tag_lenth; + char tag[0]; +} virtio_9p_config_t; +#endif +int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf, + int buf_size); +void virtio_9p_shutdown(struct virtio_device *dev); +int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer); + + +#endif /* VIRTIO_9P_H_ */ diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c new file mode 100644 index 000000000..826f2ea0e --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c @@ -0,0 +1,185 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <cpu.h> +#include <helpers.h> +#include "virtio.h" +#include "virtio-blk.h" + +#define DEFAULT_SECTOR_SIZE 512 + +/** + * Initialize virtio-block device. + * @param dev pointer to virtio device information + */ +int +virtioblk_init(struct virtio_device *dev) +{ + struct vring_avail *vq_avail; + int blk_size = DEFAULT_SECTOR_SIZE; + int features; + + /* Reset device */ + // XXX That will clear the virtq base. We need to move + // initializing it to here anyway + // + // virtio_reset_device(dev); + + /* Acknowledge device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); + + /* Tell HV that we know how to drive the device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); + + /* Device specific setup - we support F_BLK_SIZE */ + virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE); + + vq_avail = virtio_get_vring_avail(dev, 0); + vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; + vq_avail->idx = 0; + + /* Tell HV that setup succeeded */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER + |VIRTIO_STAT_DRIVER_OK); + + virtio_get_host_features(dev, &features); + if (features & VIRTIO_BLK_F_BLK_SIZE) { + blk_size = virtio_get_config(dev, + offset_of(struct virtio_blk_cfg, blk_size), + sizeof(blk_size)); + } + + return blk_size; +} + + +/** + * Shutdown the virtio-block device. + * @param dev pointer to virtio device information + */ +void +virtioblk_shutdown(struct virtio_device *dev) +{ + /* Quiesce device */ + virtio_set_status(dev, VIRTIO_STAT_FAILED); + + /* Reset device */ + virtio_reset_device(dev); +} + + +/** + * Read blocks + * @param reg pointer to "reg" property + * @param buf pointer to destination buffer + * @param blocknum block number of the first block that should be read + * @param cnt amount of blocks that should be read + * @return number of blocks that have been read successfully + */ +int +virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt) +{ + struct vring_desc *desc; + int id; + static struct virtio_blk_req blkhdr; + //struct virtio_blk_config *blkconf; + uint64_t capacity; + uint32_t vq_size, time; + struct vring_desc *vq_desc; /* Descriptor vring */ + struct vring_avail *vq_avail; /* "Available" vring */ + struct vring_used *vq_used; /* "Used" vring */ + volatile uint8_t status = -1; + volatile uint16_t *current_used_idx; + uint16_t last_used_idx; + int blk_size = DEFAULT_SECTOR_SIZE; + + //printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n", + // dev, buf, blocknum, cnt); + + /* Check whether request is within disk capacity */ + capacity = virtio_get_config(dev, + offset_of(struct virtio_blk_cfg, capacity), + sizeof(capacity)); + if (blocknum + cnt - 1 > capacity) { + puts("virtioblk_read: Access beyond end of device!"); + return 0; + } + + blk_size = virtio_get_config(dev, + offset_of(struct virtio_blk_cfg, blk_size), + sizeof(blk_size)); + if (blk_size % DEFAULT_SECTOR_SIZE) { + fprintf(stderr, "virtio-blk: Unaligned sector read %d\n", blk_size); + return 0; + } + + vq_size = virtio_get_qsize(dev, 0); + vq_desc = virtio_get_vring_desc(dev, 0); + vq_avail = virtio_get_vring_avail(dev, 0); + vq_used = virtio_get_vring_used(dev, 0); + + last_used_idx = vq_used->idx; + current_used_idx = &vq_used->idx; + + /* Set up header */ + blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER; + blkhdr.ioprio = 1; + blkhdr.sector = blocknum * blk_size / DEFAULT_SECTOR_SIZE; + + /* Determine descriptor index */ + id = (vq_avail->idx * 3) % vq_size; + + /* Set up virtqueue descriptor for header */ + desc = &vq_desc[id]; + desc->addr = (uint64_t)&blkhdr; + desc->len = sizeof(struct virtio_blk_req); + desc->flags = VRING_DESC_F_NEXT; + desc->next = (id + 1) % vq_size; + + /* Set up virtqueue descriptor for data */ + desc = &vq_desc[(id + 1) % vq_size]; + desc->addr = (uint64_t)buf; + desc->len = cnt * blk_size; + desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; + desc->next = (id + 2) % vq_size; + + /* Set up virtqueue descriptor for status */ + desc = &vq_desc[(id + 2) % vq_size]; + desc->addr = (uint64_t)&status; + desc->len = 1; + desc->flags = VRING_DESC_F_WRITE; + desc->next = 0; + + vq_avail->ring[vq_avail->idx % vq_size] = id; + mb(); + vq_avail->idx += 1; + + /* Tell HV that the queue is ready */ + virtio_queue_notify(dev, 0); + + /* Wait for host to consume the descriptor */ + time = SLOF_GetTimer() + VIRTIO_TIMEOUT; + while (*current_used_idx == last_used_idx) { + // do something better + mb(); + if (time < SLOF_GetTimer()) + break; + } + + if (status == 0) + return cnt; + + printf("virtioblk_read failed! status = %i\n", status); + + return 0; +} diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h new file mode 100644 index 000000000..ac8bf2896 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * Virtio block device definitions. + * See Virtio Spec, Appendix D, for details + */ + +#ifndef _VIRTIO_BLK_H +#define _VIRTIO_BLK_H + +#include <stdint.h> + + +struct virtio_blk_cfg { + uint64_t capacity; + uint32_t size_max; + uint32_t seg_max; + struct virtio_blk_geometry { + uint16_t cylinders; + uint8_t heads; + uint8_t sectors; + } geometry; + uint32_t blk_size; + uint32_t sectors_max; +} __attribute__ ((packed)) ; + +/* Block request */ +struct virtio_blk_req { + uint32_t type ; + uint32_t ioprio ; + uint64_t sector ; +}; + +/* Block request types */ +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 +#define VIRTIO_BLK_T_SCSI_CMD 2 +#define VIRTIO_BLK_T_SCSI_CMD_OUT 3 +#define VIRTIO_BLK_T_FLUSH 4 +#define VIRTIO_BLK_T_FLUSH_OUT 5 +#define VIRTIO_BLK_T_BARRIER 0x80000000 + +/* VIRTIO_BLK Feature bits */ +#define VIRTIO_BLK_F_BLK_SIZE (1 << 6) + +extern int virtioblk_init(struct virtio_device *dev); +extern void virtioblk_shutdown(struct virtio_device *dev); +extern int virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt); + +#endif /* _VIRTIO_BLK_H */ diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-net.c b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c new file mode 100644 index 000000000..99c19d952 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c @@ -0,0 +1,369 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * This is the implementation for the Virtio network device driver. Details + * about the virtio-net interface can be found in Rusty Russel's "Virtio PCI + * Card Specification v0.8.10", appendix C, which can be found here: + * + * http://ozlabs.org/~rusty/virtio-spec/virtio-spec.pdf + */ + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <helpers.h> +#include <cache.h> +#include <byteorder.h> +#include "virtio.h" +#include "virtio-net.h" + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +# define dprintf(fmt...) do { printf(fmt); } while(0) +#else +# define dprintf(fmt...) +#endif + +#define sync() asm volatile (" sync \n" ::: "memory") + +/* PCI virtio header offsets */ +#define VIRTIOHDR_DEVICE_FEATURES 0 +#define VIRTIOHDR_GUEST_FEATURES 4 +#define VIRTIOHDR_QUEUE_ADDRESS 8 +#define VIRTIOHDR_QUEUE_SIZE 12 +#define VIRTIOHDR_QUEUE_SELECT 14 +#define VIRTIOHDR_QUEUE_NOTIFY 16 +#define VIRTIOHDR_DEVICE_STATUS 18 +#define VIRTIOHDR_ISR_STATUS 19 +#define VIRTIOHDR_DEVICE_CONFIG 20 +#define VIRTIOHDR_MAC_ADDRESS 20 + +struct virtio_device virtiodev; +struct vqs vq[2]; /* Information about virtqueues */ + +/* See Virtio Spec, appendix C, "Device Operation" */ +struct virtio_net_hdr { + uint8_t flags; + uint8_t gso_type; + uint16_t hdr_len; + uint16_t gso_size; + uint16_t csum_start; + uint16_t csum_offset; + // uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */ +}; + +static uint16_t last_rx_idx; /* Last index in RX "used" ring */ + +/** + * Module init for virtio via PCI. + * Checks whether we're reponsible for the given device and set up + * the virtqueue configuration. + */ +static int virtionet_init_pci(struct virtio_device *dev) +{ + int i; + + dprintf("virtionet: doing virtionet_init_pci!\n"); + + if (!dev) + return -1; + + virtiodev.base = dev->base; + virtiodev.type = dev->type; + + /* Reset device */ + virtio_reset_device(&virtiodev); + + /* The queue information can be retrieved via the virtio header that + * can be found in the I/O BAR. First queue is the receive queue, + * second the transmit queue, and the forth is the control queue for + * networking options. + * We are only interested in the receive and transmit queue here. */ + + for (i=VQ_RX; i<=VQ_TX; i++) { + /* Select ring (0=RX, 1=TX): */ + vq[i].id = i-VQ_RX; + ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT, + cpu_to_le16(vq[i].id)); + + vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE)); + vq[i].desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq[i].size), 4096); + if (!vq[i].desc) { + printf("memory allocation failed!\n"); + return -1; + } + memset(vq[i].desc, 0, virtio_vring_size(vq[i].size)); + ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS, + cpu_to_le32((long)vq[i].desc / 4096)); + vq[i].avail = (void*)vq[i].desc + + vq[i].size * sizeof(struct vring_desc); + vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail + + vq[i].size * sizeof(struct vring_avail)); + + dprintf("%i: vq.id = %llx\nvq.size =%x\n vq.avail =%p\nvq.used=%p\n", + i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used); + } + + /* Acknowledge device. */ + virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE); + + return 0; +} + +/** + * Initialize the virtio-net device. + * See the Virtio Spec, chapter 2.2.1 and Appendix C "Device Initialization" + * for details. + */ +static int virtionet_init(net_driver_t *driver) +{ + int i; + + dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n", + driver->mac_addr[0], driver->mac_addr[1], + driver->mac_addr[2], driver->mac_addr[3], + driver->mac_addr[4], driver->mac_addr[5]); + + if (driver->running != 0) + return 0; + + /* Tell HV that we know how to drive the device. */ + virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); + + /* Device specific setup - we do not support special features right now */ + virtio_set_guest_features(&virtiodev, 0); + + /* Allocate memory for one transmit an multiple receive buffers */ + vq[VQ_RX].buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)) + * RX_QUEUE_SIZE); + if (!vq[VQ_RX].buf_mem) { + printf("virtionet: Failed to allocate buffers!\n"); + virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED); + return -1; + } + + /* Prepare receive buffer queue */ + for (i = 0; i < RX_QUEUE_SIZE; i++) { + struct vring_desc *desc; + /* Descriptor for net_hdr: */ + desc = &vq[VQ_RX].desc[i*2]; + desc->addr = (uint64_t)vq[VQ_RX].buf_mem + + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)); + desc->len = sizeof(struct virtio_net_hdr); + desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; + desc->next = i*2+1; + + /* Descriptor for data: */ + desc = &vq[VQ_RX].desc[i*2+1]; + desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr); + desc->len = BUFFER_ENTRY_SIZE; + desc->flags = VRING_DESC_F_WRITE; + desc->next = 0; + + vq[VQ_RX].avail->ring[i] = i*2; + } + sync(); + vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; + vq[VQ_RX].avail->idx = RX_QUEUE_SIZE; + + last_rx_idx = vq[VQ_RX].used->idx; + + vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; + vq[VQ_TX].avail->idx = 0; + + /* Tell HV that setup succeeded */ + virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE + |VIRTIO_STAT_DRIVER + |VIRTIO_STAT_DRIVER_OK); + + /* Tell HV that RX queues are ready */ + virtio_queue_notify(&virtiodev, VQ_RX); + + driver->running = 1; + + return 0; +} + + +/** + * Shutdown driver. + * We've got to make sure that the hosts stops all transfers since the buffers + * in our main memory will become invalid after this module has been terminated. + */ +static int virtionet_term(net_driver_t *driver) +{ + dprintf("virtionet_term()\n"); + + if (driver->running == 0) + return 0; + + /* Quiesce device */ + virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED); + + /* Reset device */ + virtio_reset_device(&virtiodev); + + driver->running = 0; + + return 0; +} + + +/** + * Transmit a packet + */ +static int virtionet_xmit(char *buf, int len) +{ + struct vring_desc *desc; + int id; + static struct virtio_net_hdr nethdr; + + if (len > BUFFER_ENTRY_SIZE) { + printf("virtionet: Packet too big!\n"); + return 0; + } + + dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len); + + memset(&nethdr, 0, sizeof(nethdr)); + + /* Determine descriptor index */ + id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size; + + /* Set up virtqueue descriptor for header */ + desc = &vq[VQ_TX].desc[id]; + desc->addr = (uint64_t)&nethdr; + desc->len = sizeof(struct virtio_net_hdr); + desc->flags = VRING_DESC_F_NEXT; + desc->next = id + 1; + + /* Set up virtqueue descriptor for data */ + desc = &vq[VQ_TX].desc[id+1]; + desc->addr = (uint64_t)buf; + desc->len = len; + desc->flags = 0; + desc->next = 0; + + vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id; + sync(); + vq[VQ_TX].avail->idx += 1; + sync(); + + /* Tell HV that TX queue is ready */ + virtio_queue_notify(&virtiodev, VQ_TX); + + return len; +} + + +/** + * Receive a packet + */ +static int virtionet_receive(char *buf, int maxlen) +{ + int len = 0; + int id; + + if (last_rx_idx == vq[VQ_RX].used->idx) { + /* Nothing received yet */ + return 0; + } + + id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1) + % vq[VQ_RX].size; + len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len + - sizeof(struct virtio_net_hdr); + + dprintf("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i," + " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len); + + if (len > maxlen) { + printf("virtio-net: Receive buffer not big enough!\n"); + len = maxlen; + } + +#if 0 + /* Dump packet */ + printf("\n"); + int i; + for (i=0; i<64; i++) { + printf(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i)); + if ((i%16)==15) + printf("\n"); + } + prinfk("\n"); +#endif + + /* Copy data to destination buffer */ + memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len); + + /* Move indices to next entries */ + last_rx_idx = last_rx_idx + 1; + + vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1; + sync(); + vq[VQ_RX].avail->idx += 1; + + /* Tell HV that RX queue entry is ready */ + virtio_queue_notify(&virtiodev, VQ_RX); + + return len; +} + +net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev) +{ + net_driver_t *driver; + + driver = SLOF_alloc_mem(sizeof(*driver)); + if (!driver) { + printf("Unable to allocate virtio-net driver\n"); + return NULL; + } + + memcpy(driver->mac_addr, mac_addr, 6); + driver->running = 0; + + if (virtionet_init_pci(dev)) + goto FAIL; + + if (virtionet_init(driver)) + goto FAIL; + + return driver; + +FAIL: SLOF_free_mem(driver, sizeof(*driver)); + return NULL; +} + +void virtionet_close(net_driver_t *driver) +{ + if (driver) { + virtionet_term(driver); + SLOF_free_mem(driver, sizeof(*driver)); + } +} + +int virtionet_read(char *buf, int len) +{ + if (buf) + return virtionet_receive(buf, len); + return -1; +} + +int virtionet_write(char *buf, int len) +{ + if (buf) + return virtionet_xmit(buf, len); + return -1; +} diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-net.h b/qemu/roms/SLOF/lib/libvirtio/virtio-net.h new file mode 100644 index 000000000..bc7a189f7 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-net.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef VIRTIO_NET_H +#define VIRTIO_NET_H + +#include <netdriver.h> + +#define RX_QUEUE_SIZE 128 +#define BUFFER_ENTRY_SIZE 1514 + +enum { + VQ_RX = 0, /* Receive Queue */ + VQ_TX = 1, /* Transmit Queue */ +}; + +struct vqs { + uint64_t id; /* Queue ID */ + uint32_t size; + void *buf_mem; + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; +}; + +/* Device is identified by RX queue ID: */ +#define DEVICE_ID vq[0].id + +extern net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev); +extern void virtionet_close(net_driver_t *driver); +extern int virtionet_read(char *buf, int len); +extern int virtionet_write(char *buf, int len); + +#endif diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c new file mode 100644 index 000000000..48289289a --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c @@ -0,0 +1,145 @@ +/****************************************************************************** + * Copyright (c) 2012 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <cpu.h> +#include <helpers.h> +#include "virtio.h" +#include "virtio-scsi.h" + +int virtioscsi_send(struct virtio_device *dev, + struct virtio_scsi_req_cmd *req, + struct virtio_scsi_resp_cmd *resp, + int is_read, void *buf, uint64_t buf_len) +{ + struct vring_desc *desc; + struct vring_desc *vq_desc; /* Descriptor vring */ + struct vring_avail *vq_avail; /* "Available" vring */ + struct vring_used *vq_used; /* "Used" vring */ + + volatile uint16_t *current_used_idx; + uint16_t last_used_idx; + int id; + uint32_t vq_size, time; + + int vq = VIRTIO_SCSI_REQUEST_VQ; + + vq_size = virtio_get_qsize(dev, vq); + vq_desc = virtio_get_vring_desc(dev, vq); + vq_avail = virtio_get_vring_avail(dev, vq); + vq_used = virtio_get_vring_used(dev, vq); + + last_used_idx = vq_used->idx; + current_used_idx = &vq_used->idx; + + /* Determine descriptor index */ + id = (vq_avail->idx * 3) % vq_size; + + desc = &vq_desc[id]; + desc->addr = (uint64_t)req; + desc->len = sizeof(*req); + desc->flags = VRING_DESC_F_NEXT; + desc->next = (id + 1) % vq_size; + + /* Set up virtqueue descriptor for data */ + desc = &vq_desc[(id + 1) % vq_size]; + desc->addr = (uint64_t)resp; + desc->len = sizeof(*resp); + desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; + desc->next = (id + 2) % vq_size; + + if (buf && buf_len) { + /* Set up virtqueue descriptor for status */ + desc = &vq_desc[(id + 2) % vq_size]; + desc->addr = (uint64_t)buf; + desc->len = buf_len; + desc->flags = is_read ? VRING_DESC_F_WRITE : 0; + desc->next = 0; + } else + desc->flags &= ~VRING_DESC_F_NEXT; + + vq_avail->ring[vq_avail->idx % vq_size] = id; + mb(); + vq_avail->idx += 1; + + /* Tell HV that the vq is ready */ + virtio_queue_notify(dev, vq); + + /* Wait for host to consume the descriptor */ + time = SLOF_GetTimer() + VIRTIO_TIMEOUT; + while (*current_used_idx == last_used_idx) { + // do something better + mb(); + if (time < SLOF_GetTimer()) + break; + } + + return 0; +} + +/** + * Initialize virtio-block device. + * @param dev pointer to virtio device information + */ +int virtioscsi_init(struct virtio_device *dev) +{ + struct vring_avail *vq_avail; + unsigned int idx = 0; + int qsize = 0; + + /* Reset device */ + // XXX That will clear the virtq base. We need to move + // initializing it to here anyway + // + // virtio_reset_device(dev); + + /* Acknowledge device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); + + /* Tell HV that we know how to drive the device. */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); + + /* Device specific setup - we do not support special features right now */ + virtio_set_guest_features(dev, 0); + + while(1) { + qsize = virtio_get_qsize(dev, idx); + if (!qsize) + break; + virtio_vring_size(qsize); + + vq_avail = virtio_get_vring_avail(dev, 0); + vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; + vq_avail->idx = 0; + idx++; + } + + /* Tell HV that setup succeeded */ + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER + |VIRTIO_STAT_DRIVER_OK); + + return 0; +} + +/** + * Shutdown the virtio-block device. + * @param dev pointer to virtio device information + */ +void virtioscsi_shutdown(struct virtio_device *dev) +{ + /* Quiesce device */ + virtio_set_status(dev, VIRTIO_STAT_FAILED); + + /* Reset device */ + virtio_reset_device(dev); +} diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.h b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.h new file mode 100644 index 000000000..451ba4d99 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c) 2012 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * Virtio SCSI Host device definitions. + * See Virtio Spec, Appendix I, for details + */ + +#ifndef _VIRTIO_SCSI_H +#define _VIRTIO_SCSI_H + +#define VIRTIO_SCSI_CDB_SIZE 32 +#define VIRTIO_SCSI_SENSE_SIZE 96 + +#define VIRTIO_SCSI_CONTROL_VQ 0 +#define VIRTIO_SCSI_EVENT_VQ 1 +#define VIRTIO_SCSI_REQUEST_VQ 2 + +struct virtio_scsi_config +{ + uint32_t num_queues; + uint32_t seg_max; + uint32_t max_sectors; + uint32_t cmd_per_lun; + uint32_t event_info_size; + uint32_t sense_size; + uint32_t cdb_size; + uint16_t max_channel; + uint16_t max_target; + uint32_t max_lun; +} __attribute__((packed)); + +/* This is the first element of the "out" scatter-gather list. */ +struct virtio_scsi_req_cmd { + uint8_t lun[8]; + uint64_t tag; + uint8_t task_attr; + uint8_t prio; + uint8_t crn; + char cdb[VIRTIO_SCSI_CDB_SIZE]; +}; + +/* This is the first element of the "in" scatter-gather list. */ +struct virtio_scsi_resp_cmd { + uint32_t sense_len; + uint32_t residual; + uint16_t status_qualifier; + uint8_t status; + uint8_t response; + uint8_t sense[VIRTIO_SCSI_SENSE_SIZE]; +}; + +extern int virtioscsi_init(struct virtio_device *dev); +extern void virtioscsi_shutdown(struct virtio_device *dev); +extern int virtioscsi_send(struct virtio_device *dev, + struct virtio_scsi_req_cmd *req, + struct virtio_scsi_resp_cmd *resp, + int is_read, void *buf, uint64_t buf_len); + +#endif /* _VIRTIO_SCSI_H */ diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.c b/qemu/roms/SLOF/lib/libvirtio/virtio.c new file mode 100644 index 000000000..f9c00a67a --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio.c @@ -0,0 +1,241 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> +#include <cache.h> +#include <byteorder.h> +#include "virtio.h" + +/* PCI virtio header offsets */ +#define VIRTIOHDR_DEVICE_FEATURES 0 +#define VIRTIOHDR_GUEST_FEATURES 4 +#define VIRTIOHDR_QUEUE_ADDRESS 8 +#define VIRTIOHDR_QUEUE_SIZE 12 +#define VIRTIOHDR_QUEUE_SELECT 14 +#define VIRTIOHDR_QUEUE_NOTIFY 16 +#define VIRTIOHDR_DEVICE_STATUS 18 +#define VIRTIOHDR_ISR_STATUS 19 +#define VIRTIOHDR_DEVICE_CONFIG 20 + + +/** + * Calculate ring size according to queue size number + */ +unsigned long virtio_vring_size(unsigned int qsize) +{ + return VQ_ALIGN(sizeof(struct vring_desc) * qsize + + sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) + + VQ_ALIGN(sizeof(struct vring_used) + + sizeof(struct vring_used_elem) * qsize); +} + + +/** + * Get number of elements in a vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return number of elements + */ +int virtio_get_qsize(struct virtio_device *dev, int queue) +{ + int size = 0; + + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, + cpu_to_le16(queue)); + eieio(); + size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE)); + } + + return size; +} + + +/** + * Get address of descriptor vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return pointer to the descriptor ring + */ +struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue) +{ + struct vring_desc *desc = 0; + + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, + cpu_to_le16(queue)); + eieio(); + desc = (void*)(4096L * + le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS))); + } + + return desc; +} + + +/** + * Get address of "available" vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return pointer to the "available" ring + */ +struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue) +{ + return (void*)((uint64_t)virtio_get_vring_desc(dev, queue) + + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc)); +} + + +/** + * Get address of "used" vring + * @param dev pointer to virtio device information + * @param queue virtio queue number + * @return pointer to the "used" ring + */ +struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue) +{ + return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue) + + virtio_get_qsize(dev, queue) + * sizeof(struct vring_avail)); +} + + +/** + * Reset virtio device + */ +void virtio_reset_device(struct virtio_device *dev) +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0); + } +} + + +/** + * Notify hypervisor about queue update + */ +void virtio_queue_notify(struct virtio_device *dev, int queue) +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue)); + } +} + +/** + * Set queue address + */ +void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr) +{ + if (dev->type == VIRTIO_TYPE_PCI) { + uint32_t val = qaddr; + val = val >> 12; + ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, + cpu_to_le16(queue)); + eieio(); + ci_write_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS, + cpu_to_le32(val)); + } +} + +/** + * Set device status bits + */ +void virtio_set_status(struct virtio_device *dev, int status) +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status); + } +} + + +/** + * Set guest feature bits + */ +void virtio_set_guest_features(struct virtio_device *dev, int features) + +{ + if (dev->type == VIRTIO_TYPE_PCI) { + ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, bswap_32(features)); + } +} + +/** + * Get host feature bits + */ +void virtio_get_host_features(struct virtio_device *dev, int *features) + +{ + if (dev->type == VIRTIO_TYPE_PCI && features) { + *features = bswap_32(ci_read_32(dev->base+VIRTIOHDR_DEVICE_FEATURES)); + } +} + + +/** + * Get additional config values + */ +uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size) +{ + uint64_t val = ~0ULL; + void *confbase; + + switch (dev->type) { + case VIRTIO_TYPE_PCI: + confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG; + break; + default: + return ~0ULL; + } + switch (size) { + case 1: + val = ci_read_8(confbase+offset); + break; + case 2: + val = ci_read_16(confbase+offset); + break; + case 4: + val = ci_read_32(confbase+offset); + break; + case 8: + /* We don't support 8 bytes PIO accesses + * in qemu and this is all PIO + */ + val = ci_read_32(confbase+offset); + val <<= 32; + val |= ci_read_32(confbase+offset+4); + break; + } + + return val; +} + +/** + * Get config blob + */ +int __virtio_read_config(struct virtio_device *dev, void *dst, + int offset, int len) +{ + void *confbase; + unsigned char *buf = dst; + int i; + + switch (dev->type) { + case VIRTIO_TYPE_PCI: + confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG; + break; + default: + return 0; + } + for (i = 0; i < len; i++) + buf[i] = ci_read_8(confbase + offset + i); + return len; +} diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.code b/qemu/roms/SLOF/lib/libvirtio/virtio.code new file mode 100644 index 000000000..258b9bbda --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio.code @@ -0,0 +1,164 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <virtio.h> +#include <virtio-blk.h> +#include <virtio-9p.h> +#include <virtio-scsi.h> +#include <virtio-net.h> + +/******** core virtio ********/ + +// : virtio-vring-size ( queuesize -- ringsize ) +PRIM(virtio_X2d_vring_X2d_size) + TOS.u = virtio_vring_size(TOS.u); +MIRP + +// : virtio-get-qsize ( dev queue -- queuesize ) +PRIM(virtio_X2d_get_X2d_qsize) + int queue = TOS.u; POP; + TOS.u = virtio_get_qsize(TOS.a, queue); +MIRP + +// : virtio-get-config ( dev offset size -- val ) +PRIM(virtio_X2d_get_X2d_config) + int size = TOS.u; POP; + int offset = TOS.u; POP; + TOS.u = virtio_get_config(TOS.a, offset, size); +MIRP + +// : virtio-set-qaddr ( dev queue qaddr -- ) +PRIM(virtio_X2d_set_X2d_qaddr) + unsigned int qaddr = TOS.u; POP; + int queue = TOS.u; POP; + void *dev = TOS.a; POP; + virtio_set_qaddr(dev, queue, qaddr); +MIRP + +/******** virtio-blk ********/ + +// : virtio-blk-init ( dev -- blk-size) +PRIM(virtio_X2d_blk_X2d_init) + void *dev = TOS.a; + TOS.u = virtioblk_init(dev); +MIRP + +// : virtio-blk-shutdown ( dev -- ) +PRIM(virtio_X2d_blk_X2d_shutdown) + void *dev = TOS.a; POP; + virtioblk_shutdown(dev); +MIRP + +// : virtio-blk-read ( dev blkno cnt reg -- #read ) +PRIM(virtio_X2d_blk_X2d_read) + void *dev = TOS.a; POP; + long cnt = TOS.n; POP; + long blkno = TOS.n; POP; + void *buf = TOS.a; + TOS.n = virtioblk_read(dev, buf, blkno, cnt); +MIRP + +/******** virtio-fs ********/ + +// : virtio-fs-init ( dev tx rx size -- success ) +PRIM(virtio_X2d_fs_X2d_init) + int size = TOS.n; POP; + void *rx = TOS.a; POP; + void *tx = TOS.a; POP; + void *dev = TOS.a; + + TOS.n = virtio_9p_init(dev, tx, rx, size) == 0 ? -1 : 0; +MIRP + +// : virtio-fs-shutdown ( dev -- ) +PRIM(virtio_X2d_fs_X2d_shutdown) + void *dev = TOS.a; POP; + + virtio_9p_shutdown(dev); +MIRP + +// : virtio-fs-load ( dev buf str -- #read ) +PRIM(virtio_X2d_fs_X2d_load) + char *str = TOS.a; POP; + void *buf = TOS.a; POP; + void *dev = TOS.a; + + TOS.n = virtio_9p_load(dev, str, buf); +MIRP + +/******** virtio-scsi ********/ + +// : virtio-scsi-init ( dev -- success ) +PRIM(virtio_X2d_scsi_X2d_init) + void *dev = TOS.a; + TOS.u = virtioscsi_init(dev); +MIRP + +// : virtio-scsi-shutdown ( dev -- ) +PRIM(virtio_X2d_scsi_X2d_shutdown) + void *dev = TOS.a; POP; + virtioscsi_shutdown(dev); +MIRP + +// : virtio-scsi-send ( buf_addr buf_len is_read req_ptr rsp_ptr dev -- success) +PRIM(virtio_X2d_scsi_X2d_send) + void *dev = TOS.a; POP; + void *resp = TOS.a; POP; + void *req = TOS.a; POP; + int is_read = !!TOS.n; POP; + uint64_t blen = TOS.n; POP; + void *buf = TOS.a; + TOS.n = virtioscsi_send(dev, req, resp, is_read, buf, blen); +MIRP + +/******** virtio-net ********/ + +// : virtio-net-open ( mac-addr-str len dev -- false | [ driver true ] ) +PRIM(virtio_X2d_net_X2d_open) +{ + void *dev = TOS.a; POP; + int len = TOS.u; POP; + char *mac_addr = TOS.a; + + net_driver_t *net_driver = virtionet_open(mac_addr, len, dev); + + if (net_driver) { + TOS.u = (unsigned long)net_driver; PUSH; + TOS.n = -1; + } else + TOS.n = 0; +} +MIRP + +// : virtio-net-close ( driver -- ) +PRIM(virtio_X2d_net_X2d_close) +{ + net_driver_t *driver = TOS.a; POP; + virtionet_close(driver); +} +MIRP + +// : virtio-net-read ( addr len -- actual ) +PRIM(virtio_X2d_net_X2d_read) +{ + int len = TOS.u; POP; + TOS.n = virtionet_read(TOS.a, len); +} +MIRP + +// : virtio-net-write ( addr len -- actual ) +PRIM(virtio_X2d_net_X2d_write) +{ + int len = TOS.u; POP; + TOS.n = virtionet_write(TOS.a, len); +} +MIRP diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.h b/qemu/roms/SLOF/lib/libvirtio/virtio.h new file mode 100644 index 000000000..d5759b45a --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * Copyright (c) 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _LIBVIRTIO_H +#define _LIBVIRTIO_H + +#include <stdint.h> + +/* Device status bits */ +#define VIRTIO_STAT_ACKNOWLEDGE 1 +#define VIRTIO_STAT_DRIVER 2 +#define VIRTIO_STAT_DRIVER_OK 4 +#define VIRTIO_STAT_FAILED 128 + +#define VIRTIO_TIMEOUT 5000 /* 5 sec timeout */ + +/* Definitions for vring_desc.flags */ +#define VRING_DESC_F_NEXT 1 /* buffer continues via the next field */ +#define VRING_DESC_F_WRITE 2 /* buffer is write-only (otherwise read-only) */ +#define VRING_DESC_F_INDIRECT 4 /* buffer contains a list of buffer descriptors */ + +/* Descriptor table entry - see Virtio Spec chapter 2.3.2 */ +struct vring_desc { + uint64_t addr; /* Address (guest-physical) */ + uint32_t len; /* Length */ + uint16_t flags; /* The flags as indicated above */ + uint16_t next; /* Next field if flags & NEXT */ +}; + +/* Definitions for vring_avail.flags */ +#define VRING_AVAIL_F_NO_INTERRUPT 1 + +/* Available ring - see Virtio Spec chapter 2.3.4 */ +struct vring_avail { + uint16_t flags; + uint16_t idx; + uint16_t ring[]; +}; + + +/* Definitions for vring_used.flags */ +#define VRING_USED_F_NO_NOTIFY 1 + +struct vring_used_elem { + uint32_t id; /* Index of start of used descriptor chain */ + uint32_t len; /* Total length of the descriptor chain which was used */ +}; + +struct vring_used { + uint16_t flags; + uint16_t idx; + struct vring_used_elem ring[]; +}; + +#define VIRTIO_TYPE_PCI 0 /* For virtio-pci interface */ +struct virtio_device { + void *base; /* base address */ + int type; /* VIRTIO_TYPE_PCI or VIRTIO_TYPE_VIO */ +}; + +/* Parts of the virtqueue are aligned on a 4096 byte page boundary */ +#define VQ_ALIGN(addr) (((addr) + 0xfff) & ~0xfff) + +extern unsigned long virtio_vring_size(unsigned int qsize); +extern int virtio_get_qsize(struct virtio_device *dev, int queue); +extern struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue); +extern struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue); +extern struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue); + +extern void virtio_reset_device(struct virtio_device *dev); +extern void virtio_queue_notify(struct virtio_device *dev, int queue); +extern void virtio_set_status(struct virtio_device *dev, int status); +extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr); +extern void virtio_set_guest_features(struct virtio_device *dev, int features); +extern void virtio_get_host_features(struct virtio_device *dev, int *features); +extern uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size); +extern int __virtio_read_config(struct virtio_device *dev, void *dst, + int offset, int len); + + +#endif /* _LIBVIRTIO_H */ diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.in b/qemu/roms/SLOF/lib/libvirtio/virtio.in new file mode 100644 index 000000000..c36d127c7 --- /dev/null +++ b/qemu/roms/SLOF/lib/libvirtio/virtio.in @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +cod(virtio-vring-size) +cod(virtio-get-qsize) +cod(virtio-get-config) +cod(virtio-set-qaddr) + +cod(virtio-blk-init) +cod(virtio-blk-shutdown) +cod(virtio-blk-read) + +cod(virtio-scsi-init) +cod(virtio-scsi-shutdown) +cod(virtio-scsi-send) + +cod(virtio-fs-init) +cod(virtio-fs-shutdown) +cod(virtio-fs-load) + +cod(virtio-net-open) +cod(virtio-net-close) +cod(virtio-net-read) +cod(virtio-net-write) diff --git a/qemu/roms/SLOF/llfw/boot_abort.S b/qemu/roms/SLOF/llfw/boot_abort.S new file mode 100644 index 000000000..996bdd78a --- /dev/null +++ b/qemu/roms/SLOF/llfw/boot_abort.S @@ -0,0 +1,95 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include "macros.h" +#include "termctrl.h" +#include "boot_abort.h" +#include <cpu.h> + +#define MSG_LOOK_HDR TERM_CTRL_BRIGHT, TERM_BG_RED, TERM_FG_WHITE + +ASM_ENTRY(msg_e_crc) + .ascii MSG_LOOK_HDR + .ascii "\n\r\n\rE1001 - Boot ROM CRC failure\n\r" + .ascii TERM_CTRL_RESET, "\0" + .align 2 + +ASM_ENTRY(msg_e_nomem) + .ascii MSG_LOOK_HDR + .ascii "\n\r\n\rE1002 - Memory could not be initialized\n\r" + .ascii TERM_CTRL_RESET, "\0" + .align 2 + +ASM_ENTRY(msg_e_nofile) + .ascii MSG_LOOK_HDR + .ascii "\n\r\n\rE1003 - Firmware image incomplete" + .ascii TERM_CTRL_RESET + .ascii "\n\r internal FLS1-FFS-0.\0" + .align 2 + +ASM_ENTRY(msg_e_ierror) + .ascii MSG_LOOK_HDR + .ascii "\n\r\n\rE1004 - Unspecified Internal Firmware Error" + .ascii TERM_CTRL_RESET + .ascii "\n\r internal FLSX-SE-0.\0" + .align 2 + +/* E1005 : used in memory init code */ + +/***************************************************************************** + * Boot Abort Handler + * + * Input: + * R3 - capability informatin (i/o etc.) + * R4 - handling suggestion + * R5 - error string reference + * R6 - error number + * + * Return: + * if possible input to H8 and NVRAM log and console , then reboot/halt + * + * Input definitions: + * + * R3 bits: 63 (h8/console possible) ... add more + * R4 bits: 63 (do not attempt reboot) + * R5 reference to error message string + * R6 32-bit error enumerator + * + ******************************************************************************/ +ASM_ENTRY(boot_abort) + /* save arguments */ + mr r31, r3 + mr r30, r4 + mr r29, r5 + mr r28, r6 + + /* check if i/o is possible, if yes then print message */ + li r10, ABORT_CANIO + andi. r3, r31, r10 + bne abort_noio + + /* use i/o ..., first print reference message */ + /* then add internal number if != 0 */ + mr r3, r29 + mfspr r4, HSPRG0 /* get runbase */ + or r3, r3, r4 + bl io_print + mr r3, r28 + li r28, 0 + cmpd r3, r28 + beq 0f + bl io_printhex32 +0: + + abort_noio: + b $ // FIXME + /* never reached */ + diff --git a/qemu/roms/SLOF/llfw/boot_abort.h b/qemu/roms/SLOF/llfw/boot_abort.h new file mode 100644 index 000000000..b7082063c --- /dev/null +++ b/qemu/roms/SLOF/llfw/boot_abort.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef BOOT_ABORT_H +#define BOOT_ABORT_H + +/* boot abort function suitable for assembly */ +#define BOOT_ABORT(cap, action, msg, numhint) \ + li r3, cap; \ + li r4, action; \ + LOAD32(r5, msg); \ + LOAD32(r6, numhint); \ + bl boot_abort + +/* boot abort function suitable called from c (takes r3 as hint) */ +#define BOOT_ABORT_R3HINT(cap, action, msg) \ + mr r6, r3; \ + li r3, cap; \ + li r4, action; \ + LOAD32(r5, msg); \ + bl boot_abort + +#define ABORT_CANIO (1 << 0) +#define ABORT_NOIO (1 << 1) + +#define ALTBOOT (1 << 0) +#define HALT (1 << 1) + +#endif diff --git a/qemu/roms/SLOF/llfw/clib/Makefile.inc b/qemu/roms/SLOF/llfw/clib/Makefile.inc new file mode 100644 index 000000000..70037989e --- /dev/null +++ b/qemu/roms/SLOF/llfw/clib/Makefile.inc @@ -0,0 +1,42 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include ../../make.rules + +CFLAGS_COMLIB = -pedantic -std=gnu99 -O0 +ASFLAGS_COMLIB = + + +COMLIBDIR = $(LLFWCMNDIR)/clib + +COMLIB_SRC_ASM = +COMLIB_SRC_C = iolib.c + +COMLIB_SRCS = $(COMLIB_SRC_ASM:%=$(COMLIBDIR)/%) \ + $(COMLIB_SRC_C:%=$(COMLIBDIR)/%) +COMLIB_OBJ_ASM = $(COMLIB_SRC_ASM:%.S=%.o) +COMLIB_OBJ_C = $(COMLIB_SRC_C:%.c=%.o) + + +comlib.o: $(COMLIB_OBJ_C) $(COMLIB_OBJ_ASM) + $(LD) $(LDFLAGS) $^ -o $@ -r + +%.o: $(LLFWCMNDIR)/clib/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_COMLIB) -c $< -o $@ + +%.o: $(LLFWCMNDIR)/clib/%.S + $(CC) $(CPPFLAGS) $(ASFLAGS) $(ASFLAGS_COMLIB) -c $< -o $@ + +LLFW_CLEAN_TARGETS += clean_clib +.PHONY : clean_clib +clean_clib: + rm -f $(COMLIB_OBJ_C) $(COMLIB_OBJ_ASM) comlib.o diff --git a/qemu/roms/SLOF/llfw/clib/iolib.c b/qemu/roms/SLOF/llfw/clib/iolib.c new file mode 100644 index 000000000..7f14b512d --- /dev/null +++ b/qemu/roms/SLOF/llfw/clib/iolib.c @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <stddef.h> +#include <unistd.h> +#include "iolib.h" + +void uart_send_byte(unsigned char b) +{ + asm volatile ("":::"3","4","5","6","7"); + io_putchar(b); +} + +/** + * Standard write function for the libc. + * + * @param fd file descriptor (should always be 1 or 2) + * @param buf pointer to the array with the output characters + * @param count number of bytes to be written + * @return the number of bytes that have been written successfully + */ +ssize_t write(int fd, const void *buf, size_t count) +{ + size_t i; + char *ptr = (char *)buf; + + if (fd != 1 && fd != 2) + return 0; + + for (i = 0; i < count; i++) { + if (*ptr == '\n') + uart_send_byte('\r'); + uart_send_byte(*ptr++); + } + + return i; +} diff --git a/qemu/roms/SLOF/llfw/clib/iolib.h b/qemu/roms/SLOF/llfw/clib/iolib.h new file mode 100644 index 000000000..91450058c --- /dev/null +++ b/qemu/roms/SLOF/llfw/clib/iolib.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef IOLIB_H +#define IOLIB_H + +#include <stdint.h> + +#define addr_t volatile unsigned int +#define addr8_t volatile unsigned char + +extern void halt_sys (unsigned int); + +extern void uart_send_byte(unsigned char b); +extern void io_putchar(unsigned char); + +#endif diff --git a/qemu/roms/SLOF/llfw/io_generic/Makefile.inc b/qemu/roms/SLOF/llfw/io_generic/Makefile.inc new file mode 100644 index 000000000..b6607252f --- /dev/null +++ b/qemu/roms/SLOF/llfw/io_generic/Makefile.inc @@ -0,0 +1,38 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +IOGENERICDIR = $(LLFWCMNDIR)/io_generic + +IO_GENERIC_SRC_ASM = io_generic.S +IO_GENERIC_SRC_C = + +IO_GENERIC_SRCS = $(IO_GENERIC_SRC_ASM:%=$(IOGENERICDIR)/%) \ + $(IO_GENERIC_SRC_C:%=$(IOGENERICDIR)/%) +IO_GENERIC_OBJ_ASM = $(IO_GENERIC_SRC_ASM:%.S=%.o) +IO_GENERIC_OBJ_C = $(IO_GENERIC_SRC_C:%.c=%.o) + + +io_generic_lib.o: $(IO_GENERIC_OBJ_ASM) $(IO_GENERIC_OBJ_C) + $(LD) $(LDFLAGS) $^ -o $@ -r + + +%.o: $(IOGENERICDIR)/%.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +%.o: $(IOGENERICDIR)/%.S + $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@ + + +LLFW_CLEAN_TARGETS += clean_io_generic +.PHONY : clean_io_generic +clean_io_generic: + rm -f $(IO_GENERIC_OBJ_C) $(IO_GENERIC_OBJ_ASM) io_generic_lib.o diff --git a/qemu/roms/SLOF/llfw/io_generic/io_generic.S b/qemu/roms/SLOF/llfw/io_generic/io_generic.S new file mode 100644 index 000000000..9c1db41a1 --- /dev/null +++ b/qemu/roms/SLOF/llfw/io_generic/io_generic.S @@ -0,0 +1,129 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include "macros.h" +#include "calculatecrc.h" +#include "calculatecrc.h" + + .text + +/**************************************************************************** + * prints a 0-terminated string to serial console + * + * Input: + * R3 - pointer to string in memory + * + * Returns: - + * + * Modifies Registers: + * R3, R4, R5, R6, R7, R8, R9 + ****************************************************************************/ +ASM_ENTRY(io_print) + mflr r8 + mr r9, r3 + +0: + lbz r3, 0(r9) + cmpwi r3, 0 + beq 1f + bl io_putchar + addi r9, r9, 1 + b 0b +1: + mtlr r8 + blr + +/**************************************************************************** + * prints Hex integer to the UART and the NVRAM (using board io_putchar) + * + * Input: + * R3 - integer to print + * + * Returns: - + * + * Modifies Registers: + * R3, R4, R5, R6, R7, R8, R9 + ****************************************************************************/ +#define _io_gen_print_nib(reg, src, shift) \ + srdi reg, src, shift; \ + andi. reg, reg, 0x0F; \ + cmpwi reg, 0x0A; \ + blt 0f; \ + addi reg, reg, ('A'-'0'-10); \ +0:; \ + addi reg, reg, '0'; \ + bl io_putchar + +ASM_ENTRY(io_printhex64) + mflr r8 + mr r9, r3 + +_io_printhex64: + _io_gen_print_nib(r3, r9, 60) + _io_gen_print_nib(r3, r9, 56) + _io_gen_print_nib(r3, r9, 52) + _io_gen_print_nib(r3, r9, 48) + _io_gen_print_nib(r3, r9, 44) + _io_gen_print_nib(r3, r9, 40) + _io_gen_print_nib(r3, r9, 36) + _io_gen_print_nib(r3, r9, 32) +_io_printhex32: + _io_gen_print_nib(r3, r9, 28) + _io_gen_print_nib(r3, r9, 24) + _io_gen_print_nib(r3, r9, 20) + _io_gen_print_nib(r3, r9, 16) +_io_printhex16: + _io_gen_print_nib(r3, r9, 12) + _io_gen_print_nib(r3, r9, 8) +_io_printhex8: + _io_gen_print_nib(r3, r9, 4) + _io_gen_print_nib(r3, r9, 0) + + mtlr r8 + blr + +ASM_ENTRY(io_printhex32) + mflr r8 + mr r9, r3 + b _io_printhex32 + +ASM_ENTRY(io_printhex16) + mflr r8 + mr r9, r3 + b _io_printhex16 + +ASM_ENTRY(io_printhex8) + mflr r8 + mr r9, r3 + b _io_printhex8 + + +/**************************************************************************** + * print the address and its contents as 64-bit hex values + * + * Input: + * R3 - Address to read from + * + * Returns: - + * + * Modifies Registers: + * R3, R4, R5, R6, R7, R8, R9, R10 + ****************************************************************************/ +#if 0 /* currently unused */ +ASM_ENTRY(io_dump) + mflr r10 + bl io_printhex64 + li r3,':' + bl io_putchar + ld r9,0(r9) + mr r8,r10 + b _io_printhex64 +#endif diff --git a/qemu/roms/SLOF/llfw/nvramlog.S b/qemu/roms/SLOF/llfw/nvramlog.S new file mode 100644 index 000000000..3ad2de754 --- /dev/null +++ b/qemu/roms/SLOF/llfw/nvramlog.S @@ -0,0 +1,350 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <macros.h> +#include <nvramlog.h> +#include <southbridge.h> +#include <calculatecrc.h> + +#if !defined(DISABLE_NVRAM) && !defined(RTAS_NVRAM) + +// detect overflow: if(a<b) return a else return 0 +#define NVRAM_LOG_DATA_OVERFLOW( a, b) \ + cmpd 7, a, b; \ + blt+ 7, 0f; \ + li a, 0; \ + 0: + +// get Pointer(pointer) to next byte in NVRAM data section +// and size of this data sechtion (modulo) +// modifies register pointer, modulo +#define NVRAM_POINTER_DATASIZE_BE0(pointer, modulo, address) \ + LOAD64( modulo, LLFW_LOG_BE0_LENGTH); \ + lwz pointer, LLFW_LOG_POS_POINTER(address); \ + sldi modulo, modulo, 4; \ + addi modulo, modulo,-LLFW_LOG_BE0_DATA_OFFSET +#define NVRAM_POINTER_DATASIZE_BE1(pointer, modulo, address) \ + LOAD64( modulo, LLFW_LOG_BE1_LENGTH); \ + lwz pointer, LLFW_LOG_POS_POINTER(address); \ + sldi modulo, modulo, 4; \ + addi modulo, modulo,-LLFW_LOG_BE1_DATA_OFFSET + +/**************************************************************************** + * checkLogHeaderData + * compare the fixed values in the header if any change was done since + * last initialisation. + * Flags are not checked! + * + * Retrun 0 if no manimulation was found 1 else + * + * input: + * r3 - NVRAM Base Address + * + * output: + * r3 - status: 0 = ok, 1 = corrupt + * r4 - NVRAM Base Address + * + ***************************************************************************/ +ASM_ENTRY(checkLogHeaderData) + li r4, 0 // init error flag + lbz r5, 0(r3) // check signature + addi r5, r5, -LLFW_LOG_BE0_SIGNATURE + add r4, r4, r5 + + lhz r5, LLFW_LOG_POS_LENGTH(r3) // check length + addi r5, r5, -LLFW_LOG_BE0_LENGTH + add r4, r4, r5 + + lwz r5, LLFW_LOG_POS_NAME(r3) // check name prefix + LOAD64( r6, LLFW_LOG_BE0_NAME_PREFIX) + subf r5, r6, r5 + add r4, r4, r5 + + ld r5, (LLFW_LOG_POS_NAME+4)(r3) // check name + LOAD64( r6, LLFW_LOG_BE0_NAME) + subf r5, r6, r5 + add r4, r4, r5 + + lhz r5, LLFW_LOG_POS_DATA_OFFSET(r3) //check data offset + addi r5, r5, -LLFW_LOG_BE0_DATA_OFFSET + add r4, r4, r5 + + lhz r5, LLFW_LOG_POS_FLAGS(r3) //check flags + addi r5, r5, -LLFW_LOG_BE0_FLAGS + add r4, r4, r5 + + cmpldi 7, r4, 0 + beq+ 7, 0f + li r4, 1 +0: + mr r5, r3 + mr r3, r4 + mr r4, r5 + blr +/***************************************************************************** + * checkLogPartition: check Partition Header entries and Checksum + * check also the NVRAM-Log-Partition CRC + * if Partition is not ok set the following bits to 1 + * bit 1: if Partiton Header Checksum is corrupt + * bit 2: if CRC is corrupt + * bit 3: if Header entries are corrupt + * + * input: + * r3 - NVRAM log address (BASE + NVRAM_LOG_OFFSET) + * + * output: + * r3 - CRC status + * r4 - NVRAM log address + * + * Modifies Register: R3, R4, R5, R6, R7, R8, R9 + ****************************************************************************/ +ASM_ENTRY(.checkLogPartition) + mflr r8 + mr r4, r3 // emulate "bl updateCRC_NVRAM" + li r3, 0 // with successful CRC check + li r7, 0 + cmpwi 7, r3, 0 + beq+ 7, 0f + li r7, 2 +0: + mr r3, r4 + bl .calPartitionHeaderChecksum // r3=checksum, r4=NVARM addr + lbz r6, LLFW_LOG_POS_CHECKSUM(r4) + cmpw 7, r3, r6 + beq+ 7, 0f // cal checksum must eq checksum + ori r7, r7, 1 +0: + cmpwi 7, r3, 0 + bne+ 7, 0f + ori r7, r7, 1 // 0 as checksum is invalid +0: + mr r3, r4 + bl checkLogHeaderData + cmpdi 7, r3, 0 + beq+ 7, 0f + ori r7, r7, 4 +0: + mr r3, r7 + mtlr r8 + blr +/***************************************************************************** + * checkinitLog: check the NVRAM Log Partition Header + * initialize the NVRAM if the Header was modified + * + * input: + * r3 - NVRAM BASE address + * + * output: + * r3 - 0 = check ok, no new header written + * r3 - 1 = check not ok, header and NVRAM initialized + * r4 - NVRAM log address + * + * Modifies Register: R3, R4, R5, R6, R7, r8, r9 + ****************************************************************************/ +// init is done if checkLogPartiton returns not 0 (= check failed) +ASM_ENTRY(.checkinitLog) +ASM_ENTRY(checkinitLog) + mflr r9 + bl .checkLogPartition //r3..r8, r4_out = r3_in + mtlr r9 + + cmpwi 7, r3, 0 + mr r3, r4 // r3=NVRAM_LOG address + bne- 7, .initLog // if header is not ok, init header + li r3, 0 + blr // header OK, return 0 + + +/* this is basically just a copy of .initLog + registers used: r3, r4, r5, r6, r7, r9*/ +init_log_2nd_be: + mflr r9 + li r6, LLFW_LOG_BE0_LENGTH + mulli r6, r6, 0x10 + add r6, r7, r6 + li r5, LLFW_LOG_BE1_SIGNATURE + li r4, LLFW_LOG_BE1_LENGTH + stb r5, 0(r6) + sth r4, LLFW_LOG_POS_LENGTH(r6) + li r5, LLFW_LOG_BE1_DATA_OFFSET + li r4, LLFW_LOG_BE1_FLAGS + sth r5, LLFW_LOG_POS_DATA_OFFSET(r6) + sth r4, LLFW_LOG_POS_FLAGS(r6) + li r5, 1 + + LOAD32( r4, LLFW_LOG_BE1_NAME_PREFIX) + stw r5, LLFW_LOG_POS_POINTER(r6) + stw r4, (LLFW_LOG_POS_NAME+0x00)(r6) + LOAD64( r5, LLFW_LOG_BE1_NAME) + std r5, (LLFW_LOG_POS_NAME+0x04)(r6) + mr r3, r6 + bl .calPartitionHeaderChecksum + stb r3, LLFW_LOG_POS_CHECKSUM(r6) + mtlr r9 + blr +/***************************************************************************** + * initLog: initialize the NVRAM with 0 + * write a new NVRAM Log-Partition-Header + * + * input: + * r3 - NVRAM BASE address + * + * output: + * r3 - 0 = check ok, no new header written + * r3 - 1 = check not ok, header and NVRAM initialized + * r4 - NVRAM log address + * + * Modifies Register: R3, R4, R5, R6, R7, r8, r9 + ****************************************************************************/ +ASM_ENTRY(.initLog) + mflr r8 + mr r7, r3 + + bl clearNVRAM +0: + li r5, LLFW_LOG_BE0_SIGNATURE + li r4, LLFW_LOG_BE0_LENGTH + stb r5, 0(r7) + sth r4, LLFW_LOG_POS_LENGTH(r7) + li r5, LLFW_LOG_BE0_DATA_OFFSET + li r4, LLFW_LOG_BE0_FLAGS + sth r5, LLFW_LOG_POS_DATA_OFFSET(r7) + sth r4, LLFW_LOG_POS_FLAGS(r7) + li r5, 1 + + LOAD32( r4, LLFW_LOG_BE0_NAME_PREFIX) + stw r5, LLFW_LOG_POS_POINTER(r7) + stw r4, (LLFW_LOG_POS_NAME+0x00)(r7) + LOAD64( r5, LLFW_LOG_BE0_NAME) + std r5, (LLFW_LOG_POS_NAME+0x04)(r7) + bl .calPartitionHeaderChecksum + stb r3, LLFW_LOG_POS_CHECKSUM(r7) + bl init_log_2nd_be // create a second log partition for BE1 + mr r4, r7 + li r3, 1 + mtlr r8 + blr +/***************************************************************************** + * clearNVRAM: set all not used NVRAM memory to zero + * + * + * input: + * R3 - NVRAM BASE ADDRESS + * + * output: + * R3 - NVARM END ADDRESS + * + * Modifies Register: r4, r5 + ****************************************************************************/ +ASM_ENTRY(clearNVRAM) + LOAD64( r4, NVRAM_LENGTH) + srdi r4, r4, 3 + mtctr r4 + li r5, 0x0 + LOAD64( r4, NVRAM_EMPTY_PATTERN) +0: + stdx r4, r3,r5 + addi r5, r5, 8 + bdnz+ 0b + blr +/***************************************************************************** + * writeNVRAMbyte: write next log into NVRAM + * + * + * input: + * R3 - byte to be written + * R4 - NVRAM Base Address + * + * output: + * R3 - byte that was written + * R4 - NVRAM Base Address + * + * Modifies Register: R3, R4, R5, R6 + ****************************************************************************/ +ASM_ENTRY(.writeNVRAMbyte) +ENTRY(writeLogByte) + NVRAM_POINTER_DATASIZE_BE0( r5, r6, r4) // get pointer,size of data + NVRAM_LOG_DATA_OVERFLOW( r5, r6) // check for overflow + addi r5, r5, 1 // increment pointer + stw r5, LLFW_LOG_POS_POINTER(r4) // store pointer + addi r5, r5, -1 // restore old pointer + add r6, r4, r5 // byte address in data section + + stb r3, LLFW_LOG_BE0_DATA_OFFSET(r6) + blr + +/***************************************************************************** + * writeNVRAMbyte: write next log into NVRAM + * + * + * input: + * R3 - byte to be written + * R4 - NVRAM Base Address + * + * output: + * R3 - byte that was written + * R4 - NVRAM Base Address + * + * Modifies Register: R3, R4, R5, R6 + ****************************************************************************/ +ENTRY(writeLogByteBE1) + li r6, LLFW_LOG_BE0_LENGTH + mulli r6, r6, 0x10 + add r4, r6, r4 + NVRAM_POINTER_DATASIZE_BE1( r5, r6, r4) // get pointer,size of data + NVRAM_LOG_DATA_OVERFLOW( r5, r6) // check for overflow + addi r5, r5, 1 // increment pointer + stw r5, LLFW_LOG_POS_POINTER(r4) // store pointer + addi r5, r5, -1 // restore old pointer + add r6, r4, r5 // byte address in data section + + stb r3, LLFW_LOG_BE1_DATA_OFFSET(r6) + blr + +/***************************************************************************** + * calPartitionHeaderChecksum: calculate the Checksum of the + * Partition Header as described in .... + * + * input: r3 - NVRAM BASE adresse + * + * output: R3 - the calculated checksum as 8 bit value + * R4 - NVRAM log address + * + * Modifies Register: R3, R4, R5, R6 + ****************************************************************************/ +ASM_ENTRY(.calPartitionHeaderChecksum) + mr r6, r3 + lbz r3,0(r6) // load first byte + LOAD64( r4, LLFW_LOG_POS_LENGTH) // load position of 3rd byte +.L6: + lbzx r5, r4, r6 // r5 nexed byte + addi r4, r4, 1 // r4++ (index) + add r5, r5, r3 // r5 new sum =sum + nexed byte + rldicl r5, r5, 0, 56 + cmpld 7, r5, r3 + cmpldi 6, r4, LLFW_LOG_POS_DATA_OFFSET + bge+ 7,.L5 // if new sum > sum + addi r5, r5, 1 // new sum ++ + rldicl r5, r5, 0, 56 +.L5: + mr r3,r5 // sum = new sum + blt+ 6,.L6 + + mr r4, r6 + blr + +#else /* defined(DISABLE_NVRAM) || defined(RTAS_NVRAM) */ + +ASM_ENTRY(.writeNVRAMbyte) + ENTRY(writeLogByte) + blr + +#endif diff --git a/qemu/roms/SLOF/llfw/romfs.S b/qemu/roms/SLOF/llfw/romfs.S new file mode 100644 index 000000000..325f79e5e --- /dev/null +++ b/qemu/roms/SLOF/llfw/romfs.S @@ -0,0 +1,362 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include "macros.h" +#include "romfs.h" + +/******************************************************************* + * Wrapper for romfs_lookup. + * + * Input: + * R3 = address of filename string + * R4 = address of struct romfs_t + * 0: file size (return) + * 8: flags (return) + * 10: fileaddr (return and input: tells if first search) + * 18: nextfile (return) + * 20: namep (return) + * + * Find File Procedure + * - set filename and rombase, on return 0 file properties are stored + * in romfs_t else struct not valid + * + * Listing procedure + * - clear romfs_t (important!) + * - set filename = NULL and rombase and call returns first file + * with properties in romfs_t including next-file pointer + * - if nextpointer is non-zero then just the next file is returned + * + * Returns: + * <Success>: + * R3 = 0 + * romfs_t is updated + * <FileNotFound>: + * R3 = 1 + * romfs_t not touched + * + * Potentially modifies the following registers: + * + + Example usage from C: + + int list_bootrom() + { + struct romfs_t rfs; + int i; + + printf("Build: "__TIME__" "__DATE__" \n"); + + i = 0; + memset((void*) &rfs, 0, sizeof(struct romfs_t)); + printf(" No. File Data Size Name\n"); + + while (romfs_stat(NULL, &rfs) == 0) { + i++; + printf(" %02d: %08X %08X %7d %s\n", + i, rfs.fileaddr, rfs.datap, + rfs.size, rfs.namep); + } + if (0 == i) { + printf("Error in reading ROMFS\n"); + return 1; + } + return 0; + } + *******************************************************************/ +#define RFS_T_SIZE 0x00 +#define RFS_T_FLAGS 0x08 +#define RFS_T_FILEADDR 0x10 +#define RFS_T_NEXT 0x18 +#define RFS_T_NAME 0x20 +#define RFS_T_DATA 0x28 + +#define RFS_H_NEXT 0x00 +#define RFS_H_SIZE 0x08 +#define RFS_H_FLAGS 0x10 +#define RFS_H_DATA 0x18 +#define RFS_H_NAME 0x20 + +ENTRY(romfs_stat_file) + /* save link register and romfs_t pointer */ + mflr r15 + mr r16, r4 + + /* if filename R3 is 0 then its a listing request */ + /* if not then just continue to lookup name */ + /* save R4 to R8 which is the address of header */ + li r7, 0 + cmpd r3, r7 + beq romfs_list + bl romfs_lookup + mfsprg r8, 1 + + /* if file found then go to romfs_fill_properties */ + /* else return 1 to caller */ + cmpwi r3, 0 + beq romfs_fill_properties + b romfs_stat_end + + romfs_list: + /* check if fileaddr == 0, in this case its */ + /* the first search on this handle, so return all */ + /* info for file at rombase (R8=R4) */ + ld r6, RFS_T_FILEADDR(r4) + mfsprg r8, 1 + li r7, 0 + cmpd r7, r6 + beq romfs_fill_properties + + /* check if next file != 0 by looking into */ + /* romfs_t, if not then return (next = 0) 1 */ + li r7, 0 + ld r4, RFS_T_NEXT(r4) + cmpd r7, r4 + li r3, 1 + beq romfs_stat_end + + /* now next file is available so move R8 to next */ + /* file address */ + mr r8, r4 + + romfs_fill_properties: + /* set properties in romfs_t takes R8 as address */ + /* to file header and R16 as address of romfs_t */ + mfsprg r3, 1 + std r8, RFS_T_FILEADDR(r16) + + ld r4, RFS_H_NEXT(r8) + li r7, 0 + cmpd r7, r4 + beq $ + (2 * 4) /* =0 so add no rombase */ + add r4, r4, r3 + std r4, RFS_T_NEXT(r16) + + ld r4, RFS_H_SIZE(r8) + std r4, RFS_T_SIZE(r16) + ld r4, RFS_H_FLAGS(r8) + std r4, RFS_T_FLAGS(r16) + + ld r4, RFS_H_DATA(r8) + add r4, r4, r3 + std r4, RFS_T_DATA(r16) + + addi r4, r8, RFS_H_NAME + std r4, RFS_T_NAME(r16) + + li r3, 0 + + /* restore romfs_t pointer and link register */ + romfs_stat_end: + mr r5, r16 + mtlr r15 + blr + +/******************************************************************* + * Copies the data of file referenced by name string to address + * requires root address of filesystem. + * FIXME: ignores flags + * + * Input: + * R3 = address of filename string + * R4 = ROMBASE + * R5 = destination address + * + * Returns: + * <Success>: R3 = 0, R6 = size, <FileNotFound>: R3 = 1 + * R5 is kept + * + * Potentially modifies the following registers: + * ctr, r15, r16, r17, r18 + * + * Uses the following calls with subsequent register modification: + * - romfs_lookup + *******************************************************************/ +ASM_ENTRY(romfs_load) + mflr r15 + + /* save R5 twice */ + /* lookup file, input regs */ + /* are already set */ + /* if not found, just return */ + mr r16, r5 + mr r17, r5 + bl romfs_lookup + cmpwi r3, 1 + bne 0f + mtlr r15 + blr /* abort, not found */ + + /* save data size for return */ + /* found, copy data */ + /* data size is in R6 */ +0: + //mr r3, r6 + mtctr r6 + addi r16, r16, -1 /* dest */ + addi r5, r5, -1 /* source*/ + + /* data is expected to be */ + /* 8 byte aligned */ + /* copy loop */ +0: lbzu r18, 1(r5) + stbu r18, 1(r16) + bdnz 0b + + /* restore size, keep padding */ + /* restore target address */ + /* return */ + mr r5, r17 + mtlr r15 + blr + +/******************************************************************* + * looks up a file based on filename + * + * Input: + * R3 = address of filename string + * R4 = ROMBASE + * + * Returns: + * <Success>: + * R3 = 0 + * R4 = address of file header + * R5 = address of data (real address) + * R6 = size of data + * R7 = flags for file + * <FileNotFound>: + * R3 = 1 + * + * Potentially modifies the following registers: + * R3, R4, R5, R6, R7, R8, R9 + * + * Uses the following calls with subsequent register modification: + * - romfs_namematch + *******************************************************************/ +ASM_ENTRY(romfs_lookup) + mflr r9 + + romfs_lookup_next: + /* save current file base */ + mr r8, r4 + /* name to look for */ + mr r10, r3 + /* name of file */ + mr r5, r4 + addi r5, r5, (4 /* elems */ * 8 /* elem-size */) + mr r11, r5 /* for namematch */ + /* compare */ + bl romfs_namematch + cmpwi r12, 1 + bne romfs_lookup_match + + /* load next pointer */ + /* check if next is 0 */ + /* apply root-offset */ + ld r5, 0(r4) + cmpwi r5, 0 + add r4, r4, r5 + bne romfs_lookup_next + /* last file reached, abort */ + li r3, 1 + mtlr r9 + blr + + /* here the name did match */ + /* r4 is still usable here and */ + /* pointing to the initial file */ + /* load r5 with data ptr */ + /* load r6 with data size */ + /* load r7 with flags */ + /* get abs addr of data */ + romfs_lookup_match: + li r3, 0 + ld r5, (3 * 8)(r4) /* data */ + ld r6, (1 * 8)(r4) /* len */ + ld r7, (2 * 8)(r4) /* flags */ + add r5, r5, r8 + mtlr r9 + blr + +/******************************************************************* + * compares two strings in memory, + * both must be null-terminated and 8-byte aligned + * + * Input: + * R10 = string 1 + * R11 = string 2 + * + * Returns: + * <Match>: R12 = 0 <NoMatch>: R12 = 1 + * + * Potentially modifies the following registers: + * R10, R11, r12, r13, r14 + *******************************************************************/ +romfs_namematch: + subi r10, r10, 8 + subi r11, r11, 8 + + /* + * load chars as 8byte chunk from current pos, name is + * always 8 byte aligned :) + */ + romfs_cmp_loop: + ldu r13, 8(r10) /* A */ + ldu r14, 8(r11) /* B */ + + cmpd r13, r14 + li r12, 1 + beq 1f + blr + +1: andi. r14, r14, 0xff + bne romfs_cmp_loop + + li r12, 0 + blr + +/******************************************************************* + * wrapper for romfs_lookup + * this function saves the registers from r13 - r15 on the stack + * calls romfs_lookup + * restores the saved registers + * + * the return parameters are copied to (r5) and (r5) has to + * be 0x20 big + *******************************************************************/ +ENTRY(c_romfs_lookup) + stdu r1,-0x50(r1) # allocate space on stack + + mflr r0 # save link register + std r0,0x30(r1) + + std r15,0x38(r1) # save r15 + std r14,0x40(r1) # save r14 + std r13,0x48(r1) # and r13 + + mr r15,r5 # save the pointer for the return value + + bl romfs_lookup # do the thing + + ld r0,0x30(r1) # restore link register + mtlr r0 + + std r4,0x00(r15) # copy return values + std r5,0x08(r15) # to the return pointer + std r6,0x10(r15) + std r7,0x18(r15) + + ld r13,0x48(r1) # restore registers from stack + ld r14,0x40(r1) + ld r15,0x38(r1) + + addi r1,r1,0x50 # cleanup stack + + blr diff --git a/qemu/roms/SLOF/llfw/romfs_wrap.c b/qemu/roms/SLOF/llfw/romfs_wrap.c new file mode 100644 index 000000000..323d97525 --- /dev/null +++ b/qemu/roms/SLOF/llfw/romfs_wrap.c @@ -0,0 +1,22 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <romfs.h> + +int romfs_stat(char *filename, struct romfs_t *hnd) +{ + asm volatile ("":::"3","4","5","6","7","9","10"); + asm volatile ("":::"11","12"); + asm volatile ("":::"13","14","15","16","17","18"); + + return romfs_stat_file(filename, hnd); +} diff --git a/qemu/roms/SLOF/make.rules b/qemu/roms/SLOF/make.rules new file mode 100644 index 000000000..aebc4e360 --- /dev/null +++ b/qemu/roms/SLOF/make.rules @@ -0,0 +1,76 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +############################################################################# +# BUILD ENV SETTINGS +############################################################################# + +# CROSS is the prefix of your cross-compiler. +# You can override this variable in your environment (export CROSS=...). +ARCH := $(shell uname -p) + +# Auto-detect ppc64 +ifeq ($(ARCH), ppc64) +CROSS = "" +else +CROSS ?= powerpc64-linux- +endif + +CELLSIZE ?= 64 + +HOSTCC ?= gcc +HOSTCFLAGS = -g -Wall -W -O2 -I. -I../include +DD = dd + +ONLY_CC = $(CROSS)gcc -m$(CELLSIZE) +ONLY_AS = $(CROSS)as -m$(CELLSIZE) +ONLY_LD = $(CROSS)ld -melf$(CELLSIZE)ppc + +# Verbose level: +# V=0 means completely silent +# V=1 means brief output +# V=2 means full output +V ?= 1 + +ifeq ($(V),0) +Q := @ +MAKEFLAGS += --silent +MAKE += -s +endif + +ifeq ($(V),1) +MAKEFLAGS += --silent +MAKE += -s +CC = printf "\t[CC]\t%s\n" `basename "$@"`; $(ONLY_CC) +AS = printf "\t[AS]\t%s\n" `basename "$@"`; $(ONLY_AS) +LD = printf "\t[LD]\t%s\n" `basename "$@"`; $(ONLY_LD) +CLEAN = printf "\t[CLEAN]\t%s\n" "$(DIRECTORY)$$dir" +else +CC = $(ONLY_CC) +AS = $(ONLY_AS) +LD = $(ONLY_LD) +CLEAN = echo -n +endif + +OBJCOPY ?= $(CROSS)objcopy +OBJDUMP ?= $(CROSS)objdump +STRIP ?= $(CROSS)strip +AR ?= $(CROSS)ar +RANLIB ?= $(CROSS)ranlib +CPP ?= $(CROSS)cpp + +WARNFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes +CFLAGS ?= -g -O2 -fno-builtin -ffreestanding -nostdinc -msoft-float -fno-strict-aliasing \ + -mno-altivec -mabi=no-altivec -fno-stack-protector $(WARNFLAGS) + +export CC AS LD CLEAN OBJCOPY OBJDUMP STRIP AR RANLIB CFLAGS + diff --git a/qemu/roms/SLOF/other-licence/Makefile b/qemu/roms/SLOF/other-licence/Makefile new file mode 100644 index 000000000..f46dc171e --- /dev/null +++ b/qemu/roms/SLOF/other-licence/Makefile @@ -0,0 +1,31 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +SUBDIRS= +ifeq ($(SNK_BIOSEMU_APPS), 1) +SUBDIRS += x86emu +endif +CLEANSUBDIRS = $(SUBDIRS) + + +all : + for subdir in $(SUBDIRS) ; do $(MAKE) -C $${subdir} || exit 1 ; done + +# Common targets for all subdirectories: +clean distclean depend: + for subdir in $(CLEANSUBDIRS) ; do $(MAKE) -C $${subdir} $@ ; done diff --git a/qemu/roms/SLOF/other-licence/x86emu/Makefile b/qemu/roms/SLOF/other-licence/x86emu/Makefile new file mode 100644 index 000000000..c25bc15ab --- /dev/null +++ b/qemu/roms/SLOF/other-licence/x86emu/Makefile @@ -0,0 +1,48 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +ROOTDIR ?= ../.. + +LDFLAGS = +ASFLAGS = -I./include -Wa,-mregnames + +#NOTE: -DDEBUG only needed for debugging/tracing... +CFLAGS = -UDEBUG -m64 -I. -I./include -I./include/x86emu \ + -I$(TOP)/clients/net-snk/include -I$(ROOTDIR)/include \ + -I$(ROOTDIR)/lib/libc/include -O3 -nostdinc -fno-builtin \ + -ffreestanding -Wall -Wno-unused + +X86EMU_OBJS = debug.o decode.o fpu.o ops2.o ops.o prim_ops.o sys.o + +%.o: %.S + $(CC) $(ASFLAGS) -c -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $^ + +all: libx86emu.a + +libx86emu.a: $(X86EMU_OBJS) + $(AR) -rc $@ $^ + $(RANLIB) $@ + +clean: + $(RM) *.o *.i *.s libx86emu.a + +distclean: clean + diff --git a/qemu/roms/SLOF/other-licence/x86emu/x86emu_changes.diff b/qemu/roms/SLOF/other-licence/x86emu/x86emu_changes.diff new file mode 100644 index 000000000..52b971a7f --- /dev/null +++ b/qemu/roms/SLOF/other-licence/x86emu/x86emu_changes.diff @@ -0,0 +1,877 @@ +Index: debug.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/debug.c,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- debug.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ debug.c 15 Jan 2008 13:49:25 -0000 1.3 +@@ -52,7 +52,11 @@ + void X86EMU_trace_regs (void) + { + if (DEBUG_TRACE()) { +- x86emu_dump_regs(); ++ if (M.x86.mode & (SYSMODE_PREFIX_DATA | SYSMODE_PREFIX_ADDR)) { ++ x86emu_dump_xregs(); ++ } else { ++ x86emu_dump_regs(); ++ } + } + if (DEBUG_DECODE() && ! DEBUG_DECODE_NOPRINT()) { + printk("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip); +@@ -185,7 +189,7 @@ + for (i=0; i< M.x86.enc_pos; i++) { + sprintf(buf1+2*i,"%02x", fetch_data_byte_abs(s,o+i)); + } +- printk("%-20s",buf1); ++ printk("%-20s ",buf1); + } + + static void print_decoded_instruction (void) +Index: ops2.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/ops2.c,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- ops2.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ ops2.c 20 Mar 2008 15:48:34 -0000 1.3 +@@ -149,8 +149,69 @@ + target += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", target); + TRACE_AND_STEP(); +- if (cond) ++ if (cond) { + M.x86.R_IP = (u16)target; ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " LONG COND "); ++ } ++ DECODE_CLEAR_SEGOVR(); ++ END_OF_INSTR(); ++} ++ ++/**************************************************************************** ++REMARKS: ++Handles opcode 0x0f,0xC8-0xCF ++****************************************************************************/ ++s32 x86emu_bswap(s32 reg) ++{ ++ // perform the byte swap ++ s32 temp = reg; ++ reg = (temp & 0xFF000000) >> 24; ++ reg |= (temp & 0xFF0000) >> 8; ++ reg |= (temp & 0xFF00) << 8; ++ reg |= (temp & 0xFF) << 24; ++ return reg; ++} ++ ++void x86emuOp2_bswap(u8 op2) ++{ ++ /* byte swap 32 bit register */ ++ START_OF_INSTR(); ++ DECODE_PRINTF("BSWAP\t"); ++ switch (op2) { ++ case 0xc8: ++ DECODE_PRINTF("EAX\n"); ++ M.x86.R_EAX = x86emu_bswap(M.x86.R_EAX); ++ break; ++ case 0xc9: ++ DECODE_PRINTF("ECX\n"); ++ M.x86.R_ECX = x86emu_bswap(M.x86.R_ECX); ++ break; ++ case 0xca: ++ DECODE_PRINTF("EDX\n"); ++ M.x86.R_EDX = x86emu_bswap(M.x86.R_EDX); ++ break; ++ case 0xcb: ++ DECODE_PRINTF("EBX\n"); ++ M.x86.R_EBX = x86emu_bswap(M.x86.R_EBX); ++ break; ++ case 0xcc: ++ DECODE_PRINTF("ESP\n"); ++ M.x86.R_ESP = x86emu_bswap(M.x86.R_ESP); ++ break; ++ case 0xcd: ++ DECODE_PRINTF("EBP\n"); ++ M.x86.R_EBP = x86emu_bswap(M.x86.R_EBP); ++ break; ++ case 0xce: ++ DECODE_PRINTF("ESI\n"); ++ M.x86.R_ESI = x86emu_bswap(M.x86.R_ESI); ++ break; ++ case 0xcf: ++ DECODE_PRINTF("EDI\n"); ++ M.x86.R_EDI = x86emu_bswap(M.x86.R_EDI); ++ break; ++ } ++ TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -1702,14 +1763,14 @@ + /* 0xc5 */ x86emuOp2_illegal_op, + /* 0xc6 */ x86emuOp2_illegal_op, + /* 0xc7 */ x86emuOp2_illegal_op, +-/* 0xc8 */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xc9 */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xca */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcb */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcc */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcd */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xce */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcf */ x86emuOp2_illegal_op, /* TODO: bswap */ ++/* 0xc8 */ x86emuOp2_bswap, ++/* 0xc9 */ x86emuOp2_bswap, ++/* 0xca */ x86emuOp2_bswap, ++/* 0xcb */ x86emuOp2_bswap, ++/* 0xcc */ x86emuOp2_bswap, ++/* 0xcd */ x86emuOp2_bswap, ++/* 0xce */ x86emuOp2_bswap, ++/* 0xcf */ x86emuOp2_bswap, + + /* 0xd0 */ x86emuOp2_illegal_op, + /* 0xd1 */ x86emuOp2_illegal_op, +Index: ops.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/ops.c,v +retrieving revision 1.1 +diff -u -u -r1.1 ops.c +--- ops.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ ops.c 20 Mar 2008 16:52:00 -0000 +@@ -1061,7 +1061,11 @@ + imm = (s8)fetch_byte_imm(); + DECODE_PRINTF2("PUSH\t%d\n", imm); + TRACE_AND_STEP(); +- push_word(imm); ++ if (M.x86.mode & SYSMODE_PREFIX_DATA) { ++ push_long(imm); ++ } else { ++ push_word(imm); ++ } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -1256,8 +1260,10 @@ + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); +- if (cond) ++ if (cond) { + M.x86.R_IP = target; ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " NEAR COND "); ++ } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -2516,9 +2522,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2526,6 +2534,8 @@ + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val); + M.x86.R_SI += inc; + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2559,9 +2569,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2574,6 +2586,8 @@ + } + M.x86.R_SI += inc; + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2598,16 +2612,21 @@ + + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + val1 = fetch_data_byte(M.x86.R_SI); + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(val1, val2); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && (ACCESS_FLAG(F_ZF) == 0) ) break; + if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2644,8 +2663,8 @@ + TRACE_AND_STEP(); + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(M.x86.R_SI); + val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +@@ -2655,11 +2674,16 @@ + val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word((u16)val1, (u16)val2); + } +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && ACCESS_FLAG(F_ZF) == 0 ) break; + if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2741,11 +2765,16 @@ + TRACE_AND_STEP(); + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2783,9 +2812,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2795,6 +2826,8 @@ + store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX); + } + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2817,11 +2850,16 @@ + inc = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + M.x86.R_AL = fetch_data_byte(M.x86.R_SI); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_SI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2859,9 +2897,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2871,6 +2911,8 @@ + M.x86.R_AX = fetch_data_word(M.x86.R_SI); + } + M.x86.R_SI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2894,26 +2936,36 @@ + inc = 1; + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(M.x86.R_AL, val2); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(M.x86.R_AL, val2); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { +@@ -2951,8 +3003,8 @@ + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(M.x86.R_EAX, val); +@@ -2960,16 +3012,21 @@ + val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word(M.x86.R_AX, (u16)val); + } +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(M.x86.R_EAX, val); +@@ -2977,10 +3034,15 @@ + val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word(M.x86.R_AX, (u16)val); + } +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { +@@ -3238,9 +3300,9 @@ + DECODE_PRINTF("RET\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); +- RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "NEAR"); + M.x86.R_SP += imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -3254,9 +3316,9 @@ + { + START_OF_INSTR(); + DECODE_PRINTF("RET\n"); +- RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "NEAR"); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -3471,10 +3533,10 @@ + DECODE_PRINTF("RETF\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); +- RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + M.x86.R_CS = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "FAR"); + M.x86.R_SP += imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -3488,10 +3550,10 @@ + { + START_OF_INSTR(); + DECODE_PRINTF("RETF\n"); +- RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + M.x86.R_CS = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "FAR"); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -4020,8 +4082,11 @@ + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); +- M.x86.R_CX -= 1; +- if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF)) /* CX != 0 and !ZF */ ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; ++ if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0 && !ACCESS_FLAG(F_ZF)) /* (E)CX != 0 and !ZF */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -4041,8 +4106,11 @@ + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); +- M.x86.R_CX -= 1; +- if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF)) /* CX != 0 and ZF */ ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; ++ if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0 && ACCESS_FLAG(F_ZF)) /* (E)CX != 0 and ZF */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -4062,8 +4130,11 @@ + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); +- M.x86.R_CX -= 1; +- if (M.x86.R_CX != 0) ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; ++ if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0) /* (E)CX != 0 */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -4085,8 +4156,10 @@ + target = (u16)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); +- if (M.x86.R_CX == 0) ++ if (M.x86.R_CX == 0) { + M.x86.R_IP = target; ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " CXZ "); ++ } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -4213,6 +4286,7 @@ + ip = (s16)fetch_word_imm(); + ip += (s16)M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, " NEAR "); + TRACE_AND_STEP(); + M.x86.R_IP = (u16)ip; + DECODE_CLEAR_SEGOVR(); +@@ -4233,6 +4307,7 @@ + cs = fetch_word_imm(); + DECODE_PRINTF2("%04x:", cs); + DECODE_PRINTF2("%04x\n", ip); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, cs, ip, " FAR "); + TRACE_AND_STEP(); + M.x86.R_IP = ip; + M.x86.R_CS = cs; +@@ -4254,6 +4329,7 @@ + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\n", target); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, target, " BYTE "); + TRACE_AND_STEP(); + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); +@@ -4357,6 +4433,8 @@ + DECODE_PRINTF("REPNE\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPNE; ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.mode |= SYSMODE_32BIT_REP; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -4371,6 +4449,8 @@ + DECODE_PRINTF("REPE\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPE; ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.mode |= SYSMODE_32BIT_REP; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -5013,12 +5093,14 @@ + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(destoffset); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, destval, " WORD "); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, destval2, destval, " FAR "); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + M.x86.R_CS = destval2; +Index: prim_ops.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/prim_ops.c,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- prim_ops.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ prim_ops.c 16 Jan 2008 14:18:15 -0000 1.3 +@@ -1921,7 +1921,7 @@ + void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) + { + #ifdef __HAS_LONG_LONG__ +- s64 res = (s64)d * (s64)s; ++ s64 res = (s64)(s32)d * (s64)(s32)s; + + *res_lo = (u32)res; + *res_hi = (u32)(res >> 32); +@@ -2013,7 +2013,7 @@ + void mul_long(u32 s) + { + #ifdef __HAS_LONG_LONG__ +- u64 res = (u32)M.x86.R_EAX * (u32)s; ++ u64 res = (u64)M.x86.R_EAX * s; + + M.x86.R_EAX = (u32)res; + M.x86.R_EDX = (u32)(res >> 32); +@@ -2312,16 +2312,15 @@ + } + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* in until CX is ZERO. */ +- u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? ++ /* in until (E)CX is ZERO. */ ++ u32 count = ((M.x86.mode & SYSMODE_32BIT_REP) ? + M.x86.R_ECX : M.x86.R_CX); +- + while (count--) { + single_in(size); + M.x86.R_DI += inc; + } + M.x86.R_CX = 0; +- if (M.x86.mode & SYSMODE_PREFIX_DATA) { ++ if (M.x86.mode & SYSMODE_32BIT_REP) { + M.x86.R_ECX = 0; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +@@ -2355,15 +2354,15 @@ + } + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* out until CX is ZERO. */ +- u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? ++ /* out until (E)CX is ZERO. */ ++ u32 count = ((M.x86.mode & SYSMODE_32BIT_REP) ? + M.x86.R_ECX : M.x86.R_CX); + while (count--) { + single_out(size); + M.x86.R_SI += inc; + } + M.x86.R_CX = 0; +- if (M.x86.mode & SYSMODE_PREFIX_DATA) { ++ if (M.x86.mode & SYSMODE_32BIT_REP) { + M.x86.R_ECX = 0; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +Index: sys.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/sys.c,v +retrieving revision 1.1 +retrieving revision 1.2 +diff -u -u -r1.1 -r1.2 +--- sys.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ sys.c 7 Sep 2007 10:03:13 -0000 1.2 +@@ -45,11 +45,6 @@ + #include <x86emu/regs.h> + #include "debug.h" + #include "prim_ops.h" +-#ifdef LINUXBIOS_VERSION +-#include "io.h" +-#else +-#include <sys/io.h> +-#endif + + #ifdef IN_MODULE + #include "xf86_ansic.h" +@@ -220,7 +215,7 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("inb %#04x \n", addr);) +- return inb(addr); ++ return 0; + } + + /**************************************************************************** +@@ -235,7 +230,7 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("inw %#04x \n", addr);) +- return inw(addr); ++ return 0; + } + + /**************************************************************************** +@@ -250,7 +245,7 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("inl %#04x \n", addr);) +- return inl(addr); ++ return 0; + } + + /**************************************************************************** +@@ -264,7 +259,6 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("outb %#02x -> %#04x \n", val, addr);) +- outb(val, addr); + return; + } + +@@ -279,7 +273,6 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("outw %#04x -> %#04x \n", val, addr);) +- outw(val, addr); + return; + } + +@@ -295,7 +288,6 @@ + DB(if (DEBUG_IO_TRACE()) + printk("outl %#08x -> %#04x \n", val, addr);) + +- outl(val, addr); + return; + } + +@@ -405,6 +397,6 @@ + + void X86EMU_setMemBase(void *base, size_t size) + { +- M.mem_base = (int) base; ++ M.mem_base = (unsigned long) base; + M.mem_size = size; + } +Index: include/x86emu/debug.h +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/debug.h,v +retrieving revision 1.1 +retrieving revision 1.4 +diff -u -u -r1.1 -r1.4 +--- include/x86emu/debug.h 7 Sep 2007 10:01:21 -0000 1.1 ++++ include/x86emu/debug.h 20 Mar 2008 15:25:27 -0000 1.4 +@@ -40,8 +40,6 @@ + #ifndef __X86EMU_DEBUG_H + #define __X86EMU_DEBUG_H + +-//#define DEBUG 0 +-#undef DEBUG + /*---------------------- Macros and type definitions ----------------------*/ + + /* checks to be enabled for "runtime" */ +@@ -78,6 +76,8 @@ + # define DEBUG_SYSINT() (M.x86.debug & DEBUG_SYSINT_F) + # define DEBUG_TRACECALL() (M.x86.debug & DEBUG_TRACECALL_F) + # define DEBUG_TRACECALLREGS() (M.x86.debug & DEBUG_TRACECALL_REGS_F) ++# define DEBUG_TRACEJMP() (M.x86.debug & DEBUG_TRACEJMP_F) ++# define DEBUG_TRACEJMPREGS() (M.x86.debug & DEBUG_TRACEJMP_REGS_F) + # define DEBUG_SYS() (M.x86.debug & DEBUG_SYS_F) + # define DEBUG_MEM_TRACE() (M.x86.debug & DEBUG_MEM_TRACE_F) + # define DEBUG_IO_TRACE() (M.x86.debug & DEBUG_IO_TRACE_F) +@@ -96,6 +96,8 @@ + # define DEBUG_SYSINT() 0 + # define DEBUG_TRACECALL() 0 + # define DEBUG_TRACECALLREGS() 0 ++# define DEBUG_TRACEJMP() 0 ++# define DEBUG_TRACEJMPREGS() 0 + # define DEBUG_SYS() 0 + # define DEBUG_MEM_TRACE() 0 + # define DEBUG_IO_TRACE() 0 +@@ -169,14 +171,20 @@ + x86emu_dump_regs(); \ + if (DEBUG_TRACECALL()) \ + printk("%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x); +-# define RETURN_TRACE(n,u,v) \ ++# define RETURN_TRACE(u,v,w,x,s) \ + if (DEBUG_TRACECALLREGS()) \ + x86emu_dump_regs(); \ + if (DEBUG_TRACECALL()) \ +- printk("%04x:%04x: %s\n",u,v,n); ++ printk("%04x:%04x: RET %s %04x:%04x\n",u,v,s,w,x); ++# define JMP_TRACE(u,v,w,x,s) \ ++ if (DEBUG_TRACEJMPREGS()) \ ++ x86emu_dump_regs(); \ ++ if (DEBUG_TRACEJMP()) \ ++ printk("%04x:%04x: JMP %s%04x:%04x\n", u , v, s, w, x); + #else + # define CALL_TRACE(u,v,w,x,s) +-# define RETURN_TRACE(n,u,v) ++# define RETURN_TRACE(u,v,w,x,s) ++# define JMP_TRACE(u,v,w,x,s) + #endif + + #ifdef DEBUG +Index: include/x86emu/regs.h +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/regs.h,v +retrieving revision 1.1 +retrieving revision 1.4 +diff -u -u -r1.1 -r1.4 +--- include/x86emu/regs.h 7 Sep 2007 10:01:21 -0000 1.1 ++++ include/x86emu/regs.h 15 Jan 2008 13:46:40 -0000 1.4 +@@ -231,6 +231,9 @@ + #define SYSMODE_PREFIX_REPNE 0x00000100 + #define SYSMODE_PREFIX_DATA 0x00000200 + #define SYSMODE_PREFIX_ADDR 0x00000400 ++//phueper: for REP(E|NE) Instructions, we need to decide wether it should be using ++//the 32bit ECX register as or the 16bit CX register as count register ++#define SYSMODE_32BIT_REP 0x00000800 + #define SYSMODE_INTR_PENDING 0x10000000 + #define SYSMODE_EXTRN_INTR 0x20000000 + #define SYSMODE_HALTED 0x40000000 +@@ -250,7 +253,8 @@ + SYSMODE_SEGOVR_GS | \ + SYSMODE_SEGOVR_SS | \ + SYSMODE_PREFIX_DATA | \ +- SYSMODE_PREFIX_ADDR) ++ SYSMODE_PREFIX_ADDR | \ ++ SYSMODE_32BIT_REP) + + #define INTR_SYNCH 0x1 + #define INTR_ASYNCH 0x2 +@@ -274,9 +278,9 @@ + */ + u32 mode; + volatile int intr; /* mask of pending interrupts */ +- int debug; ++ volatile int debug; + #ifdef DEBUG +- int check; ++ int check; + u16 saved_ip; + u16 saved_cs; + int enc_pos; +Index: include/x86emu/x86emu.h +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/x86emu.h,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- include/x86emu/x86emu.h 7 Sep 2007 10:01:21 -0000 1.1 ++++ include/x86emu/x86emu.h 19 Oct 2007 08:42:15 -0000 1.3 +@@ -47,6 +47,7 @@ + #include <console.h> + #define printk(x...) printk(BIOS_DEBUG, x) + #else ++#include <stdio.h> + #define printk printf + #endif + +@@ -189,6 +181,8 @@ + #define DEBUG_TRACECALL_REGS_F 0x004000 + #define DEBUG_DECODE_NOPRINT_F 0x008000 + #define DEBUG_SAVE_IP_CS_F 0x010000 ++#define DEBUG_TRACEJMP_F 0x020000 ++#define DEBUG_TRACEJMP_REGS_F 0x040000 + #define DEBUG_SYS_F (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F) + + void X86EMU_trace_regs(void); +@@ -200,5 +194,4 @@ + #ifdef __cplusplus + } /* End of "C" linkage for C++ */ + #endif +- + #endif /* __X86EMU_X86EMU_H */ diff --git a/qemu/roms/SLOF/other-licence/x86emu/x86emu_download.sh b/qemu/roms/SLOF/other-licence/x86emu/x86emu_download.sh new file mode 100755 index 000000000..d4feff9ff --- /dev/null +++ b/qemu/roms/SLOF/other-licence/x86emu/x86emu_download.sh @@ -0,0 +1,61 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ +#!/bin/bash + +#set -x +#set -e + +SVN=`which svn` +PATCH=`which patch` +DIFF_FILE=./x86emu_changes.diff + +# check wether svn, patch, ... is available... + +if [ ! -x $SVN ]; then + echo "subversion executable not found!" + exit -1 +fi +if [ ! -x $PATCH ]; then + echo "patch executable not found!" + exit -1 +fi +if [ ! -r $DIFF_FILE ]; then + echo "diff file $DIFF_FILE not found!" + exit -1 +fi + +# download the x86emu sources from LinuxBIOS subversion + +#revision known to work... +REV=496 + +echo "Checking out x86emu from coreboot-v3 repository revision $REV" +$SVN co svn://coreboot.org/repository/coreboot-v3/util/x86emu -r $REV + +echo "Copying files..." + +mkdir -p include/x86emu +cp -v x86emu/x86emu/*.c . +cp -v x86emu/x86emu/*.h include/x86emu +cp -v x86emu/include/x86emu/*.h include/x86emu + +echo "Removing checkedout subversion director..." + +rm -rf x86emu + +echo "Patching files..." + +$PATCH -p0 < x86emu_changes.diff + + +echo "done" +exit 0 diff --git a/qemu/roms/SLOF/romfs/header.img b/qemu/roms/SLOF/romfs/header.img new file mode 100644 index 000000000..794129c95 --- /dev/null +++ b/qemu/roms/SLOF/romfs/header.img @@ -0,0 +1 @@ +Key.Polynome....XXXXXXXX..Mask..XXXXXXXX.Polynome.Length....XXXX.Header.and.File.lengthXXXXXXXX... und weiter im Text! diff --git a/qemu/roms/SLOF/romfs/tools/.gitignore b/qemu/roms/SLOF/romfs/tools/.gitignore new file mode 100644 index 000000000..3e4afbce7 --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/.gitignore @@ -0,0 +1 @@ +build_romfs diff --git a/qemu/roms/SLOF/romfs/tools/Makefile b/qemu/roms/SLOF/romfs/tools/Makefile new file mode 100644 index 000000000..f86803dba --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/Makefile @@ -0,0 +1,55 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +# FIXME review -I ... +# export NEW_BUILD=1 + +TOPCMNDIR ?= ../.. +INCLCMNDIR ?= ../../include + +include $(TOPCMNDIR)/make.rules + + +CPPFLAGS = -I$(INCLCMNDIR) -I$(INCLBRDDIR) -I. +CFLAGS += $(FLAG) + +SRCS = build_ffs.c cfg_parse.c create_flash.c create_crc.c +OBJS = $(SRCS:%.c=%.o) + +all: build_romfs + +build_romfs: $(OBJS) + $(HOSTCC) $(HOSTCFLAGS) $(FLAG) -o $@ $^ + +testing: build_romfs + $(MAKE) -C test + +%.o: %.c + $(HOSTCC) $(CPPFLAGS) $(HOSTCFLAGS) $(FLAG) -c $< -o $@ + +clean: + rm -f build_romfs *.o + +distclean: clean + rm -f Makefile.dep + + +# Rules for creating the dependency file: +depend: + rm -f Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(HOSTCC) -MM $(CPPFLAGS) $(HOSTCFLAGS) $(SRCS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/romfs/tools/build_ffs.c b/qemu/roms/SLOF/romfs/tools/build_ffs.c new file mode 100644 index 000000000..218de75f0 --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/build_ffs.c @@ -0,0 +1,476 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include <cfgparse.h> +#include <createcrc.h> + +#define FFS_TARGET_HEADER_SIZE (4 * 8) + +extern int verbose; + +#define pad8_num(x) (((x) + 7) & ~7) + +static int +file_exist(const char *name, int errdisp) +{ + struct stat fileinfo; + + memset((void *) &fileinfo, 0, sizeof(struct stat)); + if (stat(name, &fileinfo) != 0) { + if (0 != errdisp) { + perror(name); + } + return 0; + } + if (S_ISREG(fileinfo.st_mode)) { + return 1; + } + return 0; +} + +static int +file_getsize(const char *name) +{ + int rc; + struct stat fi; + + rc = stat(name, &fi); + if (rc != 0) + return -1; + return fi.st_size; +} + +static int +ffshdr_compare(const void *_a, const void *_b) +{ + const struct ffs_header_t *a = *(struct ffs_header_t * const *) _a; + const struct ffs_header_t *b = *(struct ffs_header_t * const *) _b; + + if (a->romaddr == b->romaddr) + return 0; + if (a->romaddr > b->romaddr) + return 1; + return -1; +} + +static void +hdr_print(struct ffs_header_t *hdr) +{ + printf("hdr: %p\n", hdr); + printf("\taddr: %08llx token: %s\n" + "\tflags: %08llx romaddr: %08llx image_len: %08x\n" + "\tsave_len: %08llx ffsize: %08x hdrsize: %08x\n" + "\ttokensize: %08x\n", + hdr->addr, hdr->token, hdr->flags, hdr->romaddr, + hdr->imagefile_length, hdr->save_data_len, + hdr->ffsize, hdr->hdrsize, hdr->tokensize); +} + +int +reorder_ffs_chain(struct ffs_chain_t *fs) +{ + int i, j; + int free_space; + unsigned long long addr; + struct ffs_header_t *hdr; + int fix, flx, res, tab_size = fs->count; + struct ffs_header_t *fix_tab[tab_size]; /* fixed offset */ + struct ffs_header_t *flx_tab[tab_size]; /* flexible offset */ + struct ffs_header_t *res_tab[tab_size]; /* result */ + + /* determine size data to be able to do the reordering */ + for (hdr = fs->first; hdr; hdr = hdr->next) { + if (hdr->linked_to) + hdr->imagefile_length = 0; + else + hdr->imagefile_length = file_getsize(hdr->imagefile); + if (hdr->imagefile_length == -1) + return -1; + + hdr->tokensize = pad8_num(strlen(hdr->token) + 1); + hdr->hdrsize = FFS_TARGET_HEADER_SIZE + hdr->tokensize; + hdr->ffsize = + hdr->hdrsize + pad8_num(hdr->imagefile_length) + 8; + } + + memset(res_tab, 0, tab_size * sizeof(struct ffs_header_t *)); + memset(fix_tab, 0, tab_size * sizeof(struct ffs_header_t *)); + memset(flx_tab, 0, tab_size * sizeof(struct ffs_header_t *)); + + /* now start with entries having fixed offs, reorder if needed */ + for (fix = 0, flx = 0, hdr = fs->first; hdr; hdr = hdr->next) + if (needs_fix_offset(hdr)) + fix_tab[fix++] = hdr; + else + flx_tab[flx++] = hdr; + qsort(fix_tab, fix, sizeof(struct ffs_header_t *), ffshdr_compare); + + /* + * for fixed files we need to also remove the hdrsize from the + * free space because it placed in front of the romaddr + */ + for (addr = 0, res = 0, i = 0, j = 0; i < fix; i++) { + fix_tab[i]->addr = fix_tab[i]->romaddr - fix_tab[i]->hdrsize; + free_space = fix_tab[i]->addr - addr; + + /* insert as many flexible files as possible */ + for (; free_space > 0 && j < flx; j++) { + if (flx_tab[j]->ffsize <= free_space) { /* fits */ + flx_tab[j]->addr = addr; + free_space -= flx_tab[j]->ffsize; + addr += flx_tab[j]->ffsize; + res_tab[res++] = flx_tab[j]; + } else + break; + } + res_tab[res++] = fix_tab[i]; + addr = fix_tab[i]->romaddr + fix_tab[i]->ffsize - + fix_tab[i]->hdrsize; + } + /* at the end fill up the table with remaining flx entries */ + for (; j < flx; j++) { + flx_tab[j]->addr = addr; + addr += flx_tab[j]->ffsize; + res_tab[res++] = flx_tab[j]; + } + + if (verbose) { + printf("--- resulting order ---\n"); + for (i = 0; i < tab_size; i++) + hdr_print(res_tab[i]); + } + + /* to check if the requested romfs images is greater than + * the specified romfs_size it is necessary to add 8 for + * the CRC to the totalsize */ + addr += 8; + + /* sanity checking if user specified maximum romfs size */ + if ((fs->romfs_size != 0) && addr > fs->romfs_size) { + fprintf(stderr, "[build_romfs] romfs_size specified as %d " + "bytes, but %lld bytes need to be written.\n", + fs->romfs_size, addr); + return 1; + } + + /* resort result list */ + for (i = 0; i < tab_size - 1; i++) + res_tab[i]->next = res_tab[i + 1]; + res_tab[i]->next = NULL; + fs->first = res_tab[0]; + return 0; +} + +/** + * allocate memory for a romfs file including header + */ +static unsigned char * +malloc_file(int hdrsz, int datasz, int *ffsz) +{ + void *tmp; + + /* complete file size is: + * header + 8byte aligned(data) + end of file marker (-1) */ + *ffsz = hdrsz + pad8_num(datasz) + 8; + /* get the mem */ + tmp = malloc(*ffsz); + + if (!tmp) + return NULL; + + memset(tmp, 0, *ffsz); + + return (unsigned char *) tmp; +} + +static int +copy_file(struct ffs_header_t *hdr, unsigned char *ffile, int datasize, + int ffile_offset, int ffsize) +{ + int cnt = 0; + int imgfd; + int i; + + if (!file_exist(hdr->imagefile, 1)) { + printf("access error to file: %s\n", hdr->imagefile); + free(ffile); + return -1; + } + + imgfd = open(hdr->imagefile, O_RDONLY); + if (0 >= imgfd) { + perror(hdr->imagefile); + free(ffile); + return -1; + } + + /* now copy file to file buffer */ + /* FIXME using fread might be a good idea so + that we do not need to deal with shortened + reads/writes. Also error handling looks + broken to me. Are we sure that all data is + read when exiting this loop? */ + while (1) { + i = read(imgfd, ffile + ffile_offset, ffsize - ffile_offset); + if (i <= 0) + break; + ffile_offset += i; + cnt += i; + } + + /* sanity check */ + if (cnt != datasize) { + printf("BUG!!! copy error on image file [%s](e%d, g%d)\n", + hdr->imagefile, datasize, cnt); + close(imgfd); + free(ffile); + return -1; + } + + close(imgfd); + + return cnt; +} + +static uint64_t +next_file_offset(struct ffs_header_t *hdr, int rom_pos, int ffsize) +{ + uint64_t tmp; + + /* no next file; end of filesystem */ + if (hdr->next == NULL) + return 0; + + if (hdr->next->romaddr > 0) { + /* the next file does not follow directly after the + * current file because it requested to be + * placed at a special address; + * we need to calculate the offset of the + * next file; + * the next file starts at hdr->next->romaddr which + * is the address requested by the user */ + tmp = hdr->next->romaddr; + /* the next file starts, however, a bit earlier; + * we need to point at the header of the next file; + * therefore it is necessary to subtract the header size + * of the _next_ file */ + tmp -= FFS_TARGET_HEADER_SIZE; + /* also remove the length of the filename of the _next_ + * file */ + tmp -= pad8_num(strlen(hdr->next->token) + 1); + /* and it needs to be relative to the current file */ + tmp -= rom_pos; + return tmp; + } + + /* if no special treatment is required the next file just + * follows after the current file; + * therefore just return the complete filesize as offset */ + return ffsize; +} + +static int +next_file_address(struct ffs_header_t *hdr, unsigned int rom_pos, int hdrsize, + unsigned int num_files) +{ + /* check if file wants a specific address */ + void *tmp; + + if ((hdr->flags & FLAG_LLFW) == 0) + /* flag to get a specific address has been set */ + return rom_pos; + + if (hdr->romaddr == 0) + /* if the requested address is 0 then + * something is not right; ignore the flag */ + return rom_pos; + + /* check if romaddress is below current position */ + if (hdr->romaddr < (rom_pos + hdrsize)) { + printf("[%s] ERROR: requested impossible " "romaddr of %llx\n", + hdr->token, hdr->romaddr); + return -1; + } + + /* spin offset to new position */ + if (pad8_num(hdr->romaddr) != hdr->romaddr) { + printf("BUG!!!! pad8_num(hdr->romaddr) != hdr->romaddr\n"); + return -1; + } + + tmp = malloc(hdr->romaddr - rom_pos - hdrsize); + + if (!tmp) + return -1; + + memset(tmp, 0, hdr->romaddr - rom_pos - hdrsize); + if (buildDataStream(tmp, hdr->romaddr - rom_pos - hdrsize)) { + free(tmp); + printf("write failed\n"); + return -1; + } + + free(tmp); + + if (!num_files) + printf("\nWARNING: The filesystem will have no entry header!\n" + " It is still usable but you need to find\n" + " the FS by yourself in the image.\n\n"); + + return hdr->romaddr - hdrsize; +} + +int +build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime) +{ + int ofdCRC; + int ffsize, datasize, i; + int tokensize, hdrsize, ffile_offset, hdrbegin; + struct ffs_header_t *hdr; + unsigned char *ffile; + unsigned int rom_pos = 0; + unsigned int num_files = 0; + uint64_t tmp; + + if (NULL == fs->first) { + return 1; + } + hdr = fs->first; + + /* check output file and open it for creation */ + if (file_exist(outfile, 0)) { + printf("Output file (%s) will be overwritten\n", outfile); + } + + while (hdr) { + + if (hdr->linked_to) { + printf("\nBUG!!! links not supported anymore\n"); + return 1; + } + + /* add +1 to strlen for zero termination */ + tokensize = pad8_num(strlen(hdr->token) + 1); + hdrsize = FFS_TARGET_HEADER_SIZE + tokensize; + datasize = file_getsize(hdr->imagefile); + + if (datasize == -1) { + perror(hdr->imagefile); + return 1; + } + + ffile_offset = 0; + ffile = malloc_file(hdrsize, datasize, &ffsize); + + if (NULL == ffile) { + perror("alloc mem for ffile"); + return 1; + } + + /* check if file wants a specific address */ + rom_pos = next_file_address(hdr, rom_pos, hdrsize, num_files); + hdrbegin = rom_pos; + + if (hdrbegin == -1) { + /* something went wrong */ + free(ffile); + return 1; + } + + /* write header ******************************************* */ + /* next addr ********************************************** */ + tmp = next_file_offset(hdr, rom_pos, ffsize); + + *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp); + rom_pos += 8; + ffile_offset += 8; + + /* length ************************************************* */ + hdr->save_data_len = datasize; + + *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(datasize); + rom_pos += 8; + ffile_offset += 8; + + /* flags ************************************************** */ + *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(hdr->flags); + rom_pos += 8; + ffile_offset += 8; + + /* datapointer ******************************************** */ + + //save-data pointer is relative to rombase + hdr->save_data = hdrbegin + hdrsize; + hdr->save_data_valid = 1; + //changed pointers to be relative to file: + tmp = hdr->save_data - hdrbegin; + + *(uint64_t *) (ffile + ffile_offset) = cpu_to_be64(tmp); + rom_pos += 8; + ffile_offset += 8; + + /* name (token) ******************************************* */ + memset(ffile + ffile_offset, 0, tokensize); + strcpy((char *) ffile + ffile_offset, hdr->token); + rom_pos += tokensize; + ffile_offset += tokensize; + + /* image file ********************************************* */ + i = copy_file(hdr, ffile, datasize, ffile_offset, ffsize); + + if (i == -1) + return 1; + + /* pad file */ + rom_pos += i + pad8_num(datasize) - datasize; + ffile_offset += i + pad8_num(datasize) - datasize; + + /* limiter ************************************************ */ + *(uint64_t *) (ffile + ffile_offset) = -1; + rom_pos += 8; + ffile_offset += 8; + + if (buildDataStream(ffile, ffsize) != 0) { + printf + ("Failed while processing file '%s' (size = %d bytes)\n", + hdr->imagefile, datasize); + return 1; + } + free(ffile); + hdr = hdr->next; + num_files++; + } + + /* + * FIXME Current limination seems to be about 4MiB. + */ + ofdCRC = open(outfile, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (0 > ofdCRC) { + perror(outfile); + return 1; + } + i = writeDataStream(ofdCRC, notime); + close(ofdCRC); + + if (i) + return 1; + return 0; +} diff --git a/qemu/roms/SLOF/romfs/tools/cfg_parse.c b/qemu/roms/SLOF/romfs/tools/cfg_parse.c new file mode 100644 index 000000000..5137fbe4f --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/cfg_parse.c @@ -0,0 +1,371 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include <cfgparse.h> + +static int inbetween_white(char *s, int max, char **start, char **end, + char **next); +static int add_header(struct ffs_chain_t *, struct ffs_header_t *); + +static int glob_come_from_cr = 0; + +static int +find_next_entry(int file, struct ffs_chain_t *chain) +{ +#define MAX_LINE_SIZE 1024 + char lnbuf[MAX_LINE_SIZE], b0 = 0, b1 = 0; + char *start, *end, *next; + struct ffs_header_t *hdr; //, *hdr2; + int lc, rc; + char c; + + /* search for new config line */ + if (0 == glob_come_from_cr) { + while (1 == (rc = read(file, &c, 1))) { + //printf("b0=%c b1=%c c=%c\n", + // b0, b1, c); + b0 = b1; + b1 = c; + /* this looks for starting sign "<CR>[^#]" */ + if (((0x0a == b0) || (0x0d == b0)) && + (('#' != b1) && (0x0a != b1) && (0x0d != b1))) { + break; + } + } + } else { + /* normalize */ + while (1 == (rc = read(file, &c, 1))) { + //printf("read c=%c\n", c); + if ((0x0a != c) && (0x0d != c)) { + break; + } + } + glob_come_from_cr = 0; + //printf("debug: glob_come_from_cr = 0\n"); + } + if (1 != rc) { + return 1; + } + + /* now buffer it until end of line */ + memset((void *) lnbuf, 0, MAX_LINE_SIZE); + lnbuf[0] = c; + lc = 1; + while ((1 == read(file, &(lnbuf[lc]), 1)) && (lc < MAX_LINE_SIZE)) { + //printf("read lnbuf=%c\n", lnbuf[lc]); + if ((0x0a == lnbuf[lc]) || (0x0d == lnbuf[lc])) { + glob_come_from_cr = 1; + //printf("debug: glob_come_from_cr = 1\n"); + break; + } + lc++; + } + + /* allocate header */ + hdr = malloc(sizeof(struct ffs_header_t)); + if (NULL == hdr) { + perror("alloc memory"); + return 2; + } + memset((void *) hdr, 0, sizeof(struct ffs_header_t)); + + /* attach header to chain */ + if (0 != add_header(chain, hdr)) { + return 2; + } + + /**********************************************************/ + /* extract token name *********************************** */ + start = NULL; + if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) { + printf("parsing error 1"); + return 2; + } + /* get memory for it */ + hdr->token = malloc(end - start + 1); + if (NULL == hdr->token) { + return 2; + } + /* set string */ + strncpy(hdr->token, start, end - start + 1); + hdr->token[end - start] = 0; + + /**********************************************************/ + /* extract file name *********************************** */ + if (NULL == next) { + return 2; + } + start = next; + if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) { + printf("parsing error 1"); + return 2; + } + + /* get memory for it */ + hdr->imagefile = malloc(end - start + 1); + if (NULL == hdr->imagefile) { + return 2; + } + + /* check if file is existing */ + + /* set string */ + strncpy(hdr->imagefile, start, end - start + 1); + hdr->imagefile[end - start] = 0; + + /* check if entry is linked to another header */ + if (':' == *start) { + printf + ("\nERROR: links are removed as feature in this version\n"); + return 2; + + /* + start++; + if (0 != find_entry_by_token(chain, hdr->imagefile+1, &hdr2)) { + printf("[%s]: link to [%s] not found\n", + hdr->token, hdr->imagefile+1); + dump_fs_contents(chain); + return 2; + } + hdr->linked_to = hdr2; + */ + } + + /**********************************************************/ + /* extract flags name *********************************** */ + if (NULL == next) { + return 2; + } + start = next; + if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) { + printf("parsing error 1"); + return 2; + } + hdr->flags = strtoul(start, NULL, 16); + + /**********************************************************/ + /* extract rom start name *********************************** */ + if (NULL == next) { + return 2; + } + start = next; + if (inbetween_white(lnbuf, MAX_LINE_SIZE, &start, &end, &next) != 0) { + printf("parsing error 1"); + return 2; + } + if ('-' == *start) { + /* this means not specific address request for data */ + hdr->romaddr = 0; + } else { + /* data has to begin at specific address */ + hdr->romaddr = strtoul(start, NULL, 16); + } + + return 0; +} + +int +read_config(int conf_file, struct ffs_chain_t *ffs_chain) +{ + int rc; + + while (1) { + rc = find_next_entry(conf_file, ffs_chain); + if (rc != 0) + break; + } + return rc; +} + +static int +inbetween_white(char *s, int max, char **start, char **end, char **next) +{ + int pos = 0, posalt; + + if (NULL != *start) { + pos = *start - s; + s = *start; + } + + /* wind to first non white */ + while (pos < max) { + if ((' ' == *s) || (' ' == *s)) { + s++; + pos++; + continue; + } + break; + } + if (pos >= max) { + /* no non-white found */ + return 1; + } + + /* assign start */ + *start = s; + + /* wind to end of non white or end of buffer */ + posalt = pos; + while (pos < max) { + if ((' ' == *s) || (' ' == *s) || + (0x0a == *s) || (0x0d == *s)) { + break; + } + s++; + pos++; + } + + if (pos == posalt) { + return 1; + } + + *end = s; + + if ((pos + 1) >= max) { + *next = NULL; + } else { + *next = s; + } + + return 0; +} + +int +add_header(struct ffs_chain_t *chain, struct ffs_header_t *hdr) +{ + struct ffs_header_t *next; + + if (NULL == chain->first) { + chain->count = 1; + chain->first = hdr; + return 0; + } + next = chain->first; + + /* find last */ + while (NULL != next->next) { + next = next->next; + } + next->next = hdr; + chain->count++; + + return 0; +} + +void +dump_fs_contents(struct ffs_chain_t *chain) +{ + struct ffs_header_t *next; + + if (NULL == chain->first) { + printf("no contents in fs\n"); + return; + } + next = chain->first; + + while (1) { + if (NULL != next->token) { + printf("Token [%s] ", next->token); + } else { + printf(" [not-set], "); + } + + if (NULL != next->imagefile) { + printf(" <%s>, ", next->imagefile); + } else { + printf(" file<not-set>, "); + } + + printf("flags<%llx>, ", next->flags); + printf("romaddr<%llx>, ", next->romaddr); + + if (NULL != next->linked_to) { + printf("linked to [%s]", next->linked_to->token); + } + + printf("\n"); + if (NULL == next->next) { + break; + } + + next = next->next; + } + +} + +void +free_chain_memory(struct ffs_chain_t *chain) +{ + struct ffs_header_t *hdr, *next_hdr; + + if (NULL != chain->first) { + hdr = chain->first; + chain->first = NULL; + } else { + return; + } + + while (NULL != hdr) { + //printf("%p ", hdr); + if (NULL != hdr->token) { + //printf("free up %s\n", hdr->token); + free(hdr->token); + } + if (NULL != hdr->imagefile) { + free(hdr->imagefile); + } + next_hdr = hdr->next; + free(hdr); + hdr = next_hdr; + } +} + + +/* + * Detect duplicate entries in the romfs list + */ +void +find_duplicates(struct ffs_chain_t *chain) +{ + struct ffs_header_t *act, *sub; + + if (NULL == chain->first) { + printf("no contents in fs\n"); + return; + } + act = chain->first; + + do { + sub = act->next; + while (sub != NULL) { + + if (act->token == NULL || sub->token == NULL) { + printf("find_duplicates: token not set!\n"); + } else if (strcmp(act->token, sub->token) == 0) { + printf("*** NOTE: duplicate romfs file '%s'.\n", + act->token); + } + sub = sub->next; + } + + act = act->next; + + } while (act != NULL); + +} diff --git a/qemu/roms/SLOF/romfs/tools/cfgparse.h b/qemu/roms/SLOF/romfs/tools/cfgparse.h new file mode 100644 index 000000000..ed5c8856d --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/cfgparse.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef CFGPARSE_H +#define CFGPARSE_H + +#include <byteswap.h> +#include <endian.h> + +#if __BYTE_ORDER == __BIG_ENDIAN +#define cpu_to_be64(x) (x) +#else +#define cpu_to_be64(x) bswap_64(x) +#endif + +struct ffs_chain_t { + int count; + unsigned int romfs_size; + struct ffs_header_t *first; +}; + +#define FLAG_LLFW 1 /* low level firmware at fix offs in romfs */ + +#define needs_fix_offset(hdr) ((hdr)->flags & FLAG_LLFW) + +struct ffs_header_t { + unsigned long long flags; + unsigned long long romaddr; + char *token; + char *imagefile; + int imagefile_length; + struct ffs_header_t *linked_to; + struct ffs_header_t *next; + unsigned long long save_data; + unsigned long long save_data_len; + int save_data_valid; + + unsigned long long addr; /* tmp */ + int hdrsize; /* tmp */ + int tokensize; /* tmp */ + int ffsize; /* tmp */ +}; + +void dump_fs_contents(struct ffs_chain_t *chain); +void find_duplicates(struct ffs_chain_t *chain); +void free_chain_memory(struct ffs_chain_t *chain); + +int read_config(int conf_file, struct ffs_chain_t *ffs_chain); +int reorder_ffs_chain(struct ffs_chain_t *fs); +int build_ffs(struct ffs_chain_t *fs, const char *outfile, int notime); +#endif diff --git a/qemu/roms/SLOF/romfs/tools/create_crc.c b/qemu/roms/SLOF/romfs/tools/create_crc.c new file mode 100644 index 000000000..51f137d8e --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/create_crc.c @@ -0,0 +1,467 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <cfgparse.h> +#include <time.h> +#include <calculatecrc.h> +#include <product.h> +#include "createcrc.h" + +int createHeaderImage(int); +unsigned int calCRCEthernet32(unsigned char *TextPtr, + unsigned long int TextLength, + unsigned int AccumCRC); +int createCRCParameter(uint64_t * ui64RegisterMask, + unsigned int *iRegisterLength); +uint64_t calCRCbyte(unsigned char *TextPtr, uint32_t Residual, + uint64_t AccumCRC); +uint64_t calCRCword(unsigned char *TextPtr, uint32_t Residual, + uint64_t AccumCRC); +uint64_t checkCRC(unsigned char *TextPtr, uint32_t Residual, uint64_t AccumCRC); + +/* file length in bytes */ +static uint64_t ui64globalFileSize = 0; +/* space for the file stream >= 4MB + 4bytes */ +static unsigned char pucFileStream[4400000]; +/* header length in bytes */ +static uint64_t ui64globalHeaderSize = 0; +/* flag to filter detect the header in buildDataStream() */ +static int iglobalHeaderFlag = 1; +static uint64_t ui64Generator1; + +/** + * Build the file image and store it as Data Stream of bytes + * calculate a first CRC for the first file and + * catch the position of this CRC + */ +int +buildDataStream(unsigned char *pucbuf, int size) +{ + if (ui64globalFileSize + size > sizeof(pucFileStream)) { + printf("Error: File size is too big!\n"); + return -1; + } + + /* copy the data into the destination buffer */ + memcpy(pucFileStream + ui64globalFileSize, pucbuf, size); + ui64globalFileSize += size; + + if (iglobalHeaderFlag == 1) { // catch header + + ui64globalHeaderSize = ui64globalFileSize; + iglobalHeaderFlag = 0; + } + + return 0; +} + +/** + * write Header.img + */ +int +createHeaderImage(int notime) +{ + int iCounter; + uint64_t ui64RomAddr, ui64DataAddr; + time_t caltime; + struct tm *tm; + char *pcVersion; + char dastr[16] = { 0, }; + unsigned long long da = 0; + + union { + unsigned char pcArray[FLASHFS_HEADER_DATA_SIZE]; + struct stH stHeader; + } uHeader; + + /* initialize Header */ + memset(uHeader.pcArray, 0x00, FLASHFS_HEADER_DATA_SIZE); + + /* read driver info */ + if (NULL != (pcVersion = getenv("DRIVER_NAME"))) { + strncpy(uHeader.stHeader.version, pcVersion, 16); + } else if (NULL != (pcVersion = getenv("USER"))) { + strncpy(uHeader.stHeader.version, pcVersion, 16); + } else if (pcVersion == NULL) { + strncpy(uHeader.stHeader.version, "No known user!", 16); + } + + if (!notime) { + /* read time and write it into data stream */ + if ((caltime = time(NULL)) == -1) { + printf("time error\n"); + } + if ((tm = localtime(&caltime)) == NULL) { + printf("local time error\n"); + } + // length must be 13 instead 12 because of terminating + // NUL. Therefore uH.stH.platform_revison must be + // written later to overwrite the terminating NUL + if (strftime(dastr, 15, "0x%Y%m%d%H%M", tm) == 0) { + printf("strftime error\n"); + } + da = cpu_to_be64(strtoll(dastr, NULL, 16)); + } + memcpy(uHeader.stHeader.date, &da, 8); + + /* write Magic value into data stream */ + strncpy(uHeader.stHeader.magic, FLASHFS_MAGIC, 8); + /* write platform name into data stream */ + strcpy(uHeader.stHeader.platform_name, FLASHFS_PLATFORM_MAGIC); + /* write platform revision into data stream */ + strcpy(uHeader.stHeader.platform_revision, FLASHFS_PLATFORM_REVISION); + + + /* fill end of file info (8 bytes of FF) into data stream */ + uHeader.stHeader.ui64FileEnd = -1; + + /* read address of next file and address of header date, both are 64 bit values */ + ui64RomAddr = 0; + ui64DataAddr = 0; + for (iCounter = 0; iCounter < 8; iCounter++) { + /* addr of next file */ + ui64RomAddr = (ui64RomAddr << 8) + pucFileStream[FLASHFS_ROMADDR + iCounter]; + /* addr of header data */ + ui64DataAddr = (ui64DataAddr << 8) + pucFileStream[FLASHFS_DATADDR + iCounter]; + } + + /* calculate final flash-header-size and flash-file-size */ + /* calculate end addr of header */ + ui64globalHeaderSize = (uint32_t) ui64DataAddr + (uint32_t) FLASHFS_HEADER_DATA_SIZE; + /* cut 64 bit to place CRC for File-End */ + ui64globalHeaderSize -= 8; + /* add 64 bit to place CRC behind File-End */ + ui64globalFileSize += 8; + + if (ui64globalHeaderSize >= ui64RomAddr) { + printf("%s\n", "--- Header File to long"); + return 1; + } + + /* fill free space in Header with zeros */ + memset(&pucFileStream[ui64DataAddr], 0, (ui64RomAddr - ui64DataAddr)); + /* place data to header */ + memcpy(&pucFileStream[ui64DataAddr], uHeader.pcArray, + FLASHFS_HEADER_DATA_SIZE); + + /* insert header length into data stream */ + *(uint64_t *) (pucFileStream + FLASHFS_HEADER_SIZE_ADDR) = + cpu_to_be64(ui64globalHeaderSize); + + /* insert flash length into data stream */ + *(uint64_t *) (pucFileStream + ui64DataAddr + FLASHFS_FILE_SIZE_ADDR) = + cpu_to_be64(ui64globalFileSize); + + /* insert zeros as placeholder for CRC */ + *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) = 0; + *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) = 0; + + return 0; +} + +/** + * calculate standart ethernet 32 bit CRC + * generator polynome is 0x104C11DB7 + * this algorithm can be used for encoding and decoding + */ +unsigned int +calCRCEthernet32(unsigned char *TextPtr, unsigned long int TextLength, + unsigned int AccumCRC) +{ + const unsigned int CrcTableHigh[16] = { + 0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90, + 0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7, + 0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E, + 0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09 + }; + const unsigned CrcTableLow[16] = { + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, + 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, + 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD + }; + + unsigned char *Buffer = TextPtr; + unsigned long int Residual = TextLength; + + + while (Residual > 0) { + unsigned int Temp = ((AccumCRC >> 24) ^ *Buffer) & 0x000000ff; + AccumCRC <<= 8; + AccumCRC ^= CrcTableHigh[Temp / 16]; + AccumCRC ^= CrcTableLow[Temp % 16]; + ++Buffer; + --Residual; + } + return AccumCRC; +} + +/** + * create CRC Parameter: CRC Polynome, Shiftregister Mask and length + * + * ui64Generator[0] = 0; + * ui64Generator[1] = 0x42F0E1EB; + * ui64Generator[1] = (ui64Generator[1] << 32) + 0xA9EA3693; + * iRegisterLength = 63; + * ui64RegisterMask = 0xffffffff; + * ui64RegisterMask = ((ui64RegisterMask) << 32) + 0xffffffff; + * + * ucl=0x00000000ffffffff = Mask for 32 bit LSFR to cut down number of bits + * in the variable to get the same length as LFSR + * + * il = length of LSFR = degree of generator polynom reduce il by one to calculate the degree + * of the highest register in LSFR + * + * Examples: + * CRC-16 for Tap: x16 + x15 + x2 + 1 + * generator = 0x8005, il = 16, ucl = 0x000000000000FFFF + * + * CRC-16 for Floppy: x16 + x12 + x5 +1 + * generator = 0x1021, il = 16, ucl = 0x000000000000FFFF + * + * CRC-32 for Ethernet: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 + * generator = 0x04C11DB7, il = 32, ucl = 0x00000000FFFFFFFF + * + * CRC-64 SP-TrEMBL x64 + x4 + x3 + x + 1 (maximal-length LFSR) + * generator = 0x1B, il = 64, ucl = 0xFFFFFFFFFFFFFFFF + * + * CRC-64 improved + * x64 + x63 + x61 + x59 + x58 + x56 + x55 + x52 + x49 + x48 + x47 + x46+ x44 + + * x41 + x37 + x36 + x34 + x32 + x31 + x28 + x26 + x23 + x22 + x19 + x16 + x13 + + * x12 + x10 + x9 + x6 + x4 + x3 + 1 + * (see http://www.cs.ud.ac.uk/staff/D.Jones/crcbote.pdf) + * generator = 0xAD93D23594C9362D, il = 64, ucl = 0xFFFFFFFFFFFFFFFF + * + * CRC-64 DLT1 spec + * x64 + x62 + x57 + x55 + x54 + x53 + x52 + x47 + x46 + x45 + x40 + x39 + x38 + x37 + + * x35 + x33 + x32 + x31 + x29 + x27 + x24 + x23 + x22 + x21 + x19 + x17 + x13 + x12 + + * x10 + x9 + x7 + x4 + x + 1 + * (see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf -> page63) + * generator = 0x42F0E1EBA9EA3693 + * + * CRC-64 from internet G(x)= 1006003C000F0D50B + */ +int +createCRCParameter(uint64_t * ui64RegisterMask, unsigned int *uiRegisterLength) +{ + enum Generators { Tape_16, Floppy_16, Ethernet_32, SPTrEMBL_64, + SPTrEMBL_improved_64, DLT1_64 + }; + enum Generators Generator; + + Generator = CRC_METHODE; + switch (Generator) { + case Tape_16:{ + *ui64RegisterMask = 0x0000ffff; + ui64Generator1 = 0x00008005; + *uiRegisterLength = 16; + break; + } + case Floppy_16:{ + *ui64RegisterMask = 0x0000ffff; + ui64Generator1 = 0x00001021; + *uiRegisterLength = 16; + break; + } + case Ethernet_32:{ + *ui64RegisterMask = 0xffffffff; + ui64Generator1 = 0x04C11DB7; + *uiRegisterLength = 32; + break; + } + case SPTrEMBL_64:{ + *ui64RegisterMask = 0xffffffff; + *ui64RegisterMask = + ((*ui64RegisterMask) << 32) + 0xffffffff; + ui64Generator1 = 0x0000001B; + *uiRegisterLength = 64; + break; + } + case SPTrEMBL_improved_64:{ + *ui64RegisterMask = 0xffffffff; + *ui64RegisterMask = + ((*ui64RegisterMask) << 32) + 0xffffffff; + ui64Generator1 = 0xAD93D235; + ui64Generator1 = (ui64Generator1 << 32) + 0x94C9362D; + *uiRegisterLength = 64; + break; + } + case DLT1_64:{ + *ui64RegisterMask = 0xffffffff; + *ui64RegisterMask = + ((*ui64RegisterMask) << 32) + 0xffffffff; + ui64Generator1 = 0x42F0E1EB; + ui64Generator1 = (ui64Generator1 << 32) + 0xA9EA3693; + *uiRegisterLength = 64; + break; + } + } + (*uiRegisterLength)--; + + return 0; +} + +/** + * Check CRC by using Linear Feadback Shift Register (LFSR) + */ +uint64_t +calCRCbyte(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC) +{ + + uint64_t ui64Mask, ui64Generator0; + uint8_t ui8Buffer; + unsigned int uiRegisterLength; + int iShift; + + createCRCParameter(&ui64Mask, &uiRegisterLength); + + ui8Buffer = (*cPtr); + while (ui32NoWords > 0) { + for (iShift = 7; iShift >= 0; iShift--) { + + ui64Generator0 = (AccumCRC >> uiRegisterLength); + AccumCRC <<= 1; + ui64Generator0 &= 0x01; + ui64Generator0 = (0 - ui64Generator0); + AccumCRC ^= (ui64Generator1 & ui64Generator0); + } + AccumCRC ^= ui8Buffer; + AccumCRC &= ui64Mask; + ui32NoWords -= 1; + cPtr += 1; + ui8Buffer = (*cPtr); + } + return AccumCRC; +} + +/** + * Check CRC by using Linear Feadback Shift Register (LFSR) + */ +uint64_t +calCRCword(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC) +{ + + uint64_t ui64Mask, ui64Generator0; + uint16_t ui16Buffer; + unsigned int uiRegisterLength; + int iShift; + + createCRCParameter(&ui64Mask, &uiRegisterLength); + + if ((ui32NoWords % 2) != 0) { + /* if Data string does not end at word boundery add one byte */ + ui32NoWords++; + cPtr[ui32NoWords] = 0; + } + ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1)); + while (ui32NoWords > 0) { + for (iShift = 15; iShift >= 0; iShift--) { + ui64Generator0 = (AccumCRC >> uiRegisterLength); + AccumCRC <<= 1; + ui64Generator0 &= 0x01; + ui64Generator0 = (0 - ui64Generator0); + AccumCRC ^= (ui64Generator1 & ui64Generator0); + } + AccumCRC ^= ui16Buffer; + AccumCRC &= ui64Mask; + ui32NoWords -= 2; + cPtr += 2; + ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1)); + } + return AccumCRC; +} + +uint64_t +checkCRC(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC) +{ + + enum Generators { Ethernet_32 }; + enum Generators Generator; + uint64_t ui64Buffer = AccumCRC; + + Generator = CRC_METHODE; + + switch (Generator) { + case Ethernet_32:{ + /* (ui32NoWords - 4),no need of 4 bytes 0x as + * with shift-register method */ + AccumCRC = + calCRCEthernet32(cPtr, (ui32NoWords - 4), AccumCRC); + break; + } + default:{ + AccumCRC = calCRCword(cPtr, ui32NoWords, AccumCRC); + break; + } + } + + if (calCRCbyte(cPtr, ui32NoWords, ui64Buffer) != AccumCRC) { + printf("\n --- big Endian - small Endian problem --- \n"); + AccumCRC--; + } + + return (AccumCRC); +} + +/** + * insert header and file CRC into data stream + * do CRC check on header and file + * write data stream to disk + */ +int +writeDataStream(int iofd, int notime) +{ + uint64_t ui64FileCRC = 0, ui64HeaderCRC = 0, ui64RegisterMask; + unsigned int uiRegisterLength; + + if (0 != createHeaderImage(notime)) { + return 1; + } + + createCRCParameter(&ui64RegisterMask, &uiRegisterLength); + + /* calculate CRC */ + ui64HeaderCRC = checkCRC(pucFileStream, ui64globalHeaderSize, 0); + *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) = + cpu_to_be64(ui64HeaderCRC); + + ui64FileCRC = checkCRC(pucFileStream, ui64globalFileSize, 0); + *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) = + cpu_to_be64(ui64FileCRC); + + /* check CRC-implementation */ + ui64HeaderCRC = calCRCword(pucFileStream, ui64globalHeaderSize, 0); + ui64FileCRC = calCRCword(pucFileStream, ui64globalFileSize, 0); + + if ((ui64HeaderCRC != 0) || (ui64FileCRC != 0)) { + printf("\n\n %s \n %s \n\n", "CRCs not correct implemented.", + " ---> Data will not be written do disk."); + return -1; + } + + /* write file image to disk */ + if (0 < write(iofd, pucFileStream, ui64globalFileSize)) + return 0; + + printf("<< write failed >>\n"); + return -1; +} diff --git a/qemu/roms/SLOF/romfs/tools/create_flash.c b/qemu/roms/SLOF/romfs/tools/create_flash.c new file mode 100644 index 000000000..f99fd6226 --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/create_flash.c @@ -0,0 +1,163 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> + +#include <cfgparse.h> + +int verbose = 0; + +#define dprintf(fmt, args...) if (verbose) printf(fmt, ##args) + +static void +print_usage(void) +{ + printf + ("Usage: build_romfs [-?] [--help] [-s|--romfs-size <romfs_size>]\n" + "\t[-p|--smart-pad] [-n|--notime] <config-file> <output-file>\n"); +} + +unsigned long +str_to_num(const char *str) +{ + char *s = (char *) str; + unsigned long num = strtoul(s, &s, 0); + if (s) { + if (s[0] == 'K') + num <<= 10; + if (s[0] == 'M') + num <<= 20; + } + return num; +} + +/* + * NOTE: We should consider to install an exit handler which does the + * unlink() of the output file. In case of error we just do exit() and + * forget about all the clumsy error handling free/close code, which + * blows up the code significantly and makes it hard to read. + */ +int +main(int argc, char *argv[]) +{ + int conf_file, rc; + struct ffs_chain_t ffs_chain; + int c; + int smart_pad = 0; /* default */ + int notime = 0; + const char *config_file = "boot_rom.ffs"; + const char *output_file = "boot_rom.bin"; + + memset((void *) &ffs_chain, 0, sizeof(struct ffs_chain_t)); + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"romfs-size", 1, 0, 's'}, + {"smart-pad", 0, 0, 'p'}, + {"notime", 0, 0, 'n'}, + {"verbose", 0, 0, 'v'}, + {"help", 1, 0, 'h'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "s:ph?nv", long_options, + &option_index); + if (c == -1) + break; + + switch (c) { + case 's': + ffs_chain.romfs_size = str_to_num(optarg); + break; + case 'p': + smart_pad = 1; + break; + case 'n': + notime = 1; + break; + case 'v': + verbose = 1; + break; + case '?': + case 'h': + print_usage(); + return EXIT_SUCCESS; + default: + printf("?? getopt returned character code 0%o ??\n", c); + } + } + + /* two files must always be specified: config-file and output-file */ + if (optind + 2 != argc) { + print_usage(); + return EXIT_FAILURE; + } + + config_file = argv[optind++]; + output_file = argv[optind++]; + + dprintf("ROMFS FILESYSTEM CREATION V0.3 (bad parser)\n" + "Build directory structure...\n" + " smart padding %s, maximum romfs size %d bytes\n", + smart_pad ? "enabled" : "disabled", ffs_chain.romfs_size); + + conf_file = open(config_file, O_RDONLY); + if (0 >= conf_file) { + perror("load config file:"); + return EXIT_FAILURE; + } + + rc = read_config(conf_file, &ffs_chain); + close(conf_file); + if (rc < 1) { + fprintf(stderr, "flash cannot be built due to config errors\n"); + return EXIT_FAILURE; + } + + rc = EXIT_SUCCESS; + + if (verbose) + dump_fs_contents(&ffs_chain); + if (smart_pad) + /* FIXME: size is only verified during reorder */ + rc = reorder_ffs_chain(&ffs_chain); + + if (rc == EXIT_FAILURE) + goto out; + + dprintf("Build ffs and write to image file...\n"); + if (build_ffs(&ffs_chain, output_file, notime) != 0) { + fprintf(stderr, "build ffs failed\n"); + rc = EXIT_FAILURE; + } else { + rc = EXIT_SUCCESS; + } + + /* Check if there are any duplicate entries in the image, + print warning if this is the case. */ + find_duplicates(&ffs_chain); + free_chain_memory(&ffs_chain); + dprintf("\n"); + + out: + /* If the build failed, remove the target image file */ + if (rc == EXIT_FAILURE) + unlink(output_file); + + return rc; +} diff --git a/qemu/roms/SLOF/romfs/tools/createcrc.h b/qemu/roms/SLOF/romfs/tools/createcrc.h new file mode 100644 index 000000000..1f2359829 --- /dev/null +++ b/qemu/roms/SLOF/romfs/tools/createcrc.h @@ -0,0 +1,19 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +#ifndef CREATECRC_H +#define CREATECRC_H + +int buildDataStream(unsigned char *pucbuf, int size); +int createHeaderImgage(char *pcFilename); +int writeDataStream(int ofd, int notime); + +#endif diff --git a/qemu/roms/SLOF/rtas/Makefile.inc b/qemu/roms/SLOF/rtas/Makefile.inc new file mode 100644 index 000000000..4297f86a9 --- /dev/null +++ b/qemu/roms/SLOF/rtas/Makefile.inc @@ -0,0 +1,89 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +# Before including this Makefile, you should specify the following variables +# in your Makefile: +# - RTASCMNDIR : Points to the common RTAS directory +# - RTASBRDDIR : Points to the board specific RTAS directory +# - TOOLSDIR : Points to the common tools directory +# - OBJS : A list with all object files that should be linked into rtas.bin +# - BOARD_SRCS : A list with all board specific source code files +# (needed for "make depend") + + +LDFLAGS = -nostdlib +CPPFLAGS += -I$(RTASBRDDIR) -I$(RTASCMNDIR) \ + -I$(INCLCMNDIR) -I$(INCLBRDDIR) \ + -I$(LIBCMNDIR)/libc/include \ + -I$(INCLCMNDIR)/$(CPUARCH) +ASFLAGS = -Wa,-mregnames $(FLAG) +CFLAGS += -g -nostdinc -ffreestanding -Wall -Wextra -O2 -msoft-float \ + -mno-altivec -mabi=no-altivec $(FLAG) + +# Common RTAS files: +RTAS_SRC_ASM = reloc.S rtas_common.S rtas_entry.S rtas_term.S \ + rtas_cpu.S rtas_flash_asm.S rtas_mem.S rtas_ras.S +RTAS_SRC_C = rtas_call.c rtas_flash_c.c rtas_h8.c \ + rtas_nvramlog.c rtas_sensor.c rtas_init.c \ + rtas_flash_cfi.c +RTAS_SRCS = $(RTAS_SRC_ASM) $(RTAS_SRC_C) +RTAS_OBJ_ASM = $(RTAS_SRC_ASM:%.S=%.o) +RTAS_OBJ_C = $(RTAS_SRC_C:%.c=%.o) + +# Common build rules: +$(RTAS_OBJ_C): + $(CC) $(CPPFLAGS) $(CFLAGS) -c $(@:%.o=$(RTASCMNDIR)/%.c) -o $@ + +$(RTAS_OBJ_ASM): + $(CC) $(CPPFLAGS) $(ASFLAGS) -c $(@:%.o=$(RTASCMNDIR)/%.S) -o $@ + +$(TOOLSDIR)/gen_reloc_table: $(TOOLSDIR)/gen_reloc_table.c + $(MAKE) -C $(TOOLSDIR) gen_reloc_table + + +# Rules for building rtas.bin: +rtas.bin: rtas + $(OBJCOPY) -O binary $< $@ + +rtas: $(RTASCMNDIR)/rtas.lds $(OBJS) reloc_table.o $(LIBCMNDIR)/libc.a + $(LD) $(LDFLAGS) -o $@ -T $(RTASCMNDIR)/rtas.lds $(OBJS) \ + reloc_table.o $(LIBCMNDIR)/libc.a + +reloc_table.o: $(TOOLSDIR)/gen_reloc_table $(OBJS) $(LIBCMNDIR)/libc.a + $(TOOLSDIR)/create_reloc_table.sh --ld "$(ONLY_LD)" --ldflags "$(LDFLAGS)" \ + --lds "$(RTASCMNDIR)/rtas.lds" --objcopy "$(OBJCOPY)" $(OBJS) $(LIBCMNDIR)/libc.a + + +$(LIBCMNDIR)/libc.a: + $(MAKE) -C $(LIBCMNDIR) libc + + +# Rules for cleaning up: +clean_rtas: + rm -f $(OBJS) reloc_table.o rtas rtas.bin + rm -f $(RTASCMNDIR)/*~ $(RTASCMNDIR)/*.o + +distclean_rtas: clean_rtas + rm -f Makefile.dep + + +# Rules for creating the dependency file: +depend: + rm -f Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile $(RTASCMNDIR)/Makefile.inc + $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(RTAS_SRCS:%=$(RTASCMNDIR)/%) > Makefile.dep + $(CC) -MM $(CPPFLAGS) $(CFLAGS) $(BOARD_SRCS) >> Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/rtas/flash/block_lists.c b/qemu/roms/SLOF/rtas/flash/block_lists.c new file mode 100644 index 000000000..e632fd0bd --- /dev/null +++ b/qemu/roms/SLOF/rtas/flash/block_lists.c @@ -0,0 +1,275 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <product.h> +#include <stdio.h> +#include "block_lists.h" + +unsigned char sig_org[] = FLASHFS_PLATFORM_MAGIC; + +/* this function is part of the crc_lib assembler code */ +unsigned long check_flash_image(unsigned long, unsigned long, unsigned long); + +/* this functions needs to be implemented by the board specific flash code + * the functions always get 32 bytes and needs to deal with the data */ +void write_flash(unsigned long, unsigned short *); + +int progress = 0; + +int +print_progress(void) +{ + static int i = 3; + switch (i--) { + case 3: + printf("\b|"); + break; + case 2: + printf("\b/"); + break; + case 1: + printf("\b-"); + break; + case 0: + printf("\b\\"); + default: + i = 3; + } + return 0; +} + +void +print_hash(void) +{ + printf("\b# "); +} + +void +print_writing(void) +{ + int counter = 42; + printf("\nWriting Flash: |"); + while (counter--) + printf(" "); + printf("|"); + counter = 41; + while (counter--) + printf("\b"); + +} + +int +get_block_list_version(unsigned char *data) +{ + if (data[0] == 0x01) + return 1; + return 0; +} + +static long +get_image_size(unsigned long *data, unsigned long length) +{ + long size = 0; + unsigned long i; + for (i = 0; i < length / 8; i += 2) { + size += data[1 + i]; + } + return size; +} + +static long +get_image_size_v0(unsigned long *data) +{ + unsigned long bl_size = data[0]; + return get_image_size(data + 1, bl_size - 8); +} + +static long +get_image_size_v1(unsigned long *data) +{ + unsigned long *bl_addr = data; + unsigned long bl_size; + unsigned long *next; + long size = 0; + while (bl_addr) { + bl_size = bl_addr[0]; + next = (unsigned long *) bl_addr[1]; + bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL; + size += get_image_size(bl_addr + 2, bl_size - 0x10); + bl_addr = next; + } + return size; +} + +long +get_size(unsigned long *data, int version) +{ + if (version == 1) + return get_image_size_v1(data); + return get_image_size_v0(data); +} + +static unsigned long +write_one_block(unsigned long *block, unsigned long length, + unsigned long offset) +{ + unsigned long block_addr = (unsigned long) block; + unsigned long i = 0; + static unsigned int hash; + if (offset == 0) + hash = 0; + + for (i = 0; i < length; i += 32, offset += 32, block_addr += 32) { + write_flash(offset, (unsigned short *) block_addr); + if (offset % 10 == 0) { + print_progress(); + } + if (offset > hash * progress) { + print_hash(); + hash++; + } + } + + return offset; +} + +static unsigned long +write_one_list(unsigned long *bl, unsigned long length, unsigned long offset) +{ + unsigned long i; + // 0x10: /8 for pointer /2 it has to be done in steps of 2 + for (i = 0; i < length / 0x10; i++) { + offset = + write_one_block((unsigned long *) *bl, *(bl + 1), offset); + bl += 2; + } + return offset; +} + +void +write_block_list(unsigned long *bl, int version) +{ + unsigned long offset = 0; + unsigned long *bl_addr = bl; + unsigned long bl_size; + unsigned long *next; + + if (version == 0) { + // -8 = removed header length + write_one_list(bl + 1, *(bl) - 8, offset); + return; + } + + while (bl_addr) { + bl_size = bl_addr[0]; + next = (unsigned long *) bl_addr[1]; + bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL; + // -0x10 = removed header length + offset = write_one_list(bl_addr + 2, bl_size - 0x10, offset); + bl_addr = next; + } + +} + +static int +check_one_list(unsigned long *bl, unsigned long length, unsigned long crc) +{ + unsigned long i; + // 0x10: /8 for pointer /2 it has to be done in steps of 2 + for (i = 0; i < length / 0x10; i++) { + crc = check_flash_image((unsigned long) *bl, *(bl + 1), crc); + bl += 2; + } + return crc; +} + +int +image_check_crc(unsigned long *bl, int version) +{ + unsigned long *bl_addr = bl; + unsigned long bl_size; + unsigned long *next; + unsigned long crc = 0; + + if (version == 0) { + // -8 = removed header length + return check_one_list(bl + 1, *(bl) - 8, crc); + } + + while (bl_addr) { + bl_size = bl_addr[0]; + next = (unsigned long *) bl_addr[1]; + bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL; + // -0x10 = removed header length + crc = check_one_list(bl_addr + 2, bl_size - 0x10, crc); + bl_addr = next; + } + return crc; +} + +static int +check_platform_one_list(unsigned long *bl, unsigned long bytesec) +{ + unsigned long pos = bytesec; + unsigned char *sig_tmp, *sig; + unsigned long size = 0; + sig = sig_org; + + while (size < bytesec) { + size += bl[1]; + + while (size > pos) { // 32 == FLASHFS_PLATFORM_MAGIC length + sig_tmp = (unsigned char *) (bl[0] + pos); + if (*sig++ != *sig_tmp) + return -1; + if (*sig_tmp == '\0' || (pos == bytesec + 32)) { + pos = bytesec + 32; + break; + } + pos++; + } + if (pos == (bytesec + 32)) + return 0; + bl += 2; + } + return 0; +} + +int +check_platform(unsigned long *bl, unsigned int bytesec, int version) +{ + unsigned long *bl_addr = bl; + unsigned long bl_size; + unsigned long *next; + unsigned long *ptr; + ptr = bl; + + if (version == 0) { + ptr += 1; // -8 = removed header length + return check_platform_one_list(ptr, bytesec); + } + while (bl_addr) { + ptr = bl_addr + 2; // -0x10 = removed header length + bl_size = bl_addr[0]; + next = (unsigned long *) bl_addr[1]; + bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL; + if ((bl_size - 0x10) == 0) { + bl_addr = next; + continue; + } + if (check_platform_one_list(ptr, bytesec) == 0) + return 0; + + bl_addr = next; + } + return -1; +} diff --git a/qemu/roms/SLOF/rtas/flash/block_lists.h b/qemu/roms/SLOF/rtas/flash/block_lists.h new file mode 100644 index 000000000..b24b65064 --- /dev/null +++ b/qemu/roms/SLOF/rtas/flash/block_lists.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +extern int progress; +extern unsigned char sig_org[]; + +int print_progress(void); +void print_hash(void); +int get_block_list_version(unsigned char *); +int image_check_crc(unsigned long *, int); +long get_size(unsigned long *, int); +void print_writing(void); +void write_block_list(unsigned long *, int); +int check_platform(unsigned long *, unsigned int, int); diff --git a/qemu/roms/SLOF/rtas/flash/tmpXXX.update-comments b/qemu/roms/SLOF/rtas/flash/tmpXXX.update-comments new file mode 100644 index 000000000..cd3d1376d --- /dev/null +++ b/qemu/roms/SLOF/rtas/flash/tmpXXX.update-comments @@ -0,0 +1,11 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ diff --git a/qemu/roms/SLOF/rtas/reloc.S b/qemu/roms/SLOF/rtas/reloc.S new file mode 100644 index 000000000..e24d293d4 --- /dev/null +++ b/qemu/roms/SLOF/rtas/reloc.S @@ -0,0 +1,183 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <rtas.h> + +/* +Function: + Input: + r3: Destination to copy rtas code to + r4: Configuration + Output: + r3: Entry point for rtas calls +Decription: Called by OpenFirmware to instantiate rtas, needs to copy + itself to destination, also do a relocations. + +*/ + +.extern rtas_entry +.extern .stack +.extern _got +.extern _got_end +.extern __bss_start +.extern __bss_end +.extern rtas_config + + + .section ".rtasstart","ax"; + .align 3 + .globl _rtas_start +_rtas_start: + mflr r10 # save link register + bcl 20,31,.over # branch (always) to .over + +.base: + .align 3 + +/* Our Open Firmware needs to know the size of the RTAS binary and the + * size & address of the RTAS function jump table. SLOF always looks for this + * information in the following three quads here at the very beginning of the + * RTAS binary at offset 8. So DO NOT DELETE/MOVE them! */ + +._rtas_size: .quad _rtas_end-_rtas_start +._ptr_to_func_tab: .quad rtas_func_tab-_rtas_start +._ptr_to_func_tab_size: .quad rtas_func_tab_size-_rtas_start + +/* The other variables are not accessed by SLOF anymore: */ + +._rel_offset: .quad _reloc_table_start-_rtas_start +._rel_end_offset: .quad _reloc_table_end-_rtas_start +._bss_offset: .quad __bss_start-_rtas_start +._bss_end_offset: .quad __bss_end-_rtas_start +._rtas_entry_offset: .quad rtas_entry-_rtas_start +._rtas_config_offset: .quad rtas_config-_rtas_start +._rtas_stack: .quad .stack-_rtas_start+RTAS_STACKSIZE-0x60 +._rtas_toc: .quad _got-_rtas_start+0x8000 + +.over: + mflr r8 # gpr 8 is the base + addi r8,r8,_rtas_start-.base # points to _rtas_start + mr r11,r4 # Save config value + +# Copy rtas code + + ld r5,._rtas_size-_rtas_start(r8) + mr r4,r8 # Start of rtas + addi r6,r3,-8 # Destination + addi r4,r4,-8 # Source + srdi r5,r5,3 # Count in quads + mtctr r5 +0: + ldu r0,8(r4) + stdu r0,8(r6) + bdnz 0b + +# Clear bss + + ld r4,._bss_offset-_rtas_start(r8) + ld r5,._bss_end_offset-_rtas_start(r8) + li r0,0 + add r6,r3,r4 # Address bss in copied code + addi r6,r6,-8 + sub r5,r5,r4 # Calculate bss size + srdi r5,r5,3 # Count in quads + mtctr r5 +0: + stdu r0,8(r6) + bdnz 0b + +# Relocate got + + ld r4, ._rel_offset-_rtas_start(r8) + ld r5, ._rel_end_offset-_rtas_start(r8) + sub r5, r5,r4 # Calculate reloc table size + cmpdi r5, 0 # No reloc table ? + beq 1f + + add r4, r4, r3 # Calculate reloc table address + addi r4, r4, -4 + srdi r5, r5, 2 # Count in words + mtctr r5 +0: + lwzu r6, 4(r4) # Load offset out of reloc table + ldx r0, r6, r3 # Load value + add r0, r0, r3 # Add relocation offset = load address + stdx r0, r6, r3 + bdnz 0b +1: + +# Save config data + + ld r5,._rtas_config_offset-_rtas_start(r8) + add r5,r5,r3 + std r11,0(r5) + +# Flush to memory + + mr r4,r3 # Destination address + ld r5,._rtas_size-_rtas_start(r8) + + add r5,r5,r4 + addi r5,r5,127 + rlwinm r4,r4,0,0,24 + rlwinm r5,r5,0,0,24 + sub r5,r5,r4 + srwi r5,r5,7 + mtctr r5 +0: + dcbst 0,r4 + sync + icbi 0,r4 + sync + isync + addi r4,r4,128 + bdnz 0b + +# Call init function + mfmsr r11 # Switch to 64 bit mode + mr r7,r11 + rotldi r11,r11,1 + ori r11,r11,1 + rotldi r11,r11,63 + mtmsrd r11 + isync + mr r9,r1 # save old stack pointer + ld r1,._rtas_stack-_rtas_start(r8) # load new stack pointer + add r1,r1,r3 + std r9,0(r1) # save stack pointer + std r2,64(r1) # save toc + std r7,72(r1) # save old msr value + + ld r2,._rtas_toc-_rtas_start(r8) # load got pointer + add r2,r2,r3 + + bl save_regs_r3_r12 + bl .rtas_init + bl restore_regs_r3_r12 + + ld r11,72(r1) # restore msr value + ld r2,64(r1) # restore toc + ld r1,0(r1) # get old stack + + mtmsrd r11 # restore msr + isync + + +# Return rtas entry + + ld r4,._rtas_entry_offset-_rtas_start(r8) + add r3,r3,r4 + mtlr r10 + blr + + + diff --git a/qemu/roms/SLOF/rtas/rtas.lds b/qemu/roms/SLOF/rtas/rtas.lds new file mode 100644 index 000000000..a5ba1daaf --- /dev/null +++ b/qemu/roms/SLOF/rtas/rtas.lds @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) + +SECTIONS { + .text 0: + { + *(.rtasstart) + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.sfpr .glink) + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.opd) + } =0x60000000 + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + } + .got : + { + _got = .; + *(.got .toc) + } + .reloc : + { + . = ALIGN(4); + _reloc_table_start = .; + *(.reloc) + _reloc_table_end = .; + } + .bss : + { + __bss_start = .; + *(*COM* .bss .sbss .gnu.linkonce.b.*) + __bss_end = .; + } + __bss_size = (__bss_end - __bss_start); + _rtas_end = .; +} diff --git a/qemu/roms/SLOF/rtas/rtas_call.c b/qemu/roms/SLOF/rtas/rtas_call.c new file mode 100644 index 000000000..8c7532c01 --- /dev/null +++ b/qemu/roms/SLOF/rtas/rtas_call.c @@ -0,0 +1,93 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdint.h> +#include <rtas.h> +#include "rtas_table.h" + + +//#define _RTAS_TRACE +//#define _RTAS_COUNT_CALLS + + +#ifdef _RTAS_COUNT_CALLS +int rtas_callcount[0x40] __attribute__((aligned (16))); +#endif + +/* rtas_config is used to store the run-time configuration flags (which are + * provided by SLOF during instantiate-rtas) */ +long rtas_config; + + +/* Prototype */ +void rtas_call (rtas_args_t *rtas_args); + + +/* +Function: rtas_call + Input: + rtas_args: pointer to RTAS arguments structure + Output: + +Decription: Handle RTAS call. This C function is called + from the asm function rtas_entry. +*/ + +void +rtas_call (rtas_args_t *rtas_args) +{ + int idx; + +#ifdef _RTAS_COUNT_CALLS + /* Count how often every RTAS function is called. */ + if (rtas_args->token < (int)(sizeof(rtas_callcount)/sizeof(rtas_callcount[0]))) { + static int callcount_initialized = 0; + /* If the array is used the first time, we have to set all entries to 0 */ + if (!callcount_initialized) { + unsigned int i; + callcount_initialized = 1; + for (i = 0; i < sizeof(rtas_callcount)/sizeof(rtas_callcount[0]); i++) + rtas_callcount[i] = 0; + } + /* Increment the counter of the RTAS call */ + rtas_callcount[rtas_args->token] += 1; + } +#endif + +#ifdef _RTAS_TRACE + unsigned int parCnt = rtas_args->nargs; + unsigned int *pInt = rtas_args->args; + printf("\n\r*** rtas_call=0x%x", rtas_args->token); +#ifdef _RTAS_COUNT_CALLS + printf(" count=0x%x", rtas_callcount[rtas_args->token]); +#endif + printf(" len=0x%x", parCnt); + printf("\n\r "); + while(parCnt--) { + printf("0x%x ", *pInt++); + } +#endif + + idx = rtas_args->token - 1; + + /* Check if there's a function for the token: */ + if (idx >= 0 && idx < rtas_func_tab_size + && rtas_func_tab[idx].func != NULL) { + /* Now jump to the RTAS function: */ + rtas_func_tab[idx].func(rtas_args); + } + else { + /* We didn't find a function - return error code: */ + rtas_args->args[rtas_args->nargs] = -1; + } + +} diff --git a/qemu/roms/SLOF/rtas/rtas_common.S b/qemu/roms/SLOF/rtas/rtas_common.S new file mode 100644 index 000000000..35cd9a9f5 --- /dev/null +++ b/qemu/roms/SLOF/rtas/rtas_common.S @@ -0,0 +1,87 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +.globl save_regs_r3_r12 +.globl restore_regs_r3_r12 +.globl save_regs_r13_r25 +.globl restore_regs_r13_r25 + + +save_regs_r3_r12: + stdu r1,-0x80(r1) # allocate space on stack + + std r3,0x30(r1) + std r4,0x38(r1) + std r5,0x40(r1) + std r6,0x48(r1) + std r7,0x50(r1) + std r8,0x58(r1) + std r9,0x60(r1) + std r10,0x68(r1) + std r11,0x70(r1) + std r12,0x78(r1) + + blr + +restore_regs_r3_r12: + ld r3,0x30(r1) + ld r4,0x38(r1) + ld r5,0x40(r1) + ld r6,0x48(r1) + ld r7,0x50(r1) + ld r8,0x58(r1) + ld r9,0x60(r1) + ld r10,0x68(r1) + ld r11,0x70(r1) + ld r12,0x78(r1) + + addi r1,r1,0x80 # cleanup stack + + blr + +save_regs_r13_r25: + stdu r1,-0x98(r1) # allocate space on stack + + std r13,0x30(r1) + std r14,0x38(r1) + std r15,0x40(r1) + std r16,0x48(r1) + std r17,0x50(r1) + std r18,0x58(r1) + std r19,0x60(r1) + std r20,0x68(r1) + std r21,0x70(r1) + std r22,0x78(r1) + std r23,0x80(r1) + std r24,0x88(r1) + std r25,0x90(r1) + + blr + +restore_regs_r13_r25: + ld r13,0x30(r1) # restore registers from stack + ld r14,0x38(r1) + ld r15,0x40(r1) + ld r16,0x48(r1) + ld r17,0x50(r1) + ld r18,0x58(r1) + ld r19,0x60(r1) + ld r20,0x68(r1) + ld r21,0x70(r1) + ld r22,0x78(r1) + ld r23,0x80(r1) + ld r24,0x88(r1) + ld r25,0x90(r1) + + addi r1,r1,0x98 # cleanup stack + + blr diff --git a/qemu/roms/SLOF/rtas/rtas_entry.S b/qemu/roms/SLOF/rtas/rtas_entry.S new file mode 100644 index 000000000..74693aa48 --- /dev/null +++ b/qemu/roms/SLOF/rtas/rtas_entry.S @@ -0,0 +1,72 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <rtas.h> + + +/* +Function: + Input: + r3: rtas parm structure + r4: base address + Output: + +Decription: Main entry point, called from OS. Second parameter is not + used. + +*/ + .globl rtas_entry +rtas_entry: + mfmsr r11 # Get MSR to enable 64-bit mode + mr r7,r11 + rotldi r11,r11,1 + ori r11,r11,1 # Always enable 64-bit mode flag + rotldi r11,r11,63 + mtmsrd r11 # Switch to 64-bit mode + isync + + mr r9,r1 # save old stack pointer + mflr r10 # save link register + bcl 20,31,.over # branch to over +.base: + .align 3 +..got: .quad _got-.base+0x8000 +..stack: .quad .stack+RTAS_STACKSIZE-0x60-.base +.over: + mflr r8 # gpr 8 is the base + ld r1,..stack-.base(r8) # load new stack pointer + add r1,r1,r8 # add base + std r2,64(r1) # save toc + ld r2,..got-.base(r8) # load got pointer + std r7,72(r1) # save original msr + std r10,80(r1) # save link register + std r9,0(r1) # save stack pointer + add r2,r2,r8 # add base + + bl save_regs_r3_r12 + bl .rtas_call + bl restore_regs_r3_r12 + +rtas_return: + ld r11,72(r1) # restore msr value + ld r0,80(r1) # restore link register value + ld r2,64(r1) # restore toc + ld r1,0(r1) # get old stack + mtmsrd r11 # restore msr (32 bit ?) + isync + mtlr r0 + blr + + + + .globl .stack + .lcomm .stack,RTAS_STACKSIZE diff --git a/qemu/roms/SLOF/slof/Makefile.inc b/qemu/roms/SLOF/slof/Makefile.inc new file mode 100644 index 000000000..8ad33376e --- /dev/null +++ b/qemu/roms/SLOF/slof/Makefile.inc @@ -0,0 +1,171 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +# Before including this Makefile, you should specify the following variables +# in your Makefile: +# - INCLCMNDIR : Points to the common include directory +# - INCLCMNDIR : Points to the board specific include directory +# - SLOFCMNDIR : Points to the common SLOF directory +# - SLOFBRDDIR : Points to the board specific SLOF directory +# - LLFWCMNDIR : Points to the common LLFW directory +# - LLFWBRDDIR : Points to the board specific LLFW directory + +# Set LLFW directories (should normally be set from parent Makefile): +TOPBRDDIR ?= $(shell cd .. && pwd) +LLFWBRDDIR ?= $(TOPBRDDIR)/llfw +LLFWCMNDIR ?= $(SLOFCMNDIR:%/slof=%/llfw) +INCLBRDDIR ?= $(TOPBRDDIR)/include + + +CPPFLAGS += -I. -I$(INCLCMNDIR) -I$(INCLBRDDIR) -I$(INCLCMNDIR)/$(CPUARCH) +CFLAGS = -DTARG=$(TARG) -static -Wall -W -std=gnu99 \ + -O2 -fomit-frame-pointer -msoft-float $(FLAG) $(CPUARCHDEF) \ + -fno-stack-protector -fno-strict-aliasing +ASFLAGS = -Wa,-mpower4 -Wa,-mregnames $(FLAG) $(CPUARCHDEF) + +LDFLAGS += -static -nostdlib -Wl,-q,-n + +ifneq ($(TARG),unix) +CFLAGS += -nostdinc -fno-builtin +CPPFLAGS += -I$(LIBCMNDIR)/libc/include +SLOF_LIBS += $(LIBCMNDIR)/libc.a +endif + +DICT = $(SLOFCMNDIR)/prim.in $(SLOFCMNDIR)/engine.in \ + $(BOARD_SLOF_IN) $(SLOFCMNDIR)/$(TARG).in + +# Source code files with automatic dependencies: +SLOF_BUILD_SRCS = paflof.c helpers.c allocator.c + +# Flags for pre-processing Forth code with CPP: +FPPFLAGS = -nostdinc -traditional-cpp -undef -P -C $(FLAG) +FPPINCLUDES ?= -I$(SLOFBRDDIR) -I$(SLOFCMNDIR)/fs + +# Rules for pre-processing Forth code: +# - Use CPP for pre-processing #include directives +# - Use sed to strip all white spaces at the beginning of a line +# - Use sed to remove all lines that only contain a comment +# - Use sed to remove all empty lines from the file +%.fsi: %.fs +ifeq ($(V),1) + printf "\t[FPP]\t%s\n" `basename "$@"` +endif + rm -f $@ + cpp $(FPPFLAGS) $(FPPINCLUDES) $< > $@.tmp + sed -e 's/^[ ]*//' < $@.tmp \ + | sed -e '/^\\[ ]/d' \ + | sed -e '/^([ ][^)]*[ ])[ ]*$$/d' \ + | sed -e '/^$$/d' > $@ + rm -f $@.tmp + + +OF.o: OF.fsi + $(LD) -o $@ -r -bbinary $< + + +dict.xt: $(DICT) $(SLOFCMNDIR)/ref.pl + cat $(DICT) | perl $(SLOFCMNDIR)/ref.pl -s $(CELLSIZE) > dict.xt + +ifdef BOARD_SLOF_CODE +board.code: $(BOARD_SLOF_CODE) + cat $(BOARD_SLOF_CODE) > $@ +else +board.code: + echo > $@ +endif + +paflof: $(SLOFCMNDIR)/OF.lds $(SLOFCMNDIR)/ofw.o paflof.o $(SLOFCMNDIR)/entry.o \ + helpers.o allocator.o romfs.o version.o OF.o nvramlog.o $(LLFWBRDDIR)/board_io.o \ + $(LLFWBRDDIR)/io_generic_lib.o $(SLOF_LIBS) + $(CC) -T$(SLOFCMNDIR)/OF.lds $(SLOFCMNDIR)/ofw.o version.o paflof.o helpers.o allocator.o \ + $(SLOFCMNDIR)/entry.o romfs.o OF.o nvramlog.o $(LLFWBRDDIR)/board_io.o \ + $(LLFWBRDDIR)/io_generic_lib.o $(LDFLAGS) $(SLOF_LIBS) -o $@ + #save a copy of paflof before stripping + @cp $@ $@.unstripped + $(STRIP) --strip-unneeded $@ + +paflof.o: board.code dict.xt + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SLOFCMNDIR)/paflof.c + +helpers.o: + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SLOFCMNDIR)/helpers.c + +allocator.o: + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(SLOFCMNDIR)/allocator.c + +$(SLOFCMNDIR)/xvect.bin: $(SLOFCMNDIR)/lowmem.o + $(CC) $(LDFLAGS) -Wl,--oformat,binary -Ttext=0x100 -o xvect.bin.tmp $< + dd if=xvect.bin.tmp of=$(SLOFCMNDIR)/xvect.bin bs=256 skip=1 2>/dev/null + rm -f xvect.bin.tmp + +romfs.o: + $(CC) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $(LLFWCMNDIR)/romfs.S + +nvramlog.o: + $(CC) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $(LLFWCMNDIR)/nvramlog.S + +checkpoint.o: + $(CC) $(CPPFLAGS) $(ASFLAGS) -c -o $@ $(LLFWCMNDIR)/checkpoint.S + +$(LLFWBRDDIR)/board_io.o: + $(MAKE) -C $(LLFWBRDDIR) board_io.o + +$(LLFWBRDDIR)/io_generic_lib.o: + $(MAKE) -C $(LLFWBRDDIR) io_generic_lib.o + +default-font.o: $(SLOFCMNDIR)/default-font.c + $(CC) $(CPPFLAGS) $< -c -o default-font.o + +$(SLOFBRDDIR)/default-font.bin: default-font.o + $(OBJCOPY) -Obinary default-font.o $@ + +.PHONY : create_OF.ffs clean_slof distclean_slof depend + + +# Create OF.ffs automatically from file list in OF_FFS_FILES variable. +# We have to use absolute path names there, so we have to use `pwd` to +# find them out: +create_OF_ffs: + rm -f OF.ffs + @for i in $(OF_FFS_FILES) ; do \ + CURRENTDIR=`pwd` ; cd `dirname $$i` ; \ + DIRNAME=`pwd` ; cd $$CURRENTDIR ; \ + echo `basename $$i | sed -e s/\.fsi/\.fs/` \ + $$DIRNAME/`basename $$i` 0 0 >> OF.ffs ; \ + done + + +# Targets for cleaning up: +clean_slof: + rm -f $(SLOFCMNDIR)/*.o $(SLOFCMNDIR)/*.bin $(SLOFCMNDIR)/*.elf + rm -f dict.xt board.code paflof paflof.unstripped default-font.bin + rm -f $(filter %.fsi,$(OF_FFS_FILES)) + +distclean_slof: clean_slof + rm -f Makefile.dep + + +# Rules for creating the dependency file: +depend: + rm -f Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile $(SLOFCMNDIR)/Makefile.inc OF.fs + $(CC) -M -MG $(CPPFLAGS) $(CFLAGS) $(SLOF_BUILD_SRCS:%=$(SLOFCMNDIR)/%) > Makefile.dep + cpp -M -MG $(FPPFLAGS) $(FPPINCLUDES) -MT OF.fsi OF.fs >> Makefile.dep + for i in $(filter %.fsi,$(OF_FFS_FILES)) ; do \ + cpp -M -MG $(FPPFLAGS) $(FPPINCLUDES) -MT $$i \ + `echo $$i | sed -e 's/\.fsi/\.fs/'` >> Makefile.dep ; \ + done + +# Include dependency file if available: +-include Makefile.dep diff --git a/qemu/roms/SLOF/slof/OF.lds b/qemu/roms/SLOF/slof/OF.lds new file mode 100644 index 000000000..5f8b2b153 --- /dev/null +++ b/qemu/roms/SLOF/slof/OF.lds @@ -0,0 +1,65 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(_start_OF) + + +SECTIONS +{ + . = 0x0E100100; + _start_OF = .; + .slof.loader : { *(.slof.loader) } + . = ALIGN(0x100); + _slof_text = .; + .text : { *(.entry_text) *(.text) } = 0x60000000 + _slof_text_end = .; + . = ALIGN(8); + _slof_text_size = (_slof_text_end - _slof_text); + + . = ALIGN(0x100); + .opd : + { + _slof_data = .; + *(.opd) + } + . = ALIGN(8); + .got : + { + *(.got .toc) + } + + .data : { + *(.rodata .rodata.*) + *(.data .data.*) + *(.note.gnu.build-id) + } + + .comment : { *(.comment) } + .branch_lt : { *(.branch_lt) } + + . = ALIGN(8); + _slof_data_end = .; + _slof_data_size = (_slof_data_end - _slof_data); + + .bss : + { + _slof_bss = .; + *(*COM* .bss .sbss .gnu.linkonce.b.*) + _slof_bss_end = .; + } + _slof_bss_size = (_slof_bss_end - _slof_bss); + + . = ALIGN(0x1000); + the_mem = .; +} diff --git a/qemu/roms/SLOF/slof/allocator.c b/qemu/roms/SLOF/slof/allocator.c new file mode 100644 index 000000000..279b50b9c --- /dev/null +++ b/qemu/roms/SLOF/slof/allocator.c @@ -0,0 +1,219 @@ +/****************************************************************************** + * Copyright (c) 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * All functions concerning interface to slof + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <helpers.h> + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +#define dprintf(_x ...) do { printf ("%s: ", __func__); printf(_x); } while (0); +#else +#define dprintf(_x ...) +#endif + +#define DEFAULT_BLOCK_SIZE 4096 + +#define BM_WORD_SIZE (sizeof(unsigned long)) +#define BM_WORD_BITS (BM_WORD_SIZE * 8) + +struct bitmap { + unsigned long start; + unsigned long size; + unsigned long bm_size; + unsigned long block_size; + unsigned long free_blocks; + unsigned long bmw[]; +}; + +#define BIT(x) (1UL << x) +#define BM_WORD(bmw, n) (bmw[n/BM_WORD_BITS]) +#define BM_WORD_MODULO(n) (n % BM_WORD_BITS) +#define BM_NUM_BITS(reqsize, bsize) ((reqsize / bsize) + (reqsize % bsize? 1 : 0)) + +void bm_clear_bit(unsigned long *bmw, int n) +{ + BM_WORD(bmw, n) &= ~BIT(BM_WORD_MODULO(n)); +} + +void bm_set_bit(unsigned long *bmw, int n) +{ + BM_WORD(bmw, n) |= BIT(BM_WORD_MODULO(n)); +} + +bool bm_test_bit(unsigned long *bmw, int n) +{ +#ifdef DEBUG + //printf("BMW %x, bitpos %d, value %d\n", &BM_WORD(bmw, n), n, !!(BM_WORD(bmw, n) & BIT(BM_WORD_MODULO(n)))); +#endif + return !!(BM_WORD(bmw, n) & BIT(BM_WORD_MODULO(n))); +} + +/* Improvement: can use FFS routines to get faster results */ +int bm_find_bits(struct bitmap *bm, unsigned int n_bits) +{ + unsigned int i, j, total_bits; + int found = -1; + dprintf("Finding %d bits set\n", n_bits); + total_bits = BM_NUM_BITS(bm->size, bm->block_size); + for(i = 0; i < total_bits; i++) { + if (!bm_test_bit(bm->bmw, i)) + continue; + /* we have hit the boundary now, give up */ + if (i + n_bits > total_bits) + break; + /* Lets find if we have consecutive bits set */ + for(j = i; j < (i + n_bits); j++) { + if (!bm_test_bit(bm->bmw, (j))) + break; + } + /* Got it */ + if (j == (i + n_bits)) { + found = i; + break; + } + } + return found; +} + +void SLOF_bm_print(unsigned long handle) +{ + struct bitmap *bm; + unsigned int i; + + if (!handle) + return; + + bm = (struct bitmap *) handle; + printf("BITMAP: start %lx, size %ld, blocksize %ld\n\n", + bm->start, bm->size, bm->block_size); + printf("0 16 32 48 63\n"); + for(i = 0; i < BM_NUM_BITS(bm->size, bm->block_size); i++) { + if (i > 0 && (i % 64 == 0)) + printf("\n"); + else if (i > 0 && (i % 8 == 0)) + printf(" "); + printf("%d", bm_test_bit(bm->bmw, i)); + } + printf("\n\n"); +} + +unsigned long SLOF_bm_allocator_init(unsigned long start, unsigned long size, + unsigned long blocksize) +{ + struct bitmap *bm; + unsigned long alloc_size, bm_size, n_bits; + + dprintf("enter start %x, size %d, block-size %d\n", start, size, blocksize); + + if (!size) + return 0; + if (!blocksize) + blocksize = DEFAULT_BLOCK_SIZE; + + n_bits = BM_NUM_BITS(size, blocksize); + bm_size = (n_bits / BM_WORD_BITS) + ((n_bits % BM_WORD_BITS)? 1 : 0); + alloc_size = sizeof(struct bitmap) + bm_size * BM_WORD_SIZE; + dprintf("Size %ld, blocksize %ld, bm_size %ld, alloc_size %ld\n", + size, blocksize, bm_size, alloc_size); + bm = (struct bitmap *) SLOF_alloc_mem(alloc_size); + if (!bm) + return 0; + bm->start = start; + bm->size = size; + bm->bm_size = bm_size; + bm->block_size = blocksize; + bm->free_blocks = n_bits; + memset(bm->bmw, 0xFF, bm_size*BM_WORD_SIZE); + return (unsigned long)bm; +} + +unsigned long SLOF_bm_alloc(unsigned long handle, unsigned long size) +{ + struct bitmap *bm; + unsigned long n_bits; + unsigned long addr; + unsigned int i; + int bitpos; + + if (!handle) + return -1; + + bm = (struct bitmap *) handle; + + n_bits = BM_NUM_BITS(size, bm->block_size); + if (n_bits > bm->free_blocks) + return -1; + + bitpos = bm_find_bits(bm, n_bits); + if (bitpos == -1) + return -1; + + dprintf("BMW %d, bitpos %d\n", i, bitpos); + dprintf("size %d, block_size %d, n_bits %d\n", size, bm->block_size, n_bits); + for(i = bitpos; i < (bitpos + n_bits); i++) { +#ifdef DEBUG + if (!bm_test_bit(bm->bmw, i)) + dprintf("Warning: Bit already in use: %d\n", i); +#endif + bm_clear_bit(bm->bmw, i); + } + bm->free_blocks -= n_bits; + addr = bm->start + bitpos * bm->block_size; + dprintf("BMW %d, bitpos %d addr %lx free_blocks %d\n", i, bitpos, addr, bm->free_blocks); + return addr; +} + +void SLOF_bm_free(unsigned long handle, unsigned long ptr, unsigned long size) +{ + struct bitmap *bm; + unsigned long bitpos, n_bits; + unsigned long addr; + unsigned int i; + + if (!handle) + return; + + bm = (struct bitmap *) handle; + addr = (unsigned long ) ptr; + n_bits = BM_NUM_BITS(size, bm->block_size); + if (addr < bm->start || (bm->start + bm->size) < (addr + size)) { + printf("Error: Bitmap start %lx, size %ld, requested address %lx, size %ld\n", + bm->start, bm->size, addr, size); + return; + } + bitpos = (addr - bm->start) / bm->block_size; + bm->free_blocks += n_bits; + +#ifdef DEBUG + dprintf("addr %lx, bitpos %d\n", addr, bitpos); + dprintf("size %d, block_size %d, n_bits %d, free_blocks %d\n", size, bm->block_size, n_bits, bm->free_blocks); + if (addr % bm->block_size) { + dprintf("Warning: Address not aligned addr %lx\n", addr); + } +#endif + + for(i = bitpos; i < (bitpos + n_bits); i++) { +#ifdef DEBUG + if (bm_test_bit(bm->bmw, i)) + dprintf("Warning: Bit already set: %d\n", i); +#endif + bm_set_bit(bm->bmw, i); + } + + return; +} diff --git a/qemu/roms/SLOF/slof/default-font.c b/qemu/roms/SLOF/slof/default-font.c new file mode 100644 index 000000000..328f1b42b --- /dev/null +++ b/qemu/roms/SLOF/slof/default-font.c @@ -0,0 +1,1653 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* Bitmap font 8x16. + FIXME: Only characters from 0x20 - 0x7f + + +*/ + +const char bmfont_8x16[] = +{ + /* 0x20 " " */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x21 "!" */ + 0x00, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x22 """ */ + 0x00, + 0x00, + 0x28, + 0x28, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x23 "#" */ + 0x00, + 0x00, + 0x24, + 0x24, + 0x7e, + 0x24, + 0x24, + 0x7e, + 0x24, + 0x24, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x24 "$" */ + 0x00, + 0x08, + 0x1c, + 0x2a, + 0x28, + 0x28, + 0x1c, + 0x0a, + 0x0a, + 0x2a, + 0x1c, + 0x08, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x25 "%" */ + 0x00, + 0x00, + 0x30, + 0x48, + 0x30, + 0x02, + 0x0c, + 0x30, + 0x40, + 0x0c, + 0x12, + 0x0c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x26 "&" */ + 0x00, + 0x00, + 0x38, + 0x44, + 0x44, + 0x40, + 0x22, + 0x54, + 0x48, + 0x54, + 0x22, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x27 "'" */ + 0x00, + 0x00, + 0x10, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x28 "(" */ + 0x00, + 0x00, + 0x08, + 0x10, + 0x10, + 0x20, + 0x20, + 0x20, + 0x20, + 0x10, + 0x10, + 0x08, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x29 ")" */ + 0x00, + 0x00, + 0x10, + 0x08, + 0x08, + 0x04, + 0x04, + 0x04, + 0x04, + 0x08, + 0x08, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x2a "*" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x10, + 0x7c, + 0x10, + 0x28, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x2b "+" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x10, + 0x7c, + 0x10, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x2c "," */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x08, + 0x08, + 0x18, + 0x10, + 0x00, + 0x00, + 0x00, + /* 0x2d "-" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7c, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x2e "." */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x30, + 0x00, + 0x00, + 0x00, + /* 0x2f "/" */ + 0x00, + 0x00, + 0x02, + 0x04, + 0x04, + 0x08, + 0x08, + 0x10, + 0x10, + 0x20, + 0x20, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x30 "0" */ + 0x00, + 0x00, + 0x38, + 0x44, + 0x44, + 0x44, + 0x44, + 0x44, + 0x44, + 0x44, + 0x44, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x31 "1" */ + 0x00, + 0x00, + 0x08, + 0x18, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x1c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x32 "2" */ + 0x00, + 0x00, + 0x38, + 0x44, + 0x44, + 0x04, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x78, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x33 "3" */ + 0x00, + 0x00, + 0x38, + 0x44, + 0x04, + 0x04, + 0x04, + 0x18, + 0x04, + 0x04, + 0x44, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x34 "4" */ + 0x00, + 0x00, + 0x40, + 0x40, + 0x40, + 0x48, + 0x48, + 0x7e, + 0x08, + 0x08, + 0x08, + 0x08, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x35 "5" */ + 0x00, + 0x00, + 0x7e, + 0x40, + 0x40, + 0x40, + 0x78, + 0x04, + 0x02, + 0x02, + 0x04, + 0x78, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x36 "6" */ + 0x00, + 0x00, + 0x1c, + 0x20, + 0x40, + 0x40, + 0x40, + 0x78, + 0x44, + 0x44, + 0x44, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x37 "7" */ + 0x00, + 0x00, + 0x7e, + 0x42, + 0x04, + 0x08, + 0x08, + 0x10, + 0x10, + 0x20, + 0x20, + 0x20, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x38 "8" */ + 0x00, + 0x00, + 0x38, + 0x44, + 0x44, + 0x44, + 0x38, + 0x44, + 0x44, + 0x44, + 0x44, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x39 "9" */ + 0x00, + 0x00, + 0x38, + 0x44, + 0x44, + 0x44, + 0x3c, + 0x04, + 0x04, + 0x04, + 0x44, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x3a ":" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x30, + 0x00, + 0x00, + 0x30, + 0x30, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x3b ";" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x30, + 0x30, + 0x00, + 0x00, + 0x30, + 0x30, + 0x20, + 0x40, + 0x00, + 0x00, + /* 0x3c "<" */ + 0x00, + 0x00, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x40, + 0x20, + 0x10, + 0x08, + 0x04, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x3d "=" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7e, + 0x00, + 0x7e, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x3e ">" */ + 0x00, + 0x00, + 0x20, + 0x10, + 0x08, + 0x04, + 0x02, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x3f "?" */ + 0x00, + 0x00, + 0x1c, + 0x22, + 0x02, + 0x02, + 0x04, + 0x18, + 0x10, + 0x10, + 0x00, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x40 "@" */ + 0x00, + 0x00, + 0x18, + 0x24, + 0x42, + 0x4e, + 0x52, + 0x4e, + 0x40, + 0x40, + 0x24, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x41 "A" */ + 0x00, + 0x00, + 0x18, + 0x18, + 0x24, + 0x24, + 0x24, + 0x7e, + 0x42, + 0x42, + 0x42, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x42 "B" */ + 0x00, + 0x00, + 0x7c, + 0x42, + 0x42, + 0x42, + 0x7c, + 0x7c, + 0x42, + 0x42, + 0x42, + 0x7c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x44 "C" */ + 0x00, + 0x00, + 0x3c, + 0x22, + 0x60, + 0x40, + 0x40, + 0x40, + 0x40, + 0x60, + 0x22, + 0x3c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x45 "D" */ + 0x00, + 0x00, + 0x78, + 0x44, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x44, + 0x78, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x46 "E" */ + 0x00, + 0x00, + 0x7e, + 0x40, + 0x40, + 0x40, + 0x7e, + 0x7e, + 0x40, + 0x40, + 0x40, + 0x7e, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x47 "F" */ + 0x00, + 0x00, + 0x7e, + 0x40, + 0x40, + 0x40, + 0x7e, + 0x7e, + 0x40, + 0x40, + 0x40, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x48 "G" */ + 0x00, + 0x00, + 0x3c, + 0x42, + 0x40, + 0x40, + 0x40, + 0x40, + 0x4e, + 0x42, + 0x42, + 0x3c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x49 "H" */ + 0x00, + 0x00, + 0x42, + 0x42, + 0x42, + 0x42, + 0x7e, + 0x7e, + 0x42, + 0x42, + 0x42, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x49 "I" */ + 0x00, + 0x00, + 0x3c, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x3c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x4a "J" */ + 0x00, + 0x00, + 0x04, + 0x04, + 0x04, + 0x04, + 0x04, + 0x04, + 0x04, + 0x04, + 0x24, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x4b "K" */ + 0x00, + 0x00, + 0x42, + 0x44, + 0x48, + 0x50, + 0x60, + 0x60, + 0x50, + 0x48, + 0x44, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x4c "L" */ + 0x00, + 0x00, + 0x40, + 0x40, + 0x40, + 0x40, + 0x40, + 0x40, + 0x40, + 0x40, + 0x40, + 0x7e, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x4d "M" */ + 0x00, + 0x00, + 0x42, + 0x66, + 0x7e, + 0x5a, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x4e "N" */ + 0x00, + 0x00, + 0x42, + 0x62, + 0x62, + 0x52, + 0x52, + 0x4a, + 0x4a, + 0x46, + 0x46, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x4f "O" */ + 0x00, + 0x00, + 0x18, + 0x24, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x24, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x50 "P" */ + 0x00, + 0x00, + 0x70, + 0x48, + 0x44, + 0x44, + 0x48, + 0x70, + 0x40, + 0x40, + 0x40, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x51 "Q" */ + 0x00, + 0x00, + 0x18, + 0x24, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x4a, + 0x24, + 0x1a, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x52 "R" */ + 0x00, + 0x00, + 0x70, + 0x48, + 0x44, + 0x44, + 0x48, + 0x70, + 0x50, + 0x48, + 0x44, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x53 "S" */ + 0x00, + 0x00, + 0x1e, + 0x20, + 0x40, + 0x40, + 0x20, + 0x18, + 0x04, + 0x02, + 0x02, + 0x7e, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x54 "T" */ + 0x00, + 0x00, + 0x7e, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x55 "U" */ + 0x00, + 0x00, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x3c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x56 "V" */ + 0x00, + 0x00, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x24, + 0x24, + 0x24, + 0x24, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x57 "W" */ + 0x00, + 0x00, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x42, + 0x5a, + 0x66, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x58 "X" */ + 0x00, + 0x00, + 0x42, + 0x42, + 0x24, + 0x24, + 0x18, + 0x18, + 0x24, + 0x24, + 0x42, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x59 "Y" */ + 0x00, + 0x00, + 0x42, + 0x42, + 0x24, + 0x24, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x5a "Z" */ + 0x00, + 0x00, + 0x7e, + 0x42, + 0x04, + 0x04, + 0x08, + 0x10, + 0x20, + 0x20, + 0x42, + 0x7e, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x5b "[" */ + 0x00, + 0x00, + 0x30, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x30, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x5c "\" */ + 0x00, + 0x00, + 0x40, + 0x20, + 0x20, + 0x10, + 0x10, + 0x08, + 0x08, + 0x04, + 0x04, + 0x02, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x5d "]" */ + 0x00, + 0x00, + 0x18, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x5e "^" */ + 0x00, + 0x00, + 0x18, + 0x3c, + 0x66, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x5f "_" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x7e, + 0x00, + /* 0x60 "`" */ + 0x00, + 0x00, + 0x00, + 0x20, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x61 "a" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x38, + 0x44, + 0x04, + 0x3c, + 0x44, + 0x3a, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x62 "b" */ + 0x00, + 0x00, + 0x40, + 0x40, + 0x40, + 0x40, + 0x58, + 0x64, + 0x44, + 0x44, + 0x64, + 0x58, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x63 "c" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x38, + 0x44, + 0x40, + 0x40, + 0x44, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x64 "d" */ + 0x00, + 0x00, + 0x04, + 0x04, + 0x04, + 0x04, + 0x3c, + 0x4c, + 0x44, + 0x44, + 0x4c, + 0x3c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x65 "e" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x38, + 0x44, + 0x78, + 0x40, + 0x44, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x66 "f" */ + 0x00, + 0x00, + 0x0c, + 0x12, + 0x10, + 0x10, + 0x38, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x67 "g" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x34, + 0x4c, + 0x44, + 0x4c, + 0x34, + 0x04, + 0x44, + 0x38, + 0x00, + 0x00, + /* 0x68 "h" */ + 0x00, + 0x00, + 0x40, + 0x40, + 0x40, + 0x58, + 0x64, + 0x44, + 0x44, + 0x44, + 0x44, + 0x44, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x69 "i" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x08, + 0x00, + 0x18, + 0x08, + 0x08, + 0x08, + 0x08, + 0x1c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x6a "j" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x08, + 0x00, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x48, + 0x30, + 0x00, + /* 0x6b "k" */ + 0x00, + 0x00, + 0x40, + 0x40, + 0x40, + 0x44, + 0x48, + 0x50, + 0x70, + 0x48, + 0x44, + 0x42, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x6c "l" */ + 0x00, + 0x00, + 0x30, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x6d "m" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x54, + 0x2a, + 0x2a, + 0x2a, + 0x2a, + 0x6a, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x6e "n" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x58, + 0x24, + 0x24, + 0x24, + 0x24, + 0x76, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x6f "o" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x1c, + 0x22, + 0x22, + 0x22, + 0x22, + 0x1c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x70 "p" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x58, + 0x64, + 0x44, + 0x64, + 0x58, + 0x40, + 0x40, + 0x40, + 0x00, + 0x00, + /* 0x71 "q" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x34, + 0x4c, + 0x44, + 0x4c, + 0x34, + 0x04, + 0x04, + 0x04, + 0x00, + 0x00, + /* 0x72 "r" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x78, + 0x44, + 0x40, + 0x40, + 0x40, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x73 "s" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x18, + 0x24, + 0x10, + 0x08, + 0x24, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x74 "t" */ + 0x00, + 0x00, + 0x10, + 0x10, + 0x10, + 0x38, + 0x10, + 0x10, + 0x10, + 0x10, + 0x14, + 0x08, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x75 "u" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x24, + 0x24, + 0x24, + 0x24, + 0x24, + 0x1a, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x76 "v" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x44, + 0x44, + 0x44, + 0x28, + 0x28, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x77 "w" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x2a, + 0x2a, + 0x2a, + 0x2a, + 0x2a, + 0x14, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x78 "x" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x44, + 0x44, + 0x28, + 0x10, + 0x28, + 0x44, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x79 "y" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x22, + 0x22, + 0x14, + 0x14, + 0x08, + 0x08, + 0x10, + 0x20, + 0x00, + 0x00, + /* 0x7a "z" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x3c, + 0x04, + 0x08, + 0x10, + 0x20, + 0x3c, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x7b "{" */ + 0x00, + 0x04, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x10, + 0x08, + 0x08, + 0x08, + 0x08, + 0x04, + 0x00, + 0x00, + /* 0x7c "|" */ + 0x00, + 0x00, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00, + /* 0x7d "}" */ + 0x00, + 0x20, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x08, + 0x10, + 0x10, + 0x10, + 0x10, + 0x10, + 0x20, + 0x00, + 0x00, + /* 0x7e "~" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x24, + 0x54, + 0x48, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + /* 0x7f "v" */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x44, + 0x44, + 0x44, + 0x28, + 0x28, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00 +}; diff --git a/qemu/roms/SLOF/slof/engine.in b/qemu/roms/SLOF/slof/engine.in new file mode 100644 index 000000000..0344a38e3 --- /dev/null +++ b/qemu/roms/SLOF/slof/engine.in @@ -0,0 +1,542 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +// ============================================================================ +// ============================================================================ + + +// +// Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +// + +// This is the core engine of Paflof. It is almost ANS Forth compatible. +// There are two possibilities why an aspect would not be: +// a) Open Firmware requires different semantics; +// b) bugs. +// Most of the "extended" semantics defined in the OF specification are +// not implemented; just the bare essentials. For example, you can't +// use structural words (IF, THEN, BEGIN, etc.) or return-stack +// manipulation words (R> etc.) in the interpreter. + +// The data stack pointer. +raw(HERE DOVAL _A(the_mem)) + +// Some common constant numbers; smaller and faster if they are defined +// as constants, than when inlined as a literal. +con(-1 -1) +con(0 0) +con(1 1) +con(2 2) +con(3 3) +con(4 4) +con(8 8) +con(H#10 0x10) +con(H#20 0x20) +con(H#FF 0xff) +con(H#FFFF 0xffff) +con(H#FFFFFFFF 0xffffffff) +con(D#10 0x0a) + + +// Manipulating different kinds of addresses. +con(/C 1) +con(/W 2) +con(/L 4) +con(/X 8) +con(/N CELLSIZE) +con(CELL CELLSIZE) +col(/C* /C *) +col(/W* /W *) +col(/L* /L *) +col(/X* /X *) +col(/N* /N *) +col(CA+ /C* +) +col(WA+ /W* +) +col(LA+ /L* +) +col(XA+ /X* +) +col(NA+ /N* +) +col(CA1+ /C +) +col(WA1+ /W +) +col(LA1+ /L +) +col(XA1+ /X +) +col(NA1+ /N +) +col(CHAR+ CA1+) +col(CELL+ NA1+) +col(CHAR- /C -) +col(CELL- /N -) +col(CHARS /C*) +col(CELLS /N*) +col(CHARS+ CA+) +col(CELLS+ NA+) + + +// Run-time words for TO and for string literals. +col(DOTO R> CELL+ DUP >R @ CELL+ !) +col(SLITERAL R> CELL+ DUP DUP C@ + LIT(-CELLSIZE) AND >R) + + +// Stack manipulation. +col(?DUP DUP 0BRANCH(1) DUP) +col(TUCK SWAP OVER) +col(2DUP OVER OVER) +col(3DUP 2 PICK 2 PICK 2 PICK) +col(2OVER 3 PICK 3 PICK) +col(2DROP DROP DROP) +col(3DROP DROP DROP DROP) +col(NIP SWAP DROP) +col(CLEAR 0 DEPTH!) +col(ROT >R SWAP R> SWAP) +col(-ROT SWAP >R SWAP R>) +col(2SWAP >R -ROT R> -ROT) +col(2ROT >R >R 2SWAP R> R> 2SWAP) +col(ROLL DUP ?DUP 0BRANCH(6) ROT >R 1 - BRANCH(-9) ?DUP 0BRANCH(6) R> -ROT 1 - BRANCH(-9)) +col(-ROLL DUP ?DUP 0BRANCH(9) >R ROT R> SWAP >R 1 - BRANCH(-12) ?DUP 0BRANCH(6) R> SWAP 1 - BRANCH(-9)) +col(2>R R> ROT >R SWAP >R >R) +col(2R> R> R> R> ROT >R SWAP) +col(2R@ R> R> R@ OVER >R ROT >R SWAP) +cod(?PICK) + +// Arithmetic. +col(2* 1 LSHIFT) +col(U2/ 1 RSHIFT) +col(2/ 1 ASHIFT) +col(<< LSHIFT) +col(>> RSHIFT) +col(>>A ASHIFT) +col(INVERT -1 XOR) +col(NOT INVERT) + + +// Booleans. +con(TRUE -1) +con(FALSE 0) + + +// Comparisons. +col(> SWAP <) +col(U> SWAP U<) +col(<= > 0=) +col(<> = 0=) +col(>= < 0=) +col(0<= 0 <=) +col(0<> 0 <>) +col(0> 0 >) +col(0>= 0 >=) +col(U<= U> 0=) +col(U>= U< 0=) +col(WITHIN ROT DUP ROT >= 0BRANCH(3) 2DROP FALSE EXIT > 0BRANCH(2) FALSE EXIT TRUE) +col(BETWEEN 1 + WITHIN) + +// Double-cell single-bit shifts. +col(D2* 2* OVER 0< - >R 2* R>) +col(UD2/ >R U2/ R@ LIT(8*CELLSIZE-1) LSHIFT OR R> U2/) +col(D2/ >R U2/ R@ LIT(8*CELLSIZE-1) LSHIFT OR R> 2/) + + +// More arithmetic. +col(NEGATE 0 SWAP -) +col(ABS DUP 0< 0BRANCH(1) NEGATE) +col(MAX 2DUP < 0BRANCH(1) SWAP DROP) +col(MIN 2DUP > 0BRANCH(1) SWAP DROP) +col(U* *) +col(1+ 1 +) +col(1- 1 -) +col(2+ 2 +) +col(2- 2 -) +col(EVEN 1+ -1 AND) +col(BOUNDS OVER + SWAP) + + +// Double-cell and mixed-size arithmetic. +col(S>D DUP 0<) +col(DNEGATE INVERT >R NEGATE DUP 0= R> SWAP -) +col(DABS DUP 0< 0BRANCH(1) DNEGATE) +col(M+ SWAP >R DUP >R + DUP R> U< R> SWAP -) +col(D+ >R M+ R> +) +col(D- DNEGATE D+) +col(*' >R DUP 0< >R D2* R> 0BRANCH(2) R@ M+ R>) +col(UM* 0 -ROT LIT(8*CELLSIZE) 0 DODO *' DOLOOP(-3) DROP) +col(M* 2DUP XOR >R >R ABS R> ABS UM* R> 0< 0BRANCH(1) DNEGATE) +col(/' >R DUP 0< >R D2* R> OVER R@ U>= OR 0BRANCH(6) >R 1 OR R> R@ - R>) +col(UM/MOD LIT(8*CELLSIZE) 0 DODO /' DOLOOP(-3) DROP SWAP) +col(SM/REM OVER >R >R DABS R@ ABS UM/MOD R> 0< 0BRANCH(1) NEGATE R> 0< 0BRANCH(4) NEGATE SWAP NEGATE SWAP) +col(FM/MOD DUP >R 2DUP XOR 0< >R SM/REM OVER 0<> R> AND 0BRANCH(6) 1- SWAP R> + SWAP EXIT R> DROP) + + +// Division. +col(U/MOD 0 SWAP UM/MOD) +col(/MOD >R S>D R> FM/MOD) +col(/ /MOD NIP) +col(MOD /MOD DROP) +col(*/MOD >R M* R> FM/MOD) +col(*/ */MOD NIP) + + +// Splitting, joining, flipping the components of a number. +col(WBSPLIT DUP H#FF AND SWAP 8 RSHIFT) +col(LWSPLIT DUP H#FFFF AND SWAP H#10 RSHIFT) +col(XLSPLIT DUP H#FFFFFFFF AND SWAP H#20 RSHIFT) +col(LBSPLIT LWSPLIT >R WBSPLIT R> WBSPLIT) +col(XWSPLIT XLSPLIT >R LWSPLIT R> LWSPLIT) +col(XBSPLIT XLSPLIT >R LBSPLIT R> LBSPLIT) +col(BWJOIN 8 LSHIFT OR) +col(WLJOIN H#10 LSHIFT OR) +col(BLJOIN BWJOIN >R BWJOIN R> WLJOIN) +col(WBFLIP WBSPLIT SWAP BWJOIN) +col(LWFLIP LWSPLIT SWAP WLJOIN) +col(LXJOIN H#20 LSHIFT OR) +col(XLFLIP XLSPLIT SWAP LXJOIN) +col(LBFLIP LBSPLIT SWAP 2SWAP SWAP BLJOIN) +col(WXJOIN WLJOIN >R WLJOIN R> LXJOIN) +col(XWFLIP XWSPLIT SWAP 2SWAP SWAP WXJOIN) +col(BXJOIN BLJOIN >R BLJOIN R> LXJOIN) +col(XBFLIP XLSPLIT LBFLIP SWAP LBFLIP LXJOIN) + +// Aligning to cell size. +col(ALIGNED /N 1- + /N NEGATE AND) + + +// Counted loop stuff. +col(I R> R@ SWAP >R) +col(J R> R> R> R@ SWAP >R SWAP >R SWAP >R) +col(UNLOOP R> R> R> 2DROP >R) + + +// Memory accesses. +col(+! TUCK @ + SWAP !) +cod(COMP) +col(OFF FALSE SWAP !) +col(ON TRUE SWAP !) +col(<W@ W@ DUP LIT(0x8000) >= 0BRANCH(3) LIT(0x10000) -) +col(2@ DUP CELL+ @ SWAP @) +col(2! DUP >R ! R> CELL+ !) +col(WBFLIPS BOUNDS DO?DO(8) I W@ WBFLIP I W! /W DO+LOOP(-8)) +col(LWFLIPS BOUNDS DO?DO(8) I L@ LWFLIP I L! /L DO+LOOP(-8)) +col(LBFLIPS BOUNDS DO?DO(8) I L@ LBFLIP I L! /L DO+LOOP(-8)) +col(XBFLIPS BOUNDS DO?DO(8) I X@ XBFLIP I X! /X DO+LOOP(-8)) +col(XWFLIPS BOUNDS DO?DO(8) I X@ XWFLIP I X! /X DO+LOOP(-8)) +col(XLFLIPS BOUNDS DO?DO(8) I X@ XLFLIP I X! /X DO+LOOP(-8)) +cod(FILL) +col(BLANK LIT(0x20) FILL) +col(ERASE LIT(0x00) FILL) + + +// Exception handling. +var(CATCHER 0) +var(ABORT"-STR 0) +col(CATCH DEPTH >R CATCHER @ >R RDEPTH CATCHER ! EXECUTE R> CATCHER ! R> DROP 0) +col(THROW ?DUP 0BRANCH(12) CATCHER @ RDEPTH! R> CATCHER ! R> SWAP >R DEPTH! DROP R>) +col(ABORT -1 THROW) + + +// Text input. +var(#TIB TIBSIZE) +val(IB 0) +var(#IB 0) +val(SOURCE-ID 0) +col(SOURCE IB #IB @) +var(>IN 0) +col(TERMINAL TIB DOTO IB #TIB @ #IB ! 0 DOTO SOURCE-ID) + + +// ASCII codes. +con(BL 0x20) +con(BELL 7) +con(BS 8) +con(CARRET 0x0d) +con(LINEFEED 0x0a) + + +// Text output. +dfr(EMIT) +dfr(CR) +col(TYPE BOUNDS DO?DO(5) I C@ EMIT DOLOOP(-5)) +col(LL-CR CARRET EMIT LINEFEED EMIT) +col(SPACE BL EMIT) +col(SPACES 0 DO?DO(3) SPACE DOLOOP(-3)) + + +// Text manipulation. +col(COUNT DUP CHAR+ SWAP C@) +col(PACK DUP >R 1+ SWAP DUP R@ C! MOVE R>) +col(UPC DUP LIT('a') LIT('z') BETWEEN 0BRANCH(3) LIT(0x20) - ) +col(LCC DUP LIT('A') LIT('Z') BETWEEN 0BRANCH(3) LIT(0x20) + ) + + +// Text input. +dfr(KEY) +dfr(KEY?) +dfr(ACCEPT) +var(SPAN 0) +col(EXPECT ACCEPT SPAN !) +col(REFILL SOURCE-ID 0= 0BRANCH(7) SOURCE EXPECT 0 >IN ! TRUE EXIT SOURCE-ID -1 = 0BRANCH(2) FALSE EXIT LIT(0x6502) THROW) + + +// Number base. +var(BASE 16) +col(DECIMAL D#10 BASE !) +col(HEX H#10 BASE !) +col(OCTAL 8 BASE !) + + +// Pictured numeric output. +col(PAD HERE LIT(256) +) +col(TODIGIT DUP LIT(9) > 0BRANCH(3) LIT(0x27) + LIT(0x30) +) +col(MU/MOD DUP >R U/MOD R> SWAP >R UM/MOD R>) +col(<# PAD DUP !) +col(HOLD PAD DUP @ 1- TUCK SWAP ! C!) +col(SIGN 0< 0BRANCH(3) LIT('-') HOLD) +col(# BASE @ MU/MOD ROT TODIGIT HOLD) +col(#S # 2DUP OR 0BRANCH(2) BRANCH(-7)) +col(#> 2DROP PAD DUP @ TUCK -) +col((.) <# DUP >R ABS 0 #S R> SIGN #>) +col(U# BASE @ U/MOD SWAP TODIGIT HOLD) +col(U#S U# DUP 0BRANCH(2) BRANCH(-6)) +col(U#> DROP PAD DUP @ TUCK -) +col((U.) <# U#S U#>) +col(. (.) TYPE SPACE) +col(S. .) +col(U. (U.) TYPE SPACE) +col(.R SWAP (.) ROT 2DUP < 0BRANCH(5) OVER - SPACES BRANCH(1) DROP TYPE) +col(U.R SWAP (U.) ROT 2DUP < 0BRANCH(5) OVER - SPACES BRANCH(1) DROP TYPE) +col(.D BASE @ SWAP DECIMAL . BASE !) +col(.H BASE @ SWAP HEX . BASE !) +col(.S DEPTH DUP 0< 0BRANCH(2) DROP EXIT 0 DO?DO(8) DEPTH I - 1- PICK . DOLOOP(-8)) +col(? @ .) + + +// Numeric input. +col(DIGIT OVER UPC DUP LIT('A') LIT('Z') BETWEEN 0BRANCH(3) LIT(7) - LIT(0x30) - DUP ROT 0 SWAP WITHIN 0BRANCH(4) NIP TRUE BRANCH(2) DROP FALSE) +col(>NUMBER DUP 0= 0BRANCH(1) EXIT OVER C@ BASE @ DIGIT 0BRANCH(23) SWAP >R SWAP >R >R BASE @ U* SWAP BASE @ UM* ROT + R> 0 D+ R> CHAR+ R> 1- BRANCH(-35) DROP) +col($NUMBER DUP 0= 0BRANCH(4) DROP DROP TRUE EXIT >R DUP >R C@ LIT('-') = DUP 0BRANCH(15) R> CHAR+ R> 1- DUP 0= 0BRANCH(5) DROP DROP DROP TRUE EXIT >R >R 0 0 R> R> >NUMBER NIP 0= 0BRANCH(7) DROP SWAP 0BRANCH(1) NEGATE FALSE EXIT DROP DROP DROP TRUE) + + +// Data space allocation. +col(ALLOT HERE + DOTO HERE) +col(, HERE ! /N ALLOT) +col(C, HERE C! /C ALLOT) +col(W, HERE W! /W ALLOT) +col(L, HERE L! /L ALLOT) +col(X, HERE X! /X ALLOT) +col(ALIGN HERE /N 1- AND 0BRANCH(4) 0 C, BRANCH(-10)) +col(PLACE 2DUP C! CHAR+ SWAP CHARS BOUNDS DO?DO(9) DUP C@ I C! CHAR+ 1 CHARS DO+LOOP(-9) DROP) +col(STRING, HERE OVER 1+ CHARS ALLOT PLACE) + + +// Every language needs a no-op. +col(NOOP) + + +// Now it gets ugly: search-order and word-lisst infrastructure. + +raw(FORTH-WORDLIST DODOES _A(xt_NOOP+2+(8/sizeof(long))) _A(0) _A(0)) + // Engine initialisation will set this last cell to the xt of LASTWORD. + +// compilation dictionary +raw(CURRENT DOVAL _A(xt_FORTH_X2d_WORDLIST+3+(16/sizeof(long)))) + // +7 for 32-bit, +5 for 64-bit + +col(LAST CURRENT CELL+) + +// for context dictionaries +raw(SEARCH-ORDER DOVAR _A(xt_FORTH_X2d_WORDLIST+3+(16/sizeof(long))) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0)) + // +7 for 32-bit, +5 for 64-bit +// for context dictionaries +//raw(SEARCH-ORDER DOVAR _A(xt_FORTH_X2d_WORDLIST+3+(sizeof(" FORTH-WORDLIST")/sizeof(long))) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0) _A(0)) +// +7 for 32-bit, +5 for 64-bit +raw(CONTEXT DOVAL _A(xt_SEARCH_X2d_ORDER+2+(16/sizeof(long)))) +//raw(CONTEXT DOVAL _A(xt_SEARCH_X2d_ORDER+6)) +// +6 for 32-bit, +4 for 64-bit + +// Dictionary structure. +col(LINK>NAME CELL+) +col(NAME> CHAR+ DUP C@ 1+ CHARS+ ALIGNED) +col(LINK> LINK>NAME NAME>) +col(NAME>STRING CHAR+ COUNT) + +// Creating word headers. +var(LATEST 0) +dfr((REVEAL)) +col(HEADER ALIGN HERE LAST @ , LATEST ! 0 C, STRING, ALIGN) +col(REVEAL LATEST @ LINK>NAME NAME>STRING (REVEAL) LATEST @ LAST !) + + +// Finding words. +cod(STRING=CI) +// (find) ( str len head -- 0 | link ) +dfr((FIND)) +col(((FIND)) DUP 0BRANCH(15) >R 2DUP R@ LINK>NAME NAME>STRING STRING=CI 0BRANCH(3) 2DROP R> EXIT R> @ BRANCH(-18) 3DROP FALSE) +col((FIND-ORDER) CONTEXT DUP >R SEARCH-ORDER U>= 0BRANCH(18) 2DUP R@ @ CELL+ @ (FIND) ?DUP 0BRANCH(5) NIP NIP R> DROP EXIT R> CELL- BRANCH(-24) R> 3DROP 0) +col(($FIND) (FIND-ORDER) DUP 0BRANCH(6) LINK>NAME DUP NAME> SWAP C@ TRUE) +col($FIND 2DUP ($FIND) 0BRANCH(6) DROP NIP NIP TRUE BRANCH(1) FALSE) + +// Flags on words. +con('IMMEDIATE 1) +col(IMMEDIATE? 'IMMEDIATE AND 0<>) +col(IMMEDIATE LAST @ CELL+ DUP C@ 'IMMEDIATE OR SWAP C!) + +// Parsing. +col(FINDCHAR SWAP 0 DO?DO(24) OVER I + C@ OVER DUP BL = 0BRANCH(3) <= BRANCH(1) = 0BRANCH(6) I UNLOOP NIP NIP TRUE EXIT DOLOOP(-24) DROP DROP FALSE) +col(PARSE >R IB >IN @ + SPAN @ >IN @ - 2DUP R> FINDCHAR 0BRANCH(6) NIP DUP 1 + BRANCH(1) DUP >IN +!) +col(SKIPWS IB SPAN @ DUP >IN @ > 0BRANCH(14) OVER >IN @ + C@ BL <= 0BRANCH(5) 1 >IN +! BRANCH(-20) DROP DROP) +col(PARSE-WORD SKIPWS BL PARSE) +var(WHICHPOCKET 0) +// We reserved 0x1000 for the pockets. So we have 16 pockets a 0x100 +col(POCKET POCKETS WHICHPOCKET @ LIT(POCKETSIZE) * + WHICHPOCKET @ 1 + DUP LIT(NUMPOCKETS) = 0BRANCH(2) DROP 0 WHICHPOCKET !) + +col(WORD POCKET >R PARSE DUP R@ C! BOUNDS R> DUP 2SWAP DO?DO(7) CHAR+ I C@ OVER C! DOLOOP(-7) DROP) + +// Some simple parsing words. +col(CHAR PARSE-WORD DROP C@) +imm(( LIT(')') PARSE 2DROP) +// Removing comments out of the code, the code from the backslash to the next \n is removed. +// We need to start from cursor -1 (the backslash) to handle the case backslash+linefeed correctly 0x5c0a +imm(\ >IN @ 1- >IN ! LINEFEED PARSE 2DROP) + +// The compiler infrastructure. +var(STATE 0) +imm([ STATE OFF) +col(] LIT(0x100) STATE !) +col(?COMP STATE @ 0BRANCH(1) EXIT LIT(-134) THROW) + +col(COMPILE, ,) +col(: PARSE-WORD HEADER DOTICK DOCOL COMPILE, ]) +col(:NONAME ALIGN HERE DOTICK DOCOL COMPILE, ]) +imm(; ?COMP DOTICK SEMICOLON COMPILE, REVEAL [) + +// Compiling strings. +imm(C" ?COMP LIT('"') PARSE DOTICK SLITERAL COMPILE, DUP C, BOUNDS DO?DO(5) I C@ C, DOLOOP(-5) ALIGN) +imm(S" STATE @ 0BRANCH(5) C" DOTICK COUNT COMPILE, EXIT LIT('"') PARSE DUP >R POCKET DUP >R SWAP MOVE R> R>) +imm(Z" S" 2DUP + 0 SWAP C! DROP) +imm(." STATE @ 0BRANCH(5) S" DOTICK TYPE COMPILE, EXIT LIT('"') PARSE TYPE) +imm(.( LIT(')') PARSE TYPE) + +col(COMPILE R> CELL+ DUP @ COMPILE, >R) + +var(THERE 0) +col(+COMP STATE @ 1 STATE +! 0BRANCH(1) EXIT HERE THERE ! COMP-BUFFER DOTO HERE COMPILE DOCOL) +col(-COMP -1 STATE +! STATE @ 0BRANCH(1) EXIT COMPILE EXIT THERE @ DOTO HERE COMP-BUFFER EXECUTE) + +// Structure words. +col(RESOLVE-ORIG HERE OVER CELL+ - SWAP !) +imm(AHEAD +COMP DOTICK DOBRANCH COMPILE, HERE 0 COMPILE,) +imm(IF +COMP DOTICK DO0BRANCH COMPILE, HERE 0 COMPILE,) +imm(THEN ?COMP RESOLVE-ORIG -COMP) +imm(ELSE ?COMP DOTICK DOBRANCH COMPILE, HERE 0 COMPILE, SWAP RESOLVE-ORIG) + +imm(CASE +COMP 0) +imm(ENDCASE ?COMP DOTICK DROP COMPILE, ?DUP 0BRANCH(5) 1- SWAP THEN BRANCH(-8) -COMP) +imm(OF ?COMP 1+ >R DOTICK OVER COMPILE, DOTICK = COMPILE, IF DOTICK DROP COMPILE, R>) +imm(ENDOF ?COMP >R ELSE R>) + +col(RESOLVE-DEST HERE CELL+ - COMPILE,) +imm(BEGIN +COMP HERE) +imm(AGAIN ?COMP DOTICK DOBRANCH COMPILE, RESOLVE-DEST -COMP) +imm(UNTIL ?COMP DOTICK DO0BRANCH COMPILE, RESOLVE-DEST -COMP) +imm(WHILE ?COMP IF SWAP) +imm(REPEAT ?COMP AGAIN THEN) + +// Counted loops. +var(LEAVES 0) +col(RESOLVE-LOOP LEAVES @ ?DUP 0BRANCH(10) DUP @ SWAP HERE OVER - SWAP ! BRANCH(-13) HERE - COMPILE, LEAVES !) +imm(DO +COMP LEAVES @ HERE DOTICK DODO COMPILE, 0 LEAVES !) +imm(?DO +COMP LEAVES @ DOTICK DODO?DO COMPILE, HERE HERE LEAVES ! 0 COMPILE,) +imm(LOOP ?COMP DOTICK DODOLOOP COMPILE, RESOLVE-LOOP -COMP) +imm(+LOOP ?COMP DOTICK DODO+LOOP COMPILE, RESOLVE-LOOP -COMP) +imm(LEAVE ?COMP DOTICK DODOLEAVE COMPILE, LEAVES @ HERE LEAVES ! COMPILE,) +imm(?LEAVE ?COMP DOTICK DODO?LEAVE COMPILE, LEAVES @ HERE LEAVES ! COMPILE,) + +// Interpreter nesting. +col(SAVE-SOURCE R> IB >R #IB @ >R SOURCE-ID >R SPAN @ >R >IN @ >R >R) +col(RESTORE-SOURCE R> R> >IN ! R> SPAN ! R> DOTO SOURCE-ID R> #IB ! R> DOTO IB >R) + +// System replies. +str(OK-STR "ok") +str(ABORTED-STR "Aborted") +str(EXCEPTION-STR "Exception #") +str(UNKNOWN-STR "Undefined word") +dfr(HW-EXCEPTION-HANDLER) +val(SHOW-STACK? 0) +col(SHOWSTACK -1 DOTO SHOW-STACK?) +col(NOSHOWSTACK 0 DOTO SHOW-STACK?) +col(PRINT-STACK SHOW-STACK? 0BRANCH(5) >R >R .S R> R> ) +col(PRINT-EXCEPTION DUP LIT(-99) = 0BRANCH(7) DOTICK UNKNOWN-STR COUNT TYPE CR DROP EXIT DUP LIT(0x100) = 0BRANCH(2) DROP EXIT HW-EXCEPTION-HANDLER ) +col(PRINT-STATUS SPACE DUP 0= 0BRANCH(5) PRINT-STACK DOTICK OK-STR BRANCH(7) DUP -1 = 0BRANCH(6) DOTICK ABORTED-STR COUNT TYPE BRANCH(10) DUP LIT(-2) = 0BRANCH(7) ABORT"-STR @ COUNT TYPE DROP BRANCH(1) PRINT-EXCEPTION CR) + +// The compiler and interpreter. +col(COMPILE-WORD 2DUP ($FIND) 0BRANCH(10) IMMEDIATE? 0BRANCH(4) NIP NIP EXECUTE EXIT COMPILE, 2DROP EXIT 2DUP $NUMBER 0BRANCH(4) TYPE LIT(-99) THROW DOTICK DOLIT COMPILE, COMPILE, 2DROP) +col(INTERPRET-WORD 2DUP ($FIND) 0BRANCH(5) DROP NIP NIP EXECUTE EXIT 2DUP $NUMBER 0BRANCH(4) TYPE LIT(-99) THROW >R 2DROP R>) +col(INTERPRET 0 >IN ! PARSE-WORD DUP 0BRANCH(10) STATE @ 0BRANCH(3) COMPILE-WORD BRANCH(1) INTERPRET-WORD BRANCH(-14) 2DROP) + +// Evaluate, the one word to rule them all. It is evil, btw. +col(EVALUATE SAVE-SOURCE -1 DOTO SOURCE-ID DUP #IB ! SPAN ! DOTO IB DOTICK INTERPRET CATCH RESTORE-SOURCE THROW) +col(EVAL EVALUATE) + +// Abort with a message. +col(DOABORT" SWAP 0BRANCH(5) ABORT"-STR ! LIT(-2) THROW DROP) +imm(ABORT" C" DOTICK DOABORT" COMPILE,) + +// Tick. +str(UNDEFINED-STR "undefined word ") +col(SET-UNDEFINED-WORD POCKET >R DOTICK UNDEFINED-STR DUP C@ 1+ R@ SWAP MOVE R@ DUP C@ 1+ + SWAP DUP R@ C@ + R@ C! MOVE R>) +col(' PARSE-WORD $FIND 0= 0BRANCH(4) SET-UNDEFINED-WORD TRUE SWAP DOABORT") + +// The outer interpreter. +col(QUIT 0 RDEPTH! [ TERMINAL DEPTH . LIT('>') EMIT SPACE REFILL 0BRANCH(10) SPACE DOTICK INTERPRET CATCH DUP PRINT-STATUS 0BRANCH(-17) BRANCH(-23)) + +// Reading and writing to/from file; including files. +dfr(MAP-FILE) +dfr(UNMAP-FILE) +dfr(WRITE-FILE) +col(INCLUDED MAP-FILE 2DUP >R >R BOUNDS DO?DO(21) R> R@ SWAP >R R@ - R@ SWAP 2DUP LINEFEED FINDCHAR 0BRANCH(1) NIP DUP >R EVALUATE R> 1+ DO+LOOP(-21) R> R> UNMAP-FILE) +col(INCLUDE PARSE-WORD INCLUDED) + +// CREATE ... DOES> ... +col($CREATE HEADER DOTICK DODOES COMPILE, DOTICK NOOP CELL+ COMPILE, REVEAL) +col(CREATE PARSE-WORD $CREATE) +col(DODOES> R> CELL+ LATEST @ LINK> CELL+ !) +imm(DOES> DOTICK DODOES> COMPILE,) + +// Defining words. +col(CONSTANT PARSE-WORD HEADER DOTICK DOCON COMPILE, COMPILE, REVEAL) +col(VALUE PARSE-WORD HEADER DOTICK DOVAL COMPILE, COMPILE, REVEAL) +col(VARIABLE PARSE-WORD HEADER DOTICK DOVAR COMPILE, 0 COMPILE, REVEAL) +col(BUFFER: PARSE-WORD HEADER DOTICK DOBUFFER: COMPILE, ALLOT REVEAL) +col(DEFER PARSE-WORD HEADER DOTICK DODEFER COMPILE, DOTICK ABORT COMPILE, REVEAL) +col(ALIAS PARSE-WORD HEADER DOTICK DOALIAS COMPILE, ' COMPILE, REVEAL) +col(STRUCT 0) +col(END-STRUCT DROP) +col(FIELD PARSE-WORD HEADER DOTICK DOFIELD COMPILE, OVER , + REVEAL) + +// Words with (mostly) non-standard compilation behaviour. +imm(LITERAL DOTICK DOLIT COMPILE, COMPILE,) +imm([COMPILE] ' COMPILE,) +imm(POSTPONE PARSE-WORD 2DUP ($FIND) 0= 0BRANCH(4) SET-UNDEFINED-WORD TRUE SWAP DOABORT" IMMEDIATE? 0= 0BRANCH(6) DOTICK DOTICK COMPILE, COMPILE, DOTICK COMPILE, COMPILE, 2DROP) +imm([CHAR] CHAR LITERAL) +imm(['] ' DOTICK DOTICK COMPILE, COMPILE,) + +// FIND. +col(FIND DUP COUNT ($FIND) 0BRANCH(9) ROT DROP TRUE SWAP IMMEDIATE? 0BRANCH(1) NEGATE EXIT FALSE EXIT) + +// Accessing data in CREATE'd words. +imm(TO ' STATE @ 0BRANCH(5) DOTICK DOTO COMPILE, COMPILE, EXIT CELL+ !) +col(BEHAVIOR CELL+ @) +col(>BODY 2 CELLS +) +col(BODY> 2 CELLS -) + +// Making words recursive. +imm(RECURSIVE REVEAL) +imm(RECURSE LATEST @ LINK> COMPILE,) + +// Numeric input. +imm(d# PARSE-WORD BASE @ >R DECIMAL EVALUATE R> BASE !) +imm(h# PARSE-WORD BASE @ >R HEX EVALUATE R> BASE !) +imm(o# PARSE-WORD BASE @ >R OCTAL EVALUATE R> BASE !) diff --git a/qemu/roms/SLOF/slof/entry.S b/qemu/roms/SLOF/slof/entry.S new file mode 100644 index 000000000..dcff57ba0 --- /dev/null +++ b/qemu/roms/SLOF/slof/entry.S @@ -0,0 +1,210 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <macros.h> + +#define STACKSIZE 0x2000 + + # + # The generic exception code. + # + # Enter with GPR0 = vector, SPRG0 = saved GPR0 + # + + .section ".entry_text" + +the_handler: + .quad handler + +eregs: + /* the_exception_frame is a C variable which is usually + * defined in $(TARG).c + * the_exception_frame can be accessed from paflof through + * the word eregs + * in the case an excpetion is handled paflof will read + * from eregs the values of all registers and print them + * out in the exception handler */ + .quad the_exception_frame + +handler: + mtsprg 1,1 # SPRG1 = saved GPR1 + bcl 20,31,$+4 + mflr 1 + ld 1,eregs-$+4(1) # GPR1 = address of register save area + + .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15, \ + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 + std \i,\i*8(1) + .endr # save GPR2..GPR31 + + li r3, 3 // GPR3 = mode (param_1, param_2) + mr 4,0 // GPR4 = vector + + mfsprg 0,0 + std 0,0(1) # save GPR0 + mfsprg 0,1 + std 0,8(1) # save GPR1 + + cmpwi r4, 0x900 # Decrementer interrupt + bne 0f + mfdec r5 # Save old value of decrementer as reason + lis r0,0x7fff # Set decrementer to highest value + mtdec r0 +0: + mfcr 0 + std 0,0x100(1) + mfxer 0 + std 0,0x108(1) + mfsprg 0,3 # save lr + std 0,0x110(1) + mfsprg 0,2 # save ctr + std 0,0x118(1) + mfsrr0 0 + std 0,0x120(1) + mfsrr1 0 + std 0,0x128(1) + mfdar 0 + std 0,0x130(1) + mfdsisr 0 + std 0,0x138(1) # save special regs + + bcl 20, 31, over +base: + .align 3 +.the_system_stack: + .quad the_system_stack+STACKSIZE-base +over: + mflr r2 /* gpr 2 is the base */ + ld r1, .the_system_stack-base(r2) /* load stack pointer */ + add r1, r1, r2 /* add base */ + li r0, 0 + stdu r0, -0x10(r1) + stdu r1, -0x100(r1) + + lis 2,engine@ha + ld 0,engine@l(2) # set up entry + mtsrr0 0 + + ld 2,8+engine@l(2) # set up TOC pointer + + rfid +# b .engine # ...and run! + + + + # + # Swap non-volatile client interface regs, plus GPR3..GPR7. + # + +swap_ci_regs: + /* save lr */ + mflr r0 + /* let's find out where our client stack is */ + bcl 20, 31, client_over +client_base: + .align 3 +.the_client_frame: + .quad the_client_frame-client_base +client_over: + mflr r8 /* gpr 2 is the client_base */ + mtlr r0 /* restore the original lr */ + ld r0, .the_client_frame-client_base(r8) + add r8, r0, r8 /* add the client_base */ + /* r8 now contains the address of the_client_frame */ + + .irp i, 1,2,3,4,5,6,7, \ + 13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 + ld 0,\i*8(8) + std \i,\i*8(8) + mr \i,0 + .endr # swap GPR1..7, GPR13..31 + + ld 0,0x100(8) + mfcr 9 + mtcrf 0xff,0 + std 9,0x100(8) # swap CR + + ld 0,0x128(8) + mfmsr 9 + mtmsrd 0 + sync + isync + std 9,0x128(8) # swap MSR + + blr + + # + # Entry point for the OF client interface. + # + + .globl client_entry_point + .section ".opd","aw" + .align 3 +client_entry_point: + .quad .client_entry_point,.TOC.@tocbase,0 + .previous + .type .client_entry_point,@function + .globl .client_entry_point +.client_entry_point: + mflr 4 + bl swap_ci_regs # swap regs + mtlr 4 + li 3, 0 # client call + blr + + # + # Start the client. + # + + .globl call_client + .section ".opd","aw" + .align 3 +call_client: + .quad .call_client,.TOC.@tocbase,0 + .previous + .type .call_client,@function + .globl .call_client + +.call_client: # called with r3 = address, returns r3 + mflr 4 + mtctr 3 + bl swap_ci_regs + /* Check if LE loading */ + cmpwi 0,13,1 + beq 0f + bctrl + b 1f +0: /* handle LE */ + mfmsr 13 + xori 13,13,1 + mtsrr1 13 + mfctr 13 + mr 12,13 + mtsrr0 13 + rfid +#if 0 /* in case we return back, still to be tested */ + .long 0x05009f42; /* bcl 20,31,$+4 */ + .long 0xa602c87d; /* mflr r14 */ + .long 0x1c00ce39; /* addi r14,r14,28 */ + .long 0xa600e07d; /* mfmsr r15 */ + .long 0x0100ef69; /* xori r15,r15,1 */ + .long 0xa603da7d; /* mtsrr0 r14 */ + .long 0xa603fb7d; /* mtsrr1 r15 */ + .long 0x2400004c; /* rfid */ +#endif +1: + bl swap_ci_regs + mtlr 4 + li 3, -1 # client app return + blr + + .lcomm the_system_stack, STACKSIZE, 16 diff --git a/qemu/roms/SLOF/slof/fs/accept.fs b/qemu/roms/SLOF/slof/fs/accept.fs new file mode 100644 index 000000000..7e8e2717e --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/accept.fs @@ -0,0 +1,410 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Implementation of ACCEPT. Using ECMA-48 for terminal control. + +: beep bell emit ; + +: TABLE-EXECUTE + CREATE DOES> swap cells+ @ ?dup IF execute ELSE beep THEN ; + +0 VALUE accept-adr +0 VALUE accept-max +0 VALUE accept-len +0 VALUE accept-cur + +: esc 1b emit ; +: csi esc 5b emit ; + +: move-cursor ( -- ) + esc ." 8" accept-cur IF + csi base @ decimal accept-cur 0 .r base ! ." C" + THEN +; + +: redraw-line ( -- ) + accept-cur accept-len = IF EXIT THEN + move-cursor + accept-adr accept-len accept-cur /string type + csi ." K" move-cursor +; + +: full-redraw-line ( -- ) + accept-cur 0 to accept-cur move-cursor + accept-adr accept-len type + csi ." K" to accept-cur move-cursor +; + +: redraw-prompt ( -- ) + cr depth . [char] > emit +; + +: insert-char ( char -- ) + accept-len accept-max = IF drop beep EXIT THEN + accept-cur accept-len <> IF csi ." @" dup emit + accept-adr accept-cur + dup 1+ accept-len accept-cur - move + ELSE dup emit THEN + accept-adr accept-cur + c! + accept-cur 1+ to accept-cur + accept-len 1+ to accept-len redraw-line +; + +: delete-char ( -- ) + accept-cur accept-len = IF beep EXIT THEN + accept-len 1- to accept-len + accept-adr accept-cur + dup 1+ swap accept-len accept-cur - move + csi ." P" redraw-line +; + +\ * +\ * History handling +\ * + +STRUCT +cell FIELD his>next +cell FIELD his>prev +cell FIELD his>len + 0 FIELD his>buf +CONSTANT /his +0 VALUE his-head +0 VALUE his-tail +0 VALUE his-cur + +: add-history ( -- ) + accept-len 0= IF EXIT THEN + /his accept-len + alloc-mem + his-tail IF dup his-tail his>next ! ELSE dup to his-head THEN + his-tail over his>prev ! 0 over his>next ! dup to his-tail + accept-len over his>len ! accept-adr swap his>buf accept-len move +; + +: history ( -- ) + his-head BEGIN dup WHILE + cr dup his>buf over his>len @ type + his>next @ REPEAT drop +; + +: select-history ( his -- ) + dup to his-cur dup IF + dup his>len @ accept-max min dup to accept-len to accept-cur + his>buf accept-adr accept-len move ELSE + drop 0 to accept-len 0 to accept-cur THEN + full-redraw-line +; + + +\ +\ tab completion +\ + +\ tab completion state variables +0 value ?tab-pressed +0 value tab-last-adr +0 value tab-last-len + +\ compares two strings and returns the longest equal substring. +: $same-string ( addr-1 len-1 addr-2 len-2 -- addr-1 len-1' ) + dup 0= IF \ The second parameter is not a string. + 2drop EXIT \ bail out + THEN + rot min 0 0 -rot ( addr1 addr2 0 len' 0 ) + DO ( addr1 addr2 len-1' ) + 2 pick i + c@ lcc + 2 pick i + c@ lcc + = IF 1 + ELSE leave THEN + LOOP + nip +; + +: $tab-sift-words ( text-addr text-len -- sift-count ) + sift-compl-only >r true to sift-compl-only \ save sifting mode + + last BEGIN @ ?dup WHILE \ loop over all words + $inner-sift IF \ any completions possible? + \ convert to lower case for user interface sanity + 2dup bounds DO I c@ lcc I c! LOOP + ?tab-pressed IF 2dup type space THEN \ <tab><tab> prints possibilities + tab-last-adr tab-last-len $same-string \ find matching substring ... + to tab-last-len to tab-last-adr \ ... and save it + THEN + repeat + 2drop + + #sift-count 0 to #sift-count \ how many words were found? + r> to sift-compl-only \ restore sifting completion mode +; + +\ 8< node sifting for tab completion on device tree nodes below this line 8< + +#include <stack.fs> + +10 new-stack device-stack + +: (next-dev) ( node -- node' addr len ) + device-stack + dup (node>path) rot + dup child IF dup push child -rot EXIT THEN + dup peer IF peer -rot EXIT THEN + drop + BEGIN + stack-depth + WHILE + pop peer ?dup IF -rot EXIT THEN + REPEAT + 0 -rot +; + +: $inner-sift-nodes ( text-addr text-len node -- ... path-addr path-len true | false ) + (next-dev) ( text-addr text-len node' path-addr path-len ) + dup 0= IF drop false EXIT THEN + 2dup 6 pick 6 pick find-isubstr ( text-addr text-len node' path-addr path-len pos ) + 0= IF + #sift-count 1+ to #sift-count \ count completions + true + ELSE + 2drop false + THEN +; + +\ +\ test function for (next-dev) +: .nodes ( -- ) + s" /" find-node BEGIN dup WHILE + (next-dev) + type cr + REPEAT + drop + reset-stack +; + +\ node sifting wants its own pockets +create sift-node-buffer 1000 allot +0 value sift-node-num +: sift-node-buffer + sift-node-buffer sift-node-num 100 * + + sift-node-num 1+ dup 10 = IF drop 0 THEN + to sift-node-num +; + +: $tab-sift-nodes ( text-addr text-len -- sift-count ) + s" /" find-node BEGIN dup WHILE + $inner-sift-nodes IF \ any completions possible? + sift-node-buffer swap 2>r 2r@ move 2r> \ make an almost permanent copy without strdup + ?tab-pressed IF 2dup type space THEN \ <tab><tab> prints possibilities + tab-last-adr tab-last-len $same-string \ find matching substring ... + to tab-last-len to tab-last-adr \ ... and save it + THEN + REPEAT + 2drop drop + #sift-count 0 to #sift-count \ how many words were found? + reset-stack +; + +: $tab-sift ( text-addr text-len -- sift-count ) + ?tab-pressed IF beep space THEN \ cosmetical fix for <tab><tab> + + dup IF bl rsplit dup IF 2swap THEN ELSE 0 0 THEN >r >r + + 0 dup to tab-last-len to tab-last-adr \ reset last possible match + current-node @ IF \ if we are in a node? + 2dup 2>r \ save text + $tab-sift-words to #sift-count \ search in current node first + 2r> \ fetch text to complete, again + THEN + 2dup 2>r + current-node @ >r 0 set-node \ now search in global words + $tab-sift-words to #sift-count + r> set-node + 2r> $tab-sift-nodes + \ concatenate previous commands + r> r> dup IF s" " $cat THEN tab-last-adr tab-last-len $cat + to tab-last-len to tab-last-adr \ ... and save the whole string +; + +\ 8< node sifting for tab completion on device tree nodes above this line 8< + +: handle-^A + 0 to accept-cur move-cursor ; +: handle-^B + accept-cur ?dup IF 1- to accept-cur ( csi ." D" ) move-cursor THEN ; +: handle-^D + delete-char ( redraw-line ) ; +: handle-^E + accept-len to accept-cur move-cursor ; +: handle-^F + accept-cur accept-len <> IF accept-cur 1+ to accept-cur csi ." C" THEN ; +: handle-^H + accept-cur 0= IF beep EXIT THEN + handle-^B delete-char +; +: handle-^I + accept-adr accept-len + $tab-sift 0 > IF + ?tab-pressed IF + redraw-prompt full-redraw-line + false to ?tab-pressed + ELSE + tab-last-adr accept-adr tab-last-len move \ copy matching substring + tab-last-len dup to accept-len to accept-cur \ len and cursor position + full-redraw-line \ redraw new string + true to ?tab-pressed \ second tab will print possible matches + THEN + THEN +; + +: handle-^K + BEGIN accept-cur accept-len <> WHILE delete-char REPEAT ; +: handle-^L + history redraw-prompt full-redraw-line ; +: handle-^N + his-cur IF his-cur his>next @ ELSE his-head THEN + dup to his-cur select-history +; +: handle-^P + his-cur IF his-cur his>prev @ ELSE his-tail THEN + dup to his-cur select-history +; +: handle-^Q \ Does not handle terminal formatting yet. + key insert-char ; +: handle-^R + full-redraw-line ; +: handle-^U + 0 to accept-len 0 to accept-cur full-redraw-line ; + +: handle-fn + key drop beep +; + +TABLE-EXECUTE handle-CSI +0 , ' handle-^P , ' handle-^N , ' handle-^F , +' handle-^B , 0 , 0 , 0 , +' handle-^A , 0 , 0 , ' handle-^E , +0 , 0 , 0 , 0 , +0 , 0 , 0 , 0 , +0 , 0 , 0 , 0 , +0 , 0 , 0 , 0 , +0 , 0 , 0 , 0 , + +TABLE-EXECUTE handle-meta +0 , 0 , 0 , 0 , +0 , 0 , 0 , 0 , +0 , 0 , 0 , 0 , +0 , 0 , 0 , ' handle-fn , +0 , 0 , 0 , 0 , +0 , 0 , 0 , 0 , +0 , 0 , 0 , ' handle-CSI , +0 , 0 , 0 , 0 , + +: handle-ESC-O + key + dup 48 = IF + handle-^A + ELSE + dup 46 = IF + handle-^E + THEN + THEN drop +; + +: handle-ESC-5b + key + dup 31 = IF \ HOME + key drop ( drops closing 7e ) handle-^A + ELSE + dup 33 = IF \ DEL + key drop handle-^D + ELSE + dup 34 = IF \ END + key drop handle-^E + ELSE + dup 1f and handle-CSI + THEN + THEN + THEN drop +; + +: handle-ESC + key + dup 5b = IF + handle-ESC-5b + ELSE + dup 4f = IF + handle-ESC-O + ELSE + dup 1f and handle-meta + THEN + THEN drop +; + +TABLE-EXECUTE handle-control +0 , \ ^@: +' handle-^A , +' handle-^B , +0 , \ ^C: +' handle-^D , +' handle-^E , +' handle-^F , +0 , \ ^G: +' handle-^H , +' handle-^I , \ tab +0 , \ ^J: +' handle-^K , +' handle-^L , +0 , \ ^M: enter: handled in main loop +' handle-^N , +0 , \ ^O: +' handle-^P , +' handle-^Q , +' handle-^R , +0 , \ ^S: +0 , \ ^T: +' handle-^U , +0 , \ ^V: +0 , \ ^W: +0 , \ ^X: +0 , \ ^Y: insert save buffer +0 , \ ^Z: +' handle-ESC , +0 , \ ^\: +0 , \ ^]: +0 , \ ^^: +0 , \ ^_: + +: (accept) ( adr len -- len' ) + cursor-on + to accept-max to accept-adr + 0 to accept-len 0 to accept-cur + 0 to his-cur + 1b emit 37 emit + BEGIN + key dup 0d <> + WHILE + dup 9 <> IF 0 to ?tab-pressed THEN \ reset state machine + dup 7f = IF drop 8 THEN \ Handle DEL as if it was BS. ??? bogus + dup bl < IF handle-control ELSE + dup 80 and IF + dup a0 < IF 7f and handle-meta ELSE drop beep THEN + ELSE + insert-char + THEN + THEN + REPEAT + drop add-history + accept-len to accept-cur + move-cursor space + accept-len + cursor-off +; + +' (accept) to accept + diff --git a/qemu/roms/SLOF/slof/fs/alloc-mem-debug.fs b/qemu/roms/SLOF/slof/fs/alloc-mem-debug.fs new file mode 100644 index 000000000..d4ca70bbd --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/alloc-mem-debug.fs @@ -0,0 +1,116 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +\ * Dynamic memory allocation/de-allocation debug functions +\ ***************************************************************************** + + +\ Uncomment the following code for debugging bad write accesses beyond +\ the end of the allocated block: +\ Store magic value past the end of the block during alloc-mem and +\ check for this magic value when free-mem has been called. +#if 1 +: alloc-mem ( len -- addr ) + dup /n + alloc-mem ( len addr ) + 2dup + 3141592653589793 swap ! nip +; + +: free-mem ( addr len -- ) + 2dup + @ 3141592653589793 <> IF + cr ." Detected memory corrupt during free-mem of " + swap . . cr EXIT + THEN + /n + free-mem +; +#endif + + +\ Never ever assume that allocated memory is pre-initialized with 0 ... +: alloc-mem ( len -- addr ) + dup alloc-mem swap 2dup ff fill drop +; + +\ Make sure that memory block do not contain "valid" data after free-mem: +: free-mem ( addr len -- ) + 2dup ff fill free-mem +; + + +\ The following definitions are used for debugging the parameters of free-mem: +\ Store block address and size of allocated blocks +\ in an array, then check for right values on free-mem. + +1000 CONSTANT max-malloced-blocks +CREATE malloced-blocks max-malloced-blocks 2 * cells allot +malloced-blocks max-malloced-blocks 2 * cells erase + + +: alloc-mem ( len -- addr ) + dup alloc-mem dup 0= IF + cr ." alloc-mem returned 0 for size " swap . cr EXIT + THEN ( len addr ) + malloced-blocks max-malloced-blocks 0 DO ( len addr m-blocks-ptr ) + dup @ 0= IF ( len addr m-blocks-ptr ) + \ Found a free entry: store addr and len + over >r dup >r ! + r> cell+ ! + r> UNLOOP EXIT + THEN + cell+ cell+ ( len addr next-m-blocks-ptr ) + LOOP + ." Please increase max-malloced-blocks." cr ( len addr next-m-blocks-ptr ) + drop nip +; + + +: free-mem ( addr len -- ) + malloced-blocks max-malloced-blocks 0 DO ( addr len m-blocks-ptr ) + dup @ ?dup IF + ( addr len m-blocks-ptr s-addr ) + 3 pick = IF + ( addr len m-blocks-ptr ) + dup cell+ @ ( addr len m-blocks-ptr s-len ) + 2 pick = IF ( addr len m-blocks-ptr ) + \ All right, addr and len matched, + \ clear entry and call original free-mem. + dup cell+ 0 swap ! + 0 swap ! + free-mem + ELSE + >r swap cr + ." free-mem called for block " . ." with wrong size=" . cr + ." ( correct size should be: " r> cell+ @ . ." )" cr + THEN + UNLOOP EXIT + THEN ( addr len m-blocks-ptr ) + THEN + cell+ cell+ ( addr len next-m-blocks-ptr ) + LOOP + drop swap cr + ." free-mem called for block " . + ." ( size=" . + ." ) which has never been allocated before!" cr +; + + +\ Enable these for verbose debug messages: +#if 0 +: alloc-mem + cr ." alloc-mem with len=" dup . + alloc-mem + ." returned addr=" dup . cr +; + +: free-mem + cr ." free mem addr=" over . ." len=" dup . cr + free-mem +; +#endif diff --git a/qemu/roms/SLOF/slof/fs/alloc-mem.fs b/qemu/roms/SLOF/slof/fs/alloc-mem.fs new file mode 100644 index 000000000..59381a72b --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/alloc-mem.fs @@ -0,0 +1,75 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +#include <claim.fs> +\ Memory "heap" (de-)allocation. + +\ Keep a linked list of free blocks per power-of-two size. +\ Never coalesce entries when freed; split blocks when needed while allocating. + +\ 3f CONSTANT (max-heads#) +heap-end heap-start - log2 1+ CONSTANT (max-heads#) + +CREATE heads (max-heads#) cells allot +heads (max-heads#) cells erase + + +: size>head ( size -- headptr ) log2 3 max cells heads + ; + + +\ Allocate a memory block +: alloc-mem ( len -- a-addr ) + dup 0= IF EXIT THEN + 1 over log2 3 max ( len 1 log_len ) + dup (max-heads#) >= IF cr ." Out of internal memory." cr 3drop 0 EXIT THEN + lshift >r ( len R: 1<<log_len ) + size>head dup @ IF + dup @ dup >r @ swap ! r> r> drop EXIT + THEN ( headptr R: 1<<log_len) + r@ 2* recurse dup ( headptr a-addr2 a-addr2 R: 1<<log_len) + dup 0= IF r> 2drop 2drop 0 EXIT THEN + r> + >r 0 over ! swap ! r> +; + + +\ Free a memory block + +: free-mem ( a-addr len -- ) + dup 0= IF 2drop EXIT THEN size>head 2dup @ swap ! ! +; + + +: #links ( a -- n ) + @ 0 BEGIN over WHILE 1+ swap @ swap REPEAT nip +; + + +: .free ( -- ) + 0 (max-heads#) 0 DO + heads i cells + #links dup IF + cr dup . ." * " 1 i lshift dup . ." = " * dup . + THEN + + + LOOP + cr ." Total " . +; + + +\ Start with just one free block. +heap-start heap-end heap-start - free-mem + + +\ : free-mem ( a-addr len -- ) 2drop ; + +\ Uncomment the following line for debugging: +\ #include <alloc-mem-debug.fs> + diff --git a/qemu/roms/SLOF/slof/fs/archsupport.fs b/qemu/roms/SLOF/slof/fs/archsupport.fs new file mode 100644 index 000000000..cc4668769 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/archsupport.fs @@ -0,0 +1,38 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Qemu supports max 256cpus, 32K will be able to accomodate the fdt changes if +\ needed. +8000 VALUE size +: ibm,client-architecture-support ( vec -- err? ) + \ Store require parameters in nvram + \ to come back to right boot device + \ Allocate memory for H_CALL + size alloc-mem ( vec memaddr ) + swap over size ( memaddr vec memaddr size ) + \ make h_call to hypervisor + hv-cas 0= IF ( memaddr ) + dup l@ 1 >= IF \ Version number >= 1 + \ Make required changes + " /" find-node set-node + dup 4 + fdt-init + fdt-check-header + fdt-struct fdt-fix-cas-node + fdt-fix-cas-success NOT + ELSE + FALSE + THEN + ELSE + TRUE + THEN + >r size free-mem r> +; diff --git a/qemu/roms/SLOF/slof/fs/available.fs b/qemu/roms/SLOF/slof/fs/available.fs new file mode 100644 index 000000000..5eb8fa93a --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/available.fs @@ -0,0 +1,72 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +VARIABLE chosen-memory-ih 0 chosen-memory-ih ! + +\ + +\ Maintain "available" property. +\ Sun has a single memory node with "available" property +\ and separate memory controller nodes. +\ We corespond memory nodes with their respective memory controllers +\ and use /chosen/memory as default memory node to hold the "available" map +\ NOTE -> /chosen/memory is expected 2B initialized before using claim/release +\ + + +: (chosen-memory-ph) ( -- phandle ) + chosen-memory-ih @ ?dup 0= IF + s" memory" get-chosen IF + decode-int nip nip dup chosen-memory-ih ! + ihandle>phandle + ELSE 0 THEN + ELSE ihandle>phandle THEN +; + +: (set-available-prop) ( prop plen -- ) + s" available" + (chosen-memory-ph) ?dup 0<> IF set-property ELSE + cr ." Can't find chosen memory node - " + ." no available property created" cr + 2dup 2dup + THEN +; + +: update-available-property ( available-ptr -- ) + dup >r available>size@ + 0= r@ available AVAILABLE-SIZE /available * + >= or IF + available r> available - encode-bytes (set-available-prop) + ELSE + r> /available + RECURSE + THEN +; + +: update-available-property available update-available-property ; + +\ \\\\\\\\\\\\\\ Exported Interface: +\ + +\ IEEE 1275 implementation: +\ claim +\ Claim the region with given start address and size (if align parameter is 0); +\ alternatively claim any region of given alignment +\ + +\ Throw an exception if failed +\ + +: claim ( [ addr ] len align -- base ) claim update-available-property ; + +\ + +\ IEEE 1275 implementation: +\ release +\ Free the region with given start address and size +\ + +: release ( addr len -- ) release update-available-property ; + +update-available-property + diff --git a/qemu/roms/SLOF/slof/fs/banner.fs b/qemu/roms/SLOF/slof/fs/banner.fs new file mode 100644 index 000000000..efdba0c5a --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/banner.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: banner + cr ." Type 'boot' and press return to continue booting the system." + s" /packages/sms" find-node IF + cr ." Type 'sms-start' and press return to enter the configuration menu." + THEN + cr ." Type 'reset-all' and press return to reboot the system." + cr cr +; + +: .banner banner console-clean-fifo ; + diff --git a/qemu/roms/SLOF/slof/fs/base.fs b/qemu/roms/SLOF/slof/fs/base.fs new file mode 100644 index 000000000..e71e087eb --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/base.fs @@ -0,0 +1,611 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Hash for faster lookup +#include <find-hash.fs> + +: >name ( xt -- nfa ) \ note: still has the "immediate" field! + BEGIN char- dup c@ UNTIL ( @lastchar ) + dup dup aligned - cell+ char- ( @lastchar lenmodcell ) + dup >r - + BEGIN dup c@ r@ <> WHILE + cell- r> cell+ >r + REPEAT + r> drop char- +; + +\ Words missing in *.in files +VARIABLE mask -1 mask ! + +VARIABLE huge-tftp-load 1 huge-tftp-load ! +\ Default implementation for sms-get-tftp-blocksize that return 1432 (decimal) +: sms-get-tftp-blocksize 598 ; + +: default-hw-exception s" Exception #" type . ; + +' default-hw-exception to hw-exception-handler + +: diagnostic-mode? false ; \ 2B DOTICK'D later in envvar.fs + +: memory-test-suite ( addr len -- fail? ) + diagnostic-mode? IF + ." Memory test mask value: " mask @ . cr + ." No memory test suite currently implemented! " cr + THEN + false +; + +: 0.r 0 swap <# 0 ?DO # LOOP #> type ; + +\ count the number of bits equal 1 +\ the idea is to clear in each step the least significant bit +\ v&(v-1) does exactly this, so count the steps until v == 0 +: cnt-bits ( 64-bit-value -- #bits=1 ) + dup IF + 41 1 DO dup 1- and dup 0= IF drop i LEAVE THEN LOOP + THEN +; + +: bcd-to-bin ( bcd -- bin ) + dup f and swap 4 rshift a * + +; + +\ calcs the exponent of the highest power of 2 not greater than n +: 2log ( n -- lb{n} ) + 8 cells 0 DO 1 rshift dup 0= IF drop i LEAVE THEN LOOP +; + +\ calcs the exponent of the lowest power of 2 not less than n +: log2 ( n -- log2-n ) + 1- 2log 1+ +; + + +CREATE $catpad 400 allot +: $cat ( str1 len1 str2 len2 -- str3 len3 ) + >r >r dup >r $catpad swap move + r> dup $catpad + r> swap r@ move + r> + $catpad swap ; + +\ WARNING: The following two ($cat-comm & $cat-space) are dirty in a sense +\ that they add 1 or 2 characters to str1 before executing $cat +\ The ASSUMPTION is that str1 buffer provides that extra space and it is +\ responsibility of the code owner to ensure that +: $cat-comma ( str2 len2 str1 len1 -- "str1, str2" len1+len2+2 ) + 2dup + s" , " rot swap move 2+ 2swap $cat +; + +: $cat-space ( str2 len2 str1 len1 -- "str1 str2" len1+len2+1 ) + 2dup + bl swap c! 1+ 2swap $cat +; +: $cathex ( str len val -- str len' ) + (u.) $cat +; + + +: 2CONSTANT CREATE , , DOES> [ here ] 2@ ; + +\ Save XT of 2CONSTANT, put on the stack by "[ here ]" : +CONSTANT <2constant> + +: $2CONSTANT $CREATE , , DOES> 2@ ; + +: 2VARIABLE CREATE 0 , 0 , DOES> ; + + +: (is-user-word) ( name-str name-len xt -- ) -rot $CREATE , DOES> @ execute ; + +: zplace ( str len buf -- ) 2dup + 0 swap c! swap move ; +: rzplace ( str len buf -- ) 2dup + 0 swap rb! swap rmove ; + +: strdup ( str len -- dupstr len ) here over allot swap 2dup 2>r move 2r> ; + +: str= ( str1 len1 str2 len2 -- equal? ) + rot over <> IF 3drop false ELSE comp 0= THEN ; + +: test-string ( param len -- true | false ) + 0 ?DO + dup i + c@ \ Get character / byte at current index + dup 20 < swap 7e > OR IF \ Is it out of range 32 to 126 (=ASCII) + drop FALSE UNLOOP EXIT \ FALSE means: No ASCII string + THEN + LOOP + drop TRUE \ Only ASCII found --> it is a string +; + +: #aligned ( adr alignment -- adr' ) negate swap negate and negate ; +: #join ( lo hi #bits -- x ) lshift or ; +: #split ( x #bits -- lo hi ) 2dup rshift dup >r swap lshift xor r> ; + +: /string ( str len u -- str' len' ) + >r swap r@ chars + swap r> - ; +: skip ( str len c -- str' len' ) + >r BEGIN dup WHILE over c@ r@ = WHILE 1 /string REPEAT THEN r> drop ; +: scan ( str len c -- str' len' ) + >r BEGIN dup WHILE over c@ r@ <> WHILE 1 /string REPEAT THEN r> drop ; +: split ( str len char -- left len right len ) + >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; +\ reverse findchar -- search from the end of the string +: rfindchar ( str len char -- offs true | false ) + swap 1 - 0 swap do + over i + c@ + over dup bl = if <= else = then if + 2drop i dup dup leave + then + -1 +loop = +; +\ reverse split -- split at the last occurrence of char +: rsplit ( str len char -- left len right len ) + >r 2dup r> rfindchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; + +: left-parse-string ( str len char -- R-str R-len L-str L-len ) + split 2swap ; +: replace-char ( str len chout chin -- ) + >r -rot BEGIN 2dup 4 pick findchar WHILE tuck - -rot + r@ over c! swap REPEAT + r> 2drop 2drop +; +\ Duplicate string and replace \ with / +: \-to-/ ( str len -- str' len ) strdup 2dup [char] \ [char] / replace-char ; + +: isdigit ( char -- true | false ) + 30 39 between +; + +: ishexdigit ( char -- true | false ) + 30 39 between 41 46 between OR 61 66 between OR +; + +\ Variant of $number that defaults to decimal unless "0x" is +\ a prefix +: $dh-number ( addr len -- true | number false ) + base @ >r + decimal + dup 2 > IF + over dup c@ [char] 0 = + over 1 + c@ 20 or [char] x = + AND IF hex 2 + swap 2 - rot THEN drop + THEN + $number + r> base ! +; + +: // dup >r 1- + r> / ; \ division, round up + +: c@+ ( adr -- c adr' ) dup c@ swap char+ ; +: 2c@ ( adr -- c1 c2 ) c@+ c@ ; +: 4c@ ( adr -- c1 c2 c3 c4 ) c@+ c@+ c@+ c@ ; +: 8c@ ( adr -- c1 c2 c3 c4 c5 c6 c7 c8 ) c@+ c@+ c@+ c@+ c@+ c@+ c@+ c@ ; + + +: 4dup ( n1 n2 n3 n4 -- n1 n2 n3 n4 n1 n2 n3 n4 ) 2over 2over ; +: 4drop ( n1 n2 n3 n4 -- ) 2drop 2drop ; + +\ yes sometimes even something like this is needed +: 5dup ( 1 2 3 4 5 -- 1 2 3 4 5 1 2 3 4 5 ) + 4 pick 4 pick 4 pick 4 pick 4 pick ; +: 5drop 4drop drop ; +: 5nip + nip nip nip nip nip ; + +: 6dup ( 1 2 3 4 5 6 -- 1 2 3 4 5 6 1 2 3 4 5 6 ) + 5 pick 5 pick 5 pick 5 pick 5 pick 5 pick ; + +\ convert a 32 bit signed into a 64 signed +\ ( propagate bit 31 to all bits 32:63 ) +: signed ( n1 -- n2 ) dup 80000000 and IF FFFFFFFF00000000 or THEN ; + +: <l@ ( addr -- x ) l@ signed ; + +: -leading BEGIN dup WHILE over c@ bl <= WHILE 1 /string REPEAT THEN ; +: (parse-line) skipws 0 parse ; + + +\ Append two character to hex byte, if possible + +: hex-byte ( char0 char1 -- value true|false ) + 10 digit IF + swap 10 digit IF + 4 lshift or true EXIT + ELSE + 2drop 0 + THEN + ELSE + drop + THEN + false EXIT +; + +\ Parse hex string within brackets + +: parse-hexstring ( dst-adr -- dst-adr' ) + [char] ) parse cr ( dst-adr str len ) + bounds ?DO ( dst-adr ) + i c@ i 1+ c@ hex-byte IF ( dst-adr hex-byte ) + >r dup r> swap c! 1+ 2 ( dst-adr+1 2 ) + ELSE + drop 1 ( dst-adr 1 ) + THEN + +LOOP +; + +\ Add special character to string + +: add-specialchar ( dst-adr special -- dst-adr' ) + over c! 1+ ( dst-adr' ) + 1 >in +! \ advance input-index +; + +\ Parse up to next " + +: parse-" ( dst-adr -- dst-adr' ) + [char] " parse dup 3 pick + >r ( dst-adr str len R: dst-adr' ) + >r swap r> move r> ( dst-adr' ) +; + +: (") ( dst-adr -- dst-adr' ) + begin ( dst-adr ) + parse-" ( dst-adr' ) + >in @ dup span @ >= IF ( dst-adr' >in-@ ) + drop + EXIT + THEN + + ib + c@ + CASE + [char] ( OF parse-hexstring ENDOF + [char] " OF [char] " add-specialchar ENDOF + dup OF EXIT ENDOF + ENDCASE + again +; + +CREATE "pad 100 allot + +\ String with embedded hex strings +\ Example: " ba"( 12 34,4567)ab" -> >x62x61x12x34x45x67x61x62< + +: " ( [text<">< >] -- text-str text-len ) + state @ IF \ compile sliteral, pstr into dict + "pad dup (") over - ( str len ) + ['] sliteral compile, dup c, ( str len ) + bounds ?DO i c@ c, LOOP + align ['] count compile, + ELSE + pocket dup (") over - \ Interpretation, put string + THEN \ in temp buffer +; immediate + + +\ Output the carriage-return character +: (cr carret emit ; + + +\ Remove command old-name and all subsequent definitions + +: $forget ( str len -- ) + 2dup last @ ( str len str len last-bc ) + BEGIN + dup >r ( str len str len last-bc R: last-bc ) + cell+ char+ count ( str len str len found-str found-len R: last-bc ) + string=ci IF ( str len R: last-bc ) + r> @ last ! 2drop clean-hash EXIT ( -- ) + THEN + 2dup r> @ dup 0= ( str len str len next-bc next-bc ) + UNTIL + drop 2drop 2drop \ clean hash table +; + +: forget ( "old-name<>" -- ) + parse-word $forget +; + +#include <search.fs> + +\ The following constants are required in some parts +\ of the code, mainly instance variables and see. Having to reverse +\ engineer our own CFAs seems somewhat weird, but we gained a bit speed. + +\ Each colon definition is surrounded by colon and semicolon +\ constant below contain address of their xt + +: (function) ; +defer (defer) +0 value (value) +0 constant (constant) +variable (variable) +create (create) +alias (alias) (function) +cell buffer: (buffer:) + +' (function) @ \ ( <colon> ) +' (function) cell + @ \ ( ... <semicolon> ) +' (defer) @ \ ( ... <defer> ) +' (value) @ \ ( ... <value> ) +' (constant) @ \ ( ... <constant> ) +' (variable) @ \ ( ... <variable> ) +' (create) @ \ ( ... <create> ) +' (alias) @ \ ( ... <alias> ) +' (buffer:) @ \ ( ... <buffer:> ) + +\ now clean up the test functions +forget (function) + +\ and remember the constants +constant <buffer:> +constant <alias> +constant <create> +constant <variable> +constant <constant> +constant <value> +constant <defer> +constant <semicolon> +constant <colon> + +' lit constant <lit> +' sliteral constant <sliteral> +' 0branch constant <0branch> +' branch constant <branch> +' doloop constant <doloop> +' dotick constant <dotick> +' doto constant <doto> +' do?do constant <do?do> +' do+loop constant <do+loop> +' do constant <do> +' exit constant <exit> +' doleave constant <doleave> +' do?leave constant <do?leave> + + +\ provide the memory management words +\ #include <claim.fs> +\ #include "memory.fs" +#include <alloc-mem.fs> + +#include <node.fs> + +: find-substr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) + \ if substr-len == 0 ? + dup 0 = IF + \ return 0 + 2drop 2drop 0 exit THEN + \ if substr-len <= basestr-len ? + dup 3 pick <= IF + \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1 + 2 pick over - 1+ 0 DO dup 0 DO + \ substr-ptr[i] == basestr-ptr[j+i] ? + over i + c@ 4 pick j + i + c@ = IF + \ (I+1) == substr-len ? + dup i 1+ = IF + \ return J + 2drop 2drop j unloop unloop exit THEN + ELSE leave THEN + LOOP LOOP + THEN + \ if there is no match then exit with basestr-len as return value + 2drop nip +; + +: find-isubstr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) + \ if substr-len == 0 ? + dup 0 = IF + \ return 0 + 2drop 2drop 0 exit THEN + \ if substr-len <= basestr-len ? + dup 3 pick <= IF + \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1 + 2 pick over - 1+ 0 DO dup 0 DO + \ substr-ptr[i] == basestr-ptr[j+i] ? + over i + c@ lcc 4 pick j + i + c@ lcc = IF + \ (I+1) == substr-len ? + dup i 1+ = IF + \ return J + 2drop 2drop j unloop unloop exit THEN + ELSE leave THEN + LOOP LOOP + THEN + \ if there is no match then exit with basestr-len as return value + 2drop nip +; + +: find-nextline ( str-ptr str-len -- pos ) + \ run I from 0 to "str-len"-1 and check str-ptr[i] + dup 0 ?DO over i + c@ CASE + \ 0x0a (=LF) found ? + 0a OF + \ if current cursor is at end position (I == "str-len"-1) ? + dup 1- i = IF + \ return I+1 + 2drop i 1+ unloop exit THEN + \ if str-ptr[I+1] == 0x0d (=CR) ? + over i 1+ + c@ 0d = IF + \ return I+2 + 2drop i 2+ ELSE + \ else return I+1 + 2drop i 1+ THEN + unloop exit + ENDOF + \ 0x0d (=CR) found ? + 0d OF + \ if current cursor is at end position (I == "str-len"-1) ? + dup 1- i = IF + \ return I+1 + 2drop i 1+ unloop exit THEN + \ str-ptr[I+1] == 0x0a (=LF) ? + over i 1+ + c@ 0a = IF + \ return I+2 + 2drop i 2+ ELSE + \ return I+1 + 2drop i 1+ THEN + unloop exit + ENDOF + ENDCASE LOOP nip +; + +: string-at ( str1-ptr str1-len pos -- str2-ptr str2-len ) + -rot 2 pick - -rot swap chars + swap +; + +\ appends the string beginning at addr2 to the end of the string +\ beginning at addr1 +\ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!! +\ !!! BEGINNING AT ADDR1 (cp. 'strcat' in 'C' ) !!! + +: string-cat ( addr1 len1 addr2 len2 -- addr1 len1+len2 ) + \ len1 := len1+len2 + rot dup >r over + -rot + ( addr1 len1+len2 dest-ptr src-ptr len2 ) + 3 pick r> chars + -rot + ( ... dest-ptr src-ptr ) + 0 ?DO + 2dup c@ swap c! + char+ swap char+ swap + LOOP 2drop +; + +\ appends a character to the end of the string beginning at addr +\ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!! +\ !!! BEGINNING AT ADDR1 (cp. 'strcat' in 'C' ) !!! + +: char-cat ( addr len character -- addr len+1 ) + -rot 2dup >r >r 1+ rot r> r> chars + c! +; + +\ Returns true if source and destination overlap +: overlap ( src dest size -- true|false ) + 3dup over + within IF 3drop true ELSE rot tuck + within THEN +; + +: parse-2int ( str len -- val.lo val.hi ) +\ ." parse-2int ( " 2dup swap . . ." -- " + [char] , split ?dup IF eval ELSE drop 0 THEN + -rot ?dup IF eval ELSE drop 0 THEN +\ 2dup swap . . ." )" cr +; + +\ peek/poke minimal implementation, just to support FCode drivers +\ Any implmentation with full error detection will be platform specific +: cpeek ( addr -- false | byte true ) c@ true ; +: cpoke ( byte addr -- success? ) c! true ; +: wpeek ( addr -- false | word true ) w@ true ; +: wpoke ( word addr -- success? ) w! true ; +: lpeek ( addr -- false | lword true ) l@ true ; +: lpoke ( lword addr -- success? ) l! true ; + +defer reboot ( -- ) +defer halt ( -- ) +defer disable-watchdog ( -- ) +defer reset-watchdog ( -- ) +defer set-watchdog ( +n -- ) +defer set-led ( type instance state -- status ) +defer get-flashside ( -- side ) +defer set-flashside ( side -- status ) +defer read-bootlist ( -- ) +defer furnish-boot-file ( -- adr len ) +defer set-boot-file ( adr len -- ) +defer mfg-mode? ( -- flag ) +defer of-prompt? ( -- flag ) +defer debug-boot? ( -- flag ) +defer bmc-version ( -- adr len ) +defer cursor-on ( -- ) +defer cursor-off ( -- ) + +: nop-reboot ( -- ) ." reboot not available" abort ; +: nop-halt ( -- ) ." halt not available" abort ; +: nop-disable-watchdog ( -- ) ; +: nop-reset-watchdog ( -- ) ; +: nop-set-watchdog ( +n -- ) drop ; +: nop-set-led ( type instance state -- status ) drop drop drop ; +: nop-get-flashside ( -- side ) ." Cannot get flashside" cr ABORT ; +: nop-set-flashside ( side -- status ) ." Cannot set flashside" cr ABORT ; +: nop-read-bootlist ( -- ) ; +: nop-furnish-bootfile ( -- adr len ) s" net:" ; +: nop-set-boot-file ( adr len -- ) 2drop ; +: nop-mfg-mode? ( -- flag ) false ; +: nop-of-prompt? ( -- flag ) false ; +: nop-debug-boot? ( -- flag ) false ; +: nop-bmc-version ( -- adr len ) s" XXXXX" ; +: nop-cursor-on ( -- ) ; +: nop-cursor-off ( -- ) ; + +' nop-reboot to reboot +' nop-halt to halt +' nop-disable-watchdog to disable-watchdog +' nop-reset-watchdog to reset-watchdog +' nop-set-watchdog to set-watchdog +' nop-set-led to set-led +' nop-get-flashside to get-flashside +' nop-set-flashside to set-flashside +' nop-read-bootlist to read-bootlist +' nop-furnish-bootfile to furnish-boot-file +' nop-set-boot-file to set-boot-file +' nop-mfg-mode? to mfg-mode? +' nop-of-prompt? to of-prompt? +' nop-debug-boot? to debug-boot? +' nop-bmc-version to bmc-version +' nop-cursor-on to cursor-on +' nop-cursor-off to cursor-off + +: reset-all reboot ; + +\ load-base is an env. variable now, but it can +\ be overriden temporarily provided users use +\ get-load-base rather than load-base directly +\ +\ default-load-base is set here and can be +\ overriden by the board code. It will be used +\ to set the default value of the envvar "load-base" +\ when booting without a valid nvram + +10000000 VALUE default-load-base +2000000 VALUE flash-load-base +0 VALUE load-base-override + +: get-load-base + load-base-override 0<> IF load-base-override ELSE + " load-base" evaluate + THEN +; + +\ provide first level debug support +#include "debug.fs" +\ provide 7.5.3.1 Dictionary search +#include "dictionary.fs" +\ block data access for IO devices - ought to be implemented in engine +#include "rmove.fs" +\ provide a simple run time preprocessor +#include <preprocessor.fs> + +: $dnumber base @ >r decimal $number r> base ! ; +: (.d) base @ >r decimal (.) r> base ! ; + +\ IP address conversion + +: (ipaddr) ( "a.b.c.d" -- FALSE | n1 n2 n3 n4 TRUE ) + base @ >r decimal + over s" 000.000.000.000" comp 0= IF 2drop false r> base ! EXIT THEN + [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot + [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot + [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot + $number IF false r> base ! EXIT THEN + true r> base ! +; + +: (ipformat) ( n1 n2 n3 n4 -- str len ) + base @ >r decimal + 0 <# # # # [char] . hold drop # # # [char] . hold + drop # # # [char] . hold drop # # #s #> + r> base ! +; + +: ipformat ( n1 n2 n3 n4 -- ) (ipformat) type ; + + diff --git a/qemu/roms/SLOF/slof/fs/boot.fs b/qemu/roms/SLOF/slof/fs/boot.fs new file mode 100644 index 000000000..9a0ded0c2 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/boot.fs @@ -0,0 +1,300 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +0 VALUE load-size +0 VALUE go-entry +VARIABLE state-valid false state-valid ! +CREATE go-args 2 cells allot go-args 2 cells erase + +\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods + +: $bootargs + bootargs 2@ ?dup IF + ELSE s" diagnostic-mode?" evaluate and IF s" diag-file" evaluate + ELSE s" boot-file" evaluate THEN THEN +; + +: $bootdev ( -- device-name len ) + bootdevice 2@ dup IF s" " $cat THEN + s" diagnostic-mode?" evaluate IF + s" diag-device" evaluate + ELSE + s" boot-device" evaluate + THEN + $cat \ prepend bootdevice setting from vpd-bootlist + strdup + ?dup 0= IF + disable-watchdog + drop true ABORT" No boot device!" + THEN +; + + +\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous) +\ * +\ * +: set-boot-args ( str len -- ) dup IF strdup ELSE nip dup THEN bootargs 2! ; + +: (set-boot-device) ( str len -- ) + ?dup IF 1+ strdup 1- ELSE drop 0 0 THEN bootdevice 2! +; + +' (set-boot-device) to set-boot-device + +: (add-boot-device) ( str len -- ) \ Concatenate " str" to "bootdevice" + bootdevice 2@ ?dup IF $cat-space ELSE drop THEN set-boot-device +; + +' (add-boot-device) to add-boot-device + +0 value claim-list + +: no-go ( -- ) -64 boot-exception-handler ABORT ; + +defer go ( -- ) + +: go-32 ( -- ) + state-valid @ IF + 0 ciregs >r3 ! 0 ciregs >r4 ! + go-args 2@ go-entry start-elf client-data + claim-list elf-release 0 to claim-list + THEN + -6d boot-exception-handler ABORT +; + +: go-64 ( args len entry r2 -- ) + 0 ciregs >r3 ! 0 ciregs >r4 ! + start-elf64 client-data + claim-list elf-release 0 to claim-list +; + +: set-le ( -- ) + 1 ciregs >r13 ! +; + +: set-be ( -- ) + 0 ciregs >r13 ! +; + +: go-64-be ( -- ) + state-valid @ IF + set-be + go-args 2@ + go-entry @ + go-entry 8 + @ + go-64 + THEN + -6d boot-exception-handler ABORT +; + + +: go-32-be + set-be + go-32 +; + +: go-32-lev1 + set-le + go-32 +; + +: go-64-lev1 + state-valid @ IF + go-args 2@ + go-entry @ xbflip + go-entry 8 + @ xbflip + set-le + go-64 + THEN + -6d boot-exception-handler ABORT +; + +: go-64-lev2 + state-valid @ IF + go-args 2@ + go-entry 0 + set-le + go-64 + THEN + -6d boot-exception-handler ABORT +; + +: load-elf-init ( arg len file-addr -- success ) + false state-valid ! \ Not valid anymore ... + claim-list IF \ Release claimed mem + claim-list elf-release 0 to claim-list \ from last load + THEN + + true swap -1 ( arg len true file-addr -1 ) + elf-load-claim ( arg len true claim-list entry elftype ) + + ( arg len true claim-list entry elftype ) + CASE + 1 OF ['] go-32-be ENDOF ( arg len true claim-list entry go ) + 2 OF ['] go-64-be ENDOF ( arg len true claim-list entry go ) + 3 OF ['] go-64-lev1 ENDOF ( arg len true claim-list entry go ) + 4 OF ['] go-64-lev2 ENDOF ( arg len true claim-list entry go ) + 5 OF ['] go-32-lev1 ENDOF ( arg len true claim-list entry go ) + dup OF ['] no-go to go + 2drop 3drop false EXIT ENDOF ( false ) + ENDCASE + + to go to go-entry to claim-list + dup state-valid ! -rot + + 2 pick IF + go-args 2! + ELSE + 2drop + THEN +; + +: init-program ( -- ) + $bootargs get-load-base ['] load-elf-init CATCH ?dup IF + boot-exception-handler + 2drop 2drop false \ Could not claim + ELSE IF + 0 ciregs 2dup >r3 ! >r4 ! \ Valid (ELF ) Image + THEN + THEN +; + + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ Generic device load method: +\ * + +: do-load ( devstr len -- img-size ) \ Device method wrapper + use-load-watchdog? IF + \ Set watchdog timer to 10 minutes, multiply with 2 because DHCP + \ needs 1 second per try and add 1 min to avoid race conditions + \ with watchdog timeout. + 4ec set-watchdog + THEN + my-self >r current-node @ >r \ Save my-self + ." Trying to load: " $bootargs type ." from: " 2dup type ." ... " + 2dup open-dev dup IF + dup to my-self + dup ihandle>phandle set-node + -rot ( ihandle devstr len ) + my-args nip 0= IF + 2dup 1- + c@ [char] : <> IF \ Add : to device path if missing + 1+ strdup 2dup 1- + [char] : swap c! + THEN + THEN + encode-string s" bootpath" set-chosen + $bootargs encode-string s" bootargs" set-chosen + get-load-base s" load" 3 pick ['] $call-method CATCH IF + -67 boot-exception-handler 3drop drop false + ELSE + dup 0> IF + init-program + ELSE + false state-valid ! + drop 0 \ Could not load + THEN + THEN + swap close-dev device-end dup to load-size + ELSE -68 boot-exception-handler 3drop false THEN + r> set-node r> to my-self \ Restore my-self +; + +: parse-load ( "{devlist}" -- success ) \ Parse-execute boot-device list + cr BEGIN parse-word dup WHILE + ( de-alias ) do-load dup 0< IF drop 0 THEN IF + state-valid @ IF ." Successfully loaded" cr THEN + true 0d parse strdup load-list 2! EXIT + THEN + REPEAT 2drop 0 0 load-list 2! false +; + +: load ( "{params}<eol>"} -- success ) \ Client interface to load + parse-word 0d parse -leading 2swap ?dup IF + de-alias + set-boot-device + ELSE + drop + THEN + set-boot-args s" parse-load " $bootdev $cat strdup evaluate +; + +: load-next ( -- success ) \ Continue after go failed + load-list 2@ ?dup IF s" parse-load " 2swap $cat strdup evaluate + ELSE drop false THEN +; + +\ \\\\\\\\\\\\\\\\\\\\\\\\\\ +\ load/go utilities +\ -> Should be in loaders.fs + +: noload false ; + +' no-go to go + +: (go-and-catch) ( -- ) + \ Recommended Practice: Forth Source Support (scripts starting with comment) + get-load-base c@ 5c = get-load-base 1+ c@ 20 = AND IF + load-size alloc-mem ( allocated-addr ) + ?dup 0= IF ." alloc-mem failed." cr EXIT THEN + load-size >r >r ( R: allocate-addr load-size ) + get-load-base r@ load-size move \ Move away from load-base + r@ load-size evaluate \ Run the script + r> r> free-mem + EXIT + THEN + \ Assume it's a normal executable, use "go" to run it: + ['] go behavior CATCH IF -69 boot-exception-handler THEN +; + + +\ if the board does not get the bootlist from the nvram +\ then this word is supposed to be overloaded with the +\ word to get the bootlist from VPD (or from wheresoever) +read-bootlist + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ IEEE 1275 : load (user interface) +\ * +: boot + load 0= IF -65 boot-exception-handler EXIT THEN + disable-watchdog (go-and-catch) + BEGIN load-next WHILE + disable-watchdog (go-and-catch) + REPEAT + + \ When we return from boot print the banner again. + .banner +; + +: load load 0= IF -65 boot-exception-handler THEN ; + +\ \\\\ Temporary hacks for backwards compatibility +: yaboot ." Use 'boot disk' instead " ; + +: netboot ( -- rc ) ." Use 'boot net' instead " ; + +: netboot-arg ( arg-string -- rc ) + s" boot net " 2swap $cat (parse-line) $cat + evaluate +; + +: netload ( -- rc ) (parse-line) + load-base-override >r flash-load-base to load-base-override + s" load net:" strdup 2swap $cat strdup evaluate + r> to load-base-override + load-size +; + +: neteval ( -- ) FLASH-LOAD-BASE netload evaluate ; + diff --git a/qemu/roms/SLOF/slof/fs/bootmsg.fs b/qemu/roms/SLOF/slof/fs/bootmsg.fs new file mode 100644 index 000000000..524d46908 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/bootmsg.fs @@ -0,0 +1,74 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +create debugstr 255 allot +0 VALUE debuglen +\ tbl@ d# 1000 * 196e6aa / VALUE TIME1 +\ 0 VALUE TIME2 + +\ Usage: 42 cp +: cp ( checkpoint -- ) + \ cr depth 2 0.r s" : " type .s cr \ DEBUG + \ cr ." time: " tbl@ d# 1000 * 196e6aa / dup TIME1 - dup . cr TIME2 + TO TIME2 TO TIME1 + bootmsg-cp ; + +: (warning) ( id level ptr len -- ) + dup TO debuglen + debugstr swap move \ copy into buffer + 0 debuglen debugstr + c! \ terminate '\0' + debugstr bootmsg-warning +; + +\ Usage: 42 0 warning" warning-txt" +: warning" ( id level [text<">] -- ) + postpone s" state @ + IF + ['] (warning) compile, + ELSE + (warning) + THEN +; immediate + +: (debug-cp) ( id level ptr len -- ) + dup TO debuglen + debugstr swap move \ copy into buffer + 0 debuglen debugstr + c! \ terminate '\0' + debugstr bootmsg-debugcp +; + +\ Usage: 42 0 debug-cp" debug-cp-txt" +: debug-cp" ( id level [text<">] -- ) + postpone s" state @ + IF + ['] (debug-cp) compile, + ELSE + (debug-cp) + THEN +; immediate + +: (error) ( id ptr len -- ) + dup TO debuglen + debugstr swap move \ copy into buffer + 0 debuglen debugstr + c! \ terminate '\0' + debugstr bootmsg-error +; + +\ Usage: 42 error" error-txt" +: error" ( id level [text<">] -- ) + postpone s" state @ + IF + ['] (error) compile, + ELSE + (error) + THEN +; immediate + +bootmsg-nvupdate diff --git a/qemu/roms/SLOF/slof/fs/claim.fs b/qemu/roms/SLOF/slof/fs/claim.fs new file mode 100644 index 000000000..d012d3db8 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/claim.fs @@ -0,0 +1,415 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ \\\\\\\\\\\\\\ Constants +500 CONSTANT AVAILABLE-SIZE +4000 CONSTANT MIN-RAM-RESERVE \ prevent from using first pages + +: MIN-RAM-SIZE \ Initially available memory size + epapr-ima-size IF + epapr-ima-size + ELSE + 20000000 \ assumed minimal memory size + THEN +; +MIN-RAM-SIZE CONSTANT MIN-RAM-SIZE + +\ \\\\\\\\\\\\\\ Structures +\ + +\ The available element size depends strictly on the address/size +\ value formats and will be different for various device types +\ + +STRUCT + cell field available>address + cell field available>size +CONSTANT /available + + +\ \\\\\\\\\\\\\\ Global Data +CREATE available AVAILABLE-SIZE /available * allot available AVAILABLE-SIZE /available * erase +VARIABLE mem-pre-released 0 mem-pre-released ! + +\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods +: available>size@ available>size @ ; +: available>address@ available>address @ ; +: available>size! available>size ! ; +: available>address! available>address ! ; + +: available! ( addr size available-ptr -- ) + dup -rot available>size! available>address! +; + +: available@ ( available-ptr -- addr size ) + dup available>address@ swap available>size@ +; + + +\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous) +\ + +\ Warning: They are not yet really independent from available formatting +\ + + +\ + +\ Find position in the "available" where given range exists or can be inserted, +\ return pointer and logical found/notfound value +\ If error, return NULL pointer in addition to notfound code +\ + +: (?available-segment<) ( start1 end1 start2 end2 -- true/false ) drop < nip ; + +: (?available-segment>) ( start1 end1 start2 end2 -- true/false ) -rot 2drop > ; + +\ start1 to end1 is the area that should be claimed +\ start2 to end2 is the available segment +\ return true if it can not be claimed, false if it can be claimed +: (?available-segment-#) ( start1 end1 start2 end2 -- true/false ) + 2dup 5 roll -rot ( e1 s2 e2 s1 s2 e2 ) + between >r between r> and not +; + +: (find-available) ( addr addr+size-1 a-ptr a-size -- a-ptr' found ) + ?dup 0= IF -rot 2drop false EXIT THEN \ Not Found + + 2dup 2/ dup >r /available * + + ( addr addr+size-1 a-ptr a-size a-ptr' R: a-size' ) + dup available>size@ 0= IF 2drop r> RECURSE EXIT THEN + + ( addr addr+size-1 a-ptr a-size a-ptr' R: a-size' ) + dup >r available@ + ( addr addr+size-1 a-ptr a-size addr' size' R: a-size' a-ptr' ) + over + 1- 2>r 2swap + ( a-ptr a-size addr addr+size-1 ) + ( R: a-size' a-ptr' addr' addr'+size'-1 ) + + 2dup 2r@ (?available-segment>) IF + 2swap 2r> 2drop r> + /available + -rot r> - 1- nip RECURSE EXIT \ Look Right + THEN + 2dup 2r@ (?available-segment<) IF + 2swap 2r> 2drop r> + 2drop r> RECURSE EXIT \ Look Left + THEN + 2dup 2r@ (?available-segment-#) IF \ Conflict - segments overlap + 2r> 2r> 3drop 3drop 2drop + 1212 throw + THEN + 2r> 3drop 3drop r> r> drop ( a-ptr' -- ) + dup available>size@ 0<> ( a-ptr' found -- ) +; + +: (find-available) ( addr size -- seg-ptr found ) + over + 1- available AVAILABLE-SIZE ['] (find-available) catch IF + 2drop 2drop 0 false + THEN +; + + +: dump-available ( available-ptr -- ) + cr + dup available - /available / AVAILABLE-SIZE swap - 0 ?DO + dup available@ ?dup 0= IF + 2drop UNLOOP EXIT + THEN + swap . . cr + /available + + LOOP + dup +; + +: .available available dump-available ; + +\ + +\ release utils: +\ + + +\ + +\ (drop-available) just blindly compresses space of available map +\ + +: (drop-available) ( available-ptr -- ) + dup available - /available / \ current element index + AVAILABLE-SIZE swap - \ # of remaining elements + + ( first nelements ) 1- 0 ?DO + dup /available + dup available@ + + ( current next next>address next>size ) ?dup 0= IF + 2drop LEAVE \ NULL element - goto last copy + THEN + 3 roll available! ( next ) + LOOP + + \ Last element : just zero it out + 0 0 rot available! +; + +\ + +\ (stick-to-previous-available) merge the segment on stack +\ with the previous one, if possible, and modified segment parameters if merged +\ Return success code +\ + +: (stick-to-previous-available) ( addr size available-ptr -- naddr nsize nptr success ) + dup available = IF + false EXIT \ This was the first available segment + THEN + + dup /available - dup available@ + + 4 pick = IF + nip \ Drop available-ptr since we are going to previous one + rot drop \ Drop start addr, we take the previous one + + dup available@ 3 roll + rot true + ( prev-addr prev-size+size prev-ptr true ) + ELSE + drop false + ( addr size available-ptr false ) + THEN +; + +\ + +\ (insert-available) just blindly makes space for another element on given +\ position +\ + +\ insert-available should also check adjacent elements and merge if new +\ region is contiguos w. others +\ + +: (insert-available) ( available-ptr -- available-ptr ) + dup \ current element + dup available - /available / \ current element index + AVAILABLE-SIZE swap - \ # of remaining elements + + dup 0<= 3 pick available>size@ 0= or IF + \ End of "available" or came to an empty element - Exit + drop drop EXIT + THEN + + over available@ rot + + ( first first/=current/ first>address first>size nelements ) 1- 0 ?DO + 2>r + ( first current R: current>address current>size ) + + /available + dup available@ + ( first current+1/=next/ next>address next>size ) + ( R: current>address current>size ) + + 2r> 4 pick available! dup 0= IF + \ NULL element - last copy + rot /available + available! + UNLOOP EXIT + THEN + LOOP + + ( first next/=last/ last[0]>address last[0]>size ) ?dup 0<> IF + cr ." release error: available map overflow" + cr ." Dumping available property" + .available + cr ." No space for one before last entry:" cr swap . . + cr ." Dying ..." cr 123 throw + THEN + + 2drop +; + +: insert-available ( addr size available-ptr -- addr size available-ptr ) + dup available>address@ 0<> IF + \ Not empty : + dup available>address@ rot dup -rot - + + ( addr available-ptr size available>address@-size ) + + 3 pick = IF \ if (available>address@ - size == addr) + \ Merge w. next segment - no insert needed + + over available>size@ + swap + ( addr size+available>size@ available-ptr ) + + (stick-to-previous-available) IF + \ Merged w. prev & next one : discard extra seg + dup /available + (drop-available) + THEN + ELSE + \ shift the rest of "available" to make space + + swap (stick-to-previous-available) + not IF (insert-available) THEN + THEN + ELSE + (stick-to-previous-available) drop + THEN +; + +defer release + +\ + +\ claim utils: +\ + +: drop-available ( addr size available-ptr -- addr ) + dup >r available@ + ( req_addr req_size segment_addr segment_size R: available-ptr ) + + over 4 pick swap - ?dup 0<> IF + \ Segment starts before requested address : free the head space + dup 3 roll swap r> available! - + + ( req_addr req_size segment_size-segment_addr+req_addr ) + over - ?dup 0= IF + \ That's it - remainder of segment is what we claim + drop + ELSE + \ Both head and tail of segment remain unclaimed : + \ need an extra available element + swap 2 pick + swap release + THEN + ELSE + nip ( req_addr req_size segment_size ) + over - ?dup 0= IF + \ Exact match : drop the whole available segment + drop r> (drop-available) + ELSE + \ We claimed the head, need to leave the tail available + -rot over + rot r> available! + THEN + THEN + ( base R: -- ) +; + +: pwr2roundup ( value -- pwr2value ) + dup CASE + 0 OF EXIT ENDOF + 1 OF EXIT ENDOF + ENDCASE + dup 1 DO drop i dup +LOOP + dup + +; + +: (claim-best-fit) ( len align -- len base ) + pwr2roundup 1- -1 -1 + ( len align-1 best-fit-residue/=-1/ best-fit-base/=-1/ ) + + available AVAILABLE-SIZE /available * + available DO + i \ Must be saved now, before we use Return stack + -rot >r >r swap >r + + ( len i R: best-fit-base best-fit-residue align-1 ) + + available@ ?dup 0= IF drop r> r> r> LEAVE THEN \ EOL + + 2 pick - dup 0< IF + 2drop \ Can't Fit: Too Small + ELSE + dup 2 pick r@ and - 0< IF + 2drop \ Can't Fit When Aligned + ELSE + ( len i>address i>size-len ) + ( R: best-fit-base best-fit-residue align-1 ) + r> -rot dup r@ U< IF + \ Best Fit so far: drop the old one + 2r> 2drop + + ( len align-1 nu-base nu-residue R: ) + \ Now align new base and push to R: + swap 2 pick + 2 pick invert and >r >r >r + ELSE + 2drop >r + THEN + THEN + THEN + r> r> r> + /available +LOOP + + -rot 2drop ( len best-fit-base/or -1 if none found/ ) +; + +: (adjust-release0) ( 0 size -- addr' size' ) + \ segment 0 already pre-relased in early phase: adjust + 2dup MIN-RAM-SIZE dup 3 roll + -rot - + dup 0< IF 2drop ELSE + 2swap 2drop 0 mem-pre-released ! + THEN +; + + +\ \\\\\\\\\\\\\\ Exported Interface: +\ + +\ IEEE 1275 implementation: +\ claim +\ Claim the region with given start address and size (if align parameter is 0); +\ alternatively claim any region of given alignment +\ + +\ Throw an exception if failed +\ + +: claim ( [ addr ] len align -- base ) + ?dup 0<> IF + (claim-best-fit) dup -1 = IF + 2drop cr ." claim error : aligned allocation failed" cr + ." available:" cr .available + 321 throw EXIT + THEN + swap + THEN + + 2dup (find-available) not IF + drop +\ cr ." claim error : requested " . ." bytes of memory at " . +\ ." not available" cr +\ ." available:" cr .available + 2drop + 321 throw EXIT + THEN + ( req_addr req_size available-ptr ) drop-available + + ( req_addr ) +; + + +\ + +\ IEEE 1275 implementation: +\ release +\ Free the region with given start address and size +\ + +: .release ( addr len -- ) + over 0= mem-pre-released @ and IF (adjust-release0) THEN + + 2dup (find-available) IF + drop swap + cr ." release error: region " . ." , " . ." already released" cr + ELSE + ?dup 0= IF + swap + cr ." release error: Bad/conflicting region " . ." , " . + ." or available list full " cr + ELSE + ( addr size available-ptr ) insert-available + + \ NOTE: insert did not change the stack layout + \ but it may have changed any of the three values + \ in order to implement merge of free regions + \ We do not interpret these values any more + \ just blindly copy it in + + ( addr size available-ptr ) available! + THEN + THEN +; + +' .release to release + + +\ pre-release minimal memory size +0 MIN-RAM-SIZE release 1 mem-pre-released ! + +\ claim first pages used for PPC exception vectors +0 MIN-RAM-RESERVE 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop + +\ claim region used by firmware (assume 31 MiB size right now) +paflof-start ffff not and 1f00000 0 ' claim CATCH IF + ." claim failed!" cr 2drop +THEN drop diff --git a/qemu/roms/SLOF/slof/fs/client.fs b/qemu/roms/SLOF/slof/fs/client.fs new file mode 100644 index 000000000..1b2bb0326 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/client.fs @@ -0,0 +1,299 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Client interface. + +0 VALUE debug-client-interface? + +\ First, the machinery. + +VOCABULARY client-voc \ We store all client-interface callable words here. + +6789 CONSTANT sc-exit +4711 CONSTANT sc-yield + +VARIABLE client-callback \ Address of client's callback function + +: client-data ciregs >r3 @ ; +: nargs client-data la1+ l@ ; +: nrets client-data la1+ la1+ l@ ; +: client-data-to-stack + client-data 3 la+ nargs 0 ?DO dup l@ swap la1+ LOOP drop ; +: stack-to-client-data + client-data nargs nrets + 2 + la+ nrets 0 ?DO tuck l! /l - LOOP drop ; + +: call-client ( args len client-entry -- ) + \ (args, len) describe the argument string, client-entry is the address of + \ the client's .entry symbol, i.e. where we eventually branch to. + \ ciregs is a variable that describes the register set of the host processor, + \ see slof/fs/exception.fs for details + \ client-entry-point maps to client_entry_point in slof/entry.S which is + \ the SLOF entry point when calling a SLOF client interface word from the + \ client. + \ We pass the arguments for the client in R6 and R7, the client interface + \ entry point address is passed in R5. + >r ciregs >r7 ! ciregs >r6 ! client-entry-point @ ciregs >r5 ! + \ Initialise client-stack-pointer + cistack ciregs >r1 ! + \ jump-client maps to call_client in slof/entry.S + \ When jump-client returns, R3 holds the address of a NUL-terminated string + \ that holds the client interface word the client wants to call, R4 holds + \ the return address. + r> jump-client drop + BEGIN + client-data-to-stack + \ Now create a Forth-style string, look it up in the client dictionary and + \ execute it, guarded by CATCH. Result of xt == 0 is stored on the return + \ stack + client-data l@ zcount + \ XXX: Should only look in client-voc... + ALSO client-voc $find PREVIOUS + dup 0= >r IF + CATCH + \ If a client interface word needs some special treatment, like exit and + \ yield, then the implementation needs to use THROW to indicate its needs + ?dup IF + dup CASE + sc-exit OF drop r> drop EXIT ENDOF + sc-yield OF drop r> drop EXIT ENDOF + ENDCASE + \ Some special call was made but we don't know that to do with it... + THROW + THEN + stack-to-client-data + ELSE + cr type ." NOT FOUND" + THEN + \ Return to the client + r> ciregs >r3 ! ciregs >r4 @ jump-client + UNTIL ; + +: flip-stack ( a1 ... an n -- an ... a1 ) ?dup IF 1 ?DO i roll LOOP THEN ; + +: (callback) ( "service-name<>" "arguments<cr>" -- ) + client-callback @ \ client-callback points to the function prolog + dup 8 + @ ciregs >r2 ! \ Set up the TOC pointer (???) + @ call-client ; \ Resolve the function's address from the prolog +' (callback) to callback + +: (continue-client) + s" " \ make call-client happy, client won't use the string anyways. + ciregs >r4 @ call-client ; +' (continue-client) to continue-client + +\ Utility. +: string-to-buffer ( str len buf len -- len' ) + 2dup erase rot min dup >r move r> ; + +\ Now come the actual client interface words. + +ALSO client-voc DEFINITIONS + +: exit sc-exit THROW ; + +: yield sc-yield THROW ; + +: test ( zstr -- missing? ) + \ XXX: Should only look in client-voc... + zcount + debug-client-interface? IF + ." ci: test " 2dup type cr + THEN + ALSO client-voc $find PREVIOUS IF + drop FALSE + ELSE + 2drop TRUE + THEN +; + +: finddevice ( zstr -- phandle ) + zcount + debug-client-interface? IF + ." ci: finddevice " 2dup type cr + THEN + 2dup " /memory" str= IF + \ Workaround: grub passes /memory instead of /memory@0 + 2drop + " /memory@0" + THEN + find-node dup 0= IF drop -1 THEN +; + +: getprop ( phandle zstr buf len -- len' ) + >r >r zcount rot ( str-adr str-len phandle R: len buf ) + debug-client-interface? IF + ." ci: getprop " 3dup . ." '" type ." '" + THEN + get-property + debug-client-interface? IF + dup IF ." ** not found **" THEN + cr + THEN + 0= IF + r> swap dup r> min swap >r move r> + ELSE + r> r> 2drop -1 + THEN +; + +: getproplen ( phandle zstr -- len ) + zcount rot get-property 0= IF nip ELSE -1 THEN ; + +: setprop ( phandle zstr buf len -- size|-1 ) + dup >r \ save len + encode-bytes ( phandle zstr prop-addr prop-len ) + 2swap zcount rot ( prop-addr prop-len name-addr name-len phandle ) + current-node @ >r \ save current node + set-node \ change to specified node + property \ set property + r> set-node \ restore original node + r> \ always return size, because we can not fail. +; + +\ VERY HACKISH +: canon ( zstr buf len -- len' ) + 2dup erase + >r >r zcount + >r dup c@ [char] / = IF + r> r> swap r> over >r min move r> + ELSE + r> find-alias ?dup 0= IF + r> r> 2drop -1 + ELSE + dup -rot r> swap r> min move + THEN + THEN +; + +: nextprop ( phandle zstr buf -- flag ) \ -1 invalid, 0 end, 1 ok + >r zcount rot next-property IF r> zplace 1 ELSE r> drop 0 THEN ; + +: open ( zstr -- ihandle ) + zcount + debug-client-interface? IF + ." ci: open " 2dup type cr + THEN + open-dev +; + +: close ( ihandle -- ) + debug-client-interface? IF + ." ci: close " dup . cr + THEN + s" stdin" get-chosen IF + decode-int nip nip over = IF + \ End of life of SLOF now, call platform quiesce as quiesce + \ is an undocumented extension and not everybody supports it + close-dev + quiesce + ELSE + close-dev + THEN + ELSE + close-dev + THEN +; + +\ Now implemented: should return -1 if no such method exists in that node +: write ( ihandle str len -- len' ) rot s" write" rot + ['] $call-method CATCH IF 2drop 3drop -1 THEN ; +: read ( ihandle str len -- len' ) rot s" read" rot + ['] $call-method CATCH IF 2drop 3drop -1 THEN ; +: seek ( ihandle hi lo -- status ) swap rot s" seek" rot + ['] $call-method CATCH IF 2drop 3drop -1 THEN ; + +\ A real claim implementation: 3.2% memory fat :-) +: claim ( addr len align -- base ) + debug-client-interface? IF + ." ci: claim " .s cr + THEN + dup IF rot drop + ['] claim CATCH IF 2drop -1 THEN + ELSE + ['] claim CATCH IF 3drop -1 THEN + THEN +; + +: release ( addr len -- ) + debug-client-interface? IF + ." ci: release " .s cr + THEN + release +; + +: instance-to-package ( ihandle -- phandle ) + ihandle>phandle ; + +: package-to-path ( phandle buf len -- len' ) + 2>r node>path 2r> string-to-buffer ; +: instance-to-path ( ihandle buf len -- len' ) + 2>r instance>path 2r> string-to-buffer ; +: instance-to-interposed-path ( ihandle buf len -- len' ) + 2>r instance>qpath 2r> string-to-buffer ; + +: call-method ( str ihandle arg ... arg -- result return ... return ) + nargs flip-stack zcount + debug-client-interface? IF + ." ci: call-method " 2dup type cr + THEN + rot ['] $call-method CATCH + nrets 0= IF drop ELSE \ if called with 0 return args do not return the catch result + dup IF nrets 1 ?DO -444 LOOP THEN + nrets flip-stack + THEN +; + +\ From the PAPR. +: test-method ( phandle str -- missing? ) + zcount + debug-client-interface? IF + ." ci: test-method " 2dup type cr + THEN + rot find-method dup IF nip THEN 0= +; + +: milliseconds milliseconds ; + +: start-cpu ( phandle addr r3 -- ) + >r >r + s" reg" rot get-property 0= IF drop l@ + ELSE true ABORT" start-cpu called with invalid phandle" THEN + r> r> of-start-cpu drop +; + +\ Quiesce firmware and assert that all hardware is in a sane state +\ (e.g. assert that no background DMA is running anymore) +: quiesce ( -- ) + debug-client-interface? IF + ." ci: quiesce" cr + THEN + \ The main quiesce call is defined in quiesce.fs + quiesce +; + +\ +\ User Interface, defined in 6.3.2.6 +\ +: interpret ( ... zstr -- result ... ) + zcount + debug-client-interface? IF + ." ci: interpret " 2dup type cr + THEN + ['] evaluate CATCH +; + +\ Allow the client to register a callback +: set-callback ( newfunc -- oldfunc ) + client-callback @ swap client-callback ! ; + +PREVIOUS DEFINITIONS diff --git a/qemu/roms/SLOF/slof/fs/debug.fs b/qemu/roms/SLOF/slof/fs/debug.fs new file mode 100644 index 000000000..e54f729fe --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/debug.fs @@ -0,0 +1,422 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Get the name of Forth command whose execution token is xt + +: xt>name ( xt -- str len ) + BEGIN + cell - dup c@ 0 2 within IF + dup 2+ swap 1+ c@ exit + THEN + AGAIN +; + +cell -1 * CONSTANT -cell +: cell- ( n -- n-cell-size ) + [ cell -1 * ] LITERAL + +; + +\ Search for xt of given address +: find-xt-addr ( addr -- xt ) + BEGIN + dup @ <colon> = IF + EXIT + THEN + cell- + AGAIN +; + +: (.immediate) ( xt -- ) + \ is it immediate? + xt>name drop 2 - c@ \ skip len and flags + immediate? IF + ." IMMEDIATE" + THEN +; + +: (.xt) ( xt -- ) + xt>name type +; + +\ Trace back on current return stack. +\ Start at 1, since 0 is return of trace-back itself + +: trace-back ( ) + 1 + BEGIN + cr dup dup . ." : " rpick dup . ." : " + ['] tib here within IF + dup rpick find-xt-addr (.xt) + THEN + 1+ dup rdepth 5 - >= IF cr drop EXIT THEN + AGAIN +; + +VARIABLE see-my-type-column + +: (see-my-type) ( indent limit xt str len -- indent limit xt ) + dup see-my-type-column @ + dup 50 >= IF + -rot over " " comp 0= IF + \ blank causes overflow: just enforce new line with next call + 2drop see-my-type-column ! + ELSE + rot drop ( indent limit xt str len ) + \ Need to copy string since we use (u.) again (kills internal buffer): + pocket swap 2dup >r >r ( indent limit xt str pk len R: len pk ) + move r> r> ( indent limit xt pk len ) + 2 pick (u.) dup -rot + cr type ( indent limit xt pk len xt-len ) + " :" type 1+ ( indent limit xt pk len prefix-len ) + 5 pick dup spaces + ( indent limit xt pk len prefix-len ) + over + see-my-type-column ! ( indent limit xt pk len ) + type + THEN ( indent limit xt ) + ELSE + see-my-type-column ! type ( indent limit xt ) + THEN +; + +: (see-my-type-init) ( -- ) + ffff see-my-type-column ! \ just enforce a new line +; + +: (see-colon-body) ( indent limit xt -- indent limit xt ) + (see-my-type-init) \ enforce new line + BEGIN ( indent limit xt ) + cell+ 2dup <> + over @ + dup <semicolon> <> + rot and ( indent limit xt @xt flag ) + WHILE ( indent limit xt @xt ) + xt>name (see-my-type) " " (see-my-type) + dup @ ( indent limit xt @xt) + CASE + <0branch> OF cell+ dup @ + over + cell+ dup >r + (u.) (see-my-type) r> ( indent limit xt target) + 2dup < IF + over 4 pick 3 + -rot recurse + nip nip nip cell- ( indent limit xt ) + ELSE + drop ( indent limit xt ) + THEN + (see-my-type-init) ENDOF \ enforce new line + <branch> OF cell+ dup @ over + cell+ (u.) + (see-my-type) " " (see-my-type) ENDOF + <do?do> OF cell+ dup @ (u.) (see-my-type) + " " (see-my-type) ENDOF + <lit> OF cell+ dup @ (u.) (see-my-type) + " " (see-my-type) ENDOF + <dotick> OF cell+ dup @ xt>name (see-my-type) + " " (see-my-type) ENDOF + <doloop> OF cell+ dup @ (u.) (see-my-type) + " " (see-my-type) ENDOF + <do+loop> OF cell+ dup @ (u.) (see-my-type) + " " (see-my-type) ENDOF + <doleave> OF cell+ dup @ over + cell+ (u.) + (see-my-type) " " (see-my-type) ENDOF + <do?leave> OF cell+ dup @ over + cell+ (u.) + (see-my-type) " " (see-my-type) ENDOF + <sliteral> OF cell+ " """ (see-my-type) dup count dup >r + (see-my-type) " """ (see-my-type) + " " (see-my-type) + r> -cell and + ENDOF + ENDCASE + REPEAT + drop +; + +: (see-colon) ( xt -- ) + (see-my-type-init) + 1 swap 0 swap ( indent limit xt ) + " : " (see-my-type) dup xt>name (see-my-type) + rot drop 4 -rot (see-colon-body) ( indent limit xt ) + rot drop 1 -rot (see-my-type-init) " ;" (see-my-type) + 3drop +; + +\ Create words are a bit tricky. We find out where their code points. +\ If this code is part of SLOF, it is not a user generated CREATE. + +: (see-create) ( xt -- ) + dup cell+ @ + CASE + <2constant> OF + dup cell+ cell+ dup @ swap cell+ @ . . ." 2CONSTANT " + ENDOF + + <instancevalue> OF + dup cell+ cell+ @ . ." INSTANCE VALUE " + ENDOF + + <instancevariable> OF + ." INSTANCE VARIABLE " + ENDOF + + dup OF + ." CREATE " + ENDOF + ENDCASE + (.xt) +; + +\ Decompile Forth command whose execution token is xt + +: (see) ( xt -- ) + cr dup dup @ + CASE + <variable> OF ." VARIABLE " (.xt) ENDOF + <value> OF dup execute . ." VALUE " (.xt) ENDOF + <constant> OF dup execute . ." CONSTANT " (.xt) ENDOF + <defer> OF dup cell+ @ swap ." DEFER " (.xt) ." is " (.xt) ENDOF + <alias> OF dup cell+ @ swap ." ALIAS " (.xt) ." " (.xt) ENDOF + <buffer:> OF ." BUFFER: " (.xt) ENDOF + <create> OF (see-create) ENDOF + <colon> OF (see-colon) ENDOF + dup OF ." ??? PRIM " (.xt) ENDOF + ENDCASE + (.immediate) cr + ; + +\ Decompile Forth command old-name + +: see ( "old-name<>" -- ) + ' (see) +; + +\ Work in progress... + +0 value forth-ip +true value trace>stepping? +true value trace>print? +true value trace>up? +0 value trace>depth +0 value trace>rdepth +0 value trace>recurse +: trace-depth+ ( -- ) trace>depth 1+ to trace>depth ; +: trace-depth- ( -- ) trace>depth 1- to trace>depth ; + +: stepping ( -- ) + true to trace>stepping? +; + +: tracing ( -- ) + false to trace>stepping? +; + +: trace-print-on ( -- ) + true to trace>print? +; + +: trace-print-off ( -- ) + false to trace>print? +; + + +\ Add n to ip + +: fip-add ( n -- ) + forth-ip + to forth-ip +; + +\ Save execution token address and content + +0 value debug-last-xt +0 value debug-last-xt-content + +: trace-print ( -- ) + forth-ip cr u. ." : " + forth-ip @ + dup ['] breakpoint = IF drop debug-last-xt-content THEN + xt>name type ." " + ." ( " .s ." ) | " +; + +: trace-interpret ( -- ) + rdepth 1- to trace>rdepth + BEGIN + depth . [char] > dup emit emit space + source expect ( str len ) + ['] interpret catch print-status + AGAIN +; + +\ Main trace routine, trace a colon definition + +: trace-xt ( xt -- ) + trace>recurse IF + r> drop \ Drop return of 'trace-xt call + cell+ \ Step over ":" + ELSE + debug-last-xt-content <colon> = IF + \ debug colon-definition + ['] breakpoint @ debug-last-xt ! \ Re-arm break point + r> drop \ Drop return of 'trace-xt call + cell+ \ Step over ":" + ELSE + ['] breakpoint debug-last-xt ! \ Re-arm break point + 2r> 2drop + THEN + THEN + + to forth-ip + true to trace>print? + BEGIN + trace>print? IF trace-print THEN + + forth-ip ( ip ) + trace>stepping? IF + BEGIN + key + CASE + [char] d OF dup @ @ <colon> = IF \ recurse only into colon definitions + trace-depth+ + 1 to trace>recurse + dup >r @ recurse + THEN true ENDOF + [char] u OF trace>depth IF tracing trace-print-off true ELSE false THEN ENDOF + [char] f OF drop cr trace-interpret ENDOF \ quit trace and start interpreter FIXME rstack + [char] c OF tracing true ENDOF + [char] t OF trace-back false ENDOF + [char] q OF drop cr quit ENDOF + 20 OF true ENDOF + dup OF cr ." Press d: Down into current word" cr + ." Press u: Up to caller" cr + ." Press f: Switch to forth interpreter, 'resume' will continue tracing" cr + ." Press c: Switch to tracing" cr + ." Press <space>: Execute current word" cr + ." Press q: Abort execution, switch to interpreter" cr + false ENDOF + ENDCASE + UNTIL + THEN ( ip' ) + dup to forth-ip @ ( xt ) + dup ['] breakpoint = IF drop debug-last-xt-content THEN + dup ( xt xt ) + + CASE + <sliteral> OF drop forth-ip cell+ dup dup c@ + -cell and to forth-ip ENDOF + <dotick> OF drop forth-ip cell+ @ cell fip-add ENDOF + <lit> OF drop forth-ip cell+ @ cell fip-add ENDOF + <doto> OF drop forth-ip cell+ @ cell+ ! cell fip-add ENDOF + <(doito)> OF drop forth-ip cell+ @ cell+ cell+ @ >instance ! cell fip-add ENDOF + <0branch> OF drop IF + cell fip-add + ELSE + forth-ip cell+ @ cell+ fip-add THEN + ENDOF + <do?do> OF drop 2dup <> IF + swap >r >r cell fip-add + ELSE + forth-ip cell+ @ cell+ fip-add 2drop THEN + ENDOF + <branch> OF drop forth-ip cell+ @ cell+ fip-add ENDOF + <doleave> OF drop r> r> 2drop forth-ip cell+ @ cell+ fip-add ENDOF + <do?leave> OF drop IF + r> r> 2drop forth-ip cell+ @ cell+ fip-add + ELSE + cell fip-add + THEN + ENDOF + <doloop> OF drop r> 1+ r> 2dup = IF + 2drop cell fip-add + ELSE >r >r + forth-ip cell+ @ cell+ fip-add THEN + ENDOF + <do+loop> OF drop r> + r> 2dup >= IF + 2drop cell fip-add + ELSE >r >r + forth-ip cell+ @ cell+ fip-add THEN + ENDOF + + <semicolon> OF trace>depth 0> IF + trace-depth- 1 to trace>recurse + stepping drop r> recurse + ELSE + drop exit THEN + ENDOF + <exit> OF trace>depth 0> IF + trace-depth- stepping drop r> recurse + ELSE + drop exit THEN + ENDOF + dup OF execute ENDOF + ENDCASE + forth-ip cell+ to forth-ip + AGAIN +; + +\ Resume execution from tracer +: resume ( -- ) + trace>rdepth rdepth! + forth-ip cell - trace-xt +; + +\ Turn debug off, by erasing breakpoint + +: debug-off ( -- ) + debug-last-xt IF + debug-last-xt-content debug-last-xt ! \ Restore overwritten token + 0 to debug-last-xt + THEN +; + + + +\ Entry point for debug + +: (break-entry) ( -- ) + debug-last-xt dup @ ['] breakpoint <> swap ( debug-addr? debug-last-xt ) + debug-last-xt-content swap ! \ Restore overwritten token + r> drop \ Don't return to bp, but to caller + debug-last-xt-content <colon> <> and IF \ Execute non colon definition + debug-last-xt cr u. ." : " + debug-last-xt xt>name type ." " + ." ( " .s ." ) | " + key drop + debug-last-xt execute + ELSE + debug-last-xt 0 to trace>depth 0 to trace>recurse trace-xt \ Trace colon definition + THEN +; + +\ Put entry point bp defer +' (break-entry) to BP + +\ Mark an address for debugging + +: debug-address ( addr -- ) + debug-off ( xt ) \ Remove active breakpoint + dup to debug-last-xt ( xt ) \ Save token for later debug + dup @ to debug-last-xt-content ( xt ) \ Save old value + ['] breakpoint swap ! +; + +\ Mark the command indicated by xt for debugging + +: (debug ( xt -- ) + debug-off ( xt ) \ Remove active breakpoint + dup to debug-last-xt ( xt ) \ Save token for later debug + dup @ to debug-last-xt-content ( xt ) \ Save old value + ['] breakpoint @ swap ! +; + +\ Mark the command indicated by xt for debugging + +: debug ( "old-name<>" -- ) + parse-word $find IF \ Get xt for old-name + (debug + ELSE + ." undefined word " type cr + THEN +; diff --git a/qemu/roms/SLOF/slof/fs/devices/pci-class_02.fs b/qemu/roms/SLOF/slof/fs/devices/pci-class_02.fs new file mode 100644 index 000000000..271420f03 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/devices/pci-class_02.fs @@ -0,0 +1,37 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +s" network [ " type my-space pci-class-name type s" ]" type + +my-space pci-device-generic-setup +my-space pci-alias-net + +s" network" device-type + +cr + +INSTANCE VARIABLE obp-tftp-package +: open ( -- okay? ) + open IF \ enables PCI mem, io and Bus master and returns TRUE + my-args s" obp-tftp" $open-package obp-tftp-package ! true + ELSE + false + THEN ; + +: close ( -- ) + obp-tftp-package @ close-package + close ; \ disables PCI mem, io and Bus master + +: load ( addr -- len ) + s" load" obp-tftp-package @ $call-method ; + +: ping ( -- ) s" ping" obp-tftp-package @ $call-method ; diff --git a/qemu/roms/SLOF/slof/fs/devices/pci-class_0c.fs b/qemu/roms/SLOF/slof/fs/devices/pci-class_0c.fs new file mode 100644 index 000000000..39453fbc0 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/devices/pci-class_0c.fs @@ -0,0 +1,71 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +s" serial bus [ " type my-space pci-class-name type s" ]" type cr + +my-space pci-device-generic-setup + +STRUCT + /n FIELD hcd>base + /n FIELD hcd>type + /n FIELD hcd>num + /n FIELD hcd>ops + /n FIELD hcd>priv + /n FIELD hcd>nextaddr +CONSTANT /hci-dev + +: usb-setup-hcidev ( num hci-dev -- ) + >r + 10 config-l@ F AND case + 0 OF 10 config-l@ translate-my-address ENDOF \ 32-bit memory space + 4 OF \ 64-bit memory space + 14 config-l@ 20 lshift \ Read two bars + 10 config-l@ OR translate-my-address + ENDOF + ENDCASE + F not AND + ( io-base ) r@ hcd>base ! + 08 config-l@ 8 rshift 0000000F0 AND 4 rshift + ( usb-type ) r@ hcd>type ! + ( usb-num ) r@ hcd>num ! + r> drop +; + +\ Handle USB OHCI controllers: +: handle-usb-class ( -- ) + \ set Memory Write and Invalidate Enable, SERR# Enable + \ (see PCI 3.0 Spec Chapter 6.2.2 device control): + 4 config-w@ 110 or 4 config-w! + pci-master-enable \ set PCI Bus master bit and + pci-mem-enable \ memory space enable for USB scan +; + +\ Check PCI sub-class and interface type of Serial Bus Controller +\ to include the appropriate driver: +: handle-sbc-subclass ( -- ) + my-space pci-class@ ffff and CASE \ get PCI sub-class and interface + 0310 OF \ OHCI controller + handle-usb-class + set-ohci-alias + ENDOF + 0320 OF \ EHCI controller + handle-usb-class + set-ehci-alias + ENDOF + 0330 OF \ XHCI controller + handle-usb-class + set-xhci-alias + ENDOF + ENDCASE +; + +handle-sbc-subclass diff --git a/qemu/roms/SLOF/slof/fs/devices/pci-device_10de_0141.fs b/qemu/roms/SLOF/slof/fs/devices/pci-device_10de_0141.fs new file mode 100644 index 000000000..bb3b83516 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/devices/pci-device_10de_0141.fs @@ -0,0 +1,49 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +my-space pci-class-name type + +my-space pci-device-generic-setup + +pci-io-enable +pci-mem-enable + +30 config-l@ pci-find-fcode execute-rom-fcode + +: check-display ( nodepath len -- true|false ) \ true if display found and "screen" alias set +\ check if display available, set screen alias +2dup find-node \ ( path len phandle|0 ) find node +?dup IF + \ node found, get "display-type" property + s" display-type" rot get-property ( path len true|propaddr proplen 0 ) + 0= IF + ( path len propaddr proplen ) \ property found, check if the value is not "NONE" + s" NONE" 0 char-cat ( path len propaddr proplen str strlen ) \ null-terminated NONE string + str= 0= IF + ( path len ) \ "display-type" property is not "NONE" so we can set "screen" alias + s" screen" 2swap set-alias + true ( true ) \ return true + ELSE + 2drop false ( false ) \ return false + THEN + THEN +THEN +; + +get-node node>path s" /NVDA,DISPLAY-A" $cat check-display +0= IF + \ no display found on DISPLAY-A ... check DISPLAY-B + get-node node>path s" /NVDA,DISPLAY-B" $cat check-display + drop \ drop result +THEN + +s" name" get-my-property drop s" ( " type type s" ) " type cr diff --git a/qemu/roms/SLOF/slof/fs/dictionary.fs b/qemu/roms/SLOF/slof/fs/dictionary.fs new file mode 100644 index 000000000..3e5b29332 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/dictionary.fs @@ -0,0 +1,74 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: words + last @ + BEGIN ?dup WHILE + dup cell+ char+ count type space @ + REPEAT +; + +: .calls ( xt -- ) + current-node @ >r 0 set-node \ only search commands, according too IEEE1275 + + last BEGIN @ ?dup WHILE ( xt currxt ) + dup cell+ char+ ( xt currxt name* ) + dup dup c@ + 1+ aligned ( xt currxt name* CFA ) + dup @ <colon> = IF ( xt currxt name* CFA ) + BEGIN + cell+ dup @ ['] semicolon <> + WHILE ( xt currxt *name pos ) + dup @ 4 pick = IF ( xt currxt *name pos ) + over count type space + BEGIN cell+ dup @ ['] semicolon = UNTIL cell - \ eat up other occurrences + THEN + REPEAT + THEN + 2drop ( xt currxt ) + REPEAT + drop + + r> set-node \ restore node +; + +0 value #sift-count +false value sift-compl-only + +: $inner-sift ( text-addr text-len LFA -- ... word-addr word-len true | false ) + dup cell+ char+ count \ get word name + 2dup 6 pick 6 pick find-isubstr \ is there a partly match? + \ in tab completion mode the substring has to be at the beginning + sift-compl-only IF 0= ELSE over < THEN + IF + #sift-count 1+ to #sift-count \ count completions + true + ELSE + 2drop false + THEN +; + +: $sift ( text-addr text-len -- ) + current-node @ >r 0 set-node \ only search commands, according too IEEE1275 + sift-compl-only >r false to sift-compl-only \ all substrings, not only compl. + last BEGIN @ ?dup WHILE \ walk the whole dictionary + $inner-sift IF type space THEN + REPEAT + 2drop + 0 to #sift-count \ we don't need completions here. + r> to sift-compl-only \ restore previous sifting mode + r> set-node \ restore node +; + +: sifting ( "text< >" -- ) + parse-word $sift +; + diff --git a/qemu/roms/SLOF/slof/fs/display.fs b/qemu/roms/SLOF/slof/fs/display.fs new file mode 100644 index 000000000..5bb8797a2 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/display.fs @@ -0,0 +1,123 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +0 VALUE char-height +0 VALUE char-width +0 VALUE fontbytes + +CREATE display-emit-buffer 20 allot + +\ \\\\\\\\\\\\\\ Global Data + +\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods + +\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous) +\ * +\ * +defer dis-old-emit +' emit behavior to dis-old-emit + +: display-write terminal-write ; +: display-emit dup dis-old-emit display-emit-buffer tuck c! 1 terminal-write drop ; + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ Generic device methods: +\ * + + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ IEEE 1275 : display device driver initialization +\ * +: is-install ( 'open -- ) + s" defer vendor-open to vendor-open" eval + s" : open deadbeef vendor-open dup deadbeef = IF drop true ELSE nip THEN ;" eval + s" defer write ' display-write to write" eval + s" : draw-logo ['] draw-logo CATCH IF 2drop 2drop THEN ;" eval + s" : reset-screen ['] reset-screen CATCH drop ;" eval +; + +: is-remove ( 'close -- ) + s" defer close to close" eval +; + +: is-selftest ( 'selftest -- ) + s" defer selftest to selftest" eval +; + + +STRUCT + cell FIELD font>addr + cell FIELD font>width + cell FIELD font>height + cell FIELD font>advance + cell FIELD font>min-char + cell FIELD font>#glyphs +CONSTANT /font + +CREATE default-font-ctrblk /font allot default-font-ctrblk + dup font>addr 0 swap ! + dup font>width 8 swap ! + dup font>height -10 swap ! + dup font>advance 1 swap ! + dup font>min-char 20 swap ! + font>#glyphs 7f swap ! + +: display-default-font ( str len -- ) + romfs-lookup dup 0= IF drop EXIT THEN + 600 <> IF ." Only support 60x8x16 fonts ! " drop EXIT THEN + default-font-ctrblk font>addr ! +; + +s" default-font.bin" display-default-font + +\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous) +\ * +\ * + + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ Generic device methods: +\ * +: .scan-lines ( height -- scanlines ) dup 0>= IF 1- ELSE negate THEN ; + + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ * + +: set-font ( addr width height advance min-char #glyphs -- ) + default-font-ctrblk /font + /font 0 + DO + 1 cells - dup >r ! r> 1 cells + +LOOP drop + default-font-ctrblk dup font>height @ abs to char-height + dup font>width @ to char-width font>advance @ to fontbytes +; + +: >font ( char -- addr ) + dup default-font-ctrblk dup >r font>min-char @ dup r@ font>#glyphs + within + IF + r@ font>min-char @ - + r@ font>advance @ * r@ font>height @ .scan-lines * + r> font>addr @ + + ELSE + drop r> font>addr @ + THEN +; + +: default-font ( -- addr width height advance min-char #glyphs ) + default-font-ctrblk /font 0 DO dup cell+ >r @ r> 1 cells +LOOP drop +; + diff --git a/qemu/roms/SLOF/slof/fs/dma-function.fs b/qemu/roms/SLOF/slof/fs/dma-function.fs new file mode 100644 index 000000000..c1c8716ca --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/dma-function.fs @@ -0,0 +1,36 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2014 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ DMA memory allocation functions +: dma-alloc ( size -- virt ) + my-phandle TO calling-child + s" dma-alloc" my-phandle parent $call-static + 0 TO calling-child +; + +: dma-free ( virt size -- ) + my-phandle TO calling-child + s" dma-free" my-phandle parent $call-static + 0 TO calling-child +; + +: dma-map-in ( virt size cacheable? -- devaddr ) + my-phandle TO calling-child + s" dma-map-in" my-phandle parent $call-static + 0 TO calling-child +; + +: dma-map-out ( virt devaddr size -- ) + my-phandle TO calling-child + s" dma-map-out" my-phandle parent $call-static + 0 TO calling-child +; diff --git a/qemu/roms/SLOF/slof/fs/dump.fs b/qemu/roms/SLOF/slof/fs/dump.fs new file mode 100644 index 000000000..90d60c412 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/dump.fs @@ -0,0 +1,42 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Hex dump facilities. + +1 VALUE /dump +' c@ VALUE 'dump +0 VALUE dump-first +0 VALUE dump-last +0 VALUE dump-cur +: .char ( c -- ) dup bl 7f within 0= IF drop [char] . THEN emit ; +: dump-line ( -- ) + cr dump-cur dup 8 0.r [char] : emit 10 /dump / 0 DO + space dump-cur dump-first dump-last within IF + dump-cur 'dump execute /dump 2* 0.r ELSE + /dump 2* spaces THEN dump-cur /dump + to dump-cur LOOP + /dump 1 <> IF drop EXIT THEN + to dump-cur 2 spaces + 10 0 DO dump-cur dump-first dump-last within IF + dump-cur 'dump execute .char ELSE space THEN dump-cur 1+ to dump-cur LOOP ; +: (dump) ( addr len reader size -- ) + to /dump to 'dump bounds /dump negate and to dump-first to dump-last + dump-first f invert and to dump-cur + base @ hex BEGIN dump-line dump-cur dump-last >= UNTIL base ! ; +: du ( -- ) dump-last 100 'dump /dump (dump) ; +: dump ['] c@ 1 (dump) ; +: wdump ['] w@ 2 (dump) ; +: ldump ['] l@ 4 (dump) ; +: xdump ['] x@ 8 (dump) ; +: rdump ['] rb@ 1 (dump) ; +\ : iodump ['] io-c@ 1 (dump) ; +\ : siodump ['] siocfg@ 1 (dump) ; diff --git a/qemu/roms/SLOF/slof/fs/elf.fs b/qemu/roms/SLOF/slof/fs/elf.fs new file mode 100644 index 000000000..5a80c78d5 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/elf.fs @@ -0,0 +1,71 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Claim memory for segment +\ Abort, if no memory available + +false value elf-claim? +0 value last-claim + +\ cur-brk is set by elf loader to end of data segment +0 VALUE cur-brk + + +: elf-claim-segment ( addr size -- errorcode ) + 2dup + elf-claim? IF + >r + here last-claim , to last-claim \ Setup ptr to last claim + \ Put addr and size in the data space + dup , r> dup , ( addr size ) + 0 ['] claim CATCH IF + ." Memory for ELF file is already in use!" cr + true ABORT" Memory for ELF file already in use " + THEN + drop + ELSE + 2drop + THEN + + to cur-brk + 0 +; + + +\ Load ELF file and claim the corresponding memory regions. +\ A destination address can be specified. If the parameter is -1 then +\ the file is loaded to the ddress that is specified in its header. +: elf-load-claim ( file-addr destaddr -- claim-list entry imagetype ) + true to elf-claim? + 0 to last-claim + dup -1 = IF \ If destaddr == -1 then load to addr from ELF header + drop ['] elf-load-file CATCH IF false to elf-claim? ABORT THEN + ELSE + ['] elf-load-file-to-addr CATCH IF false to elf-claim? ABORT THEN + THEN + >r + last-claim swap + false to elf-claim? + r> +; + + +\ Release memory claimed before + +: elf-release ( claim-list -- ) + BEGIN + dup cell+ ( claim-list claim-list-addr ) + dup @ swap cell+ @ ( claim-list claim-list-addr claim-list-sz ) + release ( claim-list ) + @ dup 0= ( Next-element ) + UNTIL + drop +; diff --git a/qemu/roms/SLOF/slof/fs/envvar.fs b/qemu/roms/SLOF/slof/fs/envvar.fs new file mode 100644 index 000000000..33643130c --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/envvar.fs @@ -0,0 +1,412 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2012 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ configuration variables + +wordlist CONSTANT envvars + +\ list the names in envvars +: listenv ( -- ) + get-current envvars set-current words set-current +; + +\ create a definition in envvars +: create-env ( "name" -- ) + get-current envvars set-current CREATE set-current +; + +\ lay out the data for the separate envvar types +: env-int ( n -- ) 1 c, align , DOES> char+ aligned @ ; +: env-bytes ( a len -- ) + 2 c, align dup , here swap dup allot move + DOES> char+ aligned dup @ >r cell+ r> +; +: env-string ( str len -- ) 3 c, align dup , here over allot swap move DOES> char+ aligned dup @ >r cell+ r> ; +: env-flag ( f -- ) 4 c, c, DOES> char+ c@ 0<> ; +: env-secmode ( sm -- ) 5 c, c, DOES> char+ c@ ; + +\ create default envvars +: default-int ( n "name" -- ) create-env env-int ; +: default-bytes ( a len "name" -- ) create-env env-bytes ; +: default-string ( a len "name" -- ) create-env env-string ; +: default-flag ( f "name" -- ) create-env env-flag ; +: default-secmode ( sm "name" -- ) create-env env-secmode ; + +: set-option ( option-name len option len -- ) + 2swap encode-string + 2swap s" /options" find-node dup IF set-property ELSE drop 2drop 2drop THEN +; + +\ find an envvar's current and default value, and its type +: findenv ( name len -- adr def-adr type | 0 ) + 2dup envvars voc-find dup 0<> IF ( ABORT" not a configuration variable" ) + link> >body char+ >r (find-order) link> >body dup char+ swap c@ r> swap + ELSE + nip nip + THEN +; + + +: test-flag ( param len -- true | false ) + 2dup s" true" string=ci -rot s" false" string=ci or +; + +: test-secmode ( param len -- true | false ) + 2dup s" none" string=ci -rot 2dup s" command" string=ci -rot s" full" + string=ci or or +; + +: test-int ( param len -- true | false ) + $dh-number IF false ELSE drop true THEN +; + +: findtype ( param len name len -- param len name len type ) + 2dup findenv \ try to find type of envvar + dup IF \ found a type? + nip nip + EXIT + THEN + + \ No type found yet, try to auto-detect: + drop 2swap + 2dup test-flag IF + 4 -rot \ boolean type + ELSE + 2dup test-secmode IF + 5 -rot \ secmode type + ELSE + 2dup test-int IF + 1 -rot \ integer type + ELSE + 2dup test-string + IF 3 ELSE 2 THEN \ 3 = string, 2 = default to bytes + -rot + THEN + THEN + THEN + rot + >r 2swap r> +; + +\ set an envvar +: $setenv ( param len name len -- ) + 4dup set-option + findtype + -rot $CREATE + CASE + 1 OF $dh-number IF 0 THEN env-int ENDOF \ XXX: wants decimal and 0x... + 2 OF env-bytes ENDOF + 3 OF env-string ENDOF + 4 OF evaluate env-flag ENDOF + 5 OF evaluate env-secmode ENDOF \ XXX: recognize none, command, full + ENDCASE +; + +\ print an envvar +: (printenv) ( adr type -- ) + CASE + 1 OF aligned @ . ENDOF + 2 OF aligned dup cell+ swap @ swap . . ENDOF + 3 OF aligned dup @ >r cell+ r> type ENDOF + 4 OF c@ IF ." true" ELSE ." false" THEN ENDOF + 5 OF c@ . ENDOF \ XXX: print symbolically + ENDCASE +; + +: .printenv-header ( -- ) + cr + s" ---environment variable--------current value-------------default value------" + type cr +; + +DEFER old-emit +0 VALUE emit-counter + +: emit-and-count emit-counter 1 + to emit-counter old-emit ; + +: .enable-emit-counter + 0 to emit-counter + ['] emit behavior to old-emit + ['] emit-and-count to emit +; + +: .disable-emit-counter + ['] old-emit behavior to emit +; + +: .spaces ( number-of-spaces -- ) + dup 0 > IF + spaces + ELSE + drop space + THEN +; + +: .print-one-env ( name len -- ) + 3 .spaces + 2dup dup -rot type 1c swap - .spaces + findenv rot over + .enable-emit-counter + (printenv) .disable-emit-counter + 1a emit-counter - .spaces + (printenv) +; + +: .print-all-env + .printenv-header + envvars cell+ + BEGIN + @ dup + WHILE + dup link> >name + name>string .print-one-env cr + REPEAT + drop +; + +: printenv + parse-word dup 0= IF + 2drop .print-all-env + ELSE + findenv dup 0= ABORT" not a configuration variable" + rot over cr ." Current: " (printenv) + cr ." Default: " (printenv) + THEN +; + +\ set envvar(s) to default value +: (set-default) ( def-xt -- ) + dup >name name>string $CREATE dup >body c@ >r execute r> CASE + 1 OF env-int ENDOF + 2 OF env-bytes ENDOF + 3 OF env-string ENDOF + 4 OF env-flag ENDOF + 5 OF env-secmode ENDOF ENDCASE +; + +\ Environment variables might be board specific + +#include <envvar_defaults.fs> + +VARIABLE nvoff \ offset in envvar partition + +: (nvupdate-one) ( adr type -- "value" ) + CASE + 1 OF aligned @ (.d) ENDOF + 2 OF drop 0 0 ENDOF + 3 OF aligned dup @ >r cell+ r> ENDOF + 4 OF c@ IF s" true" ELSE s" false" THEN ENDOF + 5 OF c@ (.) ENDOF \ XXX: print symbolically + ENDCASE +; + +: nvupdate-one ( def-xt -- ) + >r nvram-partition-type-common get-nvram-partition ( part.addr part.len FALSE|TRUE R: def-xt ) + ABORT" No valid NVRAM." r> ( part.addr part.len def-xt ) + >name name>string ( part.addr part.len var.a var.l ) + 2dup findenv nip (nvupdate-one) + ( part.addr part.len var.addr var.len val.addr val.len ) + internal-add-env + drop +; + +: (nvupdate) ( -- ) + nvram-partition-type-common get-nvram-partition ABORT" No valid NVRAM." + erase-nvram-partition drop + envvars cell+ + BEGIN @ dup WHILE dup link> nvupdate-one REPEAT + drop +; + +: nvupdate ( -- ) + ." nvupdate is obsolete." cr +; + +: set-default + parse-word envvars voc-find + dup 0= ABORT" not a configuration variable" link> (set-default) +; + +: (set-defaults) + envvars cell+ + BEGIN @ dup WHILE dup link> (set-default) REPEAT + drop +; + +\ Preset nvram variables in RAM, but do not overwrite them in NVRAM +(set-defaults) + +: set-defaults + (set-defaults) (nvupdate) +; + +: setenv parse-word ( skipws ) 0d parse -leading 2swap $setenv (nvupdate) ; + +: get-nv ( -- ) + nvram-partition-type-common get-nvram-partition ( addr offset not-found | not-found ) \ find partition header + IF + ." No NVRAM common partition, re-initializing..." cr + internal-reset-nvram + (nvupdate) + nvram-partition-type-common get-nvram-partition IF ." NVRAM seems to be broken." cr EXIT THEN + THEN + \ partition header found: read data from nvram + drop ( addr ) \ throw away offset + BEGIN + dup rzcount dup \ make string from offset and make condition + WHILE ( offset offset length ) + 2dup [char] = split \ Split string at equal sign (=) + ( offset offset length name len param len ) + 2swap ( offset offset length param len name len ) + $setenv \ Set envvar + nip \ throw away old string begin + + 1+ \ calc new offset + REPEAT + 2drop drop \ cleanup +; + +get-nv + +: check-for-nvramrc ( -- ) + use-nvramrc? IF + s" Executing following code from nvramrc: " + s" nvramrc" evaluate $cat + nvramlog-write-string-cr + s" (!) Executing code specified in nvramrc" type + cr s" SLOF Setup = " type + \ to remove the string from the console if the nvramrc is broken + \ we need to know how many chars are printed + .enable-emit-counter + s" nvramrc" evaluate ['] evaluate CATCH IF + \ dropping the rest of the nvram string + 2drop + \ delete the chars we do not want to see + emit-counter 0 DO 8 emit LOOP + s" (!) Code in nvramrc triggered exception. " + 2dup nvramlog-write-string + type cr 12 spaces s" Aborting nvramrc execution" 2dup + nvramlog-write-string-cr type cr + s" SLOF Setup = " type + THEN + .disable-emit-counter + THEN +; + + +: (nv-findalias) ( alias-ptr alias-len -- pos ) + \ create a temporary empty string + here 0 + \ append "devalias " to the temporary string + s" devalias " string-cat + \ append "<name-str>" to the temporary string + 3 pick 3 pick string-cat + \ append a SPACE character to the temporary string + s" " string-cat + \ get nvramrc + s" nvramrc" evaluate + \ get position of the temporary string inside of nvramrc + 2swap find-substr + nip nip +; + +: (nv-build-real-entry) ( name-ptr name-len dev-ptr dev-len -- str-ptr str-len ) + \ create a temporary empty string + 2swap here 0 + \ append "devalias " to the temporary string + s" devalias " string-cat + \ append "<name-ptr>" to the temporary string + 2swap string-cat + \ append a SPACE character to the temporary string + s" " string-cat + \ append "<dev-ptr> to the temporary string + 2swap string-cat + \ append a CR character to the temporary string + 0d char-cat + \ append a LF character to the temporary string + 0a char-cat +; + +: (nv-build-null-entry) ( name-ptr name-len dev-ptr dev-len -- str-ptr str-len ) + 4drop here 0 +; + +: (nv-build-nvramrc) ( name-str name-len dev-str dev-len xt-build-entry -- ) + \ *** PART 1: check if there is still an alias definition available *** + ( alias-ptr alias-len path-ptr path-ptr call-build-entry alias-pos ) + 4 pick 4 pick (nv-findalias) + \ if our alias definition is a new one + dup s" nvramrc" evaluate nip >= IF + \ call-build-entry + drop execute + \ append content of "nvramrc" to the temporary string + s" nvramrc" evaluate string-cat + \ Allocate the temporary string + dup allot + \ write the string into nvramrc + s" nvramrc" $setenv + ELSE \ if our alias is still defined in nvramrc + \ *** PART 2: calculate the memory size for the new content of nvramrc *** + \ add number of bytes needed for nvramrc-prefix to number of bytes needed + \ for the new entry + 5 pick 5 pick 5 pick 5 pick 5 pick execute nip over + + ( alias-ptr alias-len path-ptr path-ptr build-entry-xt alias-pos tmp-len ) + \ add number of bytes needed for nvramrc-postfix + s" nvramrc" evaluate 3 pick string-at + 2dup find-nextline string-at nip + + \ *** PART 3: build the new content *** + \ allocate enough memory for new content + alloc-mem 0 + ( alias-ptr alias-len path-ptr path-ptr build-entry-xt alias-pos mem len ) + \ add nvramrc-prefix + s" nvramrc" evaluate drop 3 pick string-cat + \ add new entry + rot >r >r >r execute r> r> 2swap string-cat + ( mem, len ) ( R: alias-pos ) + \ add nvramrc-postfix + s" nvramrc" evaluate r> string-at + 2dup find-nextline string-at string-cat + ( mem len ) + \ write the temporary string into nvramrc and clean up memory + 2dup s" nvramrc" $setenv free-mem + THEN +; + +: $nvalias ( name-str name-len dev-str dev-len -- ) + 4dup ['] (nv-build-real-entry) (nv-build-nvramrc) + set-alias + s" true" s" use-nvramrc?" $setenv + (nvupdate) +; + +: nvalias ( "alias-name< >device-specifier<eol>" -- ) + parse-word parse-word dup 0<> IF + $nvalias + ELSE + 2drop 2drop + cr + " Usage: nvalias (""alias-name< >device-specifier<eol>"" -- )" type + cr + THEN +; + +: $nvunalias ( name-str name-len -- ) + s" " ['] (nv-build-null-entry) (nv-build-nvramrc) + (nvupdate) +; + +: nvunalias ( "alias-name< >" -- ) + parse-word $nvunalias +; + +: diagnostic-mode? ( -- diag-switch? ) diag-switch? ; + diff --git a/qemu/roms/SLOF/slof/fs/envvar_defaults.fs b/qemu/roms/SLOF/slof/fs/envvar_defaults.fs new file mode 100644 index 000000000..86716eff0 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/envvar_defaults.fs @@ -0,0 +1,44 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ the defaults +\ some of those are platform dependent, and should e.g. be +\ created from VPD values +true default-flag auto-boot? +s" " default-string boot-device +s" " default-string boot-file +s" boot" default-string boot-command +s" " default-string diag-device +s" " default-string diag-file +false default-flag diag-switch? +true default-flag fcode-debug? +s" " default-string input-device +s" " default-string nvramrc +s" " default-string oem-banner +false default-flag oem-banner? +0 0 default-bytes oem-logo +false default-flag oem-logo? +s" " default-string output-device +200 default-int screen-#columns +200 default-int screen-#rows +0 default-int security-#badlogins +0 default-secmode security-mode +s" " default-string security-password +0 default-int selftest-#megs +false default-flag use-nvramrc? +false default-flag direct-serial? +true default-flag real-mode? +default-load-base default-int load-base +#ifdef BIOSEMU +true default-flag use-biosemu? +0 default-int biosemu-debug +#endif diff --git a/qemu/roms/SLOF/slof/fs/exception.fs b/qemu/roms/SLOF/slof/fs/exception.fs new file mode 100644 index 000000000..dbf11fb46 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/exception.fs @@ -0,0 +1,154 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +STRUCT + cell FIELD >r0 cell FIELD >r1 cell FIELD >r2 cell FIELD >r3 + cell FIELD >r4 cell FIELD >r5 cell FIELD >r6 cell FIELD >r7 + cell FIELD >r8 cell FIELD >r9 cell FIELD >r10 cell FIELD >r11 + cell FIELD >r12 cell FIELD >r13 cell FIELD >r14 cell FIELD >r15 + cell FIELD >r16 cell FIELD >r17 cell FIELD >r18 cell FIELD >r19 + cell FIELD >r20 cell FIELD >r21 cell FIELD >r22 cell FIELD >r23 + cell FIELD >r24 cell FIELD >r25 cell FIELD >r26 cell FIELD >r27 + cell FIELD >r28 cell FIELD >r29 cell FIELD >r30 cell FIELD >r31 + cell FIELD >cr cell FIELD >xer cell FIELD >lr cell FIELD >ctr + cell FIELD >srr0 cell FIELD >srr1 cell FIELD >dar cell FIELD >dsisr +CONSTANT ciregs-size + + + +: .16 10 0.r 3 spaces ; +: .8 8 spaces 8 0.r 3 spaces ; +: .4regs cr 4 0 DO dup @ .16 8 cells+ LOOP drop ; +: .fixed-regs + cr ." R0 .. R7 R8 .. R15 R16 .. R23 R24 .. R31" + dup 8 0 DO dup .4regs cell+ LOOP drop +; + +: .special-regs + cr ." CR / XER LR / CTR SRR0 / SRR1 DAR / DSISR" + cr dup >cr @ .8 dup >lr @ .16 dup >srr0 @ .16 dup >dar @ .16 + cr dup >xer @ .16 dup >ctr @ .16 dup >srr1 @ .16 >dsisr @ .8 +; + +: .regs + cr .fixed-regs + cr .special-regs + cr cr +; + +: .hw-exception ( reason-code exception-nr -- ) + ." ( " dup . ." ) " + CASE + 200 OF ." Machine Check" ENDOF + 300 OF ." Data Storage" ENDOF + 380 OF ." Data Segment" ENDOF + 400 OF ." Instruction Storage" ENDOF + 480 OF ." Instruction Segment" ENDOF + 500 OF ." External" ENDOF + 600 OF ." Alignment" ENDOF + 700 OF ." Program" ENDOF + 800 OF ." Floating-point unavailable" ENDOF + 900 OF ." Decrementer" ENDOF + 980 OF ." Hypervisor Decrementer" ENDOF + C00 OF ." System Call" ENDOF + D00 OF ." Trace" ENDOF + F00 OF ." Performance Monitor" ENDOF + F20 OF ." VMX Unavailable" ENDOF + 1200 OF ." System Error" ENDOF + 1600 OF ." Maintenance" ENDOF + 1800 OF ." Thermal" ENDOF + dup OF ." Unknown" ENDOF + ENDCASE + ." Exception [ " . ." ]" +; + +: .sw-exception ( exception-nr -- ) + ." Exception [ " . ." ] triggered by boot firmware." +; + +\ this word gets also called for non-hardware exceptions. +: be-hw-exception ( [reason-code] exception-nr -- ) + cr cr + dup 0> IF .hw-exception ELSE .sw-exception THEN + cr eregs .regs +; +' be-hw-exception to hw-exception-handler + +: (boot-exception-handler) ( x1...xn exception-nr -- x1...xn) + dup IF + dup 0 > IF + negate cp 9 emit ." : " type + ELSE + CASE + -6d OF cr ." W3411: Client application returned." cr ENDOF + -6c OF cr ." E3400: It was not possible to boot from any device " + ." specified in the VPD." cr + ENDOF + -6b OF cr ." E3410: Boot list successfully read from VPD " + ." but no useful information received." cr + ENDOF + -6a OF cr ." E3420: Boot list could not be read from VPD." cr + ENDOF + -69 OF + cr ." E3406: Client application returned an error" + abort"-str @ count dup IF + ." : " type cr + ELSE + ." ." cr + 2drop + THEN + ENDOF + -68 OF cr ." E3405: No such device" cr ENDOF + -67 OF cr ." E3404: Not a bootable device!" cr ENDOF + -66 OF cr ." E3408: Failed to claim memory for the executable" cr + ENDOF + -65 OF cr ." E3407: Load failed" cr ENDOF + -64 OF cr ." E3403: Bad executable: " abort"-str @ count type cr + ENDOF + -63 OF cr ." E3409: Unknown FORTH Word" cr ENDOF + -2 OF cr ." E3401: Aborting boot, " abort"-str @ count type cr + ENDOF + dup OF ." E3402: Aborting boot, internal error" cr ENDOF + ENDCASE + THEN + ELSE + drop + THEN +; + +' (boot-exception-handler) to boot-exception-handler + +: throw-error ( error-code "error-string" -- ) + skipws 0a parse rot throw +; + +\ Enable external interrupt in msr + +: enable-ext-int ( -- ) + msr@ 8000 or msr! +; + +\ Disable external interrupt in msr + +: disable-ext-int ( -- ) + msr@ 8000 not and msr! +; + +\ Generate external interrupt through Internal Interrupt Controller of BE + +: gen-ext-int ( -- ) + 7fffffff dec! \ Reset decrementer + enable-ext-int \ Enable interrupt + FF 20000508418 rx! \ Interrupt priority mask + 10 20000508410 rx! \ Interrupt priority +; + diff --git a/qemu/roms/SLOF/slof/fs/fbuffer.fs b/qemu/roms/SLOF/slof/fs/fbuffer.fs new file mode 100644 index 000000000..756f05a95 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/fbuffer.fs @@ -0,0 +1,264 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +#include "terminal.fs" +#include "display.fs" + +\ \\\\\\\\\\\\\\ Global Data + +0 VALUE frame-buffer-adr +0 VALUE screen-height +0 VALUE screen-width +0 VALUE screen-depth +0 VALUE window-top +0 VALUE window-left + +0 VALUE .sc + +: screen-#rows ( -- rows ) + .sc IF + screen-height char-height / + ELSE + true to .sc + s" screen-#rows" eval + false to .sc + THEN +; + +: screen-#columns ( -- columns ) + .sc IF + screen-width char-width / + ELSE + true to .sc + s" screen-#columns" eval + false to .sc + THEN +; + +\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods + + +\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous) +\ * +\ * + +: fb8-background inverse? ; +: fb8-foreground inverse? invert ; + +: fb8-lines2bytes ( #lines -- #bytes ) char-height * screen-width * screen-depth * ; +: fb8-columns2bytes ( #columns -- #bytes ) char-width * screen-depth * ; +: fb8-line2addr ( line# -- addr ) + char-height * window-top + screen-width * screen-depth * + frame-buffer-adr + window-left screen-depth * + +; + +: fb8-erase-block ( addr len ) fb8-background rfill ; + + +0 VALUE .ab +CREATE bitmap-buffer 400 4 * allot + +: active-bits ( -- new ) .ab dup 8 > IF 8 - to .ab 8 ELSE + char-width to .ab ?dup 0= IF recurse THEN + THEN ; + +: fb8-char2bitmap ( font-height font-addr -- bitmap-buffer ) + bitmap-buffer >r + char-height rot 0> IF r> char-width 2dup fb8-erase-block + >r 1- THEN + + r> -rot char-width to .ab + ( fb-addr font-addr font-height ) + fontbytes * bounds ?DO + i c@ active-bits 0 ?DO + dup 80 and IF fb8-foreground ELSE fb8-background THEN + ( fb-addr fbyte colr ) 2 pick ! 1 lshift + swap screen-depth + swap + LOOP drop + LOOP drop + bitmap-buffer +; + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ * IEEE 1275: Frame buffer support routines +\ * + +: fb8-draw-logo ( line# addr width height -- ) ." fb8-draw-logo ( " .s ." )" cr + 2drop 2drop +; + +: fb8-toggle-cursor ( -- ) + line# fb8-line2addr column# fb8-columns2bytes + + char-height 0 ?DO + char-width screen-depth * 0 ?DO dup dup rb@ -1 xor swap rb! 1+ LOOP + screen-width screen-depth * + char-width screen-depth * - + LOOP drop +; + +: fb8-draw-character ( char -- ) + >r default-font over + r@ -rot between IF + 2swap 3drop r> >font fb8-char2bitmap ( bitmap-buf ) + line# fb8-line2addr column# fb8-columns2bytes + ( bitmap-buf fb-addr ) + char-height 0 ?DO + 2dup char-width screen-depth * mrmove + screen-width screen-depth * + >r char-width screen-depth * + r> + LOOP 2drop + ELSE 2drop r> 3drop THEN +; + +: fb8-insert-lines ( n -- ) + fb8-lines2bytes >r line# fb8-line2addr dup dup r@ + + #lines line# - fb8-lines2bytes r@ - rmove + r> fb8-erase-block +; + +: fb8-delete-lines ( n -- ) + fb8-lines2bytes >r line# fb8-line2addr dup dup r@ + swap + #lines fb8-lines2bytes r@ - dup >r rmove + r> + r> fb8-erase-block +; + +: fb8-insert-characters ( n -- ) + line# fb8-line2addr column# fb8-columns2bytes + >r + #columns column# - 2dup >= IF + nip dup 0> IF fb8-columns2bytes r> ELSE r> 2drop EXIT THEN + ELSE + fb8-columns2bytes swap fb8-columns2bytes tuck - + over r@ tuck + rot char-height 0 ?DO + 3dup rmove + -rot screen-width screen-depth * tuck + -rot + swap rot + LOOP + 3drop r> + THEN + char-height 0 ?DO + dup 2 pick fb8-erase-block screen-width screen-depth * + + LOOP + 2drop +; + +: fb8-delete-characters ( n -- ) + line# fb8-line2addr column# fb8-columns2bytes + >r + #columns column# - 2dup >= IF + nip dup 0> IF fb8-columns2bytes r> ELSE r> 2drop EXIT THEN + ELSE + fb8-columns2bytes swap fb8-columns2bytes tuck - + over r@ + 2dup + r> swap >r rot char-height 0 ?DO + 3dup rmove + -rot screen-width screen-depth * tuck + -rot + swap rot + LOOP + 3drop r> over - + THEN + char-height 0 ?DO + dup 2 pick fb8-erase-block screen-width screen-depth * + + LOOP + 2drop +; + +: fb8-reset-screen ( -- ) ( Left as no-op by design ) ; + +: fb8-erase-screen ( -- ) + frame-buffer-adr screen-height screen-width * screen-depth * fb8-erase-block +; + +: fb8-invert-screen ( -- ) + frame-buffer-adr screen-height screen-width * screen-depth * 2dup /x / 0 ?DO + dup rx@ -1 xor over rx! xa1+ + LOOP 3drop +; + +: fb8-blink-screen ( -- ) fb8-invert-screen fb8-invert-screen ; + +: fb8-install ( width height #columns #lines -- ) + 1 to screen-depth + 2swap to screen-height to screen-width + screen-#rows min to #lines + screen-#columns min to #columns + screen-height char-height #lines * - 2/ to window-top + screen-width char-width #columns * - 2/ to window-left + ['] fb8-toggle-cursor to toggle-cursor + ['] fb8-draw-character to draw-character + ['] fb8-insert-lines to insert-lines + ['] fb8-delete-lines to delete-lines + ['] fb8-insert-characters to insert-characters + ['] fb8-delete-characters to delete-characters + ['] fb8-erase-screen to erase-screen + ['] fb8-blink-screen to blink-screen + ['] fb8-invert-screen to invert-screen + ['] fb8-reset-screen to reset-screen + ['] fb8-draw-logo to draw-logo +; + +: fb-install ( width height #columns #lines depth -- ) + >r + fb8-install + r> to screen-depth +; + + +\ Install display related FCODE evaluator tokens +: fb8-set-tokens ( -- ) + ['] is-install 0 11C set-token + ['] is-remove 0 11D set-token + ['] is-selftest 0 11E set-token + + ['] #lines 0 150 set-token + ['] #columns 0 151 set-token + ['] line# 0 152 set-token + ['] column# 0 153 set-token + ['] inverse? 0 154 set-token + ['] inverse-screen? 0 155 set-token + ['] draw-character 0 157 set-token + ['] reset-screen 0 158 set-token + ['] toggle-cursor 0 159 set-token + ['] erase-screen 0 15A set-token + ['] blink-screen 0 15B set-token + ['] invert-screen 0 15C set-token + ['] insert-characters 0 15D set-token + ['] delete-characters 0 15E set-token + ['] insert-lines 0 15F set-token + ['] delete-lines 0 160 set-token + ['] draw-logo 0 161 set-token + ['] frame-buffer-adr 0 162 set-token + ['] screen-height 0 163 set-token + ['] screen-width 0 164 set-token + ['] window-top 0 165 set-token + ['] window-left 0 166 set-token + \ ['] foreground-color 0 168 set-token \ 16-color extension - n/a + \ ['] background-color 0 169 set-token \ 16-color extension - n/a + ['] default-font 0 16A set-token + ['] set-font 0 16B set-token + ['] char-height 0 16C set-token + ['] char-width 0 16D set-token + ['] >font 0 16E set-token + ['] fontbytes 0 16F set-token + + ['] fb8-draw-character 0 180 set-token + ['] fb8-reset-screen 0 181 set-token + ['] fb8-toggle-cursor 0 182 set-token + ['] fb8-erase-screen 0 183 set-token + ['] fb8-blink-screen 0 184 set-token + ['] fb8-invert-screen 0 185 set-token + ['] fb8-insert-characters 0 186 set-token + ['] fb8-delete-characters 0 187 set-token + ['] fb8-insert-lines 0 188 set-token + ['] fb8-delete-lines 0 189 set-token + ['] fb8-draw-logo 0 18A set-token + ['] fb8-install 0 18B set-token +; +fb8-set-tokens + + +\ \\\\\\\\\\\\ Debug Stuff \\\\\\\\\\\\\\\\ + +: fb8-dump-bitmap cr char-height 0 ?do char-width 0 ?do dup c@ if ." @" else ." ." then 1+ loop cr loop drop ; + +: fb8-dump-char >font -b swap fb8-char2bitmap fb8-dump-bitmap ; diff --git a/qemu/roms/SLOF/slof/fs/fcode/1275.fs b/qemu/roms/SLOF/slof/fs/fcode/1275.fs new file mode 100644 index 000000000..c2a67bcc9 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/fcode/1275.fs @@ -0,0 +1,465 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +: fcode-revision ( -- n ) + 00030000 \ major * 65536 + minor + ; + +: b(lit) ( -- n ) + next-ip read-fcode-num32 + ?compile-mode IF literal, THEN + ; + +: b(") + next-ip read-fcode-string + ?compile-mode IF fc-string, align postpone count THEN + ; + +: b(') + next-ip read-fcode# get-token drop ?compile-mode IF literal, THEN + ; + +: ?jump-direction ( n -- ) + dup 8000 >= IF + 10000 - \ Create cell-sized negative value + THEN + fcode-offset - \ IP is already behind offset, so subtract offset size +; + +: ?negative + 8000 and + ; + +: dest-on-top + 0 >r BEGIN dup @ 0= WHILE >r REPEAT + BEGIN r> dup WHILE swap REPEAT + drop + ; + +: read-fcode-offset + next-ip + ?offset16 IF + read-fcode-num16 + ELSE + read-byte + dup 80 and IF FF00 or THEN \ Fake 16-bit signed offset + THEN +; + +: b?branch ( flag -- ) + ?compile-mode IF + read-fcode-offset ?negative IF + dest-on-top postpone until + ELSE + postpone if + THEN + ELSE + ( flag ) IF + fcode-offset jump-n-ip \ Skip over offset value + ELSE + read-fcode-offset + ?jump-direction jump-n-ip + THEN + THEN +; immediate + +: bbranch ( -- ) + ?compile-mode IF + read-fcode-offset + ?negative IF + dest-on-top postpone again + ELSE + postpone else + get-ip next-ip fcode@ B2 = IF + drop + ELSE + set-ip + THEN + THEN + ELSE + read-fcode-offset ?jump-direction jump-n-ip + THEN +; immediate + +: b(<mark) ( -- ) + ?compile-mode IF postpone begin THEN + ; immediate + +: b(>resolve) ( -- ) + ?compile-mode IF postpone then THEN + ; immediate + +: b(;) + <semicolon> compile, reveal + postpone [ +; immediate + +: b(:) ( -- ) + <colon> compile, ] + ; immediate + +: b(case) ( sel -- sel ) + postpone case + ; immediate + +: b(endcase) + postpone endcase + ; immediate + +: b(of) + postpone of + read-fcode-offset drop \ read and discard offset + ; immediate + +: b(endof) + postpone endof + read-fcode-offset drop + ; immediate + +: b(do) + postpone do + read-fcode-offset drop + ; immediate + +: b(?do) + postpone ?do + read-fcode-offset drop + ; immediate + +: b(loop) + postpone loop + read-fcode-offset drop + ; immediate + +: b(+loop) + postpone +loop + read-fcode-offset drop + ; immediate + +: b(leave) + postpone leave + ; immediate + + +0 VALUE fc-instance? +: fc-instance ( -- ) \ Mark next defining word as instance-specific. + TRUE TO fc-instance? +; + +: new-token \ unnamed local fcode function + align here next-ip read-fcode# 0 swap set-token + ; + +: external-token ( -- ) \ named local fcode function + next-ip read-fcode-string + \ fc-instance? IF cr ." ext instance token: " 2dup type ." in " pwd cr THEN + header ( str len -- ) \ create a header in the current dictionary entry + new-token + ; + +: new-token + eva-debug? IF + s" x" get-ip >r next-ip read-fcode# r> set-ip (u.) $cat strdup + header + THEN + new-token +; + +\ decide wether or not to give a new token an own name in the dictionary +: named-token + fcode-debug? IF + external-token + ELSE + next-ip read-fcode-string 2drop \ Forget about the name + new-token + THEN +; + +: b(to) ( val -- ) + next-ip read-fcode# + get-token drop ( val xt ) + dup @ ( val xt @xt ) + dup <value> = over <defer> = OR IF + \ Destination is value or defer + drop + >body cell - + ( val addr ) + ?compile-mode IF + literal, postpone ! + ELSE + ! + THEN + ELSE + <create> <> IF ( val xt ) + TRUE ABORT" Invalid destination for FCODE b(to)" + THEN + dup cell+ @ ( val xt @xt+1cell ) + dup <instancevalue> <> swap <instancedefer> <> AND IF + TRUE ABORT" Invalid destination for FCODE b(to)" + THEN + \ Destination is instance-value or instance-defer + >body @ ( val instance-offset ) + ?compile-mode IF + literal, postpone >instance postpone ! + ELSE + >instance ! + THEN + ELSE + THEN +; immediate + +: b(value) + fc-instance? IF + <create> , \ Needed for "(instance?)" for example + <instancevalue> , + (create-instance-var) + FALSE TO fc-instance? + ELSE + <value> , , + THEN + reveal +; + +: b(variable) + fc-instance? IF + <create> , \ Needed for "(instance?)" + <instancevariable> , + 0 (create-instance-var) + FALSE TO fc-instance? + ELSE + <variable> , 0 , + THEN + reveal +; + +: b(constant) + <constant> , , reveal + ; + +: undefined-defer + cr cr ." Uninitialized defer word has been executed!" cr cr + true fcode-end ! + ; + +: b(defer) + fc-instance? IF + <create> , \ Needed for "(instance?)" + <instancedefer> , + ['] undefined-defer (create-instance-var) + reveal + FALSE TO fc-instance? + ELSE + <defer> , reveal + postpone undefined-defer + THEN +; + +: b(create) + <variable> , + postpone noop reveal + ; + +: b(field) ( E: addr -- addr+offset ) ( F: offset size -- offset+size ) + <colon> , over literal, + postpone + + <semicolon> compile, + reveal + + +; + +: b(buffer:) ( E: -- a-addr) ( F: size -- ) + fc-instance? IF + <create> , \ Needed for "(instance?)" + <instancebuffer> , + (create-instance-buf) + FALSE TO fc-instance? + ELSE + <buffer:> , allot + THEN + reveal +; + +: suspend-fcode ( -- ) + noop \ has to be implemented more efficiently ;-) + ; + +: offset16 ( -- ) + 2 to fcode-offset + ; + +: version1 ( -- ) + 1 to fcode-spread + 1 to fcode-offset + read-header + ; + +: start0 ( -- ) + 0 to fcode-spread + offset16 + read-header + ; + +: start1 ( -- ) + 1 to fcode-spread + offset16 + read-header + ; + +: start2 ( -- ) + 2 to fcode-spread + offset16 + read-header + ; + +: start4 ( -- ) + 4 to fcode-spread + offset16 + read-header + ; + +: end0 ( -- ) + true fcode-end ! + ; + +: end1 ( -- ) + end0 + ; + +: ferror ( -- ) + clear end0 + cr ." FCode# " fcode-num @ . ." not assigned!" + cr ." FCode evaluation aborted." cr + ." ( -- S:" depth . ." R:" rdepth . ." ) " .s cr + abort + ; + +: reset-local-fcodes + FFF 800 DO ['] ferror 0 i set-token LOOP + ; + +: byte-load ( addr xt -- ) + >r >r + save-evaluator-state + r> r> + reset-fcode-end + 1 to fcode-spread + dup 1 = IF drop ['] rb@ THEN to fcode-rb@ + set-ip + reset-local-fcodes + depth >r + evaluate-fcode + r> depth 1- <> IF + clear end0 + cr ." Ambiguous stack depth after byte-load!" + cr ." FCode evaluation aborted." cr cr + ELSE + restore-evaluator-state + THEN + ['] c@ to fcode-rb@ +; + +\ Functions for accessing memory ... since some FCODE programs use the normal +\ memory access functions for accessing MMIO memory, too, we got to use a little +\ hack to support them: When address is bigger than MIN-RAM-SIZE, assume the +\ FCODE is trying to access MMIO memory and use the register based access +\ functions instead! +: fc-c@ ( addr -- byte ) dup MIN-RAM-SIZE > IF rb@ ELSE c@ THEN ; +: fc-w@ ( addr -- word ) dup MIN-RAM-SIZE > IF rw@ ELSE w@ THEN ; +: fc-<w@ ( addr -- word ) fc-w@ dup 8000 >= IF 10000 - THEN ; +: fc-l@ ( addr -- long ) dup MIN-RAM-SIZE > IF rl@ ELSE l@ THEN ; +: fc-<l@ ( addr -- long ) fc-l@ signed ; +: fc-x@ ( addr -- dlong ) dup MIN-RAM-SIZE > IF rx@ ELSE x@ THEN ; +: fc-c! ( byte addr -- ) dup MIN-RAM-SIZE > IF rb! ELSE c! THEN ; +: fc-w! ( word addr -- ) dup MIN-RAM-SIZE > IF rw! ELSE w! THEN ; +: fc-l! ( long addr -- ) dup MIN-RAM-SIZE > IF rl! ELSE l! THEN ; +: fc-x! ( dlong addr -- ) dup MIN-RAM-SIZE > IF rx! ELSE x! THEN ; + +: fc-fill ( add len byte -- ) 2 pick MIN-RAM-SIZE > IF rfill ELSE fill THEN ; +: fc-move ( src dst len -- ) + 2 pick MIN-RAM-SIZE > \ Check src + 2 pick MIN-RAM-SIZE > \ Check dst + OR IF rmove ELSE move THEN +; + +\ Destroy virtual mapping (should maybe also update "address" property here?) +: free-virtual ( virt size -- ) + s" map-out" $call-parent +; + +\ Map the specified region, return virtual address +: map-low ( phys.lo ... size -- virt ) + my-space swap s" map-in" $call-parent +; + +\ Get MAC address +: mac-address ( -- mac-str mac-len ) + s" local-mac-address" get-my-property IF + 0 0 + THEN +; + +\ Output line and column number - not used yet +VARIABLE #line +0 #line ! +VARIABLE #out +0 #out ! + +\ Display device status +: display-status ( n -- ) + ." Device status: " . cr +; + +\ Obsolete variables: +VARIABLE group-code +0 group-code ! + +\ Obsolete: Allocate memory for DMA +: dma-alloc ( byte -- virtual ) + s" dma-alloc" $call-parent +; + +\ Obsolete: Get params property +: my-params ( -- addr len ) + s" params" get-my-property IF + 0 0 + THEN +; + +\ Obsolete: Convert SBus interrupt level to CPU interrupt level +: sbus-intr>cpu ( sbus-intr# -- cpu-intr# ) +; + +\ Obsolete: Set "intr" property +: intr ( interrupt# vector -- ) + >r sbus-intr>cpu encode-int r> encode-int+ s" intr" property +; + +\ Obsolete: Create the "name" property +: driver ( addr len -- ) + encode-string s" name" property +; + +\ Obsolete: Return type of CPU +: processor-type ( -- cpu-type ) + 0 +; + +\ Obsolete: Return firmware version +: firmware-version ( -- n ) + 10000 \ Just a dummy value +; + +\ Obsolete: Return fcode-version +: fcode-version ( -- n ) + fcode-revision +; diff --git a/qemu/roms/SLOF/slof/fs/fcode/core.fs b/qemu/roms/SLOF/slof/fs/fcode/core.fs new file mode 100644 index 000000000..8fd98ec19 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/fcode/core.fs @@ -0,0 +1,173 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: ?offset16 ( -- true|false ) + fcode-offset 2 = + ; + +: ?arch64 ( -- true|false ) + cell 8 = + ; + +: ?bigendian ( -- true|false ) + deadbeef fcode-num ! + fcode-num ?arch64 IF 4 + THEN + c@ de = + ; + +: reset-fcode-end ( -- ) + false fcode-end ! + ; + +: get-ip ( -- n ) + ip @ + ; + +: set-ip ( n -- ) + ip ! + ; + +: next-ip ( -- ) + get-ip 1+ set-ip + ; + +: jump-n-ip ( n -- ) + get-ip + set-ip + ; + +: read-byte ( -- n ) + get-ip fcode-rb@ + ; + +: ?compile-mode ( -- on|off ) + state @ + ; + +: save-evaluator-state + get-ip eva-debug? IF ." saved ip " dup . cr THEN + fcode-end @ eva-debug? IF ." saved fcode-end " dup . cr THEN + fcode-offset eva-debug? IF ." saved fcode-offset " dup . cr THEN +\ local fcodes are currently NOT saved! + fcode-spread eva-debug? IF ." saved fcode-spread " dup . cr THEN + ['] fcode@ behavior eva-debug? IF ." saved fcode@ " dup . cr THEN + ; + +: restore-evaluator-state + eva-debug? IF ." restored fcode@ " dup . cr THEN to fcode@ + eva-debug? IF ." restored fcode-spread " dup . cr THEN to fcode-spread +\ local fcodes are currently NOT restored! + eva-debug? IF ." restored fcode-offset " dup . cr THEN to fcode-offset + eva-debug? IF ." restored fcode-end " dup . cr THEN fcode-end ! + eva-debug? IF ." restored ip " dup . cr THEN set-ip + ; + +: token-table-index ( fcode# -- addr ) + cells token-table + + ; + +: join-immediate ( xt immediate? addr -- xt+immediate? addr ) + -rot + swap + ; + +: split-immediate ( xt+immediate? -- xt immediate? ) + dup 1 and 2dup - rot drop swap + ; + +: literal, ( n -- ) + postpone literal + ; + +: fc-string, + postpone sliteral + dup c, bounds ?do i c@ c, loop + ; + +: set-token ( xt immediate? fcode# -- ) + token-table-index join-immediate ! + ; + +: get-token ( fcode# -- xt immediate? ) + token-table-index @ split-immediate + ; + +( ---------------------------------------------------- ) + +#include "little-big.fs" + +( ---------------------------------------------------- ) + +: read-fcode# ( -- FCode# ) + read-byte + dup 01 0F between IF drop read-fcode-num16 THEN + ; + +: read-header ( adr -- ) + next-ip read-byte drop + next-ip read-fcode-num16 drop + next-ip read-fcode-num32 drop + ; + +: read-fcode-string ( -- str len ) + read-byte \ get string length ( -- len ) + next-ip get-ip \ get string addr ( -- len str ) + swap \ type needs the parameters swapped ( -- str len ) + dup 1- jump-n-ip \ jump to the end of the string in FCode + ; + + +-1 VALUE break-fcode-addr +0 VALUE break-fcode-steps + +: evaluate-fcode ( -- ) + BEGIN + get-ip break-fcode-addr = IF + TRUE fcode-end ! + THEN + fcode-end @ 0= + WHILE + fcode@ ( fcode# ) + eva-debug? IF + dup + get-ip 8 u.r ." : " + ." [" 3 u.r ." ] " + THEN + \ When it is not immediate and in compile-mode, then compile + get-token 0= ?compile-mode AND IF ( xt ) + compile, + ELSE \ immediate or "interpretation" mode + eva-debug? IF dup xt>name type space THEN + execute + THEN + eva-debug? IF .s cr THEN + break-fcode-steps IF + break-fcode-steps 1- TO break-fcode-steps + break-fcode-steps 0= IF + TRUE fcode-end ! + THEN + THEN + next-ip + REPEAT +; + +\ Run FCODE for n steps +: steps-fcode ( n -- ) + to break-fcode-steps + break-fcode-addr >r -1 to break-fcode-addr + reset-fcode-end + evaluate-fcode + r> to break-fcode-addr +; + +\ Step through one FCODE instruction +: step-fcode ( -- ) + 1 steps-fcode +; diff --git a/qemu/roms/SLOF/slof/fs/fcode/evaluator.fs b/qemu/roms/SLOF/slof/fs/fcode/evaluator.fs new file mode 100644 index 000000000..8f0bae527 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/fcode/evaluator.fs @@ -0,0 +1,119 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +variable ip +variable fcode-end +variable fcode-num + 1 value fcode-spread + 2 value fcode-offset +false value eva-debug? +true value fcode-debug? +defer fcode-rb@ +defer fcode@ + +' c@ to fcode-rb@ + +create token-table 2000 cells allot \ 1000h = 4096d + +#include "core.fs" +#include "1275.fs" +#include "tokens.fs" +#include "locals.fs" + +0 value buff +0 value buff-size + +' read-fcode# to fcode@ + +( ---------------------------------------------------- ) + +: execute-rom-fcode ( addr len | false -- ) + reset-fcode-end + ?dup IF + diagnostic-mode? IF ." , executing ..." cr THEN + dup >r r@ alloc-mem dup >r swap rmove + r@ set-ip evaluate-fcode + diagnostic-mode? IF ." Done." cr THEN + r> r> free-mem + THEN +; + +: rom-code-ignored ( image-addr name len -- image-addr ) + diagnostic-mode? IF + type ." code found in image " dup . ." , ignoring ..." cr + ELSE + 2drop + THEN +; + +: pci-find-rom ( baseaddr -- addr ) + dup IF + dup rw@-le aa55 = IF + diagnostic-mode? IF ." Device ROM header found at " dup . cr THEN + ELSE + drop 0 + THEN + THEN +; + +: pci-find-fcode ( baseaddr -- addr len | false ) + BEGIN + 1ff NOT and \ Image must start at 512 byte boundary + pci-find-rom dup + WHILE + dup 18 + rw@-le + ( pcir-addr ) + \ Check for PCIR magic ... since pcir-addr might not be + \ 4-byte aligned, we've got to use two reads here: + dup rw@-le 4350 ( 'PC' ) <> ( pcir-addr hasPC? ) + over 2+ rw@-le 5249 ( 'IR' ) <> OR IF + diagnostic-mode? IF + ." Invalid PCI Data structure, ignoring ROM contents" cr + THEN + drop false EXIT + THEN ( pcir-addr ) + dup 14 + rb@ CASE \ Get image code type + 0 OF s" Intel x86 BIOS" rom-code-ignored ENDOF + 1 OF + diagnostic-mode? IF + ." Open Firmware FCode found in image at " dup . cr + THEN + dup 1ff NOT AND \ Back to the ROM image header + dup 2+ rw@-le + \ Pointer to FCODE (PCI bus binding ch.9) + swap 10 + rw@-le 200 * \ Image length + EXIT + ENDOF + 2 OF s" HP PA RISC" rom-code-ignored ENDOF + 3 OF s" EFI" rom-code-ignored ENDOF + dup OF s" Unknown type" rom-code-ignored ENDOF + ENDCASE + dup 15 + rb@ 80 and IF \ End of last image? + drop false EXIT + THEN + dup 10 + rw@-le 200 * + \ Next image start + REPEAT +; + + +\ Prepare and run a FCODE program from a PCI Option ROM. +: pci-execute-fcode ( baseaddr -- ) + pci-find-fcode dup 0= IF + 2drop EXIT + THEN ( addr len ) + fc-set-pci-mmio-tokens \ Prepare PCI access functions + \ Now run the FCODE: + ['] execute-rom-fcode CATCH IF + cr ." FCODE failed!" cr + 2drop + THEN + fc-set-normal-mmio-tokens \ Restore normal MMIO access functions +; diff --git a/qemu/roms/SLOF/slof/fs/fcode/little-big.fs b/qemu/roms/SLOF/slof/fs/fcode/little-big.fs new file mode 100644 index 000000000..309c626a9 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/fcode/little-big.fs @@ -0,0 +1,96 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ little- and big-endian FCODE IP access functions + + +?bigendian [IF] \ Big endian access functions first + + +: read-fcode-num16 ( -- n ) + 0 fcode-num ! + ?arch64 IF + read-byte fcode-num 6 + C! + next-ip + read-byte fcode-num 7 + C! + ELSE + read-byte fcode-num 2 + C! + next-ip + read-byte fcode-num 3 + C! + THEN + fcode-num @ +; + +: read-fcode-num32 ( -- n ) + 0 fcode-num ! + ?arch64 IF + read-byte fcode-num 4 + C! + next-ip + read-byte fcode-num 5 + C! + next-ip + read-byte fcode-num 6 + C! + next-ip + read-byte fcode-num 7 + C! + ELSE + read-byte fcode-num 0 + C! + next-ip + read-byte fcode-num 1 + C! + next-ip + read-byte fcode-num 2 + C! + next-ip + read-byte fcode-num 3 + C! + THEN + fcode-num @ +; + + +[ELSE] \ Now the little endian access functions + + +: read-fcode-num16 ( -- n ) + 0 fcode-num ! + ?arch64 IF + read-byte fcode-num 7 + C! + next-ip + read-byte fcode-num 6 + C! + ELSE + read-byte fcode-num 1 + C! + next-ip + read-byte fcode-num 0 + C! + THEN + fcode-num @ +; + +: read-fcode-num32 ( adr -- n ) + 0 fcode-num ! + ?arch64 IF + read-byte fcode-num 7 + C! + next-ip + read-byte fcode-num 6 + C! + next-ip + read-byte fcode-num 5 + C! + next-ip + read-byte fcode-num 4 + C! + ELSE + read-byte fcode-num 3 + C! + next-ip + read-byte fcode-num 2 + C! + next-ip + read-byte fcode-num 1 + C! + next-ip + read-byte fcode-num 0 + C! + THEN + fcode-num @ +; + + +[THEN] diff --git a/qemu/roms/SLOF/slof/fs/fcode/locals.fs b/qemu/roms/SLOF/slof/fs/fcode/locals.fs new file mode 100644 index 000000000..5381df058 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/fcode/locals.fs @@ -0,0 +1,155 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +\ * +\ * Support for old-fashioned local values in FCODE. +\ * +\ * There is one old FCODE tokenizer that uses the FCODE opcodes in the range +\ * of 0x407 to 0x41f for supporting Forth local values. Each locals stack +\ * frame contains 8 variables. The opcodes from 0x407 to 0x40f are used to +\ * push 0 up to 8 values from the normal data stack into the current locals +\ * stack frame. All other variables in the current stack frame are not +\ * pre-initialized. +\ * The opcodes from 0x410 to 0x417 can be used for reading the first, second, +\ * ... eighth value out of the locals stack frame, and the opcode from 0x418 +\ * to 0x41f can be used to set the first, second, ... eighth value in the +\ * stack frame respectively. +\ * + +80 cells CONSTANT LOCALS-STACK-SIZE + +LOCALS-STACK-SIZE BUFFER: localsstackbuf + +localsstackbuf VALUE localsstack + + +: fc-local@ ( n -- val ) + cells localsstack swap - @ +; + +: fc-local-1-@ 1 fc-local@ ; +: fc-local-2-@ 2 fc-local@ ; +: fc-local-3-@ 3 fc-local@ ; +: fc-local-4-@ 4 fc-local@ ; +: fc-local-5-@ 5 fc-local@ ; +: fc-local-6-@ 6 fc-local@ ; +: fc-local-7-@ 7 fc-local@ ; +: fc-local-8-@ 8 fc-local@ ; + + +: fc-local! ( val n -- ) + cells localsstack swap - ! +; + +: fc-local-1-! 1 fc-local! ; +: fc-local-2-! 2 fc-local! ; +: fc-local-3-! 3 fc-local! ; +: fc-local-4-! 4 fc-local! ; +: fc-local-5-! 5 fc-local! ; +: fc-local-6-! 6 fc-local! ; +: fc-local-7-! 7 fc-local! ; +: fc-local-8-! 8 fc-local! ; + + +0 VALUE uses-locals? + +\ Create space for the current function on the locals stack. +\ Pre-initialized the n first locals with the n top-most data stack items. +\ Note: Each function can use up to 8 (initialized or uninitialized) locals. +: (fc-push-locals) ( ... n -- ) + \ cr ." pushing " dup . ." locals" cr + 8 cells localsstack + TO localsstack + localsstack localsstackbuf - + LOCALS-STACK-SIZE > ABORT" Locals stack exceeded!" + ?dup IF + ( ... n ) 1 swap DO + i fc-local! \ Store pre-initialized locals + -1 +LOOP + THEN +; + +: fc-push-locals ( n -- ) + \ cr ." compiling push for " dup . ." locals" cr + uses-locals? ABORT" Definition pushes locals multiple times!" + true TO uses-locals? + ( n ) ['] literal execute + ['] (fc-push-locals) compile, +; + +: fc-push-0-locals 0 fc-push-locals ; +: fc-push-1-locals 1 fc-push-locals ; +: fc-push-2-locals 2 fc-push-locals ; +: fc-push-3-locals 3 fc-push-locals ; +: fc-push-4-locals 4 fc-push-locals ; +: fc-push-5-locals 5 fc-push-locals ; +: fc-push-6-locals 6 fc-push-locals ; +: fc-push-7-locals 7 fc-push-locals ; +: fc-push-8-locals 8 fc-push-locals ; + + +: fc-pop-locals ( -- ) + \ ." popping locals" cr + localsstack 8 cells - TO localsstack + localsstack localsstackbuf - 0 < ABORT" Locals stack undeflow!" +; + + +: fc-locals-exit + uses-locals? IF + \ ." compiling pop-locals for exit" cr + ['] fc-pop-locals compile, + THEN + ['] exit compile, +; + +: fc-locals-b(;) + uses-locals? IF + \ ." compiling pop-locals for b(;)" cr + ['] fc-pop-locals compile, + THEN + false TO uses-locals? + ['] b(;) execute +; + + +: fc-set-locals-tokens ( -- ) + ['] fc-push-0-locals 1 407 set-token + ['] fc-push-1-locals 1 408 set-token + ['] fc-push-2-locals 1 409 set-token + ['] fc-push-3-locals 1 40a set-token + ['] fc-push-4-locals 1 40b set-token + ['] fc-push-5-locals 1 40c set-token + ['] fc-push-6-locals 1 40d set-token + ['] fc-push-7-locals 1 40e set-token + ['] fc-push-8-locals 1 40f set-token + + ['] fc-local-1-@ 0 410 set-token + ['] fc-local-2-@ 0 411 set-token + ['] fc-local-3-@ 0 412 set-token + ['] fc-local-4-@ 0 413 set-token + ['] fc-local-5-@ 0 414 set-token + ['] fc-local-6-@ 0 415 set-token + ['] fc-local-7-@ 0 416 set-token + ['] fc-local-8-@ 0 417 set-token + + ['] fc-local-1-! 0 418 set-token + ['] fc-local-2-! 0 419 set-token + ['] fc-local-3-! 0 41a set-token + ['] fc-local-4-! 0 41b set-token + ['] fc-local-5-! 0 41c set-token + ['] fc-local-6-! 0 41d set-token + ['] fc-local-7-! 0 41e set-token + ['] fc-local-8-! 0 41f set-token + + ['] fc-locals-exit 1 33 set-token + ['] fc-locals-b(;) 1 c2 set-token +; +fc-set-locals-tokens diff --git a/qemu/roms/SLOF/slof/fs/fcode/tokens.fs b/qemu/roms/SLOF/slof/fs/fcode/tokens.fs new file mode 100644 index 000000000..3efc17e06 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/fcode/tokens.fs @@ -0,0 +1,480 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: fc-abort ." FCode called abort: IP " get-ip . ( ." STACK: " .s ) depth dup 0< IF abort THEN . rdepth . cr abort ; +: fc-0 ." 0(lit): STACK ( S: " depth . ." R: " rdepth . ." ): " depth 0> IF .s THEN 0 ; +: fc-1 ." 1(lit): STACK ( S: " depth . ." R: " rdepth . ." ): " depth 0> IF .s THEN 1 ; + +: parse-1hex 1 hex-decode-unit ; + +\ Adjust functions for accessing MMIO registers. According to IEEE 1275, +\ a bus device can substitute bus-specific implementations of r*@ and r*! +\ for use by its children, e.g. with respect to byte-order. Since PCI is +\ little endian by default, we've got to use the little endian accessor +\ functions for the PCI bus (some FCODE programs are expecting this behavior). +: fc-set-pci-mmio-tokens ( -- ) + ['] rw@-le 0 232 set-token + ['] rw!-le 0 233 set-token + ['] rl@-le 0 234 set-token + ['] rl!-le 0 235 set-token + ['] rx@-le 0 22E set-token + ['] rx!-le 0 22F set-token +; + +\ Set normal MMIO access token behavior: +: fc-set-normal-mmio-tokens ( -- ) + ['] rw@ 0 232 set-token + ['] rw! 0 233 set-token + ['] rl@ 0 234 set-token + ['] rl! 0 235 set-token + ['] rx@ 0 22E set-token + ['] rx! 0 22F set-token +; + +: reset-token-table + FFF 0 DO ['] ferror 0 i set-token LOOP + ; + +reset-token-table + +' end0 0 00 set-token + +\ 01...0F beginning code of 2-byte FCode sequences + +' b(lit) 1 10 set-token + +' b(') 1 11 set-token +' b(") 1 12 set-token +' bbranch 1 13 set-token +' b?branch 1 14 set-token +' b(loop) 1 15 set-token +' b(+loop) 1 16 set-token +' b(do) 1 17 set-token +' b(?do) 1 18 set-token +' i 0 19 set-token +' j 0 1A set-token +' b(leave) 1 1B set-token +' b(of) 1 1C set-token +' execute 0 1D set-token +' + 0 1E set-token +' - 0 1F set-token +' * 0 20 set-token +' / 0 21 set-token +' mod 0 22 set-token +' and 0 23 set-token +' or 0 24 set-token +' xor 0 25 set-token +' invert 0 26 set-token +' lshift 0 27 set-token +' rshift 0 28 set-token +' >>a 0 29 set-token +' /mod 0 2A set-token +' u/mod 0 2B set-token +' negate 0 2C set-token +' abs 0 2D set-token +' min 0 2E set-token +' max 0 2F set-token +' >r 0 30 set-token +' r> 0 31 set-token +' r@ 0 32 set-token +' exit 0 33 set-token +' 0= 0 34 set-token +' 0<> 0 35 set-token +' 0< 0 36 set-token +' 0<= 0 37 set-token +' 0> 0 38 set-token +' 0>= 0 39 set-token +' < 0 3A set-token +' > 0 3B set-token +' = 0 3C set-token +' <> 0 3D set-token +' u> 0 3E set-token +' u<= 0 3F set-token +' u< 0 40 set-token +' u>= 0 41 set-token +' >= 0 42 set-token +' <= 0 43 set-token +' between 0 44 set-token +' within 0 45 set-token +' DROP 0 46 set-token +' DUP 0 47 set-token +' OVER 0 48 set-token +' SWAP 0 49 set-token +' ROT 0 4A set-token +' -ROT 0 4B set-token +' TUCK 0 4C set-token +' nip 0 4D set-token +' pick 0 4E set-token +' roll 0 4F set-token +' ?dup 0 50 set-token +' depth 0 51 set-token +' 2drop 0 52 set-token +' 2dup 0 53 set-token +' 2over 0 54 set-token +' 2swap 0 55 set-token +' 2rot 0 56 set-token +' 2/ 0 57 set-token +' u2/ 0 58 set-token +' 2* 0 59 set-token +' /c 0 5A set-token +' /w 0 5B set-token +' /l 0 5C set-token +' /n 0 5D set-token +' ca+ 0 5E set-token +' wa+ 0 5F set-token +' la+ 0 60 set-token +' na+ 0 61 set-token +' char+ 0 62 set-token +' wa1+ 0 63 set-token +' la1+ 0 64 set-token +' cell+ 0 65 set-token +' chars 0 66 set-token +' /w* 0 67 set-token +' /l* 0 68 set-token +' cells 0 69 set-token +' on 0 6A set-token +' off 0 6B set-token +' +! 0 6C set-token +' @ 0 6D set-token +' fc-l@ 0 6E set-token +' fc-w@ 0 6F set-token +' fc-<w@ 0 70 set-token +' fc-c@ 0 71 set-token +' ! 0 72 set-token +' fc-l! 0 73 set-token +' fc-w! 0 74 set-token +' fc-c! 0 75 set-token +' 2@ 0 76 set-token +' 2! 0 77 set-token +' fc-move 0 78 set-token +' fc-fill 0 79 set-token +' comp 0 7A set-token +' noop 0 7B set-token +' lwsplit 0 7C set-token +' wljoin 0 7D set-token +' lbsplit 0 7E set-token +' bljoin 0 7F set-token +' wbflip 0 80 set-token +' upc 0 81 set-token +' lcc 0 82 set-token +' pack 0 83 set-token +' count 0 84 set-token +' body> 0 85 set-token +' >body 0 86 set-token +' fcode-revision 0 87 set-token +' span 0 88 set-token +' unloop 0 89 set-token +' expect 0 8A set-token +' alloc-mem 0 8B set-token +' free-mem 0 8C set-token +' key? 0 8D set-token +' key 0 8E set-token +' emit 0 8F set-token +' type 0 90 set-token +' (cr 0 91 set-token +' cr 0 92 set-token +' #out 0 93 set-token +' #line 0 94 set-token +' hold 0 95 set-token +' <# 0 96 set-token +' u#> 0 97 set-token +' sign 0 98 set-token +' u# 0 99 set-token +' u#s 0 9A set-token +' u. 0 9B set-token +' u.r 0 9C set-token +' . 0 9D set-token +' .r 0 9E set-token +' .s 0 9F set-token +' base 0 A0 set-token +\ ' convert 0 A1 set-token \ historical, not supported +' $number 0 A2 set-token +' digit 0 A3 set-token +' -1 0 A4 set-token +' 0 0 A5 set-token +' 1 0 A6 set-token +' 2 0 A7 set-token +' 3 0 A8 set-token +' bl 0 A9 set-token +' bs 0 AA set-token +' bell 0 AB set-token +' bounds 0 AC set-token +' here 0 AD set-token +' aligned 0 AE set-token +' wbsplit 0 AF set-token +' bwjoin 0 B0 set-token +' b(<mark) 1 B1 set-token +' b(>resolve) 1 B2 set-token +\ ' set-token-table 0 B3 set-token \ historical, not supported +\ ' set-table 0 B4 set-token \ historical, not supported +' new-token 0 B5 set-token +' named-token 0 B6 set-token +' b(:) 1 B7 set-token +' b(value) 1 B8 set-token +' b(variable) 1 B9 set-token +' b(constant) 1 BA set-token +' b(create) 1 BB set-token +' b(defer) 1 BC set-token +' b(buffer:) 1 BD set-token +' b(field) 1 BE set-token +\ ' b(code) 0 BF set-token \ historical, not supported +' fc-instance 1 C0 set-token +\ ' ferror 0 C1 set-token \ Reserved +' b(;) 1 C2 set-token +' b(to) 1 C3 set-token +' b(case) 1 C4 set-token +' b(endcase) 1 C5 set-token +' b(endof) 1 C6 set-token +' # 0 C7 set-token +' #s 0 C8 set-token +' #> 0 C9 set-token +' external-token 0 CA set-token +' $find 0 CB set-token +' offset16 0 CC set-token +' evaluate 0 CD set-token +\ 0 CE reserved +\ 0 CF reserved +' c, 0 D0 set-token +' w, 0 D1 set-token +' l, 0 D2 set-token +' , 0 D3 set-token +' um* 0 D4 set-token +' um/mod 0 D5 set-token +\ 0 D6 reserved +\ 0 D7 reserved +' d+ 0 D8 set-token +' d- 0 D9 set-token +' get-token 0 DA set-token +' set-token 0 DB set-token +' state 0 DC set-token \ possibly broken +' compile, 0 DD set-token +' behavior 0 DE set-token + +\ Tokens 0xDF to 0xEF are reserved + +' start0 0 F0 set-token +' start1 0 F1 set-token +' start2 0 F2 set-token +' start4 0 F3 set-token + +\ Tokens 0xF4 to 0xFB are reserved + +' ferror 0 FC set-token +' version1 0 FD set-token + +\ ' 4-byte-id 0 FE set-token \ Historical, not supported +' end1 0 FF set-token + +\ 0 100 set-token \ reserved +' dma-alloc 0 101 set-token \ Obsolete +' my-address 0 102 set-token +' my-space 0 103 set-token +\ ' memmap 0 104 set-token \ Obsolete +' free-virtual 0 105 set-token +\ ' >physical 0 106 set-token \ Obsolete + +\ Tokens 0x107 to 0x10e are reserved + +' my-params 0 10f set-token \ Obsolete +' property 0 110 set-token +' encode-int 0 111 set-token +' encode+ 0 112 set-token +' encode-phys 0 113 set-token +' encode-string 0 114 set-token +' encode-bytes 0 115 set-token +' reg 0 116 set-token +' intr 0 117 set-token \ Obsolete +' driver 0 118 set-token \ Obsolete +' model 0 119 set-token +' device-type 0 11A set-token +' parse-2int 0 11B set-token +\ ' is-install 0 11C set-token \ Will be set by framebuffer code +\ ' is-remove 0 11D set-token \ Will be set by framebuffer code +\ ' is-selftest 0 11E set-token \ Will be set by framebuffer code +' new-device 0 11F set-token +' diagnostic-mode? 0 120 set-token +' display-status 0 121 set-token \ Maybe obsolete +' memory-test-suite 0 122 set-token +' group-code 0 123 set-token \ Obsolete +' mask 0 124 set-token +' get-msecs 0 125 set-token +' ms 0 126 set-token +' finish-device 0 127 set-token +' decode-phys 0 128 set-token +\ ' push-package 0 129 set-token \ TODO - from proposal 215 +\ ' pop-package 0 12A set-token \ TODO - from proposal 215 +' interpose 0 12B set-token \ Recommended practice: Interposition + +\ Tokens 0x12C to 0x12F are reserved + +' map-low 0 130 set-token +' sbus-intr>cpu 0 131 set-token \ Obsolete + +\ Tokens 0x132 to 0x14f are reserved + +\ The following tokens will be set by the framebuffer code: +\ ' #lines 0 150 set-token +\ ' #columns 0 151 set-token +\ ' line# 0 152 set-token +\ ' column# 0 153 set-token +\ ' inverse? 0 154 set-token +\ ' inverse-screen? 0 155 set-token +\ ' frame-buffer-busy 0 156 set-token \ Historical, not supported +\ ' draw-character 0 157 set-token +\ ' reset-screen 0 158 set-token +\ ' toggle-cursor 0 159 set-token +\ ' erase-screen 0 15A set-token +\ ' blink-screen 0 15B set-token +\ ' invert-screen 0 15C set-token +\ ' insert-characters 0 15D set-token +\ ' delete-characters 0 15E set-token +\ ' insert-lines 0 15F set-token +\ ' delete-lines 0 160 set-token +\ ' draw-logo 0 161 set-token +\ ' frame-buffer-adr 0 162 set-token +\ ' screen-height 0 163 set-token +\ ' screen-width 0 164 set-token +\ ' window-top 0 165 set-token +\ ' window-left 0 166 set-token +\ ' 0 167 set-token \ Reserved +\ ' foreground-color 0 168 set-token \ From 16-color recommended practice +\ ' background-color 0 169 set-token \ From 16-color recommended practice +\ ' default-font 0 16A set-token +\ ' set-font 0 16B set-token +\ ' char-height 0 16C set-token +\ ' char-width 0 16D set-token +\ ' >font 0 16E set-token +\ ' fontbytes 0 16F set-token + +\ Tokens 0x170 to 0x17C are obsolete fb1 functions +\ Tokens 0x17D to 0x17F are reserved + +\ The following tokens will be set by the framebuffer code, too: +\ ' fb8-draw-character 0 180 set-token +\ ' fb8-reset-screen 0 181 set-token +\ ' fb8-toggle-cursor 0 182 set-token +\ ' fb8-erase-screen 0 183 set-token +\ ' fb8-blink-screen 0 184 set-token +\ ' fb8-invert-screen 0 185 set-token +\ ' fb8-insert-characters 0 186 set-token +\ ' fb8-delete-characters 0 187 set-token +\ ' fb8-insert-lines 0 188 set-token +\ ' fb8-delete-lines 0 189 set-token +\ ' fb8-draw-logo 0 18A set-token +\ ' fb8-install 0 18B set-token + +\ Tokens 0x18C to 0x18F are reserved +\ Tokens 0x190 to 0x196 are obsolete VMEbus tokens +\ Tokens 0x197 to 0x19F are reserved + +\ ' return-buffer 0 1A0 set-token \ Historical, not supported +\ ' xmit-packet 0 1A1 set-token \ Historical, not supported +\ ' poll-packet 0 1A2 set-token \ Historical, not supported +\ 0 1A3 set-token \ reserved +' mac-address 0 1A4 set-token + +\ Tokens 0x1A5 to 0x200 are reserved + +' device-name 0 201 set-token +' my-args 0 202 set-token +' my-self 0 203 set-token +' find-package 0 204 set-token +' open-package 0 205 set-token +' close-package 0 206 set-token +' find-method 0 207 set-token +' call-package 0 208 set-token +' $call-parent 0 209 set-token +' my-parent 0 20A set-token +' ihandle>phandle 0 20B set-token +\ 0 20C set-token \ reserved +' my-unit 0 20D set-token +' $call-method 0 20E set-token +' $open-package 0 20F set-token +' processor-type 0 210 set-token \ Obsolete +' firmware-version 0 211 set-token \ Obsolete +' fcode-version 0 212 set-token \ Obsolete +\ ' alarm 0 213 set-token \ TODO +' (is-user-word) 0 214 set-token +' suspend-fcode 0 215 set-token +' fc-abort 0 216 set-token +' catch 0 217 set-token +' throw 0 218 set-token +\ ' user-abort 0 219 set-token \ TODO +' get-my-property 0 21A set-token +' decode-int 0 21B set-token +' decode-string 0 21C set-token +' get-inherited-property 0 21D set-token +' delete-property 0 21E set-token +' get-package-property 0 21F set-token +' cpeek 0 220 set-token +' wpeek 0 221 set-token +' lpeek 0 222 set-token +' cpoke 0 223 set-token +' wpoke 0 224 set-token +' lpoke 0 225 set-token +' lwflip 0 226 set-token +' lbflip 0 227 set-token +' lbflips 0 228 set-token +\ ' adr-mask 0 229 set-token \ Historical, not supported + +\ Tokens 0x22A to 0x22F are reserved + +' rb@ 0 230 set-token +' rb! 0 231 set-token +fc-set-normal-mmio-tokens \ Set rw@, rw!, rl@, rl!, rx@ and rx! + +' wbflips 0 236 set-token +' lwflips 0 237 set-token +\ ' probe 0 238 set-token \ Obsolete +\ ' probe-virtual 0 239 set-token \ Obsolete +\ 0 23A reserved +' child 0 23B set-token +' peer 0 23C set-token +' next-property 0 23D set-token +' byte-load 0 23E set-token +' set-args 0 23F set-token +' left-parse-string 0 240 set-token + +\ 64-bit extension tokens: +' bxjoin 0 241 set-token +' fc-<l@ 0 242 set-token +' lxjoin 0 243 set-token +' wxjoin 0 244 set-token +' x, 0 245 set-token +' fc-x@ 0 246 set-token +' fc-x! 0 247 set-token +' /x 0 248 set-token +' /x* 0 249 set-token +' xa+ 0 24A set-token +' xa1+ 0 24B set-token +' xbflip 0 24C set-token +' xbflips 0 24D set-token +' xbsplit 0 24E set-token +' xlflip 0 24F set-token +' xlflips 0 250 set-token +' xlsplit 0 251 set-token +' xwflip 0 252 set-token +' xwflips 0 253 set-token +' xwsplit 0 254 set-token + +\ 0 255 RESERVED FCODES +\ ... +\ 0 5FF RESERVED FCODES + +\ 0 600 VENDOR FCODES +\ ... +\ 0 7FF VENDOR FCODES + +\ 0 800 LOCAL FCODES +\ ... +\ 0 FFF LOCAL FCODES + diff --git a/qemu/roms/SLOF/slof/fs/find-hash.fs b/qemu/roms/SLOF/slof/fs/find-hash.fs new file mode 100644 index 000000000..a40ccbd4f --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/find-hash.fs @@ -0,0 +1,77 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +#ifdef HASH_DEBUG +0 value from-hash +0 value not-from-hash +0 value hash-collisions +#endif + +clean-hash + +: hash-find ( str len head -- 0 | link ) + >r 2dup 2dup hash ( str len str len hash R: head ) + dup >r @ dup ( str len str len *hash *hash R: head hash ) + IF ( str len str len *hash R: head hash ) + link>name name>string string=ci ( str len true|false R: head hash ) + dup 0= + IF +#ifdef HASH_DEBUG + hash-collisions 1+ + to hash-collisions +#endif + THEN + ELSE + nip nip ( str len 0 R: head hash ) + THEN + IF \ hash found + 2drop r> @ r> drop ( *hash R: ) +#ifdef HASH_DEBUG + from-hash 1+ to from-hash +#endif + exit + THEN \ hash not found + r> r> swap >r ((find)) ( str len head R: hash=0 ) + dup + IF +#ifdef HASH_DEBUG + not-from-hash 1+ + to not-from-hash +#endif + dup r> ! ( link R: ) + ELSE + r> drop ( 0 R: ) + THEN +; + +: hash-reveal hash off ; + +' hash-reveal to (reveal) +' hash-find to (find) + +#ifdef HASH_DEBUG +\ print out all entries in the hash table +: dump-hash-table ( -- ) + cr + hash-table hash-size 0 DO + dup @ dup 0<> IF + over . s" : " type link>name name>string type cr + ELSE + drop + THEN + cell+ + LOOP drop + s" hash-collisions: " type hash-collisions . cr + s" from-hash: " type from-hash . cr + s" not-from-hash: " type not-from-hash . cr +; +#endif diff --git a/qemu/roms/SLOF/slof/fs/generic-disk.fs b/qemu/roms/SLOF/slof/fs/generic-disk.fs new file mode 100644 index 000000000..0543c890e --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/generic-disk.fs @@ -0,0 +1,68 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Generic disk support + +\ Input: +\ name of device ( e.g. "disk", "cdrom", ... ) +\ dev# + +\ Needs from parent in device tree: +\ dev-read-blocks ( addr block# #blocks phys.lo ... phys.hi -- #read ) +\ block-size +\ max-transfer + +\ Provides: +\ open ( -- okay? ) +\ close ( -- ) +\ read ( addr len -- actual ) +\ seek ( pos.lo pos.hi -- status ) +\ read-blocks ( addr block# #blocks -- #read ) +\ Uses: +\ disk-label package interpose for partition and file systems support +\ deblocker package for byte read support + +( str len phys.lo ... phys.hi -- ) +new-device set-unit ( str len ) + 2dup device-name + s" 0 pci-alias-" 2swap $cat evaluate + s" block" device-type + +\ Requiered interface for deblocker + + s" block-size" $call-parent CONSTANT block-size + s" max-transfer" $call-parent CONSTANT max-transfer + +: read-blocks ( addr block# #blocks -- #read ) + my-unit s" dev-read-blocks" $call-parent +; + +INSTANCE VARIABLE deblocker + +: open ( -- okay? ) + 0 0 s" deblocker" $open-package dup deblocker ! dup IF + s" disk-label" find-package IF + my-args rot interpose + THEN + THEN 0<> ; + +: close ( -- ) + deblocker @ close-package ; + +: seek ( pos.lo pos.hi -- status ) + s" seek" deblocker @ $call-method ; + +: read ( addr len -- actual ) + s" read" deblocker @ $call-method ; + +finish-device diff --git a/qemu/roms/SLOF/slof/fs/graphics.fs b/qemu/roms/SLOF/slof/fs/graphics.fs new file mode 100644 index 000000000..7d5d9306d --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/graphics.fs @@ -0,0 +1,87 @@ +\ ***************************************************************************** +\ * Copyright (c) 2015 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Provide some of the functions that are defined in the +\ "OF Recommended Practice: 8bit Graphics Extension" document + +: draw-rectangle ( adr x y w h -- ) + frame-buffer-adr 0= IF 4drop drop EXIT THEN + 0 ?DO + 4dup drop ( adr x y w adr x y ) + \ calculate offset into framebuffer: ((y + i) * width + x) * depth + i + screen-width * + screen-depth * ( adr x y w adr offs ) + frame-buffer-adr + ( adr x y w adr fb_adr ) + over 3 pick screen-depth * i * + ( adr x y w adr fb_adr src ) + swap 3 pick screen-depth * ( adr x y w adr src fb_adr len ) + rmove \ copy line ( adr x y w adr ) + drop ( adr x y w ) + LOOP + 4drop +; + +: fill-rectangle ( col x y w h -- ) + frame-buffer-adr 0= IF 4drop drop EXIT THEN + 0 ?DO + 4dup drop ( col x y w col x y ) + \ calculate offset into framebuffer: ((y + i) * width + x) * depth + i + screen-width * + screen-depth * ( col x y w col offs ) + frame-buffer-adr + ( col x y w col adr ) + 2 pick screen-depth * 2 pick ( col x y w col adr len col ) + rfill \ draw line ( col x y w col ) + drop ( col x y w ) + LOOP + 4drop +; + +: read-rectangle ( adr x y w h -- ) + frame-buffer-adr 0= IF 4drop drop EXIT THEN + 0 ?DO + 4dup drop ( adr x y w adr x y ) + \ calculate offset into framebuffer: ((y + i) * width + x) * depth + i + screen-width * + screen-depth * ( adr x y w adr offs ) + frame-buffer-adr + ( adr x y w adr fb_adr ) + over 3 pick screen-depth * i * + ( adr x y w adr fb_adr dst ) + 3 pick ( adr x y w adr fb_adr dst w ) + rmove \ copy line ( adr x y w adr ) + drop ( adr x y w ) + LOOP + 4drop +; + +: dimensions ( -- width height ) + screen-width screen-height +; + +\ Initialize a default palette (not a standard command, but useful anyway) +: init-default-palette + \ Grayscale ramp for upper colors + 100 10 DO + i i i i color! + LOOP + \ Standard colors from "16-color Text Extension" specification + 00 00 00 0 color! + 00 00 aa 1 color! + 00 aa 00 2 color! + 00 aa aa 3 color! + aa 00 00 4 color! + aa 00 aa 5 color! + aa 55 00 6 color! + aa aa aa 7 color! + 55 55 55 8 color! + 55 55 ff 9 color! + 55 ff 55 a color! + 55 ff ff b color! + ff 55 55 c color! + ff 55 ff d color! + ff ff 55 e color! + ff ff ff f color! +; diff --git a/qemu/roms/SLOF/slof/fs/history.fs b/qemu/roms/SLOF/slof/fs/history.fs new file mode 100644 index 000000000..2c2c70fe0 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/history.fs @@ -0,0 +1,107 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Create debug section in NVRAM +: debug-init-nvram ( -- ) + nvram-partition-type-debug get-nvram-partition IF + cr ." Could not find debug partition in NVRAM - " + nvram-partition-type-debug s" debug" d# 1024 new-nvram-partition + ABORT" Failed to create DEBUG NVRAM partition" + 2dup erase-nvram-partition drop + ." created." cr + THEN + s" debug-nvram-partition" $2constant +; + +debug-init-nvram + +: debug-add-env ( "name" "value" -- ) debug-nvram-partition 2rot 2rot internal-add-env drop ; +: debug-set-env ( "name" "value" -- ) debug-nvram-partition 2rot 2rot internal-set-env drop ; +: debug-get-env ( "name" -- "value" TRUE | FALSE) debug-nvram-partition 2swap internal-get-env ; + +: debug-get-history-enabled ( -- n ) s" history-enabled?" debug-get-env IF $number IF 0 THEN ELSE 0 THEN ; +: debug-set-history-enabled ( n -- ) (.) s" history-enabled?" 2swap debug-set-env ; + + +debug-get-history-enabled constant nvram-history? + +nvram-history? [IF] + +: history-init-nvram ( -- ) + nvram-partition-type-history get-nvram-partition IF + cr ." Could not find history partition in NVRAM - " + nvram-partition-type-history s" history" d# 2048 new-nvram-partition + ABORT" Failed to create SMS NVRAM partition" + 2dup erase-nvram-partition drop + ." created" cr + THEN + s" history-nvram-partition" $2constant +; + +history-init-nvram + +0 value (history-len) +0 value (history-adr) + +: (history-load-one) ( str len -- len ) + \ 2dup ." loading " type cr + to (history-len) to (history-adr) + /his (history-len) + alloc-mem ( his ) + his-tail 0= IF dup to his-tail THEN + his-head over his>next ! to his-head + his-head his>next @ his>prev his-head swap ! + (history-len) his-head his>len ! + (history-adr) his-head his>buf (history-len) move + (history-len) 1+ +; + +: history-load ( -- ) + history-nvram-partition drop BEGIN dup WHILE + dup rzcount ( part str len ) + dup IF + (history-load-one) + + ELSE + 3drop 0 + THEN + REPEAT + drop +; + +: (history-store-one) ( pos len saddr slen -- FALSE | npos nlen TRUE ) + dup 3 pick < IF \ enough space + dup >r rot >r + \ 2dup ." storing " type cr + bounds DO dup i c@ swap nvram-c! 1+ LOOP + dup 0 swap nvram-c! 1+ + r> r> - 1- true + ELSE + 2drop false + THEN +; + +: history-store ( -- ) + history-nvram-partition erase-nvram-partition drop + history-nvram-partition his-tail BEGIN dup WHILE + dup his>buf over his>len @ + ( position len link saddr slen ) + rot >r (history-store-one) r> + swap IF his>prev @ ELSE drop 0 THEN + REPEAT + 2drop drop +; + +\ redefine "end of SLOF" words to safe history +: reset-all history-store reset-all ; +: reboot history-store reboot ; +: boot history-store boot ; + +[THEN] diff --git a/qemu/roms/SLOF/slof/fs/ide.fs b/qemu/roms/SLOF/slof/fs/ide.fs new file mode 100644 index 000000000..d6f16edd0 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/ide.fs @@ -0,0 +1,612 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +\ +\ 26.06.2007 added: two devices (Master/Slave) per channel + +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +: decode-unit 1 hex-decode-unit ; +: encode-unit 1 hex-encode-unit ; + +0 VALUE >ata \ base address for command-block +0 VALUE >ata1 \ base address for control block + +true VALUE no-timeout \ flag that no timeout occurred + +0c CONSTANT #cdb-bytes \ command descriptor block (12 bytes) +800 CONSTANT atapi-size +200 CONSTANT ata-size + +\ ***************************** +\ Some register access helpers. +\ ***************************** +: ata-ctrl! 2 >ata1 + io-c! ; \ device control reg +: ata-astat@ 2 >ata1 + io-c@ ; \ read alternate status + +: ata-data@ 0 >ata + io-w@ ; \ data reg +: ata-data! 0 >ata + io-w! ; \ data reg +: ata-err@ 1 >ata + io-c@ ; \ error reg +: ata-feat! 1 >ata + io-c! ; \ feature reg +: ata-cnt@ 2 >ata + io-c@ ; \ sector count reg +: ata-cnt! 2 >ata + io-c! ; \ sector count reg +: ata-lbal! 3 >ata + io-c! ; \ lba low reg +: ata-lbal@ 3 >ata + io-c@ ; \ lba low reg +: ata-lbam! 4 >ata + io-c! ; \ lba mid reg +: ata-lbam@ 4 >ata + io-c@ ; \ lba mid reg +: ata-lbah! 5 >ata + io-c! ; \ lba high reg +: ata-lbah@ 5 >ata + io-c@ ; \ lba high reg +: ata-dev! 6 >ata + io-c! ; \ device reg +: ata-dev@ 6 >ata + io-c@ ; \ device reg +: ata-cmd! 7 >ata + io-c! ; \ command reg +: ata-stat@ 7 >ata + io-c@ ; \ status reg + +\ ********************************************************************** +\ ATA / ATAPI Commands specifications: +\ - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) +\ - ATA Packet Interface for CD-ROMs SFF-8020i +\ - ATA/ATAPI Host Adapters Standard (T13/1510D) +\ ********************************************************************** +00 CONSTANT cmd#nop \ ATA and ATAPI +08 CONSTANT cmd#device-reset \ ATAPI only (mandatory) +20 CONSTANT cmd#read-sector \ ATA and ATAPI +90 CONSTANT cmd#execute-device-diagnostic \ ATA and ATAPI +a0 CONSTANT cmd#packet \ ATAPI only (mandatory) +a1 CONSTANT cmd#identify-packet-device \ ATAPI only (mandatory) +ec CONSTANT cmd#identify-device \ ATA and ATAPI + +\ ***************************** +\ Setup Regs for ATA: +\ BAR 0 & 1 : Device 0 +\ BAR 2 & 3 : Device 1 +\ ***************************** +: set-regs ( n -- ) + dup + 01 and \ only Chan 0 or Chan 1 allowed + 3 lshift dup 10 + config-l@ -4 and to >ata + 14 + config-l@ -4 and to >ata1 + 02 ata-ctrl! \ disable interrupts + 02 and + IF + 10 + ELSE + 00 + THEN + ata-dev! +; + +ata-size VALUE block-size +80000 VALUE max-transfer \ Arbitrary, really + +CREATE sector d# 512 allot +CREATE packet-cdb #cdb-bytes allot +CREATE return-buffer atapi-size allot + +scsi-open \ add scsi functions + +\ ******************************** +\ show all ATAPI-registers +\ data-register not read in order +\ to not influence PIO mode +\ ******************************** +: show-regs + cr + cr ." alt. Status: " ata-astat@ . + cr ." Status : " ata-stat@ . + cr ." Device : " ata-dev@ . + cr ." Error-Reg : " ata-err@ . + cr ." Sect-Count : " ata-cnt@ . + cr ." LBA-Low : " ata-lbal@ . + cr ." LBA-Med : " ata-lbam@ . + cr ." LBA-High : " ata-lbah@ . +; + +\ *************************************************** +\ reads ATAPI-Status and displays it if check-bit set +\ *************************************************** +: status-check ( -- ) + ata-stat@ + dup + 01 and \ is 'check' flag set ? + IF + cr + ." - ATAPI-Status: " . + ata-err@ \ retrieve sense code + dup + 60 = \ sense code = 6 ? + IF + ." ( media changed or reset )" \ 'unit attention' + drop \ drop err-reg content + ELSE + dup + ." (Err : " . \ show err-reg content + space + rshift 4 .sense-text \ show text string + 29 emit + THEN + cr + ELSE + drop \ remove unused status + THEN +; + +\ ************************************* +\ Wait for interface ready condition +\ Bit 7 of Status-Register is busy flag +\ new version with abort after 5 sec. +\ ************************************* +: wait-for-ready + get-msecs \ start timer + BEGIN + ata-stat@ 80 and 0<> \ busy flag still set ? + no-timeout and + WHILE \ yes + dup get-msecs swap + - \ calculate timer difference + FFFF AND \ reduce to 65.5 seconds + d# 5000 > \ difference > 5 seconds ? + IF + false to no-timeout + THEN + REPEAT + drop +; + +\ ************************************* +\ wait for specific status bits +\ new version with abort after 5 sec. +\ ************************************* +: wait-for-status ( val mask -- ) + get-msecs \ initial timer value (start) + >r + BEGIN + 2dup \ val mask + ata-stat@ and <> \ expected status ? + no-timeout and \ and no timeout ? + WHILE + get-msecs r@ - \ calculate timer difference + FFFF AND \ mask-off overflow bits + d# 5000 > \ 5 seconds exceeded ? + IF + false to no-timeout \ set global flag + THEN + REPEAT + r> \ clean return stack + 3drop +; + +\ ********************************* +\ remove extra spaces from string end +\ ********************************* +: cut-string ( saddr nul -- ) + swap + over + + swap + 1 rshift \ bytecount -> wordcount + 0 do + /w - + dup ( addr -- addr addr ) + w@ ( addr addr -- addr nuw ) + dup ( addr nuw -- addr nuw nuw ) + 2020 = + IF + drop + 0 + ELSE + LEAVE + THEN + over + w! + LOOP + drop + drop +; + +\ **************************************************** +\ prints model-string received by identify device +\ **************************************************** +: show-model ( dev# chan# -- ) + 2dup + ." CH " . \ channel 0 / 1 + 0= IF ." / MA" \ Master / Slave + ELSE ." / SL" + THEN + swap + 2 * + ." (@" . ." ) : " \ device number + sector 1 + + c@ + 80 AND 0= + IF + ." ATA-Drive " + ELSE + ." ATAPI-Drive " + THEN + + 22 emit \ start string display with " + sector d# 54 + \ string starts 54 bytes from buffer start + dup + d# 40 \ and is 40 chars long + cut-string \ remove all trailing spaces + + BEGIN + dup + w@ + wbflip + wbsplit + dup 0<> \ first char + IF + emit + dup 0<> \ second char + IF + emit + wa1+ \ increment address for next + false + ELSE \ second char = EndOfString + drop + true + THEN + ELSE \ first char = EndOfString + drop + drop + true + THEN + UNTIL \ end of string detected + drop + 22 emit \ end string display + + sector c@ \ get lower byte of first doublet + 80 AND \ check bit 7 + IF + ." (removable media)" + THEN + + sector 1 + + c@ + 80 AND 0= IF \ is this an ATA drive ? + sector d# 120 + \ get word 60 + 61 + rl@-le \ read 32-bit as little endian value + d# 512 \ standard ATA block-size + swap + .capacity-text ( block-size #blocks -- ) + THEN + + sector d# 98 + \ goto word 49 + w@ + wbflip + 200 and 0= IF cr ." ** LBA is not supported " THEN + + sector c@ \ get lower byte of first doublet + 03 AND 01 = \ we use 12-byte packet commands (=00b) + IF + cr ." packet size = 16 ** not supported ! **" + THEN + no-timeout not \ any timeout occurred so far ? + IF + cr ." ** timeout **" + THEN +; + +\ **************************** +\ ATA functions +\ **************************** +: pio-sector ( addr -- ) 100 0 DO ata-data@ + over w! wa1+ LOOP drop ; +: pio-sector ( addr -- ) + wait-for-ready pio-sector ; +: pio-sectors ( n addr -- ) swap 0 ?DO dup pio-sector 200 + LOOP drop ; + +: lba! lbsplit + 0f and 40 or \ always set LBA-mode + LBA (27..24) + ata-dev@ 10 and or \ add current device-bit (DEV) + ata-dev! \ set LBA (27..24) + ata-lbah! \ set LBA (23..16) + ata-lbam! \ set LBA (15..8) + ata-lbal! \ set LBA (7..0) +; + +: read-sectors ( lba count addr -- ) + >r dup >r ata-cnt! lba! 20 ata-cmd! r> r> pio-sectors ; + +: read-sectors ( lba count addr dev-nr -- ) + set-regs ( lba count addr ) \ Set ata regs + BEGIN >r dup 100 > WHILE + over 100 r@ read-sectors + >r 100 + r> 100 - r> 20000 + REPEAT + r> read-sectors +; + +: ata-read-blocks ( addr block# #blocks dev# -- #read ) + swap dup >r swap >r rot r> ( addr block# #blocks dev # R: #blocks ) + read-sectors r> ( R: #read ) +; + +\ ******************************* +\ ATAPI functions +\ preset LBA register with maximum +\ allowed block-size (16-bits) +\ ******************************* +: set-lba ( block-length -- ) + lbsplit ( quad -- b1.lo b2 b3 b4.hi ) + drop \ skip upper two bytes + drop + ata-lbah! + ata-lbam! +; + +\ ******************************************* +\ gets byte-count and reads a block of words +\ from data-register to a buffer +\ ******************************************* +: read-pio-block ( buff-addr -- buff-addr-new ) + ata-lbah@ 8 lshift \ get block length High + ata-lbam@ or \ get block length Low + 1 rshift \ bcount -> wcount + dup + 0> IF \ any data to transfer? + 0 DO \ words to read + dup \ buffer-address + ata-data@ swap w! \ write 16-bits + wa1+ \ address of next entry + LOOP + ELSE + drop ( buff-addr wcount -- buff-addr ) + THEN + wait-for-ready +; + +\ ******************************************** +\ ATAPI support +\ Send a command block (12 bytes) in PIO mode +\ read data if requested +\ ******************************************** +: send-atapi-packet ( req-buffer -- ) + >r ( R: req-buffer ) + atapi-size set-lba \ set regs to length limit + 00 ata-feat! + cmd#packet ata-cmd! \ A0 = ATAPI packet command + 48 C8 wait-for-status ( val mask -- ) \ BSY:0 DRDY:1 DRQ:1 + 6 0 do + packet-cdb i 2 * + \ transfer command block (12 bytes) + w@ + ata-data! \ 6 doublets PIO transfer to device + loop \ copy packet to data-reg + status-check ( -- ) \ status err bit set ? -> display + wait-for-ready ( -- ) \ busy released ? + BEGIN + ata-stat@ 08 and 08 = WHILE \ Data-Request-Bit set ? + r> \ get last target buffer address + read-pio-block \ only if from device requested + >r \ start of next block + REPEAT + r> \ original value + drop \ return clean +; + +: atapi-packet-io ( -- ) + return-buffer atapi-size erase \ clear return buffer + return-buffer send-atapi-packet \ send 'packet-cdb' , get 'return-buffer' +; + + + +\ ******************************** +\ ATAPI packet commands +\ ******************************** + +\ Methods to access atapi disk + +: atapi-test ( -- true|false ) + packet-cdb scsi-build-test-unit-ready \ command-code: 00 + atapi-packet-io ( ) \ send CDB, get return-buffer + ata-stat@ 1 and IF false ELSE true THEN +; + +: atapi-sense ( -- ascq asc sense-key ) + d# 252 packet-cdb scsi-build-request-sense ( alloc-len cdb -- ) + atapi-packet-io ( ) \ send CDB, get return-buffer + return-buffer scsi-get-sense-data ( cdb-addr -- ascq asc sense-key ) +; + +: atapi-read-blocks ( address block# #blocks dev# -- #read-blocks ) + set-regs ( address block# #blocks ) + dup >r ( address block# #blocks ) + packet-cdb scsi-build-read-10 ( address block# #blocks cdb -- ) + send-atapi-packet ( address -- ) + r> \ return requested number of blocks +; + +\ *************************************** +\ read capacity of drive medium +\ use SCSI-Support Package +\ *************************************** +: atapi-read-capacity ( -- ) + packet-cdb scsi-build-read-cap-10 \ fill block with command + atapi-packet-io ( ) \ send CDB, get return-buffer + return-buffer scsi-get-capacity-10 ( cdb -- block-size #blocks ) + .capacity-text ( block-size #blocks -- ) + status-check ( -- ) +; + +\ *************************************** +\ read capacity of drive medium +\ use SCSI-Support Package +\ *************************************** +: atapi-read-capacity-ext ( -- ) + packet-cdb scsi-build-read-cap-16 \ fill block with command + atapi-packet-io ( ) \ send CDB, get return-buffer + return-buffer scsi-get-capacity-16 ( cdb -- block-size #blocks ) + .capacity-text ( block-size #blocks -- ) + status-check ( -- ) +; + + +\ *********************************************** +\ wait until media in drive is ready ( max 5 sec) +\ *********************************************** +: wait-for-media-ready ( -- true|false ) + get-msecs \ initial timer value (start) + >r + BEGIN + atapi-test \ unit ready? false if not + not + no-timeout and + WHILE + atapi-sense ( -- ascq asc sense-key ) + 02 = \ sense key 2 = media error + IF \ check add. sense code + 3A = \ asc: device not ready ? + IF + false to no-timeout + ." empty (" . 29 emit \ show asc qualifier + ELSE + drop \ discard asc qualifier + THEN \ medium not present, abort waiting + ELSE + drop \ discard asc + drop \ discard ascq + THEN + get-msecs r@ - \ calculate timer difference + FFFF AND \ mask-off overflow bits + d# 5000 > \ 5 seconds exceeded ? + IF + false to no-timeout \ set global flag + THEN + REPEAT + r> + drop + no-timeout +; + +\ ****************************************************** +\ Method pointer for read-blocks methods +\ controller implements 2 channels (primary / secondary) +\ for 2 devices each (master / slasve) +\ ****************************************************** +\ 2 channels (primary/secondary) per controller +2 CONSTANT #chan + +\ 2 devices (master/slave) per channel +2 CONSTANT #dev + +\ results in a total of devices +\ connected to a controller with +\ two separate channels (4) +: #totaldev #dev #chan * ; + +CREATE read-blocks-xt #totaldev cells allot read-blocks-xt #totaldev cells erase + +\ Execute read-blocks of device +: dev-read-blocks ( address block# #blocks dev# -- #read-blocks ) + dup cells read-blocks-xt + @ execute +; + +\ ********************************************************** +\ Read device type +\ Signature ATAPI ATA +\ --------------------------------------------- +\ Sector Count 01h 01h +\ Sector Number 01h 01h +\ Cylinder Low 14h 00h +\ Cylinder High EBh 00h +\ Device/Head 00h or 10h 00h or 01h +\ see also ATA/ATAPI errata at: +\ http://suif.stanford.edu/~csapuntz/blackmagic.html +\ ********************************************************** +: read-ident ( -- true|false ) + false + 00 ata-lbal! \ clear previous signature + 00 ata-lbam! + 00 ata-lbah! + cmd#identify-device ata-cmd! wait-for-ready \ first try ATA, ATAPI aborts command + ata-stat@ CF and 48 = + IF + drop true \ cmd accepted, this is a ATA + d# 512 set-lba \ set LBA to sector-length + ELSE \ ATAPI sends signature instead + ata-lbam@ 14 = IF \ cylinder low = 14 ? + ata-lbah@ EB = IF \ cylinder high = EB ? + cmd#device-reset ata-cmd! wait-for-ready \ only supported by ATAPI + cmd#identify-packet-device ata-cmd! wait-for-ready \ first try ata + ata-stat@ CF and 48 = IF + drop true \ replace flag + THEN + THEN + THEN + THEN + dup IF + ata-stat@ 8 AND IF \ data requested (as expected) ? + sector read-pio-block + drop \ discard address end + ELSE + drop false + THEN + THEN + + no-timeout not IF \ check without any timeout ? + drop + false \ no, detection discarded + THEN +; + +scsi-close \ remove scsi commands from word list + + +\ ************************************************* +\ Init controller ( chan 0 and 1 ) +\ device 0 (= master) and device 1 ( = slave) +\ #dev #chan Dev-ID +\ ---------------------- +\ 0 0 0 Master of Channel 0 +\ 0 1 1 Master of Channel 1 +\ 1 0 2 Slave of Channel 0 +\ 1 1 3 Slave of Channel 1 +\ ************************************************* +: find-disks ( -- ) + #chan 0 DO \ check 2 channels (primary & secondary) + #dev 0 DO \ check 2 devices per channel (master / slave) + i 2 * j + + set-regs \ set base address and dev-register for register access + ata-stat@ 7f and 7f <> \ Check, if device is connected + IF + true to no-timeout \ preset timeout-flag + read-ident ( -- true|false ) + IF + i j show-model \ print manufacturer + device string + sector 1+ c@ C0 and 80 = \ Check for ata or atapi + IF + wait-for-media-ready \ wait up to 5 sec if not ready + no-timeout and + IF + atapi-read-capacity + atapi-size to block-size \ ATAPI: 2048 bytes + 80000 to max-transfer + ['] atapi-read-blocks i 2 * j + cells read-blocks-xt + ! + s" cdrom" strdup i 2 * j + s" generic-disk.fs" included + ELSE + ." -" \ show hint for not registered + THEN + ELSE + ata-size to block-size \ ATA: 512 bytes + 80000 to max-transfer + ['] ata-read-blocks i 2 * j + cells read-blocks-xt + ! + s" disk" strdup i 2 * j + s" generic-disk.fs" included + THEN + cr + THEN + THEN + i 2 * j + 200 + cp + LOOP + LOOP +; + +find-disks + diff --git a/qemu/roms/SLOF/slof/fs/instance.fs b/qemu/roms/SLOF/slof/fs/instance.fs new file mode 100644 index 000000000..9e5c9215e --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/instance.fs @@ -0,0 +1,193 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Support for device node instances. + +0 VALUE my-self + +400 CONSTANT max-instance-size + +STRUCT + /n FIELD instance>node + /n FIELD instance>parent + /n FIELD instance>args + /n FIELD instance>args-len + /n FIELD instance>size + /n FIELD instance>#units + /n FIELD instance>unit1 \ For instance-specific "my-unit" + /n FIELD instance>unit2 + /n FIELD instance>unit3 + /n FIELD instance>unit4 +CONSTANT /instance-header + +: >instance ( offset -- myself+offset ) + my-self 0= ABORT" No instance!" + dup my-self instance>size @ >= ABORT" Instance access out of bounds!" + my-self + +; + +: (create-instance-var) ( initial-value -- ) + get-node + dup node>instance-size @ cell+ max-instance-size + >= ABORT" Instance is bigger than max-instance-size!" + dup node>instance-template @ ( iv phandle tmp-ih ) + swap node>instance-size dup @ ( iv tmp-ih *instance-size instance-size ) + dup , \ compile current instance ptr + swap 1 cells swap +! ( iv tmp-ih instance-size ) + + ! +; + +: create-instance-var ( "name" initial-value -- ) + CREATE (create-instance-var) PREVIOUS +; + +: (create-instance-buf) ( buffersize -- ) + aligned \ align size to multiples of cells + dup get-node node>instance-size @ + ( buffersize' newinstancesize ) + max-instance-size > ABORT" Instance is bigger than max-instance-size!" + get-node node>instance-template @ get-node node>instance-size @ + + over erase \ clear according to IEEE 1275 + get-node node>instance-size @ ( buffersize' old-instance-size ) + dup , \ compile current instance ptr + + get-node node>instance-size ! \ store new size +; + +: create-instance-buf ( "name" buffersize -- ) + CREATE (create-instance-buf) PREVIOUS +; + +VOCABULARY instance-words ALSO instance-words DEFINITIONS + +: VARIABLE 0 create-instance-var DOES> [ here ] @ >instance ; +: VALUE create-instance-var DOES> [ here ] @ >instance @ ; +: DEFER 0 create-instance-var DOES> [ here ] @ >instance @ execute ; +: BUFFER: create-instance-buf DOES> [ here ] @ >instance ; + +PREVIOUS DEFINITIONS + +\ Save XTs of the above instance-words (put on the stack with "[ here ]") +CONSTANT <instancebuffer> +CONSTANT <instancedefer> +CONSTANT <instancevalue> +CONSTANT <instancevariable> + +\ check whether a value or a defer word is an +\ instance word: It must be a CREATE word and +\ the DOES> part must do >instance as first thing + +: (instance?) ( xt -- xt true|false ) + dup @ <create> = IF + dup cell+ @ cell+ @ ['] >instance = + ELSE + false + THEN +; + +\ This word does instance values in compile mode. +\ It corresponds to DOTO from engine.in +: (doito) ( value R:*CFA -- ) + r> cell+ dup >r + @ cell+ cell+ @ >instance ! +; +' (doito) CONSTANT <(doito)> + +: to ( value wordname<> -- ) + ' (instance?) + state @ IF + \ compile mode handling normal or instance value + IF ['] (doito) ELSE ['] DOTO THEN + , , EXIT + THEN + IF + cell+ cell+ @ >instance ! \ interp mode instance value + ELSE + cell+ ! \ interp mode normal value + THEN +; IMMEDIATE + +: behavior ( defer-xt -- contents-xt ) + dup cell+ @ <instancedefer> = IF \ Is defer-xt an INSTANCE DEFER ? + 2 cells + @ >instance @ + ELSE + behavior + THEN +; + +: INSTANCE ALSO instance-words ; + +: my-parent my-self instance>parent @ ; +: my-args my-self instance>args 2@ swap ; + +\ copy args from original instance to new created +: set-my-args ( old-addr len -- ) + dup IF \ IF len > 0 ( old-addr len ) + dup alloc-mem \ | allocate space for new args ( old-addr len new-addr ) + 2dup my-self instance>args 2! \ | write into instance struct ( old-addr len new-addr ) + swap move \ | and copy the args ( ) + ELSE \ ELSE ( old-addr len ) + my-self instance>args 2! \ | set new args to zero, too ( ) + THEN \ FI +; + +\ Current node has already been set, when this is called. +: create-instance-data ( -- instance ) + get-node dup node>instance-template @ ( phandle instance-template ) + swap node>instance-size @ ( instance-template instance-size ) + dup >r + dup alloc-mem dup >r swap move r> ( instance ) + dup instance>size r> swap ! \ Store size for destroy-instance + dup instance>#units 0 swap ! \ Use node unit by default +; +: create-instance ( -- ) + my-self create-instance-data + dup to my-self instance>parent ! + get-node my-self instance>node ! +; + +: destroy-instance ( instance -- ) + dup instance>args @ ?dup IF \ Free instance args? + over instance>args-len @ free-mem + THEN + dup instance>size @ free-mem +; + +: ihandle>phandle ( ihandle -- phandle ) + dup 0= ABORT" no current instance" instance>node @ +; + +: push-my-self ( ihandle -- ) r> my-self >r >r to my-self ; +: pop-my-self ( -- ) r> r> to my-self >r ; +: call-package push-my-self execute pop-my-self ; +: $call-static ( ... str len node -- ??? ) +\ cr ." call for " 3dup -rot type ." on node " . + find-method IF execute ELSE -1 throw THEN +; + +: $call-my-method ( str len -- ) + my-self ihandle>phandle $call-static +; + +: $call-method ( str len ihandle -- ) + push-my-self + ['] $call-my-method CATCH ?dup IF + pop-my-self THROW + THEN + pop-my-self +; + +0 VALUE calling-child + +: $call-parent + my-self ihandle>phandle TO calling-child + my-parent $call-method + 0 TO calling-child +; diff --git a/qemu/roms/SLOF/slof/fs/little-endian.fs b/qemu/roms/SLOF/slof/fs/little-endian.fs new file mode 100644 index 000000000..f2e4e8d42 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/little-endian.fs @@ -0,0 +1,77 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +deadbeef here l! +here c@ de = CONSTANT ?bigendian +here c@ ef = CONSTANT ?littleendian + + +?bigendian [IF] + +: l!-le >r lbflip r> l! ; +: l@-le l@ lbflip ; + +: w!-le >r wbflip r> w! ; +: w@-le w@ wbflip ; + +: rx!-le >r xbflip r> rx! ; +: rx@-le rx@ xbflip ; + +: rl!-le >r lbflip r> rl! ; +: rl@-le rl@ lbflip ; + +: rw!-le >r wbflip r> rw! ; +: rw@-le rw@ wbflip ; + +: l!-be l! ; +: l@-be l@ ; + +: w!-be w! ; +: w@-be w@ ; + +: rl!-be rl! ; +: rl@-be rl@ ; + +: rw!-be rw! ; +: rw@-be rw@ ; + + +[ELSE] + +: l!-le l! ; +: l@-le l@ ; + +: w!-le w! ; +: w@-le w@ ; + +: rx!-le rx! ; +: rx@-le rx@ ; + +: rl!-le rl! ; +: rl@-le rl@ ; + +: rw!-le rw! ; +: rw@-le rw@ ; + +: l!-be >r lbflip r> l! ; +: l@-be l@ lbflip ; + +: w!-be >r wbflip r> w! ; +: w@-be w@ wbflip ; + +: rl!-be >r lbflip r> rl! ; +: rl@-be rl@ lbflip ; + +: rw!-be >r wbflip r> rw! ; +: rw@-be rw@ wbflip ; + +[THEN] diff --git a/qemu/roms/SLOF/slof/fs/loaders.fs b/qemu/roms/SLOF/slof/fs/loaders.fs new file mode 100644 index 000000000..276ba6bca --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/loaders.fs @@ -0,0 +1,94 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ \\\\\\\\\\\\\\ Global Data +CREATE bootdevice 2 cells allot bootdevice 2 cells erase +CREATE bootargs 2 cells allot bootargs 2 cells erase +CREATE load-list 2 cells allot load-list 2 cells erase + +: start-elf ( arg len entry -- ) + msr@ 7fffffffffffffff and 2000 or ciregs >srr1 ! call-client +; + +: start-elf64 ( arg len entry r2 -- ) + msr@ 2000 or ciregs >srr1 ! + ciregs >r2 ! + call-client \ entry point is pointer to .opd +; + +: set-bootpath + s" disk" find-alias + dup IF ELSE drop s" boot-device" evaluate find-alias THEN + dup IF strdup ELSE 0 THEN + encode-string s" bootpath" set-chosen +; + +: set-netbootpath + s" net" find-alias + ?dup IF strdup encode-string s" bootpath" set-chosen THEN +; + +: set-bootargs + skipws 0 parse dup 0= IF + 2drop s" boot-file" evaluate + THEN + encode-string s" bootargs" set-chosen +; + +: .(client-exec) ( arg len -- rc ) + s" snk" romfs-lookup 0<> IF + \ Load SNK client 15 MiB after Paflof... FIXME: Hard-coded offset is ugly! + paflof-start f00000 + + elf-load-file-to-addr drop \ FIXME - check this for LE, currently its BE only + dup @ swap 8 + @ \ populate entry r2 + start-elf64 client-data + ELSE + 2drop false + THEN +; +' .(client-exec) to (client-exec) + +: .client-exec ( arg len -- rc ) set-bootargs (client-exec) ; +' .client-exec to client-exec + +: netflash ( -- rc ) s" netflash 2000000 " (parse-line) $cat set-netbootpath + client-exec +; + +: netsave ( "addr len {filename}[,params]" -- rc ) + (parse-line) dup 0> IF + s" netsave " 2swap $cat set-netbootpath client-exec + ELSE + cr + ." Usage: netsave addr len [bootp|dhcp,]filename[,siaddr][,ciaddr][,giaddr][,bootp-retries][,tftp-retries][,use_ci]" + cr 2drop + THEN +; + +: ping ( "{device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]}" -- ) + my-self >r current-node @ >r \ Save my-self + (parse-line) open-dev dup IF + dup to my-self dup ihandle>phandle set-node + dup + s" ping" rot ['] $call-method CATCH IF + cr + ." Not a pingable device" + cr 3drop + THEN + swap close-dev + ELSE + cr + ." Usage: ping device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]" + cr drop + THEN + r> set-node r> to my-self \ Restore my-self +; diff --git a/qemu/roms/SLOF/slof/fs/logging.fs b/qemu/roms/SLOF/slof/fs/logging.fs new file mode 100644 index 000000000..002c48091 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/logging.fs @@ -0,0 +1,45 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Words to write to nvram log + +defer nvramlog-write-byte + +: .nvramlog-write-byte ( byte -- ) +#if defined(DISABLE_NVRAM) || defined(RTAS_NVRAM) + drop +#else + 0 1 asm-cout +#endif +; + +' .nvramlog-write-byte to nvramlog-write-byte + +: nvramlog-write-string ( str len -- ) + dup 0> IF + 0 DO dup c@ + nvramlog-write-byte char+ LOOP + ELSE + drop + THEN drop ; + +: nvramlog-write-number ( number format -- ) + 0 swap <# 0 ?DO # LOOP #> + nvramlog-write-string ; + +: nvramlog-write-string-cr ( str len -- ) + nvramlog-write-string + a nvramlog-write-byte d nvramlog-write-byte ; + +\ as long as dual-emit is enabled +\ the string is written into NVRAM as well!! +: log-string ( str len -- ) type ; diff --git a/qemu/roms/SLOF/slof/fs/node.fs b/qemu/roms/SLOF/slof/fs/node.fs new file mode 100644 index 000000000..22bf77b6f --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/node.fs @@ -0,0 +1,766 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Device nodes. + +false VALUE debug-find-component? + +VARIABLE device-tree +VARIABLE current-node +: get-node current-node @ dup 0= ABORT" No active device tree node" ; + +STRUCT + cell FIELD node>peer + cell FIELD node>parent + cell FIELD node>child + cell FIELD node>properties + cell FIELD node>words + cell FIELD node>instance-template + cell FIELD node>instance-size + cell FIELD node>space? + cell FIELD node>space + cell FIELD node>addr1 + cell FIELD node>addr2 + cell FIELD node>addr3 +END-STRUCT + +: find-method ( str len phandle -- false | xt true ) + node>words @ voc-find dup IF link> true THEN ; + +\ Instances. +#include "instance.fs" + +: create-node ( parent -- new ) + max-instance-size alloc-mem ( parent instance-mem ) + dup max-instance-size erase >r ( parent R: instance-mem ) + align wordlist >r wordlist >r ( parent R: instance-mem wl wl ) + here ( parent new R: instance-mem wl wl ) + 0 , swap , 0 , \ Set node>peer, node>parent & node>child + r> , r> , \ Set node>properties & node>words to wl + r> , /instance-header , \ Set instance-template & instance-size + FALSE , 0 , \ Set node>space? and node>space + 0 , 0 , 0 , \ Set node>addr* +; + +: peer node>peer @ ; +: parent node>parent @ ; +: child node>child @ ; +: peer dup IF peer ELSE drop device-tree @ THEN ; + + +: link ( new head -- ) \ link a new node at the end of a linked list + BEGIN dup @ WHILE @ REPEAT ! ; +: link-node ( parent child -- ) + swap dup IF node>child link ELSE drop device-tree ! THEN ; + +\ Set a node as active node. +: set-node ( phandle -- ) + current-node @ IF previous THEN + dup current-node ! + ?dup IF node>words @ also context ! THEN + definitions ; +: get-parent get-node parent ; + + +: new-node ( -- phandle ) \ active node becomes new node's parent; + \ new node becomes active node +\ XXX: change to get-node, handle root node creation specially + current-node @ dup create-node + tuck link-node dup set-node ; + +: finish-node ( -- ) + \ TODO: maybe resize the instance template buffer here (or in finish-device)? + get-node parent set-node +; + +: device-end ( -- ) 0 set-node ; + +\ Properties. +CREATE $indent 100 allot VARIABLE indent 0 indent ! +#include "property.fs" + +\ Unit address. +: #address-cells s" #address-cells" rot parent get-property + ABORT" parent doesn't have a #address-cells property!" + decode-int nip nip +; + +\ my-#address-cells returns the #address-cells property of the parent node. +\ child-#address-cells returns the #address-cells property of the current node. + +\ This is confusing in several ways: Remember that a node's address is always +\ described in the parent's address space, thus the parent's property is taken +\ into regard, rather than the own. + +\ Also, an address-cell here is always a 32bit cell, no matter whether the +\ "real" cell size is 32bit or 64bit. + +: my-#address-cells ( -- #address-cells ) + get-node #address-cells +; + +: child-#address-cells ( -- #address-cells ) + s" #address-cells" get-node get-property + ABORT" node doesn't have a #address-cells property!" + decode-int nip nip +; + +: child-#size-cells ( -- #address-cells ) + s" #size-cells" get-node get-property + ABORT" node doesn't have a #size-cells property!" + decode-int nip nip +; + +: encode-phys ( phys.hi ... phys.low -- prop len ) + encode-first? IF encode-start ELSE here 0 THEN + my-#address-cells 0 ?DO rot encode-int+ LOOP +; + +: encode-child-phys ( phys.hi ... phys.low -- prop len ) + encode-first? IF encode-start ELSE here 0 THEN + child-#address-cells 0 ?DO rot encode-int+ LOOP +; + +: encode-child-size ( size.hi ... size.low -- prop len ) + encode-first? IF encode-start ELSE here 0 THEN + child-#size-cells 0 ?DO rot encode-int+ LOOP +; + +: decode-phys + my-#address-cells BEGIN dup WHILE 1- >r decode-int r> swap >r REPEAT drop + my-#address-cells BEGIN dup WHILE 1- r> swap REPEAT drop ; +: decode-phys-and-drop + my-#address-cells BEGIN dup WHILE 1- >r decode-int r> swap >r REPEAT 3drop + my-#address-cells BEGIN dup WHILE 1- r> swap REPEAT drop ; +: reg >r encode-phys r> encode-int+ s" reg" property ; + + +: >space node>space @ ; +: >space? node>space? @ ; +: >address dup >r #address-cells dup 3 > IF r@ node>addr3 @ swap THEN + dup 2 > IF r@ node>addr2 @ swap THEN + 1 > IF r@ node>addr1 @ THEN r> drop ; +: >unit dup >r >address r> >space ; + +: (my-phandle) ( -- phandle ) + my-self ?dup IF + ihandle>phandle + ELSE + get-node dup 0= ABORT" no active node" + THEN +; + +: my-space ( -- phys.hi ) + (my-phandle) >space +; +: my-address (my-phandle) >address ; + +\ my-unit returns the unit address of the current _instance_ - that means +\ it returns the same values as my-space and my-address together _or_ it +\ returns a unit address that has been set manually while opening the node. +: my-unit + my-self instance>#units @ IF + 0 my-self instance>#units @ 1- DO + my-self instance>unit1 i cells + @ + -1 +LOOP + ELSE + my-self ihandle>phandle >unit + THEN +; + +\ Return lower 64 bit of address +: my-unit-64 ( -- phys.lo+1|phys.lo ) + my-unit ( phys.lo ... phys.hi ) + (my-phandle) #address-cells ( phys.lo ... phys.hi #ad-cells ) + CASE + 1 OF EXIT ENDOF + 2 OF lxjoin EXIT ENDOF + 3 OF drop lxjoin EXIT ENDOF + dup OF 2drop lxjoin EXIT ENDOF + ENDCASE +; + +: set-space get-node dup >r node>space ! true r> node>space? ! ; +: set-address my-#address-cells 1 ?DO + get-node node>space i cells + ! LOOP ; +: set-unit set-space set-address ; +: set-unit-64 ( phys.lo|phys.hi -- ) + my-#address-cells 2 <> IF + ." set-unit-64: #address-cells <> 2 " abort + THEN + xlsplit set-unit +; + +\ Never ever use this in actual code, only when debugging interactively. +\ Thank you. +: set-args ( arg-str len unit-str len -- ) + s" decode-unit" get-parent $call-static set-unit set-my-args +; + +: $cat-unit + dup parent 0= IF drop EXIT THEN + dup >space? not IF drop EXIT THEN + dup >r >unit s" encode-unit" r> parent $call-static + dup IF + dup >r here swap move s" @" $cat here r> $cat + ELSE + 2drop + THEN +; + +: $cat-instance-unit + dup parent 0= IF drop EXIT THEN + \ No instance unit, use node unit + dup instance>#units @ 0= IF + ihandle>phandle $cat-unit + EXIT + THEN + dup >r push-my-self + ['] my-unit CATCH IF pop-my-self r> drop EXIT THEN + pop-my-self + s" encode-unit" + r> ihandle>phandle parent + $call-static + dup IF + dup >r here swap move s" @" $cat here r> $cat + ELSE + 2drop + THEN +; + +\ Getting basic info about a node. +: node>name dup >r s" name" rot get-property IF r> (u.) ELSE 1- r> drop THEN ; +: node>qname dup node>name rot ['] $cat-unit CATCH IF drop THEN ; +: node>path + here 0 rot + BEGIN dup WHILE dup parent REPEAT + 2drop + dup 0= IF [char] / c, THEN + BEGIN + dup + WHILE + [char] / c, node>qname here over allot swap move + REPEAT + drop here 2dup - allot over - +; + +: interposed? ( ihandle -- flag ) + \ We cannot actually detect if an instance is interposed; instead, we look + \ if an instance is part of the "normal" chain that would be opened by + \ open-dev and friends, if there were no interposition. + dup instance>parent @ dup 0= IF 2drop false EXIT THEN + ihandle>phandle swap ihandle>phandle parent <> ; + +: instance>qname + dup >r interposed? IF s" %" ELSE 0 0 THEN + r@ dup ihandle>phandle node>name + rot ['] $cat-instance-unit CATCH IF drop THEN + $cat r> instance>args 2@ swap + dup IF 2>r s" :" $cat 2r> $cat ELSE 2drop THEN +; + +: instance>qpath \ With interposed nodes. + here 0 rot BEGIN dup WHILE dup instance>parent @ REPEAT 2drop + dup 0= IF [char] / c, THEN + BEGIN dup WHILE [char] / c, instance>qname here over allot swap move + REPEAT drop here 2dup - allot over - ; +: instance>path \ Without interposed nodes. + here 0 rot BEGIN dup WHILE + dup interposed? 0= IF dup THEN instance>parent @ REPEAT 2drop + dup 0= IF [char] / c, THEN + BEGIN dup WHILE [char] / c, instance>qname here over allot swap move + REPEAT drop here 2dup - allot over - ; + +: .node node>path type ; +: pwd get-node .node ; + +: .instance instance>qpath type ; +: .chain dup instance>parent @ ?dup IF recurse THEN + cr dup . instance>qname type ; + + +\ Alias helper +defer find-node +: set-alias ( alias-name len device-name len -- ) + encode-string + 2swap s" /aliases" find-node ?dup IF + set-property + ELSE + 4drop + THEN +; + +: find-alias ( alias-name len -- false | dev-path len ) + s" /aliases" find-node dup IF + get-property 0= IF 1- dup 0= IF nip THEN ELSE false THEN + THEN +; + +: .alias ( alias-name len -- ) + find-alias dup IF type ELSE ." no alias available" THEN ; + +: (.print-alias) ( lfa -- ) + link> dup >name name>string + \ Don't print name property + 2dup s" name" string=ci IF 2drop drop + ELSE cr type space ." : " execute type + THEN ; + +: (.list-alias) ( phandle -- ) + node>properties @ cell+ @ BEGIN dup WHILE dup (.print-alias) @ REPEAT drop ; + +: list-alias ( -- ) + s" /aliases" find-node dup IF (.list-alias) THEN ; + +\ return next available name for aliasing or +\ false if more than MAX-ALIAS aliases found +8 CONSTANT MAX-ALIAS +1 VALUE alias-ind +: get-next-alias ( $alias-name -- $next-alias-name|FALSE ) + 2dup find-alias IF + drop + 1 TO alias-ind + BEGIN + 2dup alias-ind $cathex 2dup find-alias + WHILE + drop 2drop + alias-ind 1 + TO alias-ind + alias-ind MAX-ALIAS = IF + 2drop FALSE EXIT + THEN + REPEAT + strdup 2swap 2drop + THEN +; + +: devalias ( "{alias-name}<>{device-specifier}<cr>" -- ) + parse-word parse-word dup IF set-alias + ELSE 2drop dup IF .alias + ELSE 2drop list-alias THEN THEN ; + +\ sub-alias does a single iteration of an alias at the beginning od dev path +\ expression. de-alias will repeat this until all indirect alising is resolved +: sub-alias ( arg-str arg-len -- arg' len' | false ) + 2dup + 2dup [char] / findchar ?dup IF ELSE 2dup [char] : findchar THEN + ( a l a l [p] -1|0 ) IF nip dup ELSE 2drop 0 THEN >r + ( a l l p -- R:p | a l -- R:0 ) + find-alias ?dup IF ( a l a' p' -- R:p | a' l' -- R:0 ) + r@ IF + 2swap r@ - swap r> + swap $cat strdup ( a" l-p+p' -- ) + ELSE + ( a' l' -- R:0 ) r> drop ( a' l' -- ) + THEN + ELSE + ( a l -- R:p | -- R:0 ) r> IF 2drop THEN + false ( 0 -- ) + THEN +; + +: de-alias ( arg-str arg-len -- arg' len' ) + BEGIN + over c@ [char] / <> dup IF drop 2dup sub-alias ?dup THEN + WHILE + 2swap 2drop + REPEAT +; + + +\ Display the device tree. +: +indent ( not-last? -- ) + IF s" | " ELSE s" " THEN $indent indent @ + swap move 4 indent +! ; +: -indent ( -- ) -4 indent +! ; + +: ls-phandle ( node -- ) . ." : " ; + +: ls-node ( node -- ) + cr dup ls-phandle + $indent indent @ type + dup peer IF ." |-- " ELSE ." +-- " THEN + node>qname type +; + +: (ls) ( node -- ) + child BEGIN dup WHILE dup ls-node dup child IF + dup peer +indent dup recurse -indent THEN peer REPEAT drop ; + +: ls ( -- ) + get-node cr + dup ls-phandle + dup node>path type + (ls) + 0 indent ! +; + +: show-devs ( {device-specifier}<eol> -- ) + skipws 0 parse dup IF de-alias ELSE 2drop s" /" THEN ( str len ) + find-node dup 0= ABORT" No such device path" (ls) +; + + +VARIABLE interpose-node +2VARIABLE interpose-args +: interpose ( arg len phandle -- ) interpose-node ! interpose-args 2! ; + + +0 VALUE user-instance-#units +CREATE user-instance-units 4 cells allot + +\ Copy the unit information (specified by the user) that we've found during +\ "find-component" into the current instance data structure +: copy-instance-unit ( -- ) + user-instance-#units IF + user-instance-#units my-self instance>#units ! + user-instance-units my-self instance>unit1 user-instance-#units cells move + 0 to user-instance-#units + THEN +; + + +: open-node ( arg len phandle -- ihandle|0 ) + current-node @ >r my-self >r \ Save current node and instance + set-node create-instance set-my-args + copy-instance-unit + \ Execute "open" method if available, and assume default of + \ success (=TRUE) for nodes without open method: + s" open" get-node find-method IF execute ELSE TRUE THEN + 0= IF + my-self destroy-instance 0 to my-self + THEN + my-self ( ihandle|0 ) + r> to my-self r> set-node \ Restore current node and instance + \ Handle interposition: + interpose-node @ IF + my-self >r to my-self + interpose-args 2@ interpose-node @ + interpose-node off recurse + r> to my-self + THEN +; + +: close-node ( ihandle -- ) + my-self >r to my-self + s" close" ['] $call-my-method CATCH IF 2drop THEN + my-self destroy-instance r> to my-self ; + +: close-dev ( ihandle -- ) + my-self >r to my-self + BEGIN my-self WHILE my-parent my-self close-node to my-self REPEAT + r> to my-self ; + +: new-device ( -- ) + my-self new-node ( parent-ihandle phandle ) + node>instance-template @ ( parent-ihandle ihandle ) + dup to my-self ( parent-ihanlde ihandle ) + instance>parent ! + get-node my-self instance>node ! + max-instance-size my-self instance>size ! +; + +: finish-device ( -- ) + \ Set unit address to first entry of reg property if it has not been set yet + get-node >space? 0= IF + s" reg" get-node get-property 0= IF + decode-int set-space 2drop + THEN + THEN + finish-node my-parent to my-self +; + +\ Set the instance template as current instance for extending it +\ (i.e. to be able to declare new INSTANCE VARIABLEs etc. there) +: extend-device ( phandle -- ) + my-self >r + dup set-node + node>instance-template @ + dup to my-self + r> swap instance>parent ! +; + +: split ( str len char -- left len right len ) + >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; +: generic-decode-unit ( str len ncells -- addr.lo ... addr.hi ) + dup >r -rot BEGIN r@ WHILE r> 1- >r [char] , split 2swap + $number IF 0 THEN r> swap >r >r REPEAT r> 3drop + BEGIN dup WHILE 1- r> swap REPEAT drop ; +: generic-encode-unit ( addr.lo ... addr.hi ncells -- str len ) + 0 0 rot ?dup IF 0 ?DO rot (u.) $cat s" ," $cat LOOP 1- THEN ; +: hex-decode-unit ( str len ncells -- addr.lo ... addr.hi ) + base @ >r hex generic-decode-unit r> base ! ; +: hex-encode-unit ( addr.lo ... addr.hi ncells -- str len ) + base @ >r hex generic-encode-unit r> base ! ; + +: hex64-decode-unit ( str len ncells -- addr.lo ... addr.hi ) + dup 2 <> IF + hex-decode-unit + ELSE + drop + base @ >r hex + $number IF 0 0 ELSE xlsplit THEN + r> base ! + THEN +; + +: hex64-encode-unit ( addr.lo ... addr.hi ncells -- str len ) + dup 2 <> IF + hex-encode-unit + ELSE + drop + base @ >r hex + lxjoin (u.) + r> base ! + THEN +; + +: handle-leading-/ ( path len -- path' len' ) + dup IF over c@ [char] / = IF 1 /string device-tree @ set-node THEN THEN ; +: match-name ( name len node -- match? ) + over 0= IF 3drop true EXIT THEN + s" name" rot get-property IF 2drop false EXIT THEN + 1- string=ci ; \ XXX should use decode-string + +0 VALUE #search-unit +CREATE search-unit 4 cells allot + +: match-unit ( node -- match? ) + \ A node with no space is a wildcard and will always match + dup >space? IF + node>space search-unit #search-unit 0 ?DO 2dup @ swap @ <> IF + 2drop false UNLOOP EXIT THEN cell+ swap cell+ swap LOOP 2drop true + ELSE drop true THEN +; +: match-node ( name len node -- match? ) + dup >r match-name r> match-unit and ; \ XXX e3d +: find-kid ( name len -- node|0 ) + dup -1 = IF \ are we supposed to stay in the same node? -> resolve-relatives + 2drop get-node + ELSE + get-node child >r BEGIN r@ WHILE 2dup r@ match-node + IF 2drop r> EXIT THEN r> peer >r REPEAT + r> 3drop false + THEN ; + +: set-search-unit ( unit len -- ) + 0 to #search-unit + 0 to user-instance-#units + dup 0= IF 2drop EXIT THEN + s" #address-cells" get-node get-property THROW + decode-int to #search-unit 2drop + s" decode-unit" get-node $call-static + #search-unit 0 ?DO search-unit i cells + ! LOOP +; + +: resolve-relatives ( path len -- path' len' ) + \ handle .. + 2dup 2 = swap s" .." comp 0= and IF + get-node parent ?dup IF + set-node drop -1 + ELSE + s" Already in root node." type + THEN + THEN + \ handle . + 2dup 1 = swap c@ [CHAR] . = and IF + drop -1 + THEN +; + +\ XXX This is an old hack that allows wildcard nodes to work +\ by not having a #address-cells in the parent and no +\ decode unit. This should be removed. +\ (It appears to be still used on js2x) +: set-instance-unit ( unitaddr len -- ) + dup 0= IF 2drop 0 to user-instance-#units EXIT THEN + 2dup 0 -rot bounds ?DO + i c@ [char] , = IF 1+ THEN \ Count the commas + LOOP + 1+ dup to user-instance-#units + hex-decode-unit + user-instance-#units 0 ?DO + user-instance-units i cells + ! + LOOP +; + +: split-component ( path. -- path'. args. name. unit. ) + [char] / split 2swap ( path'. component. ) + [char] : split 2swap ( path'. args. name@unit. ) + [char] @ split ( path'. args. name. unit. ) +; + +: find-component ( path len -- path' len' args len node|0 ) + debug-find-component? IF + ." find-component for " 2dup type cr + THEN + split-component ( path'. args. name. unit. ) + debug-find-component? IF + ." -> unit =" 2dup type cr + ." -> stack =" .s cr + THEN + ['] set-search-unit CATCH IF + \ XXX: See comment in set-instance-unit + ." WARNING: Obsolete old wildcard hack " .s cr + set-instance-unit + THEN + resolve-relatives find-kid ( path' len' args len node|0 ) + + \ If resolve returned a wildcard node, and we haven't hit + \ the above gross hack then copy the unit + dup IF dup >space? not #search-unit 0 > AND user-instance-#units 0= AND IF + #search-unit dup to user-instance-#units 0 ?DO + search-unit i cells + @ user-instance-units i cells + ! + LOOP + THEN THEN + + \ XXX This can go away with the old wildcard hack + dup IF dup >space? user-instance-#units 0 > AND IF + \ User supplied a unit value, but node also has different physical unit + cr ." find-component with unit mismatch!" .s cr + drop 0 + THEN THEN +; + +: .find-node ( path len -- phandle|0 ) + current-node @ >r + handle-leading-/ current-node @ 0= IF 2drop r> set-node 0 EXIT THEN + BEGIN dup WHILE \ handle one component: + find-component ( path len args len node ) dup 0= IF + 3drop 2drop r> set-node 0 EXIT THEN + set-node 2drop REPEAT 2drop + get-node r> set-node ; +' .find-node to find-node +: find-node ( path len -- phandle|0 ) de-alias find-node ; + +: delete-node ( phandle -- ) + dup node>instance-template @ max-instance-size free-mem + dup node>parent @ node>child @ ( phandle 1st peer ) + 2dup = IF + node>peer @ swap node>parent @ node>child ! + EXIT + THEN + dup node>peer @ + BEGIN + 2 pick 2dup <> + WHILE + drop + nip dup node>peer @ + dup 0= IF 2drop drop unloop EXIT THEN + REPEAT + drop + node>peer @ swap node>peer ! + drop +; + +: open-dev ( path len -- ihandle|0 ) + 0 to user-instance-#units + de-alias current-node @ >r + handle-leading-/ current-node @ 0= IF 2drop r> set-node 0 EXIT THEN + my-self >r + 0 to my-self + 0 0 >r >r + BEGIN + dup + WHILE \ handle one component: + ( arg len ) r> r> get-node open-node to my-self + find-component ( path len args len node ) dup 0= IF + 3drop 2drop my-self close-dev + r> to my-self + r> set-node + 0 EXIT + THEN + set-node + >r >r + REPEAT + 2drop + \ open final node + r> r> get-node open-node to my-self + my-self r> to my-self r> set-node +; + +: select-dev open-dev dup to my-self ihandle>phandle set-node ; +: unselect-dev my-self close-dev 0 to my-self device-end ; + +: find-device ( str len -- ) \ set as active node + find-node dup 0= ABORT" No such device path" set-node ; +: dev parse-word find-device ; + +: (lsprop) ( node --) + dup cr $indent indent @ type ." node: " node>qname type + false +indent (.properties) cr -indent +; +: (show-children) ( node -- ) + child BEGIN + dup + WHILE + dup (lsprop) dup child IF false +indent dup recurse -indent THEN peer + REPEAT + drop +; +: lsprop ( {device-specifier}<eol> -- ) + skipws 0 parse dup IF de-alias ELSE 2drop s" /" THEN + find-device get-node dup dup + cr ." node: " node>path type (.properties) cr (show-children) + 0 indent ! +; + + +\ node>path does not allot the memory, since it is internally only used +\ for typing. +\ The external variant needs to allot memory ! + +: (node>path) node>path ; + +: node>path ( phandle -- str len ) + node>path dup allot +; + +\ Support for support packages. + +\ The /packages node. +0 VALUE packages + +\ Find a support package (or arbitrary nodes when name is absolute) +: find-package ( name len -- false | phandle true ) + dup 0 <= IF + 2drop FALSE EXIT + THEN + \ According to IEEE 1275 Proposal 215 (Extensible Client Services Package), + \ the find-package method can be used to get the phandle of arbitrary nodes + \ (i.e. not only support packages) when the name starts with a slash. + \ Some FCODE programs depend on this behavior so let's support this, too! + over c@ [char] / = IF + find-node dup IF TRUE THEN EXIT + THEN + \ Ok, let's look for support packages instead. We can't use the standard + \ find-node stuff, as we are required to find the newest (i.e., last in our + \ tree) matching package, not just any. + 0 >r packages child + BEGIN + dup + WHILE + dup >r node>name 2over string=ci r> swap IF + r> drop dup >r + THEN + peer + REPEAT + 3drop + r> dup IF true THEN +; + +: open-package ( arg len phandle -- ihandle | 0 ) open-node ; +: close-package ( ihandle -- ) close-node ; +: $open-package ( arg len name len -- ihandle | 0 ) + find-package IF open-package ELSE 2drop false THEN ; + + +\ device tree translate-address +#include <translate.fs> diff --git a/qemu/roms/SLOF/slof/fs/nvram.fs b/qemu/roms/SLOF/slof/fs/nvram.fs new file mode 100644 index 000000000..5ea58d17f --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/nvram.fs @@ -0,0 +1,182 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2014 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +51 CONSTANT nvram-partition-type-cpulog +\ types 53-55 are omitted because they have been used for +\ storing binary tables in the past +60 CONSTANT nvram-partition-type-sas +61 CONSTANT nvram-partition-type-sms +6e CONSTANT nvram-partition-type-debug +6f CONSTANT nvram-partition-type-history +70 CONSTANT nvram-partition-type-common +7f CONSTANT nvram-partition-type-freespace +a0 CONSTANT nvram-partition-type-linux + +: rztype ( str len -- ) \ stop at zero byte, read with nvram-c@ + 0 DO + dup i + nvram-c@ ?dup IF ( str char ) + emit + ELSE ( str ) + drop UNLOOP EXIT + THEN + LOOP +; + +create tmpStr 500 allot +: rzcount ( zstr -- str len ) + dup tmpStr >r BEGIN + dup nvram-c@ dup r> dup 1+ >r c! + WHILE + char+ + REPEAT + r> drop over - swap drop tmpStr swap +; + +: calc-header-cksum ( offset -- cksum ) + dup nvram-c@ + 10 2 DO + over I + nvram-c@ + + LOOP + wbsplit + nip +; + +: bad-header? ( offset -- flag ) + dup 2+ nvram-w@ ( offset length ) + 0= IF ( offset ) + drop true EXIT ( ) + THEN + dup calc-header-cksum ( offset checksum' ) + swap 1+ nvram-c@ ( checksum ' checksum ) + <> ( flag ) +; + +: .header ( offset -- ) + cr ( offset ) + dup bad-header? IF ( offset ) + ." BAD HEADER -- trying to print it anyway" cr + THEN + space ( offset ) + \ print type + dup nvram-c@ 2 0.r ( offset ) + space space ( offset ) + \ print length + dup 2+ nvram-w@ 10 * 5 .r ( offset ) + space space ( offset ) + \ print name + 4 + 0c rztype ( ) +; + +: .headers ( -- ) + cr cr ." Type Size Name" + cr ." ========================" + 0 BEGIN ( offset ) + dup nvram-c@ ( offset type ) + WHILE + dup .header ( offset ) + dup 2+ nvram-w@ 10 * + ( offset offset' ) + dup nvram-size < IF ( offset ) + ELSE + drop EXIT ( ) + THEN + REPEAT + drop ( ) + cr cr +; + +: reset-nvram ( -- ) + internal-reset-nvram +; + +: dump-partition ['] nvram-c@ 1 (dump) ; + +: type-no-zero ( addr len -- ) + 0 DO + dup I + dup nvram-c@ 0= IF drop ELSE nvram-c@ emit THEN + LOOP + drop +; + +: type-no-zero-part ( from-str cnt-str addr len ) + 0 DO + dup i + dup nvram-c@ 0= IF + drop + ELSE + ( from-str cnt-str addr addr+i ) + ( from-str==0 AND cnt-str > 0 ) + 3 pick 0= 3 pick 0 > AND IF + dup 1 type-no-zero + THEN + + nvram-c@ a = IF + 2 pick 0= IF + over 1- 0 max + rot drop swap + THEN + 2 pick 1- 0 max + 3 roll drop rot rot + ( from-str-- cnt-str-- addr addr+i ) + THEN + THEN + LOOP + drop +; + +: (dmesg-prepare) ( base-addr -- base-addr' addr len act-off ) + 10 - \ go back to header + dup 14 + nvram-l@ dup >r + ( base-addr act-off ) ( R: act-off ) + over over over + swap 10 + nvram-w@ + >r + ( base-addr act-off ) ( R: act-off nvram-act-addr ) + over 2 + nvram-w@ 10 * swap - over swap + ( base-addr base-addr start-size ) ( R: act-off nvram-act-addr ) + r> swap rot 10 + nvram-w@ - r> +; + +: .dmesg ( base-addr -- ) + (dmesg-prepare) >r + ( base-addr addr len ) + cr type-no-zero + ( base-addr ) ( R: act-off ) + dup 10 + nvram-w@ + r> type-no-zero +; + +: .dmesg-part ( from-str cnt-str base-addr -- ) + (dmesg-prepare) >r + ( from-str cnt-str base-addr addr len ) + >r >r -rot r> r> + ( base-addr from-str cnt-str addr len ) + cr type-no-zero-part rot + ( base-addr ) ( R: act-off ) + dup 10 + nvram-w@ + r> type-no-zero-part +; + +: dmesg-part ( from-str cnt-str -- left-from-str left-cnt-str ) + 2dup + s" ibm,CPU0log" get-named-nvram-partition IF + 2drop EXIT + THEN + drop .dmesg-part nip nip +; + +: dmesg2 ( -- ) + s" ibm,CPU1log" get-named-nvram-partition IF + ." No log partition." cr EXIT + THEN + drop .dmesg +; + +: dmesg ( -- ) + s" ibm,CPU0log" get-named-nvram-partition IF + ." No log partition." cr EXIT + THEN + drop .dmesg +; diff --git a/qemu/roms/SLOF/slof/fs/packages.fs b/qemu/roms/SLOF/slof/fs/packages.fs new file mode 100644 index 000000000..f640d8f61 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages.fs @@ -0,0 +1,52 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2015 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ ============================================================================= +\ SUPPORT PACKAGES +\ ============================================================================= + + +s" packages" device-name +get-node to packages + +\ new-device +\ #include "packages/filler.fs" +\ finish-device + +new-device +#include "packages/deblocker.fs" +finish-device + +new-device +#include "packages/disk-label.fs" +finish-device + +new-device +#include "packages/fat-files.fs" +finish-device + +new-device +#include "packages/rom-files.fs" +finish-device + +new-device +#include "packages/ext2-files.fs" +finish-device + +new-device +#include "packages/obp-tftp.fs" +finish-device + +new-device +#include "packages/iso-9660.fs" +finish-device diff --git a/qemu/roms/SLOF/slof/fs/packages/deblocker.fs b/qemu/roms/SLOF/slof/fs/packages/deblocker.fs new file mode 100644 index 000000000..83cd71278 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/deblocker.fs @@ -0,0 +1,70 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ ============================================================================= +\ ============================================================================= + + +\ The deblocker. Allows block devices to be used as a (seekable) byte device. + +s" deblocker" device-name + +INSTANCE VARIABLE offset +INSTANCE VARIABLE block-size +INSTANCE VARIABLE max-transfer +INSTANCE VARIABLE my-block +INSTANCE VARIABLE adr +INSTANCE VARIABLE len +INSTANCE VARIABLE fail-count + +: open + s" block-size" ['] $call-parent CATCH IF 2drop false EXIT THEN + block-size ! + s" max-transfer" ['] $call-parent CATCH IF 2drop false EXIT THEN + max-transfer ! + block-size @ alloc-mem my-block ! + 0 offset ! + true ; +: close my-block @ block-size @ free-mem ; + +: seek ( lo hi -- status ) \ XXX: perhaps we should fail if the underlying + \ device would fail at this offset + lxjoin offset ! 0 ; +: block+remainder ( -- block# remainder ) offset @ block-size @ u/mod swap ; +: read-blocks ( addr block# #blocks -- actual ) s" read-blocks" $call-parent ; +: read ( addr len -- actual ) + dup >r len ! adr ! + \ First, handle a partial block at the start. + block+remainder dup IF ( block# offset-in-block ) + >r my-block @ swap 1 read-blocks drop + my-block @ r@ + adr @ block-size @ r> - len @ min dup >r move + r> dup negate len +! dup adr +! offset +! ELSE 2drop THEN + + \ Now, in a loop read max. max-transfer sized runs of whole blocks. + 0 fail-count ! + BEGIN len @ block-size @ >= WHILE + adr @ block+remainder drop len @ max-transfer @ min block-size @ / read-blocks + dup 0= IF + 1 fail-count +! + fail-count @ 5 >= IF r> drop EXIT THEN + ELSE + 0 fail-count ! + THEN + block-size @ * dup negate len +! dup adr +! offset +! + REPEAT + + \ And lastly, handle a partial block at the end. + len @ IF my-block @ block+remainder drop 1 read-blocks drop + my-block @ adr @ len @ move THEN + + r> ; diff --git a/qemu/roms/SLOF/slof/fs/packages/disk-label.fs b/qemu/roms/SLOF/slof/fs/packages/disk-label.fs new file mode 100644 index 000000000..fe1c25e7a --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/disk-label.fs @@ -0,0 +1,660 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Set debug-disk-label? to true to get debug messages for the disk-label code. +false VALUE debug-disk-label? + +\ This value defines the maximum number of blocks (512b) to load from a PREP +\ partition. This is required to keep the load time in reasonable limits if the +\ PREP partition becomes big. +\ If we ever want to put a large kernel with initramfs from a PREP partition +\ we might need to increase this value. The default value is 65536 blocks (32MB) +d# 65536 value max-prep-partition-blocks + +s" disk-label" device-name + +0 INSTANCE VALUE partition +0 INSTANCE VALUE part-offset +0 INSTANCE VALUE disk-chrp-boot + +0 INSTANCE VALUE part-start +0 INSTANCE VALUE lpart-start +0 INSTANCE VALUE part-size +0 INSTANCE VALUE dos-logical-partitions + +0 INSTANCE VALUE block-size +0 INSTANCE VALUE block + +0 INSTANCE VALUE args +0 INSTANCE VALUE args-len + +0 INSTANCE VALUE gpt-part-size +0 INSTANCE VALUE seek-pos + + +INSTANCE VARIABLE block# \ variable to store logical sector# +INSTANCE VARIABLE hit# \ partition counter +INSTANCE VARIABLE success-flag + +\ ISO9660 specific information +0ff constant END-OF-DESC +3 constant PARTITION-ID +48 constant VOL-PART-LOC + + +\ DOS partition label (MBR) specific structures + +STRUCT + 1b8 field mbr>boot-loader + /l field mbr>disk-signature + /w field mbr>null + 40 field mbr>partition-table + /w field mbr>magic + +CONSTANT /mbr + +STRUCT + /c field part-entry>active + /c field part-entry>start-head + /c field part-entry>start-sect + /c field part-entry>start-cyl + /c field part-entry>id + /c field part-entry>end-head + /c field part-entry>end-sect + /c field part-entry>end-cyl + /l field part-entry>sector-offset + /l field part-entry>sector-count + +CONSTANT /partition-entry + +STRUCT + 8 field gpt>signature + 4 field gpt>revision + 4 field gpt>header-size + 4 field gpt>header-crc32 + 4 field gpt>reserved + 8 field gpt>current-lba + 8 field gpt>backup-lba + 8 field gpt>first-lba + 8 field gpt>last-lba + 10 field gpt>disk-guid + 8 field gpt>part-entry-lba + 4 field gpt>num-part-entry + 4 field gpt>part-entry-size + 4 field gpt>part-array-crc32 + 1a4 field gpt>reserved + +CONSTANT /gpt-header + +STRUCT + 10 field gpt-part-entry>part-type-guid + 10 field gpt-part-entry>part-guid + 8 field gpt-part-entry>first-lba + 8 field gpt-part-entry>last-lba + 8 field gpt-part-entry>attribute + 48 field gpt-part-entry>part-name + +CONSTANT /gpt-part-entry + +\ Defined by IEEE 1275-1994 (3.8.1) + +: offset ( d.rel -- d.abs ) + part-offset xlsplit d+ +; + +: seek ( pos.lo pos.hi -- status ) + offset + debug-disk-label? IF 2dup ." seek-parent: pos.hi=0x" u. ." pos.lo=0x" u. THEN + s" seek" $call-parent + debug-disk-label? IF dup ." status=" . cr THEN +; + +: read ( addr len -- actual ) + debug-disk-label? IF 2dup swap ." read-parent: addr=0x" u. ." len=" .d THEN + s" read" $call-parent + debug-disk-label? IF dup ." actual=" .d cr THEN +; + + +\ read sector to array "block" +: read-sector ( sector-number -- ) + \ block-size is 0x200 on disks, 0x800 on cdrom drives + block-size * 0 seek drop \ seek to sector + block block-size read drop \ read sector +; + +: (.part-entry) ( part-entry ) + cr ." part-entry>active: " dup part-entry>active c@ .d + cr ." part-entry>start-head: " dup part-entry>start-head c@ .d + cr ." part-entry>start-sect: " dup part-entry>start-sect c@ .d + cr ." part-entry>start-cyl: " dup part-entry>start-cyl c@ .d + cr ." part-entry>id: " dup part-entry>id c@ .d + cr ." part-entry>end-head: " dup part-entry>end-head c@ .d + cr ." part-entry>end-sect: " dup part-entry>end-sect c@ .d + cr ." part-entry>end-cyl: " dup part-entry>end-cyl c@ .d + cr ." part-entry>sector-offset: " dup part-entry>sector-offset l@-le .d + cr ." part-entry>sector-count: " dup part-entry>sector-count l@-le .d + cr +; + +: (.name) r@ begin cell - dup @ <colon> = UNTIL xt>name cr type space ; + +: init-block ( -- ) + s" block-size" ['] $call-parent CATCH IF ABORT" parent has no block-size." THEN + to block-size + d# 4096 alloc-mem + dup d# 4096 erase + to block + debug-disk-label? IF + ." init-block: block-size=" block-size .d ." block=0x" block u. cr + THEN +; + +: partition>part-entry ( partition -- part-entry ) + 1- /partition-entry * block mbr>partition-table + +; + +: partition>start-sector ( partition -- sector-offset ) + partition>part-entry part-entry>sector-offset l@-le +; + +\ This word returns true if the currently loaded block has _NO_ MBR magic +: no-mbr? ( -- true|false ) + 0 read-sector + 1 partition>part-entry part-entry>id c@ ee = IF TRUE EXIT THEN \ GPT partition found + block mbr>magic w@-le aa55 <> +; + +\ This word returns true if the currently loaded block has _NO_ GPT partition id +: no-gpt? ( -- true|false ) + 0 read-sector + 1 partition>part-entry part-entry>id c@ ee <> +; + +: pc-extended-partition? ( part-entry-addr -- true|false ) + part-entry>id c@ ( id ) + dup 5 = swap ( true|false id ) + dup f = swap ( true|false true|false id ) + 85 = ( true|false true|false true|false ) + or or ( true|false ) +; + +: count-dos-logical-partitions ( -- #logical-partitions ) + no-mbr? IF 0 EXIT THEN + 0 5 1 DO ( current ) + i partition>part-entry ( current part-entry ) + dup pc-extended-partition? IF + part-entry>sector-offset l@-le ( current sector ) + dup to part-start to lpart-start ( current ) + BEGIN + part-start read-sector \ read EBR + 1 partition>start-sector IF + \ ." Logical Partition found at " part-start .d cr + 1+ + THEN \ another logical partition + 2 partition>start-sector + ( current relative-sector ) + ?dup IF lpart-start + to part-start false ELSE true THEN + UNTIL + ELSE + drop + THEN + LOOP +; + +: (get-dos-partition-params) ( ext-part-start part-entry -- offset count active? id ) + dup part-entry>sector-offset l@-le rot + swap ( offset part-entry ) + dup part-entry>sector-count l@-le swap ( offset count part-entry ) + dup part-entry>active c@ 80 = swap ( offset count active? part-entry ) + part-entry>id c@ ( offset count active? id ) +; + +: find-dos-partition ( partition# -- false | offset count active? id true ) + to partition 0 to part-start 0 to part-offset + + \ no negative partitions + partition 0<= IF 0 to partition false EXIT THEN + + \ load MBR and check it + no-mbr? IF 0 to partition false EXIT THEN + + partition 4 <= IF \ Is this a primary partition? + 0 partition partition>part-entry + (get-dos-partition-params) + \ FIXME sanity checks? + true EXIT + ELSE + partition 4 - 0 5 1 DO ( logical-partition current ) + i partition>part-entry ( log-part current part-entry ) + dup pc-extended-partition? IF + part-entry>sector-offset l@-le ( log-part current sector ) + dup to part-start to lpart-start ( log-part current ) + BEGIN + part-start read-sector \ read EBR + 1 partition>start-sector IF \ first partition entry + 1+ 2dup = IF ( log-part current ) + 2drop + part-start 1 partition>part-entry + (get-dos-partition-params) + true UNLOOP EXIT + THEN + 2 partition>start-sector + ( log-part current relative-sector ) + + ?dup IF lpart-start + to part-start false ELSE true THEN + ELSE + true + THEN + UNTIL + ELSE + drop + THEN + LOOP + 2drop false + THEN +; + +: try-dos-partition ( -- okay? ) + \ Read partition table and check magic. + no-mbr? IF cr ." No DOS disk-label found." cr false EXIT THEN + + count-dos-logical-partitions TO dos-logical-partitions + + debug-disk-label? IF + ." Found " dos-logical-partitions .d ." logical partitions" cr + ." Partition = " partition .d cr + THEN + + partition 1 5 dos-logical-partitions + + within 0= IF + cr ." Partition # not 1-" 4 dos-logical-partitions + . cr false EXIT + THEN + + \ Could/should check for valid partition here... the magic is not enough really. + + \ Get the partition offset. + + partition find-dos-partition IF + ( offset count active? id ) + 2drop + to part-size + block-size * to part-offset + true + ELSE + false + THEN +; + +\ Check for an ISO-9660 filesystem on the disk +\ : try-iso9660-partition ( -- true|false ) +\ implement me if you can ;-) +\ ; + + +\ Check for an ISO-9660 filesystem on the disk +\ (cf. CHRP IEEE 1275 spec., chapter 11.1.2.3) +: has-iso9660-filesystem ( -- TRUE|FALSE ) + \ Seek to the beginning of logical 2048-byte sector 16 + \ refer to Chapter C.11.1 in PAPR 2.0 Spec + \ was: 10 read-sector, but this might cause trouble if you + \ try booting an ISO image from a device with 512b sectors. + 10 800 * 0 seek drop \ seek to sector + block 800 read drop \ read sector + \ Check for CD-ROM volume magic: + block c@ 1 = + block 1+ 5 s" CD001" str= + and + dup IF 800 to block-size THEN +; + + +\ Load from first active DOS boot partition. + +\ NOTE: block-size is always 512 bytes for DOS partition tables. + +: load-from-dos-boot-partition ( addr -- size ) + no-mbr? IF drop FALSE EXIT THEN \ read MBR and check for DOS disk-label magic + + count-dos-logical-partitions TO dos-logical-partitions + + debug-disk-label? IF + ." Found " dos-logical-partitions .d ." logical partitions" cr + ." Partition = " partition .d cr + THEN + + \ Now walk through the partitions: + 5 dos-logical-partitions + 1 DO + \ ." checking partition " i . + i find-dos-partition IF ( addr offset count active? id ) + 41 = and ( addr offset count prep-boot-part? ) + IF ( addr offset count ) + max-prep-partition-blocks min \ reduce load size + swap ( addr count offset ) + block-size * to part-offset + 0 0 seek drop ( addr offset ) + block-size * read ( size ) + UNLOOP EXIT + ELSE + 2drop ( addr ) + THEN + THEN + LOOP + drop 0 +; + +\ Check for GPT PReP partition GUID +9E1A2D38 CONSTANT GPT-PREP-PARTITION-1 +C612 CONSTANT GPT-PREP-PARTITION-2 +4316 CONSTANT GPT-PREP-PARTITION-3 +AA26 CONSTANT GPT-PREP-PARTITION-4 +8B49521E5A8B CONSTANT GPT-PREP-PARTITION-5 + +: gpt-prep-partition? ( -- true|false ) + block gpt-part-entry>part-type-guid l@-le GPT-PREP-PARTITION-1 = IF + block gpt-part-entry>part-type-guid 4 + w@-le + GPT-PREP-PARTITION-2 = IF + block gpt-part-entry>part-type-guid 6 + w@-le + GPT-PREP-PARTITION-3 = IF + block gpt-part-entry>part-type-guid 8 + w@ + GPT-PREP-PARTITION-4 = IF + block gpt-part-entry>part-type-guid a + w@ + block gpt-part-entry>part-type-guid c + l@ swap lxjoin + GPT-PREP-PARTITION-5 = IF + TRUE EXIT + THEN + THEN + THEN + THEN + THEN + FALSE +; + +: load-from-gpt-prep-partition ( addr -- size ) + no-gpt? IF drop FALSE EXIT THEN + debug-disk-label? IF + cr ." GPT partition found " cr + THEN + 1 read-sector block gpt>part-entry-lba l@-le + block-size * to seek-pos + block gpt>part-entry-size l@-le to gpt-part-size + block gpt>num-part-entry l@-le dup 0= IF FALSE EXIT THEN + 1+ 1 ?DO + seek-pos 0 seek drop + block gpt-part-size read drop gpt-prep-partition? IF + debug-disk-label? IF + ." GPT PReP partition found " cr + THEN + block gpt-part-entry>first-lba x@ xbflip + block gpt-part-entry>last-lba x@ xbflip + over - 1+ ( addr offset len ) + swap ( addr len offset ) + block-size * to part-offset + 0 0 seek drop ( addr len ) + block-size * read ( size ) + UNLOOP EXIT + THEN + seek-pos gpt-part-size i * + to seek-pos + LOOP + FALSE +; + +\ Extract the boot loader path from a bootinfo.txt file +\ In: address and length of buffer where the bootinfo.txt has been loaded to. +\ Out: string address and length of the boot loader (within the input buffer) +\ or a string with length = 0 when parsing failed. + +\ Here is a sample bootinfo file: +\ <chrp-boot> +\ <description>Linux Distribution</description> +\ <os-name>Linux</os-name> +\ <boot-script>boot &device;:1,\boot\yaboot.ibm</boot-script> +\ <icon size=64,64 color-space=3,3,2> +\ <bitmap>[..]</bitmap> +\ </icon> +\ </chrp-boot> + +: parse-bootinfo-txt ( addr len -- str len ) + 2dup s" <boot-script>" find-substr ( addr len pos1 ) + 2dup = IF + \ String not found + 3drop 0 0 EXIT + THEN + dup >r - swap r> + swap ( addr1 len1 ) + + 2dup s" &device;:" find-substr ( addr1 len1 posdev ) + 2dup = IF + 3drop 0 0 EXIT + THEN + 9 + \ Skip the "&device;:" string + dup >r - swap r> + swap ( addr2 len2 ) + 2dup s" </boot-script>" find-substr nip ( addr2 len3 ) + + debug-disk-label? IF + ." Extracted boot loader from bootinfo.txt: '" + 2dup type ." '" cr + THEN +; + +\ Try to load \ppc\bootinfo.txt from the disk (used mainly on CD-ROMs), and if +\ available, get the boot loader path from this file and load it. +\ See the "CHRP system binding to IEEE 1275" specification for more information +\ about bootinfo.txt. An example file can be found in the comment of +\ parse-bootinfo-txt ( addr len -- str len ) + +: load-chrp-boot-file ( addr -- size ) + \ Create bootinfo.txt path name and load that file: + my-parent instance>path + disk-chrp-boot @ 1 = IF + s" :1,\ppc\bootinfo.txt" $cat strdup ( addr str len ) + ELSE + s" :\ppc\bootinfo.txt" $cat strdup ( addr str len ) + THEN + open-dev dup 0= IF 2drop 0 EXIT THEN + >r dup ( addr addr R:ihandle ) + dup s" load" r@ $call-method ( addr addr size R:ihandle ) + r> close-dev ( addr addr size ) + + \ Now parse the information from bootinfo.txt: + parse-bootinfo-txt ( addr fnstr fnlen ) + dup 0= IF 3drop 0 EXIT THEN + \ Does the string contain parameters (i.e. a white space)? + 2dup 20 findchar IF + ( addr fnstr fnlen offset ) + >r 2dup r@ - 1- swap r@ + 1+ swap ( addr fnstr fnlen pstr plen R: offset ) + encode-string s" bootargs" set-chosen + drop r> + THEN + + \ Create the full path to the boot loader: + my-parent instance>path ( addr fnstr fnlen nstr nlen ) + s" :" $cat 2swap $cat strdup ( addr str len ) + \ Update the bootpath: + 2dup encode-string s" bootpath" set-chosen + \ And finally load the boot loader itself: + open-dev dup 0= IF ." failed to load CHRP boot loader." 2drop 0 EXIT THEN + >r s" load" r@ $call-method ( size R:ihandle ) + r> close-dev ( size ) +; + +\ load from a bootable partition +: load-from-boot-partition ( addr -- size ) + debug-disk-label? IF ." Trying DOS boot " .s cr THEN + dup load-from-dos-boot-partition ?dup 0 <> IF nip EXIT THEN + + debug-disk-label? IF ." Trying CHRP boot " .s cr THEN + 1 disk-chrp-boot ! + dup load-chrp-boot-file ?dup 0 <> IF .s cr nip EXIT THEN + 0 disk-chrp-boot ! + + debug-disk-label? IF ." Trying GPT boot " .s cr THEN + load-from-gpt-prep-partition + \ More boot partition formats ... +; + +\ parse partition number from my-args + +\ my-args has the following format +\ [<partition>[,<path>]] + +\ | example my-args | example boot command | +\ +------------------+---------------------------+ +\ | 1,\boot\vmlinuz | boot disk:1,\boot\vmlinuz | +\ | 2 | boot disk:2 | + +\ 0 means the whole disk, this is the same behavior +\ as if no partition is specified (yaboot wants this). + +: parse-partition ( -- okay? ) + 0 to partition + 0 to part-offset + 0 to part-size + + my-args to args-len to args + + debug-disk-label? IF + cr ." disk-label parse-partition: my-args=" my-args type cr + THEN + + \ Called without arguments? + args-len 0 = IF true EXIT THEN + + \ Check for "full disk" arguments. + my-args [char] , findchar 0= IF \ no comma? + args c@ isdigit not IF \ ... and not a partition number? + true EXIT \ ... then it's not a partition we can parse + THEN + ELSE + drop + THEN + my-args [char] , split to args-len to args + dup 0= IF 2drop true EXIT THEN \ no first argument + + \ Check partition #. + base @ >r decimal $number r> base ! + IF cr ." Not a partition #" false EXIT THEN + + \ Store part #, done. + to partition + true +; + + +\ try-files and try-partitions + +: (interpose-filesystem) ( str len -- ) + find-package IF args args-len rot interpose THEN +; + +: try-dos-files ( -- found? ) + no-mbr? IF false EXIT THEN + + \ block 0 byte 0-2 is a jump instruction in all FAT + \ filesystems. + \ e9 and eb are jump instructions in x86 assembler. + block c@ e9 <> IF + block c@ eb <> + block 2+ c@ 90 <> or + IF false EXIT THEN + THEN + s" fat-files" (interpose-filesystem) + true +; + +: try-ext2-files ( -- found? ) + 2 read-sector \ read first superblock + block d# 56 + w@-le \ fetch s_magic + ef53 <> IF false EXIT THEN \ s_magic found? + s" ext2-files" (interpose-filesystem) + true +; + + +: try-iso9660-files + has-iso9660-filesystem 0= IF false exit THEN + s" iso-9660" (interpose-filesystem) + true +; + +: try-files ( -- found? ) + \ If no path, then full disk. + args-len 0= IF true EXIT THEN + + try-dos-files IF true EXIT THEN + try-ext2-files IF true EXIT THEN + try-iso9660-files IF true EXIT THEN + + \ ... more filesystem types here ... + + false +; + +: try-partitions ( -- found? ) + try-dos-partition IF try-files EXIT THEN + \ try-iso9660-partition IF try-files EXIT THEN + \ ... more partition types here... + false +; + +\ Interface functions for disk-label package +\ as defined by IEEE 1275-1994 3.8.1 + +: close ( -- ) + debug-disk-label? IF ." Closing disk-label: block=0x" block u. ." block-size=" block-size .d cr THEN + block d# 4096 free-mem +; + + +: open ( -- true|false ) + init-block + + parse-partition 0= IF + close + false EXIT + THEN + + partition IF + try-partitions + ELSE + try-files + THEN + dup 0= IF debug-disk-label? IF ." not found." cr THEN close THEN \ free memory again +; + + +\ Boot & Load w/o arguments is assumed to be boot from boot partition + +: load ( addr -- size ) + debug-disk-label? IF + ." load: " dup u. cr + THEN + + args-len IF + TRUE ABORT" Load done w/o filesystem" + ELSE + partition IF + 0 0 seek drop + part-size IF + part-size max-prep-partition-blocks min \ Load size + ELSE + max-prep-partition-blocks + THEN + 200 * read + ELSE + has-iso9660-filesystem IF + dup load-chrp-boot-file ?dup 0 > IF nip EXIT THEN + THEN + load-from-boot-partition + dup 0= ABORT" No boot partition found" + THEN + THEN +; diff --git a/qemu/roms/SLOF/slof/fs/packages/ext2-files.fs b/qemu/roms/SLOF/slof/fs/packages/ext2-files.fs new file mode 100644 index 000000000..262c64a34 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/ext2-files.fs @@ -0,0 +1,188 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +s" ext2-files" device-name + +INSTANCE VARIABLE first-block +INSTANCE VARIABLE inode-size +INSTANCE VARIABLE block-size +INSTANCE VARIABLE inodes/group + +INSTANCE VARIABLE group-desc-size +INSTANCE VARIABLE group-descriptors + +: seek s" seek" $call-parent ; +: read s" read" $call-parent ; + +INSTANCE VARIABLE data +INSTANCE VARIABLE #data +INSTANCE VARIABLE indirect-block +INSTANCE VARIABLE dindirect-block + +: free-data + data @ ?dup IF #data @ free-mem 0 data ! THEN ; +: read-data ( offset size -- ) + free-data dup #data ! alloc-mem data ! + xlsplit seek -2 and ABORT" ext2-files read-data: seek failed" + data @ #data @ read #data @ <> ABORT" ext2-files read-data: read failed" ; + +: read-block ( block# -- ) + block-size @ * block-size @ read-data ; + +INSTANCE VARIABLE inode +INSTANCE VARIABLE file-len +INSTANCE VARIABLE blocks +INSTANCE VARIABLE #blocks +INSTANCE VARIABLE ^blocks +INSTANCE VARIABLE #blocks-left +: blocks-read ( n -- ) dup negate #blocks-left +! 4 * ^blocks +! ; +: read-indirect-blocks ( indirect-block# -- ) + read-block data @ data off + dup #blocks-left @ 4 * block-size @ min dup >r ^blocks @ swap move + r> 2 rshift blocks-read block-size @ free-mem ; + +: read-double-indirect-blocks ( double-indirect-block# -- ) + \ Resolve one level of indirection and call read-indirect-block + read-block data @ indirect-block ! data off + BEGIN + indirect-block @ l@-le dup 0 <> + WHILE + read-indirect-blocks + 4 indirect-block +! \ point to next indirect block + REPEAT + drop \ drop 0, the invalid block number +; + +: read-triple-indirect-blocks ( triple-indirect-block# -- ) + \ Resolve one level of indirection and call double-indirect-block + read-block data @ dindirect-block ! data off + BEGIN + dindirect-block @ l@-le dup 0 <> + WHILE + read-double-indirect-blocks + 4 dindirect-block +! \ point to next double indirect block + REPEAT + drop \ drop 0, the invalid block number +; + +: read-block#s ( -- ) + blocks @ ?dup IF #blocks @ 4 * free-mem THEN + inode @ 4 + l@-le file-len ! + file-len @ block-size @ // #blocks ! + #blocks @ 4 * alloc-mem blocks ! + blocks @ ^blocks ! #blocks @ #blocks-left ! + #blocks-left @ c min \ # direct blocks + inode @ 28 + over 4 * ^blocks @ swap move blocks-read + #blocks-left @ IF inode @ 58 + l@-le read-indirect-blocks THEN + #blocks-left @ IF inode @ 5c + l@-le read-double-indirect-blocks THEN + #blocks-left @ IF inode @ 60 + l@-le read-triple-indirect-blocks THEN ; +: read-inode ( inode# -- ) + 1- inodes/group @ u/mod \ # in group, group # + 20 * group-descriptors @ + 8 + l@-le block-size @ * \ # in group, inode table + swap inode-size @ * + xlsplit seek drop inode @ inode-size @ read drop +; + +: .rwx ( bits last-char-if-special special? -- ) + rot dup 4 and IF ." r" ELSE ." -" THEN + dup 2 and IF ." w" ELSE ." -" THEN + swap IF 1 and 0= IF upc THEN emit ELSE + 1 and IF ." x" ELSE ." -" THEN drop THEN ; +CREATE mode-chars 10 allot s" ?pc?d?b?-?l?s???" mode-chars swap move +: .mode ( mode -- ) + dup c rshift f and mode-chars + c@ emit + dup 6 rshift 7 and over 800 and 73 swap .rwx + dup 3 rshift 7 and over 400 and 73 swap .rwx + dup 7 and swap 200 and 74 swap .rwx ; +: .inode ( -- ) + base @ >r decimal + inode @ w@-le .mode \ file mode + inode @ 1a + w@-le 5 .r \ link count + inode @ 02 + w@-le 9 .r \ uid + inode @ 18 + w@-le 9 .r \ gid + inode @ 04 + l@-le 9 .r \ size + r> base ! ; + +: do-super ( -- ) + 400 400 read-data + data @ 14 + l@-le first-block ! + 400 data @ 18 + l@-le lshift block-size ! + data @ 28 + l@-le inodes/group ! + \ Check revision level... in revision 0, the inode size is always 128 + data @ 4c + l@-le 0= IF + 80 inode-size ! + ELSE + data @ 58 + w@-le inode-size ! + THEN + data @ 20 + l@-le group-desc-size ! + + \ Read the group descriptor table: + first-block @ 1+ block-size @ * + group-desc-size @ + read-data + data @ group-descriptors ! + + \ We keep the group-descriptor memory area, so clear data pointer: + data off +; + +INSTANCE VARIABLE current-pos + +: read ( adr len -- actual ) + file-len @ current-pos @ - min \ can't go past end of file + current-pos @ block-size @ u/mod 4 * blocks @ + l@-le read-block + block-size @ over - rot min >r ( adr off r: len ) + data @ + swap r@ move r> dup current-pos +! ; +: read ( adr len -- actual ) + ( check if a file is selected, first ) + dup >r BEGIN dup WHILE 2dup read dup 0= ABORT" ext2-files: read failed" + /string REPEAT 2drop r> ; +: seek ( lo hi -- status ) + lxjoin dup file-len @ > IF drop true EXIT THEN current-pos ! false ; +: load ( adr -- len ) + file-len @ read dup file-len @ <> ABORT" ext2-files: failed loading file" ; + +: .name ( adr -- ) dup 8 + swap 6 + c@ type ; +: read-dir ( inode# -- adr ) + read-inode read-block#s file-len @ alloc-mem + 0 0 seek ABORT" ext2-files read-dir: seek failed" + dup file-len @ read file-len @ <> ABORT" ext2-files read-dir: read failed" ; +: .dir ( inode# -- ) + read-dir dup BEGIN 2dup file-len @ - > over l@-le tuck and WHILE + cr dup 8 0.r space read-inode .inode space space dup .name + dup 4 + w@-le + REPEAT 2drop file-len @ free-mem ; +: (find-file) ( adr name len -- inode#|0 ) + 2>r dup BEGIN 2dup file-len @ - > over l@-le and WHILE + dup 8 + over 6 + c@ 2r@ str= IF 2r> 2drop nip l@-le EXIT THEN + dup 4 + w@-le + REPEAT 2drop 2r> 2drop 0 ; +: find-file ( inode# name len -- inode#|0 ) + 2>r read-dir dup 2r> (find-file) swap file-len @ free-mem ; +: find-path ( inode# name len -- inode#|0 ) + dup 0= IF 3drop 0 ." empty name " EXIT THEN + over c@ [char] \ = IF 1 /string ." slash " RECURSE EXIT THEN + [char] \ split 2>r find-file ?dup 0= IF + 2r> 2drop false ." not found " EXIT THEN + r@ 0<> IF 2r> ." more... " RECURSE EXIT THEN + 2r> 2drop ." got it " ; + +: close + inode @ inode-size @ free-mem + group-descriptors @ group-desc-size @ free-mem + free-data + blocks @ ?dup IF #blocks @ 4 * free-mem THEN +; + +: open + 0 data ! 0 blocks ! 0 #blocks ! + do-super + inode-size @ alloc-mem inode ! + my-args nip 0= IF 0 0 ELSE + 2 my-args find-path ?dup 0= IF close false EXIT THEN THEN + read-inode read-block#s 0 0 seek 0= ; diff --git a/qemu/roms/SLOF/slof/fs/packages/fat-files.fs b/qemu/roms/SLOF/slof/fs/packages/fat-files.fs new file mode 100644 index 000000000..0cec3664e --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/fat-files.fs @@ -0,0 +1,188 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +s" fat-files" device-name + +INSTANCE VARIABLE bytes/sector +INSTANCE VARIABLE sectors/cluster +INSTANCE VARIABLE #reserved-sectors +INSTANCE VARIABLE #fats +INSTANCE VARIABLE #root-entries +INSTANCE VARIABLE total-#sectors +INSTANCE VARIABLE media-descriptor +INSTANCE VARIABLE sectors/fat +INSTANCE VARIABLE sectors/track +INSTANCE VARIABLE #heads +INSTANCE VARIABLE #hidden-sectors + +INSTANCE VARIABLE fat-type +INSTANCE VARIABLE bytes/cluster +INSTANCE VARIABLE fat-offset +INSTANCE VARIABLE root-offset +INSTANCE VARIABLE cluster-offset +INSTANCE VARIABLE #clusters + +: seek s" seek" $call-parent ; +: read s" read" $call-parent ; + +INSTANCE VARIABLE data +INSTANCE VARIABLE #data + +: free-data + data @ ?dup IF #data @ free-mem 0 data ! THEN ; +: read-data ( offset size -- ) + free-data dup #data ! alloc-mem data ! + xlsplit seek -2 and ABORT" fat-files read-data: seek failed" + data @ #data @ read #data @ <> ABORT" fat-files read-data: read failed" ; + +CREATE fat-buf 8 allot +: read-fat ( cluster# -- data ) + fat-buf 8 erase + 1 #split fat-type @ * 2/ 2/ fat-offset @ + + xlsplit seek -2 and ABORT" fat-files read-fat: seek failed" + fat-buf 8 read 8 <> ABORT" fat-files read-fat: read failed" + fat-buf 8c@ bxjoin fat-type @ dup >r 2* #split drop r> #split + rot IF swap THEN drop ; + +INSTANCE VARIABLE next-cluster + +: read-cluster ( cluster# -- ) + dup bytes/cluster @ * cluster-offset @ + bytes/cluster @ read-data + read-fat dup #clusters @ >= IF drop 0 THEN next-cluster ! ; +: read-dir ( cluster# -- ) + ?dup 0= IF root-offset @ #root-entries @ 20 * read-data 0 next-cluster ! + ELSE read-cluster THEN ; + +: .time ( x -- ) + base @ >r decimal + b #split 2 0.r [char] : emit 5 #split 2 0.r [char] : emit 2* 2 0.r + r> base ! ; +: .date ( x -- ) + base @ >r decimal + 9 #split 7bc + 4 0.r [char] - emit 5 #split 2 0.r [char] - emit 2 0.r + r> base ! ; +: .attr ( attr -- ) + 6 0 DO dup 1 and IF s" RHSLDA" drop i + c@ ELSE bl THEN emit u2/ LOOP drop ; +: .dir-entry ( adr -- ) + dup 0b + c@ 8 and IF drop EXIT THEN \ volume label, not a file + dup c@ e5 = IF drop EXIT THEN \ deleted file + cr + dup 1a + 2c@ bwjoin [char] # emit 4 0.r space \ starting cluster + dup 18 + 2c@ bwjoin .date space + dup 16 + 2c@ bwjoin .time space + dup 1c + 4c@ bljoin base @ decimal swap a .r base ! space \ size in bytes + dup 0b + c@ .attr space + dup 8 BEGIN 2dup 1- + c@ 20 = over and WHILE 1- REPEAT type + dup 8 + 3 BEGIN 2dup 1- + c@ 20 = over and WHILE 1- REPEAT dup IF + [char] . emit type ELSE 2drop THEN + drop ; +: .dir-entries ( adr n -- ) + 0 ?DO dup i 20 * + dup c@ 0= IF drop LEAVE THEN .dir-entry LOOP drop ; +: .dir ( cluster# -- ) + read-dir BEGIN data @ #data @ 20 / .dir-entries next-cluster @ WHILE + next-cluster @ read-cluster REPEAT ; + +: str-upper ( str len adr -- ) \ Copy string to adr, uppercase + -rot bounds ?DO i c@ upc over c! char+ LOOP drop ; +CREATE dos-name b allot +: make-dos-name ( str len -- ) + dos-name b bl fill + 2dup [char] . findchar IF + 3dup 1+ /string 3 min dos-name 8 + str-upper nip THEN + 8 min dos-name str-upper ; + +: (find-file) ( -- cluster file-len is-dir? true | false ) + data @ BEGIN dup data @ #data @ + < WHILE + dup dos-name b comp WHILE 20 + REPEAT + dup 1a + 2c@ bwjoin swap dup 1c + 4c@ bljoin swap 0b + c@ 10 and 0<> true + ELSE drop false THEN ; +: find-file ( dir-cluster name len -- cluster file-len is-dir? true | false ) + make-dos-name read-dir BEGIN (find-file) 0= WHILE next-cluster @ WHILE + next-cluster @ read-cluster REPEAT false ELSE true THEN ; +: find-path ( dir-cluster name len -- cluster file-len true | false ) + dup 0= IF 3drop false ." empty name " EXIT THEN + over c@ [char] \ = IF 1 /string RECURSE EXIT THEN + [char] \ split 2>r find-file 0= IF 2r> 2drop false ." not found " EXIT THEN + r@ 0<> <> IF 2drop 2r> 2drop false ." no dir<->file match " EXIT THEN + r@ 0<> IF drop 2r> RECURSE EXIT THEN + 2r> 2drop true ; + +: do-super ( -- ) + 0 200 read-data + data @ 0b + 2c@ bwjoin bytes/sector ! + data @ 0d + c@ sectors/cluster ! + bytes/sector @ sectors/cluster @ * bytes/cluster ! + data @ 0e + 2c@ bwjoin #reserved-sectors ! + data @ 10 + c@ #fats ! + data @ 11 + 2c@ bwjoin #root-entries ! + data @ 13 + 2c@ bwjoin total-#sectors ! + data @ 15 + c@ media-descriptor ! + data @ 16 + 2c@ bwjoin sectors/fat ! + data @ 18 + 2c@ bwjoin sectors/track ! + data @ 1a + 2c@ bwjoin #heads ! + data @ 1c + 2c@ bwjoin #hidden-sectors ! + + \ For FAT16 and FAT32: + total-#sectors @ 0= IF data @ 20 + 4c@ bljoin total-#sectors ! THEN + + \ For FAT32: + sectors/fat @ 0= IF data @ 24 + 4c@ bljoin sectors/fat ! THEN + + \ XXX add other FAT32 stuff (offsets 28, 2c, 30) + + \ Compute the number of data clusters, decide what FAT type we are. + total-#sectors @ #reserved-sectors @ - sectors/fat @ #fats @ * - + #root-entries @ 20 * bytes/sector @ // - sectors/cluster @ / + dup #clusters ! + dup ff5 < IF drop c ELSE fff5 < IF 10 ELSE 20 THEN THEN fat-type ! + base @ decimal base ! + + \ Starting offset of first fat. + #reserved-sectors @ bytes/sector @ * fat-offset ! + + \ Starting offset of root dir. + #fats @ sectors/fat @ * bytes/sector @ * fat-offset @ + root-offset ! + + \ Starting offset of "cluster 0". + #root-entries @ 20 * bytes/sector @ tuck // * root-offset @ + + bytes/cluster @ 2* - cluster-offset ! ; + + +INSTANCE VARIABLE file-cluster +INSTANCE VARIABLE file-len +INSTANCE VARIABLE current-pos +INSTANCE VARIABLE pos-in-data + +: seek ( lo hi -- status ) + lxjoin dup current-pos ! file-cluster @ read-cluster + \ Read and skip blocks until we are where we want to be. + BEGIN dup #data @ >= WHILE #data @ - next-cluster @ dup 0= IF + 2drop true EXIT THEN read-cluster REPEAT pos-in-data ! false ; +: read ( adr len -- actual ) + file-len @ current-pos @ - min \ can't go past end of file + #data @ pos-in-data @ - min >r \ length for this transfer + data @ pos-in-data @ + swap r@ move \ move the data + r@ pos-in-data +! r@ current-pos +! pos-in-data @ #data @ = IF + next-cluster @ ?dup IF read-cluster 0 pos-in-data ! THEN THEN r> ; +: read ( adr len -- actual ) + file-len @ min \ len cannot be greater than file size + dup >r BEGIN dup WHILE 2dup read dup 0= ABORT" fat-files: read failed" + /string ( tuck - >r + r> ) REPEAT 2drop r> ; +: load ( adr -- len ) + file-len @ read dup file-len @ <> ABORT" fat-files: failed loading file" ; + +: close free-data ; +: open + do-super + 0 my-args find-path 0= IF close false EXIT THEN + file-len ! file-cluster ! 0 0 seek 0= ; diff --git a/qemu/roms/SLOF/slof/fs/packages/filler.fs b/qemu/roms/SLOF/slof/fs/packages/filler.fs new file mode 100644 index 000000000..bd5c17a39 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/filler.fs @@ -0,0 +1,21 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +s" filler" device-name + +: block-size s" block-size" $call-parent ; +: seek s" seek" $call-parent ; +: read s" read" $call-parent ; + +: open true ; +: close ; diff --git a/qemu/roms/SLOF/slof/fs/packages/iso-9660.fs b/qemu/roms/SLOF/slof/fs/packages/iso-9660.fs new file mode 100644 index 000000000..6eda8be70 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/iso-9660.fs @@ -0,0 +1,325 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +s" iso-9660" device-name + + +0 VALUE iso-debug-flag + +\ Method for code clean up - For release version of code iso-debug-flag is +\ cleared and for debugging it is set + +: iso-debug-print ( str len -- ) iso-debug-flag IF type cr ELSE 2drop THEN ; + + +\ -------------------------------------------------------- +\ GLOBAL VARIABLES +\ -------------------------------------------------------- + + +0 VALUE path-tbl-size +0 VALUE path-tbl-addr +0 VALUE root-dir-size +0 VALUE vol-size +0 VALUE logical-blk-size +0 VALUE path-table +0 VALUE count + + +\ INSTANCE VARIABLES + + +INSTANCE VARIABLE dir-addr +INSTANCE VARIABLE data-buff +INSTANCE VARIABLE #data +INSTANCE VARIABLE ptable +INSTANCE VARIABLE file-loc +INSTANCE VARIABLE file-size +INSTANCE VARIABLE cur-file-offset +INSTANCE VARIABLE self +INSTANCE VARIABLE index + + +\ -------------------------------------------------------- +\ COLON DEFINITIONS +\ -------------------------------------------------------- + + +\ This method is used to seek to the required position +\ Which calls seek of disk-label + +: seek ( pos.lo pos.hi -- status ) s" seek" $call-parent ; + + +\ This method is used to read the contents of disk +\ it calls read of disk-label + + + : read ( addr len -- actual ) s" read" $call-parent ; + + +\ This method releases the memory used as scratch pad buffer. + +: free-data ( -- ) + data-buff @ ( data-buff ) + ?DUP IF #data @ free-mem 0 data-buff ! 0 #data ! THEN +; + + +\ This method will release the previous allocated scratch pad buffer and +\ allocates a fresh buffer and copies the required number of bytes from the +\ media in to it. + +: read-data ( offset size -- ) + dup #data @ > IF + free-data dup dup ( offset size size size ) + #data ! alloc-mem data-buff ! ( offset size ) + THEN + swap xlsplit ( size pos.lo pos.hi ) + seek -2 and ABORT" seek failed." + data-buff @ over read ( size actual ) + <> ABORT" read failed." +; + + +\ This method extracts the information required from primary volume +\ descriptor and stores the required information in the global variables + +: extract-vol-info ( -- ) + 10 800 * 800 read-data + data-buff @ 88 + l@-be to path-tbl-size \ read path table size + data-buff @ 94 + l@-be to path-tbl-addr \ read big-endian path table + data-buff @ a2 + l@-be dir-addr ! \ gather of root directory info + data-buff @ 0aa + l@-be to root-dir-size \ get volume info + data-buff @ 54 + l@-be to vol-size \ size in blocks + data-buff @ 82 + l@-be to logical-blk-size + path-tbl-size alloc-mem dup TO path-table path-tbl-size erase + path-tbl-addr 800 * xlsplit seek drop + path-table path-tbl-size read drop \ pathtable in-system-memory copy +; + + +\ This method coverts the iso file name to user readble form + +: file-name ( str len -- str' len' ) + 2dup [char] ; findchar IF + ( str len offset ) + nip \ Omit the trailing ";1" revision of ISO9660 file name + 2dup + 1- ( str newlen endptr ) + c@ [CHAR] . = IF + 1- ( str len' ) \ Remove trailing dot + THEN + THEN +; + + +\ triplicates top stack element + +: dup3 ( num -- num num num ) dup dup dup ; + + +\ This method is used for traversing records of path table. If the +\ file identifier length is odd 1 byte padding is done else not. + +: get-next-record ( rec-addr -- next-rec-offset ) + dup3 ( rec-addr rec-addr rec-addr rec-addr ) + self @ 1 + self ! ( rec-addr rec-addr rec-addr rec-addr ) + c@ 1 AND IF ( rec-addr rec-addr rec-addr ) + c@ + 9 ( rec-addr rec-addr' rec-len ) + ELSE + c@ + 8 ( rec-addr rec-addr' rec-len ) + THEN + + swap - ( next-rec-offset ) +; + + +\ This method does search of given directory name in the path table +\ and returns true if finds a match else false. + +: path-table-search ( str len -- TRUE | FALSE ) + path-table path-tbl-size + path-table ptable @ + DO ( str len ) + 2dup I 6 + w@-be index @ = ( str len str len ) + -rot I 8 + I c@ + iso-debug-flag IF + ." ISO: comparing path name '" + 4dup type ." ' with '" type ." '" cr + THEN + string=ci and IF ( str len ) + s" Directory Matched!! " iso-debug-print ( str len ) + self @ index ! ( str len ) + I 2 + l@-be dir-addr ! I dup ( str len rec-addr ) + get-next-record + path-table - ptable ! ( str len ) + 2drop TRUE UNLOOP EXIT ( TRUE ) + THEN + I get-next-record ( str len next-rec-offset ) + +LOOP + 2drop + FALSE ( FALSE ) + s" Invalid path / directory " iso-debug-print +; + + +\ METHOD for searching for a file with in a direcotory + +: search-file-dir ( str len -- TRUE | FALSE ) + dir-addr @ 800 * dir-addr ! ( str len ) + dir-addr @ 100 read-data ( str len ) + data-buff @ 0e + l@-be dup >r ( str len rec-len ) + 100 > IF ( str len ) + s" size dir record" iso-debug-print ( str len ) + dir-addr @ r@ read-data ( str len ) + THEN + r> data-buff @ + data-buff @ DO ( str len ) + I 19 + c@ 2 and 0= I c@ 0<> and IF ( str len ) + 2dup ( str len str len ) + I 21 + I 20 + c@ ( str len str len str' len' ) + iso-debug-flag IF + ." ISO: comparing file name '" + 4dup type ." ' with '" type ." '" cr + THEN + file-name string=ci IF ( str len ) + s" File found!" iso-debug-print ( str len ) + I 6 + l@-be 800 * ( str len file-loc ) + file-loc ! ( str len ) + I 0e + l@-be file-size ! ( str len ) + 2drop + TRUE ( TRUE ) + UNLOOP + EXIT + THEN + THEN + ( str len ) + I c@ ?dup 0= IF + 800 I 7ff AND - + iso-debug-flag IF + ." skipping " dup . ." bytes at end of sector" cr + THEN + THEN + ( str len offset ) + +LOOP + 2drop + FALSE ( FALSE ) + s" file not found" iso-debug-print +; + + +\ This method splits the given absolute path in to directories from root and +\ calls search-path-table. when string reaches to state when it can not be +\ split i.e., end of the path, calls search-file-dir is made to search for +\ file . + +: search-path ( str len -- FALSE|TRUE ) + 0 ptable ! + 1 self ! + 1 index ! + dup ( str len len ) + 0= IF + 3drop FALSE ( FALSE ) + s" Empty path name " iso-debug-print EXIT ( FALSE ) + THEN + OVER c@ ( str len char ) + [char] \ = IF ( str len ) + swap 1 + swap 1 - BEGIN ( str len ) + [char] \ split ( str len str' len ' ) + dup 0 = IF ( str len str' len ' ) + 2drop search-file-dir EXIT ( TRUE | FALSE ) + ELSE + 2swap path-table-search invert IF ( str' len ' ) + 2drop FALSE EXIT ( FALSE ) + THEN + THEN + AGAIN + ELSE BEGIN + [char] \ split dup 0 = IF ( str len str' len' ) + 2drop search-file-dir EXIT ( TRUE | FALSE ) + ELSE + 2swap path-table-search invert IF ( str' len ' ) + 2drop FALSE EXIT ( FALSE ) + THEN + THEN + AGAIN + THEN +; + + +\ this method will seek and read the file in to the given memory location + +0 VALUE loc +: load ( addr -- len ) + dup to loc ( addr ) + file-loc @ xlsplit seek drop + file-size @ read ( file-size ) + iso-debug-flag IF s" Bytes returned from read:" type dup . cr THEN + dup file-size @ <> ABORT" read failed!" +; + + + +\ memory used by the file system will be freed + +: close ( -- ) + free-data count 1 - dup to count 0 = IF + path-table path-tbl-size free-mem + 0 TO path-table + THEN +; + + +\ open method of the file system + +: open ( -- TRUE | FALSE ) + 0 data-buff ! + 0 #data ! + 0 ptable ! + 0 file-loc ! + 0 file-size ! + 0 cur-file-offset ! + 1 self ! + 1 index ! + count 0 = IF + s" extract-vol-info called " iso-debug-print + extract-vol-info + THEN + count 1 + to count + my-args search-path IF + file-loc @ xlsplit seek drop + TRUE ( TRUE ) + ELSE + close + FALSE ( FALSE ) + THEN + 0 cur-file-offset ! + s" opened ISO9660 package" iso-debug-print +; + + +\ public seek method + +: seek ( pos.lo pos.hi -- status ) + lxjoin dup cur-file-offset ! ( offset ) + file-loc @ + xlsplit ( pos.lo pos.hi ) + s" seek" $call-parent ( status ) +; + + +\ public read method + + : read ( addr len -- actual ) + file-size @ cur-file-offset @ - ( addr len remainder-of-file ) + min ( addr len|remainder-of-file ) + s" read" $call-parent ( actual ) + dup cur-file-offset @ + cur-file-offset ! ( actual ) + cur-file-offset @ ( offset actual ) + xlsplit seek drop ( actual ) +; + diff --git a/qemu/roms/SLOF/slof/fs/packages/obp-tftp.fs b/qemu/roms/SLOF/slof/fs/packages/obp-tftp.fs new file mode 100644 index 000000000..89143a669 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/obp-tftp.fs @@ -0,0 +1,71 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +s" obp-tftp" device-name + +INSTANCE VARIABLE ciregs-buffer + +: open ( -- okay? ) + ciregs-size alloc-mem ciregs-buffer ! + true +; + +: load ( addr -- size ) + + \ Save old client interface register + ciregs ciregs-buffer @ ciregs-size move + + s" bootargs" get-chosen 0= IF 0 0 THEN >r >r + s" bootpath" get-chosen 0= IF 0 0 THEN >r >r + + \ Set bootpath to current device + my-parent ihandle>phandle node>path encode-string + s" bootpath" set-chosen + + \ Generate arg string for snk like + \ "netboot load-addr length filename" + (u.) s" netboot " 2swap $cat s" 60000000 " $cat + + \ Allocate 1720 bytes to store the BOOTP-REPLY packet + 6B8 alloc-mem dup >r (u.) $cat s" " $cat + huge-tftp-load @ IF s" 1 " ELSE s" 0 " THEN $cat + \ Add desired TFTP-Blocksize as additional argument + s" 1432 " $cat + \ Add OBP-TFTP Bootstring argument, e.g. "10.128.0.1,bootrom.bin,10.128.40.1" + my-args $cat + + \ Call SNK netboot loadr + (client-exec) dup 0< IF drop 0 THEN + + \ Restore to old client interface register + ciregs-buffer @ ciregs ciregs-size move + + \ Recover buffer address of BOOTP-REPLY packet + r> + + r> r> over IF s" bootpath" set-chosen ELSE 2drop THEN + r> r> over IF s" bootargs" set-chosen ELSE 2drop THEN + + \ Store BOOTP-REPLY packet as property + dup 6B8 encode-bytes s" bootp-response" s" /chosen" find-node set-property + + \ free buffer + 6B8 free-mem +; + +: close ( -- ) + ciregs-buffer @ ciregs-size free-mem +; + +: ping ( -- ) + s" ping " my-args $cat (client-exec) +; diff --git a/qemu/roms/SLOF/slof/fs/packages/rom-files.fs b/qemu/roms/SLOF/slof/fs/packages/rom-files.fs new file mode 100644 index 000000000..418cf4e05 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/rom-files.fs @@ -0,0 +1,85 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ package which adds support to read the romfs +\ this package is somehow limited as the maximum supported length +\ for a file name is hardcoded to 0x100 + +s" rom-files" device-name + +INSTANCE VARIABLE length +INSTANCE VARIABLE next-file +INSTANCE VARIABLE buffer +INSTANCE VARIABLE buffer-size +INSTANCE VARIABLE file +INSTANCE VARIABLE file-size +INSTANCE VARIABLE found + +: open true + 100 dup buffer-size ! alloc-mem buffer ! false found ! ; +: close buffer @ buffer-size @ free-mem ; + +: read ( addr len -- actual ) s" read" $call-parent ; + +: seek ( lo hi -- status ) s" seek" $call-parent ; + +: .read-file-name ( offset -- str len ) + \ move to the file name offset + 0 seek drop + \ read <buffer-size> bytes from that address + buffer @ buffer-size @ read drop + \ write a 0 to make sure it is a 0 terminated string + buffer-size @ 1 - buffer @ + 0 swap c! + buffer @ zcount ; + +: .print-info ( offset -- ) + dup 2 spaces 6 0.r 2 spaces dup + 8 + 0 seek drop length 8 read drop + 6 length @ swap 0.r 2 spaces + 20 + .read-file-name type cr ; + +: .list-header cr + s" --offset---size-----file-name----" type cr ; + +: list + .list-header + 0 0 BEGIN + dup + .print-info dup 0 seek drop + next-file 8 read drop next-file @ + dup 0= UNTIL 2drop ; + +: (find-file) ( name len -- offset | -1 ) + 0 0 seek drop false found ! + file-size ! file ! 0 0 BEGIN + dup + 20 + .read-file-name file @ file-size @ + str= IF true found ! THEN + dup 0 seek drop + next-file 8 read drop next-file @ + dup 0= found @ or UNTIL drop found @ 0= + IF drop -1 THEN ; + +: load ( addr -- size ) + my-parent instance>args 2@ [char] \ left-parse-string 2drop + (find-file) dup -1 = IF 2drop 0 ELSE + \ got to the beginning + 0 0 seek drop + \ read the file size + dup 8 + 0 seek drop + here 8 read drop here @ ( dest-addr offset file-size ) + \ read data start offset + over 18 + 0 seek drop + here 8 read drop here @ ( dest-addr offset file-size data-offset ) + rot + 0 seek drop ( dest-addr file-size ) + read + THEN +; diff --git a/qemu/roms/SLOF/slof/fs/packages/sms.fs b/qemu/roms/SLOF/slof/fs/packages/sms.fs new file mode 100644 index 000000000..d8c672f72 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/packages/sms.fs @@ -0,0 +1,29 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +s" /packages" find-device + +new-device + s" sms" device-name + + : open true ; + + : close ; + + \ The rest of methods is loaded dynamically from the romfs + \ on a first call to sms-start + +finish-device + +device-end \ leave /packages + diff --git a/qemu/roms/SLOF/slof/fs/pci-bridge.fs b/qemu/roms/SLOF/slof/fs/pci-bridge.fs new file mode 100644 index 000000000..e6af7b65c --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/pci-bridge.fs @@ -0,0 +1,65 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ get the PUID from the node above +get-node CONSTANT my-phandle +s" my-puid" my-phandle parent $call-static CONSTANT my-puid + +\ Save the bus number provided by this bridge +pci-bus-number 1+ CONSTANT my-bus + +s" pci-config-bridge.fs" included +s" dma-function.fs" included + +\ generate the rom-fs filename from the vendor and device ID "pci-bridge_VENDORID_DEVICEID.fs" +: filename ( -- str len ) + s" pci-bridge_" + my-space pci-vendor@ 4 int2str $cat + s" _" $cat + my-space pci-device@ 4 int2str $cat + s" .fs" $cat +; + +\ Set up the Bridge with either default or special settings +: setup ( -- ) + \ is there special handling for this device, given vendor and device id? + filename romfs-lookup ?dup + IF + \ give it a special treatment + evaluate + ELSE + \ no special handling for this device, attempt autoconfiguration + my-space pci-class-name type 2a emit cr + my-space pci-bridge-generic-setup + my-space pci-reset-2nd + THEN +; + +\ Disable Bus Master, Memory Space and I/O Space for +\ this device and so for the scanning for the devices behind +pci-device-disable + +\ Enalbe #PERR and #SERR reporting +pci-error-enable + +\ Print out device information +my-space 42 pci-out \ config-addr ascii('B') + +\ and set up the bridge +setup + +\ And enable Bus Master IO and MEM access again. +\ we need that on bridges so that the devices behind +\ can set their state on their own. +pci-master-enable +pci-mem-enable +pci-io-enable diff --git a/qemu/roms/SLOF/slof/fs/pci-class-code-names.fs b/qemu/roms/SLOF/slof/fs/pci-class-code-names.fs new file mode 100644 index 000000000..f3a49454d --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/pci-class-code-names.fs @@ -0,0 +1,264 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: pci-class-name-00 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 01 OF s" display" ENDOF + dup OF s" unknown-legacy-device" ENDOF + ENDCASE +; + +: pci-class-name-01 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" scsi" ENDOF + 01 OF s" ide" ENDOF + 02 OF s" fdc" ENDOF + 03 OF s" ipi" ENDOF + 04 OF s" raid" ENDOF + 05 OF s" ata" ENDOF + 06 OF s" sata" ENDOF + 07 OF s" sas" ENDOF + dup OF s" mass-storage" ENDOF + ENDCASE +; + +: pci-class-name-02 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" ethernet" ENDOF + 01 OF s" token-ring" ENDOF + 02 OF s" fddi" ENDOF + 03 OF s" atm" ENDOF + 04 OF s" isdn" ENDOF + 05 OF s" worldfip" ENDOF + 05 OF s" picmg" ENDOF + dup OF s" network" ENDOF + ENDCASE +; + +: pci-class-name-03 ( addr -- str len ) + pci-class@ FFFF and CASE + 0000 OF s" vga" ENDOF + 0001 OF s" 8514-compatible" ENDOF + 0100 OF s" xga" ENDOF + 0200 OF s" 3d-controller" ENDOF + dup OF s" display" ENDOF + ENDCASE +; + +: pci-class-name-04 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" video" ENDOF + 01 OF s" sound" ENDOF + 02 OF s" telephony" ENDOF + dup OF s" multimedia-device" ENDOF + ENDCASE +; + +: pci-class-name-05 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" memory" ENDOF + 01 OF s" flash" ENDOF + dup OF s" memory-controller" ENDOF + ENDCASE +; + +: pci-class-name-06 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" host" ENDOF + 01 OF s" isa" ENDOF + 02 OF s" eisa" ENDOF + 03 OF s" mca" ENDOF + 04 OF s" pci" ENDOF + 05 OF s" pcmcia" ENDOF + 06 OF s" nubus" ENDOF + 07 OF s" cardbus" ENDOF + 08 OF s" raceway" ENDOF + 09 OF s" semi-transparent-pci" ENDOF + 0A OF s" infiniband" ENDOF + dup OF s" unkown-bridge" ENDOF + ENDCASE +; + +: pci-class-name-07 ( addr -- str len ) + pci-class@ FFFF and CASE + 0000 OF s" serial" ENDOF + 0001 OF s" 16450-serial" ENDOF + 0002 OF s" 16550-serial" ENDOF + 0003 OF s" 16650-serial" ENDOF + 0004 OF s" 16750-serial" ENDOF + 0005 OF s" 16850-serial" ENDOF + 0006 OF s" 16950-serial" ENDOF + 0100 OF s" parallel" ENDOF + 0101 OF s" bi-directional-parallel" ENDOF + 0102 OF s" ecp-1.x-parallel" ENDOF + 0103 OF s" ieee1284-controller" ENDOF + 01FE OF s" ieee1284-device" ENDOF + 0200 OF s" multiport-serial" ENDOF + 0300 OF s" modem" ENDOF + 0301 OF s" 16450-modem" ENDOF + 0302 OF s" 16550-modem" ENDOF + 0303 OF s" 16650-modem" ENDOF + 0304 OF s" 16750-modem" ENDOF + 0400 OF s" gpib" ENDOF + 0500 OF s" smart-card" ENDOF + dup OF s" communication-controller" ENDOF + ENDCASE +; + + +: pci-class-name-08 ( addr -- str len ) + pci-class@ FFFF and CASE + 0000 OF s" interrupt-controller" ENDOF + 0001 OF s" isa-pic" ENDOF + 0002 OF s" eisa-pic" ENDOF + 0010 OF s" io-apic" ENDOF + 0020 OF s" iox-apic" ENDOF + 0100 OF s" dma-controller" ENDOF + 0101 OF s" isa-dma" ENDOF + 0102 OF s" eisa-dma" ENDOF + 0200 OF s" timer" ENDOF + 0201 OF s" isa-system-timer" ENDOF + 0202 OF s" eisa-system-timer" ENDOF + 0300 OF s" rtc" ENDOF + 0301 OF s" isa-rtc" ENDOF + 0400 OF s" hot-plug-controller" ENDOF + 0500 OF s" sd-host-conrtoller" ENDOF + dup OF s" system-periphal" ENDOF + ENDCASE +; + +: pci-class-name-09 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" keyboard" ENDOF + 01 OF s" pen" ENDOF + 02 OF s" mouse" ENDOF + 03 OF s" scanner" ENDOF + 04 OF s" gameport" ENDOF + dup OF s" input-controller" ENDOF + ENDCASE +; + +: pci-class-name-0A ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" dock" ENDOF + dup OF s" docking-station" ENDOF + ENDCASE +; + +: pci-class-name-0B ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" 386" ENDOF + 01 OF s" 486" ENDOF + 02 OF s" pentium" ENDOF + 10 OF s" alpha" ENDOF + 20 OF s" powerpc" ENDOF + 30 OF s" mips" ENDOF + 40 OF s" co-processor" ENDOF + dup OF s" cpu" ENDOF + ENDCASE +; + +: pci-class-name-0C ( addr -- str len ) + pci-class@ FFFF and CASE + 0000 OF s" firewire" ENDOF + 0100 OF s" access-bus" ENDOF + 0200 OF s" ssa" ENDOF + 0300 OF s" usb-uhci" ENDOF + 0310 OF s" usb-ohci" ENDOF + 0320 OF s" usb-ehci" ENDOF + 0330 OF s" usb-xhci" ENDOF + 0380 OF s" usb" ENDOF + 03FE OF s" usb-device" ENDOF + 0400 OF s" fibre-channel" ENDOF + 0500 OF s" smb" ENDOF + 0600 OF s" infiniband" ENDOF + 0700 OF s" ipmi-smic" ENDOF + 0701 OF s" ipmi-kbrd" ENDOF + 0702 OF s" ipmi-bltr" ENDOF + 0800 OF s" sercos" ENDOF + 0900 OF s" canbus" ENDOF + dup OF s" serial-bus" ENDOF + ENDCASE +; + +: pci-class-name-0D ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" irda" ENDOF + 01 OF s" consumer-ir" ENDOF + 10 OF s" rf-controller" ENDOF + 11 OF s" bluetooth" ENDOF + 12 OF s" broadband" ENDOF + 20 OF s" enet-802.11a" ENDOF + 21 OF s" enet-802.11b" ENDOF + dup OF s" wireless-controller" ENDOF + ENDCASE +; + + +: pci-class-name-0E ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + dup OF s" intelligent-io" ENDOF + ENDCASE +; + +: pci-class-name-0F ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 01 OF s" satelite-tv" ENDOF + 02 OF s" satelite-audio" ENDOF + 03 OF s" satelite-voice" ENDOF + 04 OF s" satelite-data" ENDOF + dup OF s" satelite-devoce" ENDOF + ENDCASE +; + +: pci-class-name-10 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" network-encryption" ENDOF + 01 OF s" entertainment-encryption" ENDOF + dup OF s" encryption" ENDOF + ENDCASE +; + +: pci-class-name-11 ( addr -- str len ) + pci-class@ 8 rshift FF and CASE + 00 OF s" dpio" ENDOF + 01 OF s" counter" ENDOF + 10 OF s" measurement" ENDOF + 20 OF s" managment-card" ENDOF + dup OF s" data-processing-controller" ENDOF + ENDCASE +; + +\ create a string holding the predefined Class-Code-Names +: pci-class-name ( addr -- str len ) + dup pci-class@ 10 rshift CASE + 00 OF pci-class-name-00 ENDOF + 01 OF pci-class-name-01 ENDOF + 02 OF pci-class-name-02 ENDOF + 03 OF pci-class-name-03 ENDOF + 04 OF pci-class-name-04 ENDOF + 05 OF pci-class-name-05 ENDOF + 06 OF pci-class-name-06 ENDOF + 07 OF pci-class-name-07 ENDOF + 08 OF pci-class-name-08 ENDOF + 09 OF pci-class-name-09 ENDOF + 0A OF pci-class-name-0A ENDOF + 0B OF pci-class-name-0B ENDOF + 0C OF pci-class-name-0C ENDOF + 0C OF pci-class-name-0D ENDOF + 0C OF pci-class-name-0E ENDOF + 0C OF pci-class-name-0F ENDOF + 0C OF pci-class-name-10 ENDOF + 0C OF pci-class-name-11 ENDOF + dup OF drop s" unknown" ENDOF + ENDCASE +; diff --git a/qemu/roms/SLOF/slof/fs/pci-config-bridge.fs b/qemu/roms/SLOF/slof/fs/pci-config-bridge.fs new file mode 100644 index 000000000..689325318 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/pci-config-bridge.fs @@ -0,0 +1,111 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Generic config space access function - xt is execution token of rtas-config-xx +: config-xt ( config-addr xt -- data ) + puid >r \ Safe puid + my-puid TO puid \ Set my-puid + swap dup ffff00 AND 0= IF \ Has bus-device-function been specified? + my-space OR \ No: use my-space instead + THEN + swap execute \ Execute the rtas-config-xx function + r> TO puid \ Restore previous puid +; + +\ define the config reads +: config-b@ ( config-addr -- data ) ['] rtas-config-b@ config-xt ; +: config-w@ ( config-addr -- data ) ['] rtas-config-w@ config-xt ; +: config-l@ ( config-addr -- data ) ['] rtas-config-l@ config-xt ; + +\ define the config writes +: config-b! ( data config-addr -- ) ['] rtas-config-b! config-xt ; +: config-w! ( data config-addr -- ) ['] rtas-config-w! config-xt ; +: config-l! ( data config-addr -- ) ['] rtas-config-l! config-xt ; + +\ for Debug purposes: dumps the whole config space +: config-dump puid >r my-puid TO puid my-space pci-dump r> TO puid ; + +\ needed to find the right path in the device tree +: decode-unit ( addr len -- phys.lo ... phys.hi ) + 2 hex-decode-unit \ decode string + B lshift swap \ shift the devicenumber to the right spot + 8 lshift or \ add the functionnumber + my-bus 10 lshift or \ add the busnumber + 0 0 rot \ make phys.lo = 0 = phys.mid +; + +\ needed to have the right unit address in the device tree listing +\ phys.lo=phys.mid=0 , phys.hi=config-address +: encode-unit ( phys.lo ... phys.hi -- unit-str unit-len ) + nip nip \ forget the both zeros + dup 8 rshift 7 and swap \ calc Functionnumber + B rshift 1F and \ calc Devicenumber + over IF \ IF Function!=0 + 2 hex-encode-unit \ | create string with DevNum,FnNum + ELSE \ ELSE + nip 1 hex-encode-unit \ | create string with only DevNum + THEN \ FI +; + +: map-in ( phys.lo phys.mid phys.hi size -- virt ) + \ ." map-in called: " .s cr + \ Ignore the size, phys.lo and phys.mid, get BAR from config space + drop nip nip ( phys.hi ) + \ Sanity check whether config address is in expected range: + dup FF AND dup 10 28 WITHIN NOT swap 30 <> AND IF + cr ." phys.hi = " . cr + ABORT" map-in with illegal config space address" + THEN + 00FFFFFF AND \ Need only bus-dev-fn+register bits + dup config-l@ ( phys.hi' bar.lo ) + dup 7 AND 4 = IF \ Is it a 64-bit BAR? + swap 4 + config-l@ lxjoin \ Add upper part of 64-bit BAR + ELSE + nip + THEN + F NOT AND \ Clear indicator bits + \ TODO: Use translate-address here! +; + +: map-out ( virt size -- ) + \ ." map-out called: " .s cr + 2drop +; + +: dma-alloc ( ... size -- virt ) + \ ." dma-alloc called: " .s cr + alloc-mem +; + +: dma-free ( virt size -- ) + \ ." dma-free called: " .s cr + free-mem +; + +: dma-map-in ( ... virt size cacheable? -- devaddr ) + \ ." dma-map-in called: " .s cr + 2drop +; + +: dma-map-out ( virt devaddr size -- ) + \ ." dma-map-out called: " .s cr + 2drop drop +; + +: dma-sync ( virt devaddr size -- ) + \ XXX should we add at least a memory barrier here? + \ ." dma-sync called: " .s cr + 2drop drop +; + +: open true ; +: close ; diff --git a/qemu/roms/SLOF/slof/fs/pci-device.fs b/qemu/roms/SLOF/slof/fs/pci-device.fs new file mode 100644 index 000000000..7b177585a --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/pci-device.fs @@ -0,0 +1,105 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +get-node CONSTANT my-phandle + +\ get the PUID from the node above +s" my-puid" my-phandle parent $call-static CONSTANT my-puid + +\ define the config reads +: config-b@ puid >r my-puid TO puid my-space + rtas-config-b@ r> TO puid ; +: config-w@ puid >r my-puid TO puid my-space + rtas-config-w@ r> TO puid ; +: config-l@ puid >r my-puid TO puid my-space + rtas-config-l@ r> TO puid ; + +\ define the config writes +: config-b! puid >r my-puid TO puid my-space + rtas-config-b! r> TO puid ; +: config-w! puid >r my-puid TO puid my-space + rtas-config-w! r> TO puid ; +: config-l! puid >r my-puid TO puid my-space + rtas-config-l! r> TO puid ; + +\ for Debug purposes: dumps the whole config space +: config-dump puid >r my-puid TO puid my-space pci-dump r> TO puid ; + +\ prepare the device for subsequent use +\ this word should be overloaded by the device file (if present) +\ the device file can call this file before implementing +\ its own open functionality +: open + puid >r \ save the old puid + my-puid TO puid \ set up the puid to the devices Hostbridge + pci-master-enable \ And enable Bus Master, IO and MEM access again. + pci-mem-enable \ enable mem access + pci-io-enable \ enable io access + r> TO puid \ restore puid + true +; + +\ close the previously opened device +\ this word should be overloaded by the device file (if present) +\ the device file can call this file after its implementation +\ of own close functionality +: close + puid >r \ save the old puid + my-puid TO puid \ set up the puid + pci-device-disable \ and disable the device + r> TO puid \ restore puid +; + +s" dma-function.fs" included + +\ generate the rom-fs filename from the vendor and device ID "pci-device_VENDORID_DEVICEID.fs" +: devicefile ( -- str len ) + s" pci-device_" + my-space pci-vendor@ 4 int2str $cat + s" _" $cat + my-space pci-device@ 4 int2str $cat + s" .fs" $cat +; + +\ generate the rom-fs filename from the base-class id "pci-class_BASECLASS.fs" +: classfile ( -- str len ) + s" pci-class_" + my-space pci-class@ 10 rshift 2 int2str $cat + s" .fs" $cat +; + +\ Set up the device with either default or special settings +: setup ( -- ) + \ is there special handling for this device, given vendor and device id? + devicefile romfs-lookup ?dup + IF + \ give it a special treatment + evaluate + ELSE + classfile romfs-lookup ?dup + IF + \ give it a pci-class related treatment + evaluate + ELSE + \ no special handling for this device, attempt autoconfiguration + my-space pci-class-name type 2a emit cr + my-space pci-device-generic-setup + THEN + THEN +; + +\ Disable Bus Master, Memory Space and I/O Space for this device +\ if Bus Master function is needed it should be enabled/disabled by open/close in the device driver code +pci-device-disable + +\ Enalbe #PERR and #SERR reporting +pci-error-enable + +\ Print out device information +my-space 44 pci-out \ config-addr ascii('D') + +\ and set up the device +setup diff --git a/qemu/roms/SLOF/slof/fs/pci-helper.fs b/qemu/roms/SLOF/slof/fs/pci-helper.fs new file mode 100644 index 000000000..a4f69f1f3 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/pci-helper.fs @@ -0,0 +1,195 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ---------------------------------------------------------- +\ **************** PCI Helper functions ******************* +\ ---------------------------------------------------------- + +\ convert an integer to string of len digits +: int2str ( int len -- str len ) swap s>d rot <# 0 ?DO # LOOP #> ; + +\ convert addr to busnr +: pci-addr2bus ( addr -- busnr ) 10 rshift FF and ; + +\ convert addr to devnr +: pci-addr2dev ( addr -- dev ) B rshift 1F and ; + +\ convert addr to functionnumber +: pci-addr2fn ( addr -- dev ) 8 rshift 7 and ; + +\ convert busnr devnr to addr +: pci-bus2addr ( busnr devnr -- addr ) B lshift swap 10 lshift + ; + +\ print out a pci config addr +: pci-addr-out ( addr -- ) dup pci-addr2bus 2 0.r space FFFF and 4 0.r ; + +\ Dump out the whole configspace +: pci-dump ( addr -- ) + 10 0 DO + dup + cr i 4 * + + dup pci-addr-out space + rtas-config-l@ 8 0.r + LOOP + drop cr +; + + +\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\ the following functions use l@ to fetch the data, +\ that's because the some pcie cores have probs with w@ +\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +\ read Vendor ID +: pci-vendor@ ( addr -- id ) rtas-config-l@ FFFF and ; + +\ read Device ID +: pci-device@ ( addr -- id ) rtas-config-l@ 10 rshift ; + +\ read Status +: pci-status@ ( addr -- status ) 4 + rtas-config-l@ 10 rshift ; + +\ read Revision ID +: pci-revision@ ( addr -- id ) 8 + rtas-config-b@ ; + +\ read Class Code +: pci-class@ ( addr -- class ) 8 + rtas-config-l@ 8 rshift ; + +\ read Cache Line Size +: pci-cache@ ( addr -- size ) C + rtas-config-b@ ; + +\ read Header Type +: pci-htype@ ( addr -- type ) E + rtas-config-b@ ; + +\ read Sub Vendor ID +: pci-sub-vendor@ ( addr -- sub-id ) 2C + rtas-config-l@ FFFF and ; + +\ read Sub Device ID +: pci-sub-device@ ( addr -- sub-id ) 2C + rtas-config-l@ 10 rshift FFFF and ; + +\ read Interrupt Pin +: pci-interrupt@ ( addr -- interrupt ) 3D + rtas-config-b@ ; + +\ read Minimum Grant +: pci-min-grant@ ( addr -- min-gnt ) 3E + rtas-config-b@ ; + +\ read Maximum Latency +: pci-max-lat@ ( addr -- max-lat ) 3F + rtas-config-b@ ; + +\ Check if Capabilities are valid +: pci-capabilities? ( addr -- 0|1 ) pci-status@ 4 rshift 1 and ; + +\ fetch the offset of the next capability +: pci-cap-next ( cap-addr -- next-cap-off ) rtas-config-b@ FC and ; + +\ calc the address of the next capability +: pci-cap-next-addr ( cap-addr -- next-cap-addr ) 1+ dup pci-cap-next dup IF swap -100 and + ELSE nip THEN ; + + +\ Dump out all capabilities +: pci-cap-dump ( addr -- ) + cr + dup pci-capabilities? IF + 33 + BEGIN + pci-cap-next-addr dup 0<> + WHILE + dup pci-addr-out s" : " type + dup rtas-config-b@ 2 0.r cr + REPEAT + s" end found " + ELSE + s" capabilities not enabled!" + THEN + type cr drop +; + +\ search the capability-list for this id +: pci-cap-find ( addr id -- capp-addr|0 ) + swap dup pci-capabilities? IF + 33 + BEGIN + pci-cap-next-addr dup 0<> IF + dup rtas-config-b@ 2 pick = + ELSE + true + THEN + UNTIL + nip + ELSE + 2drop 0 + THEN +; + +\ check wether this device is a pci-express device +: pci-express? ( addr -- 0|1 ) 10 pci-cap-find 0<> ; + +\ check wether this device is a pci-express device +: pci-x? ( addr -- 0|1 ) 07 pci-cap-find 0<> ; + +\ check wether this device has extended config space +: pci-config-ext? ( addr -- 0|1 ) pci-express? ; + + +\ Disable Bus Master, Memory Space and I/O Space for this device +: pci-device-disable ( -- ) my-space 4 + dup rtas-config-l@ 7 invert and swap rtas-config-l! ; + +\ Enable Bus Master +: pci-master-enable ( -- ) my-space 4 + dup rtas-config-l@ 4 or swap rtas-config-l! ; + +\ Disable Bus Master +: pci-master-disable ( -- ) my-space 4 + dup rtas-config-l@ 4 invert and swap rtas-config-l! ; + +\ Enable response to mem accesses of pci device +: pci-mem-enable ( -- ) my-space 4 + dup rtas-config-w@ 2 or swap rtas-config-w! ; + +\ Enable response to I/O accesses of pci-device +: pci-io-enable ( -- ) my-space 4 + dup rtas-config-w@ 1 or swap rtas-config-w! ; + +\ Enable Bus Master, I/O and mem access +: pci-enable ( -- ) my-space 4 + dup rtas-config-w@ 7 or swap rtas-config-w! ; + +\ Enable #PERR and #SERR errors of pci-device +: pci-error-enable ( -- ) my-space 4 + dup rtas-config-w@ 140 or swap rtas-config-w! ; + +\ prints out the ScanInformation about a device +\ char is a sign for device type e.g. D - device ; B - bridge +: pci-out ( addr char -- ) + 15 spaces + over pci-addr-out + s" (" type emit s" ) : " type + dup pci-vendor@ 4 0.r space + pci-device@ 4 0.r + 4 spaces +; + + +\ set and fetch the interrupt Pin +: pci-irq-line@ ( addr -- irq-pin ) 3C + rtas-config-b@ ; +: pci-irq-line! ( pin addr -- ) 3C + rtas-config-b! ; + +\ set and fetch primary bus number +: pci-bus-prim! ( nr addr -- ) 18 + dup rtas-config-l@ FFFFFF00 and rot + swap rtas-config-l! ; +: pci-bus-prim@ ( addr -- nr ) 18 + rtas-config-l@ FF and ; + +\ set and fetch secondary bus number +: pci-bus-scnd! ( nr addr -- ) 18 + dup rtas-config-l@ FFFF00FF and rot 8 lshift + swap rtas-config-l! ; +: pci-bus-scnd@ ( addr -- nr ) 18 + rtas-config-l@ 8 rshift FF and ; + +\ set and fetch subordinate bus number +: pci-bus-subo! ( nr addr -- ) 18 + dup rtas-config-l@ FF00FFFF and rot 10 lshift + swap rtas-config-l! ; +: pci-bus-subo@ ( addr -- nr ) 18 + rtas-config-l@ 10 rshift FF and ; + +\ set and fetch primary, secondary and subordinate bus number +: pci-bus! ( subo scnd prim addr -- ) swap rot 8 lshift + rot 10 lshift + swap 18 + dup rtas-config-l@ FF000000 and rot + swap rtas-config-l! ; +: pci-bus@ ( addr -- subo scnd prim ) 18 + rtas-config-l@ dup 10 rshift FF and swap dup 8 rshift FF and swap FF and ; + +\ Reset secondary Status +: pci-reset-2nd ( addr -- ) 1C + dup rtas-config-l@ FFFF0000 or swap rtas-config-l! ; diff --git a/qemu/roms/SLOF/slof/fs/pci-properties.fs b/qemu/roms/SLOF/slof/fs/pci-properties.fs new file mode 100644 index 000000000..4f134024f --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/pci-properties.fs @@ -0,0 +1,668 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +#include "pci-class-code-names.fs" + +\ read the various bar type sizes +: pci-bar-size@ ( bar-addr -- bar-size ) -1 over rtas-config-l! rtas-config-l@ ; +: pci-bar-size-mem@ ( bar-addr -- mem-size ) pci-bar-size@ -10 and invert 1+ FFFFFFFF and ; +: pci-bar-size-io@ ( bar-addr -- io-size ) pci-bar-size@ -4 and invert 1+ FFFFFFFF and ; + +\ fetch raw bar size but keep original BAR value +: pci-bar-size ( bar-addr -- bar-size-raw ) + dup rtas-config-l@ swap \ fetch original Value ( bval baddr ) + -1 over rtas-config-l! \ make BAR show size ( bval baddr ) + dup rtas-config-l@ \ and fetch the size ( bval baddr bsize ) + -rot rtas-config-l! \ restore Value +; + +\ calc 32 bit MEM BAR size +: pci-bar-size-mem32 ( bar-addr -- bar-size ) + pci-bar-size \ fetch raw size + -10 and invert 1+ \ calc size + FFFFFFFF and \ keep lower 32 bits +; + +\ calc 32 bit ROM BAR size +: pci-bar-size-rom ( bar-addr -- bar-size ) + pci-bar-size \ fetch raw size + FFFFF800 and invert 1+ \ calc size + FFFFFFFF and \ keep lower 32 bits +; + +\ calc 64 bit MEM BAR size +: pci-bar-size-mem64 ( bar-addr -- bar-size ) + dup pci-bar-size \ fetch raw size lower 32 bits + swap 4 + pci-bar-size \ fetch raw size upper 32 bits + 20 lshift + \ and put them together + -10 and invert 1+ \ calc size +; + +\ calc IO BAR size +: pci-bar-size-io ( bar-addr -- bar-size ) + pci-bar-size \ fetch raw size + -4 and invert 1+ \ calc size + FFFFFFFF and \ keep lower 32 bits +; + + +\ decode the Bar Type +\ +----------------------------------------------------------------------------------------+ +\ | 3 2 1 0 | +\ | +----------------------------+-+--+-+ | +\ | MEM-BAR : | Base Address |P|TT|0| P - prefechtable ; TT - 00 : 32 Bit | +\ | +----------------------------+-+--+-+ 10 : 64 Bit | +\ | +-------------------------------+-+-+ | +\ | IO-BAR : | Base Address |0|1| | +\ | +-------------------------------+-+-+ | +\ | That is: 0 - no encoded BarType | +\ | 1 - IO - Bar | +\ | 2 - Memory 32 Bit | +\ | 3 - Memory 32 Bit prefetchable | +\ | 4 - Memory 64 Bit | +\ | 5 - Memory 64 Bit prefetchable | +\ +----------------------------------------------------------------------------------------+ +: pci-bar-code@ ( bar-addr -- 0|1..4|5 ) + rtas-config-l@ dup \ fetch the BaseAddressRegister + 1 and IF \ IO BAR ? + 2 and IF 0 ELSE 1 THEN \ only '01' is valid + ELSE \ Memory BAR ? + F and CASE + 0 OF 2 ENDOF \ Memory 32 Bit Non-Prefetchable + 8 OF 3 ENDOF \ Memory 32 Bit Prefetchable + 4 OF 4 ENDOF \ Memory 64 Bit Non-Prefetchable + C OF 5 ENDOF \ Memory 64 Bit Prefechtable + dup OF 0 ENDOF \ Not a valid BarType + ENDCASE + THEN +; + +\ *************************************************************************************** +\ Assigning the new Value to the BARs +\ *************************************************************************************** +\ align the current mem and set var to next mem +\ align with a size of 0 returns 0 !!! +: assign-var ( size var -- al-mem ) + 2dup @ \ ( size var size cur-mem ) read current free mem + swap #aligned \ ( size var al-mem ) align the mem to the size + dup 2swap -rot + \ ( al-mem var new-mem ) add size to aligned mem + swap ! \ ( al-mem ) set variable to new mem +; + +\ set bar to current free mem ( in variable ) and set variable to next free mem +: assign-bar-value32 ( bar size var -- 4 ) + over IF \ IF size > 0 + assign-var \ | ( bar al-mem ) set variable to next mem + swap rtas-config-l! \ | ( -- ) set the bar to al-mem + ELSE \ ELSE + 2drop drop \ | clear stack + THEN \ FI + 4 \ size of the base-address-register +; + +\ set bar to current free mem ( in variable ) and set variable to next free mem +: assign-bar-value64 ( bar size var -- 8 ) + over IF \ IF size > 0 + assign-var \ | ( bar al-mem ) set variable to next mem + swap \ | ( al-mem addr ) calc config-addr of this bar + 2dup rtas-config-l! \ | ( al-mem addr ) set the Lower part of the bar to al-mem + 4 + swap 20 rshift \ | ( al-mem>>32 addr ) prepare the upper part of the al-mem + swap rtas-config-l! \ | ( -- ) and set the upper part of the bar + ELSE \ ELSE + 2drop drop \ | clear stack + THEN \ FI + 8 \ size of the base-address-register +; + +\ Setup a prefetchable 64bit BAR and return its size +: assign-mem64-bar ( bar-addr -- 8 ) + dup pci-bar-size-mem64 \ fetch size + pci-next-mem64 @ 0 = IF \ Check if we have 64-bit memory range + pci-next-mem + ELSE + pci-next-mem64 + THEN + assign-bar-value64 \ and set it all +; + +\ Setup a prefetchable 32bit BAR and return its size +: assign-mem32-bar ( bar-addr -- 4 ) + dup pci-bar-size-mem32 \ fetch size + pci-next-mem \ var to change + assign-bar-value32 \ and set it all +; + +\ Setup a non-prefetchable 64bit BAR and return its size +: assign-mmio64-bar ( bar-addr -- 8 ) + dup pci-bar-size-mem64 \ fetch size + pci-next-mem64 @ 0 = IF \ Check if we have 64-bit memory range + pci-next-mmio + ELSE + pci-next-mem64 \ for board-qemu we will use same range + THEN + assign-bar-value64 \ and set it all +; + +\ Setup a non-prefetchable 32bit BAR and return its size +: assign-mmio32-bar ( bar-addr -- 4 ) + dup pci-bar-size-mem32 \ fetch size + pci-next-mmio \ var to change + assign-bar-value32 \ and set it all +; + +\ Setup an IO-Bar and return the size of the base-address-register +: assign-io-bar ( bar-addr -- 4 ) + dup pci-bar-size-io \ fetch size + pci-next-io \ var to change + assign-bar-value32 \ and set it all +; + +\ Setup an Expansion ROM bar +: assign-rom-bar ( bar-addr -- ) + dup pci-bar-size-rom \ fetch size + dup IF \ IF size > 0 + over >r \ | save bar addr for enable + pci-next-mmio \ | var to change + assign-bar-value32 \ | and set it + drop \ | forget the BAR length + r@ rtas-config-l@ \ | fetch BAR + 1 or r> rtas-config-l! \ | and enable the ROM + ELSE \ ELSE + 2drop \ | clear stack + THEN +; + +\ Setup the BAR due to its type and return the size of the register (4 or 8 Bytes ) used as increment for the BAR-Loop +: assign-bar ( bar-addr -- reg-size ) + dup pci-bar-code@ \ calc BAR type + dup IF \ IF >0 + CASE \ | CASE Setup the right type + 1 OF assign-io-bar ENDOF \ | - set up an IO-Bar + 2 OF assign-mmio32-bar ENDOF \ | - set up an 32bit MMIO-Bar + 3 OF assign-mem32-bar ENDOF \ | - set up an 32bit MEM-Bar (prefetchable) + 4 OF assign-mmio64-bar ENDOF \ | - set up an 64bit MMIO-Bar + 5 OF assign-mem64-bar ENDOF \ | - set up an 64bit MEM-Bar (prefetchable) + ENDCASE \ | ESAC + ELSE \ ELSE + ABORT \ | Throw an exception + THEN \ FI +; + +\ Setup all the bars of a pci device +: assign-all-device-bars ( configaddr -- ) + 28 10 DO \ BARs start at 10 and end at 27 + dup i + \ calc config-addr of the BAR + assign-bar \ and set it up + +LOOP \ add 4 or 8 to the index and loop + 30 + assign-rom-bar \ set up the ROM if available +; + +\ Setup all the bars of a pci device +: assign-all-bridge-bars ( configaddr -- ) + 18 10 DO \ BARs start at 10 and end at 17 + dup i + \ calc config-addr of the BAR + assign-bar \ and set it up + +LOOP \ add 4 or 8 to the index and loop + 38 + assign-rom-bar \ set up the ROM if available +; + +\ +---------------------------------------------------------------------------------------+ +\ | Numerical Representaton of a PCI address (PCI Bus Binding 2.2.1.1) | +\ | | +\ | 31 24 16 11 8 0 | +\ | +--------+--------+-----+---+--------+ | +\ | phys.hi: |npt000ss| bus | dev |fnc| reg | n - 0 relocatable | +\ | +--------+--------+-----+---+--------+ p - 1 prefetchable | +\ | t - 1 aliased or <1MB or <64KB | +\ | ss - 00 Configuration Space | +\ | 01 I/O Space | +\ | 10 Memory Space 32bits | +\ | 11 Memory Space 64bits | +\ +---------------------------------------------------------------------------------------+ + +\ *************************************************************************************** +\ Generating the assigned-addresses property +\ *************************************************************************************** +\ generate assigned-addresses property for 64Bit MEM-BAR and return BAR-reg-size +: gen-mem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 ) + dup pci-bar-size-mem64 \ fetch BAR Size ( paddr plen baddr bsize ) + dup IF \ IF Size > 0 + >r dup rtas-config-l@ \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size) + over 4 + rtas-config-l@ \ | fetch upper 32 bits ( paddr plen baddr val.lo val.hi R: size) + 20 lshift + -10 and >r \ | calc 64 bit value and save it ( paddr plen baddr R: size val ) + 83000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) + r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) + r> encode-64+ \ | Encode size ( paddr plen ) + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 8 \ sizeof(BAR) = 8 Bytes +; + +\ generate assigned-addresses property for prefetchable 64Bit MEM-BAR and return BAR-reg-size +: gen-pmem64-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 8 ) + dup pci-bar-size-mem64 \ fetch BAR Size ( paddr plen baddr bsize ) + dup IF \ IF Size > 0 + >r dup rtas-config-l@ \ | save size and fetch lower 32 bits ( paddr plen baddr val.lo R: size) + over 4 + rtas-config-l@ \ | fetch upper 32 bits ( paddr plen baddr val.lo val.hi R: size) + 20 lshift + -10 and >r \ | calc 64 bit value and save it ( paddr plen baddr R: size val ) + C3000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) + r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) + r> encode-64+ \ | Encode size ( paddr plen ) + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 8 \ sizeof(BAR) = 8 Bytes +; + +\ generate assigned-addresses property for 32Bit MEM-BAR and return BAR-reg-size +: gen-mem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) + dup pci-bar-size-mem32 \ fetch BAR Size ( paddr plen baddr bsize ) + dup IF \ IF Size > 0 + >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) + -10 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) + 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) + r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) + r> encode-64+ \ | Encode size ( paddr plen ) + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 4 \ sizeof(BAR) = 4 Bytes +; + +\ generate assigned-addresses property for prefetchable 32Bit MEM-BAR and return BAR-reg-size +: gen-pmem32-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) + dup pci-bar-size-mem32 \ fetch BAR Size ( paddr plen baddr bsize ) + dup IF \ IF Size > 0 + >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) + -10 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) + C2000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) + r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) + r> encode-64+ \ | Encode size ( paddr plen ) + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 4 \ sizeof(BAR) = 4 Bytes +; + +\ generate assigned-addresses property for IO-BAR and return BAR-reg-size +: gen-io-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len 4 ) + dup pci-bar-size-io \ fetch BAR Size ( paddr plen baddr bsize ) + dup IF \ IF Size > 0 + >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) + -4 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) + 81000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) + r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) + r> encode-64+ \ | Encode size ( paddr plen ) + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 4 \ sizeof(BAR) = 4 Bytes +; + +\ generate assigned-addresses property for ROM-BAR +: gen-rom-bar-prop ( prop-addr prop-len bar-addr -- prop-addr prop-len ) + dup pci-bar-size-rom \ fetch BAR Size ( paddr plen baddr bsize ) + dup IF \ IF Size > 0 + >r dup rtas-config-l@ \ | save size and fetch value ( paddr plen baddr val R: size) + FFFFF800 and >r \ | calc 32 bit value and save it ( paddr plen baddr R: size val ) + 82000000 or encode-int+ \ | Encode config addr ( paddr plen R: size val ) + r> encode-64+ \ | Encode assigned addr ( paddr plen R: size ) + r> encode-64+ \ | Encode size ( paddr plen ) + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI +; + +\ add another BAR to the assigned addresses property and return the size of the encoded register +: pci-add-assigned-address ( prop-addr prop-len bar-addr -- prop-addr prop-len bsize ) + dup pci-bar-code@ \ calc BAR type ( paddr plen baddr btype) + CASE \ CASE for the BAR types ( paddr plen baddr ) + 0 OF drop 4 ENDOF \ - not a valid type so do nothing + 1 OF gen-io-bar-prop ENDOF \ - IO-BAR + 2 OF gen-mem32-bar-prop ENDOF \ - MEM32 + 3 OF gen-pmem32-bar-prop ENDOF \ - MEM32 prefetchable + 4 OF gen-mem64-bar-prop ENDOF \ - MEM64 + 5 OF gen-pmem64-bar-prop ENDOF \ - MEM64 prefetchable + ENDCASE \ ESAC ( paddr plen bsize ) +; + +\ generate the assigned address property for a PCI device +: pci-device-assigned-addresses-prop ( addr -- ) + encode-start \ provide mem for property ( addr paddr plen ) + 2 pick 30 + gen-rom-bar-prop \ assign the rom bar + 28 10 DO \ we have 6 possible BARs + 2 pick i + \ calc BAR address ( addr paddr plen bar-addr ) + pci-add-assigned-address \ and generate the props for the BAR + +LOOP \ increase Index by returned len + s" assigned-addresses" property drop \ and write it into the device tree +; + +\ generate the assigned address property for a PCI bridge +: pci-bridge-assigned-addresses-prop ( addr -- ) + encode-start \ provide mem for property + 2 pick 38 + gen-rom-bar-prop \ assign the rom bar + 18 10 DO \ we have 2 possible BARs + 2 pick i + \ ( addr paddr plen current-addr ) + pci-add-assigned-address \ and generate the props for the BAR + +LOOP \ increase Index by returned len + s" assigned-addresses" property drop \ and write it into the device tree +; + +\ check if the range is valid and if so encode it into +\ child.hi child.mid child.lo parent.hi parent.mid parent.lo size.hi size.lo +\ This is needed to translate the childrens addresses +\ We implement only 1:1 mapping for all PCI bridges +: pci-bridge-gen-range ( paddr plen base limit type -- paddr plen ) + >r over - \ calc size ( paddr plen base size R:type ) + dup 0< IF \ IF Size < 0 ( paddr plen base size R:type ) + 2drop r> drop \ | forget values ( paddr plen ) + ELSE \ ELSE + 1+ swap 2swap \ | adjust stack ( size base paddr plen R:type ) + r@ encode-int+ \ | Child type ( size base paddr plen R:type ) + 2 pick encode-64+ \ | Child address ( size base paddr plen R:type ) + r> encode-int+ \ | Parent type ( size base paddr plen ) + rot encode-64+ \ | Parent address ( size paddr plen ) + rot encode-64+ \ | Encode size ( paddr plen ) + THEN \ FI +; + + +\ generate an mmio space to the ranges property +: pci-bridge-gen-mmio-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) + 2 pick 20 + rtas-config-l@ \ fetch Value ( addr paddr plen val ) + dup 0000FFF0 and 10 lshift \ calc base-address ( addr paddr plen val base ) + swap 000FFFFF or \ calc limit-address ( addr paddr plen base limit ) + 02000000 pci-bridge-gen-range \ and generate it ( addr paddr plen ) +; + +\ generate an mem space to the ranges property +: pci-bridge-gen-mem-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) + 2 pick 24 + rtas-config-l@ \ fetch Value ( addr paddr plen val ) + dup 000FFFFF or \ calc limit Bits 31:0 ( addr paddr plen val limit.31:0 ) + swap 0000FFF0 and 10 lshift \ calc base Bits 31:0 ( addr paddr plen limit.31:0 base.31:0 ) + 4 pick 28 + rtas-config-l@ \ fetch upper Basebits ( addr paddr plen limit.31:0 base.31:0 base.63:32 ) + 20 lshift or swap \ and calc Base ( addr paddr plen base.63:0 limit.31:0 ) + 4 pick 2C + rtas-config-l@ \ fetch upper Limitbits ( addr paddr plen base.63:0 limit.31:0 limit.63:32 ) + 20 lshift or \ and calc Limit ( addr paddr plen base.63:0 limit.63:0 ) + 42000000 pci-bridge-gen-range \ and generate it ( addr paddr plen ) +; + +\ generate an io space to the ranges property +: pci-bridge-gen-io-range ( addr prop-addr prop-len -- addr prop-addr prop-len ) + 2 pick 1C + rtas-config-l@ \ fetch Value ( addr paddr plen val ) + dup 0000F000 and 00000FFF or \ calc Limit Bits 15:0 ( addr paddr plen val limit.15:0 ) + swap 000000F0 and 8 lshift \ calc Base Bits 15:0 ( addr paddr plen limit.15:0 base.15:0 ) + 4 pick 30 + rtas-config-l@ \ fetch upper Bits ( addr paddr plen limit.15:0 base.15:0 val ) + dup FFFF and 10 lshift rot or \ calc Base ( addr paddr plen limit.15:0 val base.31:0 ) + -rot FFFF0000 and or \ calc Limit ( addr paddr plen base.31:0 limit.31:0 ) + 01000000 pci-bridge-gen-range \ and generate it ( addr paddr plen ) +; + +\ generate the ranges property for a PCI bridge +: pci-bridge-range-props ( addr -- ) + encode-start \ provide mem for property + pci-bridge-gen-mmio-range \ generate the non prefetchable Memory Entry + pci-bridge-gen-mem-range \ generate the prefetchable Memory Entry + pci-bridge-gen-io-range \ generate the IO Entry + dup IF \ IF any space present (propsize>0) + s" ranges" property \ | write it into the device tree + ELSE \ ELSE + s" " s" ranges" property + 2drop \ | forget the properties + THEN \ FI + drop \ forget the address +; + +\ create the interrupt map for this bridge +: pci-bridge-interrupt-map ( -- ) + encode-start \ create the property ( paddr plen ) + get-node child \ find the first child ( paddr plen handle ) + BEGIN dup WHILE \ Loop as long as the handle is non-zero ( paddr plen handle ) + dup >r >space \ Get the my-space ( paddr plen addr R: handle ) + pci-gen-irq-entry \ and Encode the interrupt settings ( paddr plen R: handle) + r> peer \ Get neighbour ( paddr plen handle ) + REPEAT \ process next childe node ( paddr plen handle ) + drop \ forget the null ( paddr plen ) + s" interrupt-map" property \ and set it ( -- ) + 1 encode-int s" #interrupt-cells" property \ encode the cell# + f800 encode-int 0 encode-int+ 0 encode-int+ \ encode the bit mask for config addr (Dev only) + 7 encode-int+ s" interrupt-map-mask" property \ encode IRQ#=7 and generate property +; + +\ *************************************************************************************** +\ Generating the reg property +\ *************************************************************************************** +\ reg = config-addr 0 0 0 0 [BAR-config-addr 0 0 size.high size.low] + +\ encode the reg prop for a nonprefetchable 32bit MEM-BAR +: encode-mem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 ) + dup pci-bar-size-mem32 \ calc BAR-size ( not changing the BAR ) + dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) + >r 02000000 or encode-int+ \ | save size and encode BAR addr + 0 encode-64+ \ | make mid and lo zero + r> encode-64+ \ | encode size + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 4 \ BAR-Len = 4 (32Bit) +; + +\ encode the reg prop for a prefetchable 32bit MEM-BAR +: encode-pmem32-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 4 ) + dup pci-bar-size-mem32 \ calc BAR-size ( not changing the BAR ) + dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) + >r 42000000 or encode-int+ \ | save size and encode BAR addr + 0 encode-64+ \ | make mid and lo zero + r> encode-64+ \ | encode size + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 4 \ BAR-Len = 4 (32Bit) +; + +\ encode the reg prop for a nonprefetchable 64bit MEM-BAR +: encode-mem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 ) + dup pci-bar-size-mem64 \ calc BAR-size ( not changing the BAR ) + dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) + >r 03000000 or encode-int+ \ | save size and encode BAR addr + 0 encode-64+ \ | make mid and lo zero + r> encode-64+ \ | encode size + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 8 \ BAR-Len = 8 (64Bit) +; + +\ encode the reg prop for a prefetchable 64bit MEM-BAR +: encode-pmem64-bar ( prop-addr prop-len BAR-addr -- prop-addr prop-len 8 ) + dup pci-bar-size-mem64 \ calc BAR-size ( not changing the BAR ) + dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) + >r 43000000 or encode-int+ \ | save size and encode BAR addr + 0 encode-64+ \ | make mid and lo zero + r> encode-64+ \ | encode size + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 8 \ BAR-Len = 8 (64Bit) +; + +\ encode the reg prop for a ROM-BAR +: encode-rom-bar ( prop-addr prop-len configaddr -- prop-addr prop-len ) + dup pci-bar-size-rom \ fetch raw BAR-size + dup IF \ IF BAR is used + >r 02000000 or encode-int+ \ | save size and encode BAR addr + 0 encode-64+ \ | make mid and lo zero + r> encode-64+ \ | calc and encode the size + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI +; + +\ encode the reg prop for an IO-BAR +: encode-io-bar ( prop-addr prop-len BAR-addr BAR-value -- prop-addr prop-len 4 ) + dup pci-bar-size-io \ calc BAR-size ( not changing the BAR ) + dup IF \ IF BAR-size > 0 ( paddr plen baddr bsize ) + >r 01000000 or encode-int+ \ | save size and encode BAR addr + 0 encode-64+ \ | make mid and lo zero + r> encode-64+ \ | encode size + ELSE \ ELSE + 2drop \ | don't do anything + THEN \ FI + 4 \ BAR-Len = 4 (32Bit) +; + +\ write the representation of this BAR into the reg property +: encode-bar ( prop-addr prop-len bar-addr -- prop-addr prop-len bar-len ) + dup pci-bar-code@ \ calc BAR type + CASE \ CASE for the BAR types ( paddr plen baddr val ) + 0 OF drop 4 ENDOF \ - not a valid type so do nothing + 1 OF encode-io-bar ENDOF \ - IO-BAR + 2 OF encode-mem32-bar ENDOF \ - MEM32 + 3 OF encode-pmem32-bar ENDOF \ - MEM32 prefetchable + 4 OF encode-mem64-bar ENDOF \ - MEM64 + 5 OF encode-pmem64-bar ENDOF \ - MEM64 prefetchable + ENDCASE \ ESAC ( paddr plen blen ) +; + +\ Setup reg property +\ first encode the configuration space address +: pci-reg-props ( configaddr -- ) + dup encode-int \ configuration space ( caddr paddr plen ) + 0 encode-64+ \ make the rest 0 + 0 encode-64+ \ encode the size as 0 + 2 pick pci-htype@ \ fetch Header Type ( caddr paddr plen type ) + 1 and IF \ IF Bridge ( caddr paddr plen ) + 18 10 DO \ | loop over all BARs + 2 pick i + \ | calc bar-addr ( caddr paddr plen baddr ) + encode-bar \ | encode this BAR ( caddr paddr plen blen ) + +LOOP \ | increase LoopIndex by the BARlen + 2 pick 38 + \ | calc ROM-BAR for a bridge ( caddr paddr plen baddr ) + encode-rom-bar \ | encode the ROM-BAR ( caddr paddr plen ) + ELSE \ ELSE ordinary device ( caddr paddr plen ) + 28 10 DO \ | loop over all BARs + 2 pick i + \ | calc bar-addr ( caddr paddr plen baddr ) + encode-bar \ | encode this BAR ( caddr paddr plen blen ) + +LOOP \ | increase LoopIndex by the BARlen + 2 pick 30 + \ | calc ROM-BAR for a device ( caddr paddr plen baddr ) + encode-rom-bar \ | encode the ROM-BAR ( caddr paddr plen ) + THEN \ FI ( caddr paddr plen ) + s" reg" property \ and store it into the property + drop +; + +\ *************************************************************************************** +\ Generating common properties +\ *************************************************************************************** +\ set up common properties for devices and bridges +: pci-common-props ( addr -- ) + dup pci-class-name device-name + dup pci-vendor@ encode-int s" vendor-id" property + dup pci-device@ encode-int s" device-id" property + dup pci-revision@ encode-int s" revision-id" property + dup pci-class@ encode-int s" class-code" property + 3 encode-int s" #address-cells" property + 2 encode-int s" #size-cells" property + + dup pci-config-ext? IF 1 encode-int s" ibm,pci-config-space-type" property THEN + + dup pci-status@ + dup 9 rshift 3 and encode-int s" devsel-speed" property + dup 7 rshift 1 and IF 0 0 s" fast-back-to-back" property THEN + dup 6 rshift 1 and IF 0 0 s" 66mhz-capable" property THEN + 5 rshift 1 and IF 0 0 s" udf-supported" property THEN + dup pci-cache@ ?dup IF encode-int s" cache-line-size" property THEN + pci-interrupt@ ?dup IF encode-int s" interrupts" property THEN +; + +\ set up device only properties +: pci-device-props ( addr -- ) + \ FIXME no s" compatible" prop + \ FIXME no s" alternate-reg" prop + \ FIXME no s" fcode-rom-offset" prop + \ FIXME no s" power-consumption" prop + dup pci-common-props + dup pci-min-grant@ encode-int s" min-grant" property + dup pci-max-lat@ encode-int s" max-latency" property + dup pci-sub-device@ ?dup IF encode-int s" subsystem-id" property THEN + dup pci-sub-vendor@ ?dup IF encode-int s" subsystem-vendor-id" property THEN + dup pci-device-assigned-addresses-prop + pci-reg-props + pci-hotplug-enabled IF + \ QEMU uses static assignments for my-drc-index: + \ 40000000h + $bus << 8 + $slot << 3 + dup dup pci-addr2bus 8 lshift + swap pci-addr2dev 3 lshift or + 40000000 + encode-int s" ibm,my-drc-index" property + \ QEMU uses "Slot $bus*32$slotno" for loc-code + dup dup pci-addr2bus 20 * + swap pci-addr2dev + + a base ! + s" Slot " rot $cathex + hex + encode-string s" ibm,loc-code" property + THEN +; + +\ set up bridge only properties +: pci-bridge-props ( addr -- ) + \ FIXME no s" slot-names" prop + \ FIXME no s" bus-master-capable" prop + \ FIXME no s" clock-frequency" prop + dup pci-bus@ + encode-int s" primary-bus" property + encode-int s" secondary-bus" property + encode-int s" subordinate-bus" property + dup pci-bus@ drop encode-int rot encode-int+ s" bus-range" property + pci-device-slots encode-int s" slot-names" property + dup pci-bridge-range-props + dup pci-bridge-assigned-addresses-prop + \ Only create interrupt-map when it doesn't already exist + \ (it can be provided by qemu) + s" interrupt-map" get-node get-property IF + pci-bridge-interrupt-map + ELSE 2drop THEN + pci-reg-props +; + + +\ used to set up all unknown Bridges. +\ If a Bridge has no special handling for setup +\ the device file (pci-bridge_VENDOR_DEVICE.fs) can call +\ this word to setup busses and scan beyond. +: pci-bridge-generic-setup ( addr -- ) + pci-device-slots >r \ save the slot array on return stack + dup pci-common-props \ set the common properties before scanning the bus + s" pci" device-type \ the type is allways "pci" + dup pci-bridge-probe \ find all device connected to it + dup assign-all-bridge-bars \ set up all memory access BARs + dup pci-set-irq-line \ set the interrupt pin + dup pci-set-capabilities \ set up the capabilities + pci-bridge-props \ and generate all properties + r> TO pci-device-slots \ and reset the slot array +; + +DEFER func-pci-device-props + +\ used for an gerneric device set up +\ if a device has no special handling for setup +\ the device file (pci-device_VENDOR_DEVICE.fs) can call +\ this word to setup the device +: pci-device-generic-setup ( config-addr -- ) + dup assign-all-device-bars \ calc all BARs + dup pci-set-irq-line \ set the interrupt pin + dup pci-set-capabilities \ set up the capabilities + dup func-pci-device-props \ and generate all properties + drop \ forget the config-addr +; + +' pci-device-props TO func-pci-device-props diff --git a/qemu/roms/SLOF/slof/fs/pci-scan.fs b/qemu/roms/SLOF/slof/fs/pci-scan.fs new file mode 100644 index 000000000..b8b9fe61f --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/pci-scan.fs @@ -0,0 +1,344 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ---------------------------------------------------------- +\ ********** Variables to be set by host bridge ********** +\ ---------------------------------------------------------- + +\ Values of the next free memory area +VARIABLE pci-next-mem \ prefetchable memory mapped +VARIABLE pci-max-mem +VARIABLE pci-next-mmio \ non-prefetchable memory +VARIABLE pci-max-mmio +VARIABLE pci-next-io \ I/O space +VARIABLE pci-max-io +VARIABLE pci-next-mem64 \ prefetchable 64-bit memory mapped +VARIABLE pci-max-mem64 + +\ Counter of busses found +0 VALUE pci-bus-number +\ Counter of devices found +0 VALUE pci-device-number +\ bit field of devices plugged into this bridge +0 VALUE pci-device-slots +\ byte field holding the device-slot number vector of the current device +\ the vector can be as deep as the max depth of bridges possible +\ 3,4,5 means +\ the 5th slot on the bus of the bridge in +\ the 4th slot on the bus of the bridge in +\ the 3rd slot on the HostBridge bus +here 100 allot CONSTANT pci-device-vec +0 VALUE pci-device-vec-len +\ enable/disable creation of hotplug-specific properties +0 VALUE pci-hotplug-enabled + + +\ Fixme Glue to the pci-devices ... remove this later +: next-pci-mem ( addr -- addr ) pci-next-mem ; +: next-pci-mmio ( addr -- addr ) pci-next-mmio ; +: next-pci-io ( addr -- addr ) pci-next-io ; + + +#include "pci-helper.fs" + +\ Dump out the pci device-slot vector +: pci-vec ( -- ) + cr s" device-vec(" type + pci-device-vec-len dup 2 0.r s" ):" type + 1+ 0 DO + pci-device-vec i + c@ + space 2 0.r + LOOP + cr +; + +\ prints out all relevant pci variables +: pci-var-out ( -- ) + s" mem:" type pci-next-mem @ 16 0.r cr + s" mmio:" type pci-next-mmio @ 16 0.r cr + s" io:" type pci-next-io @ 16 0.r cr +; + + +\ Update the device-slot number vector +\ Set the bit of the DeviceSlot in the Slot array +: pci-set-slot ( addr -- ) + pci-addr2dev dup \ calc slot number + pci-device-vec-len \ the end of the vector + pci-device-vec + c! \ and update the vector + 80000000 swap rshift \ calc bit position of the device slot + pci-device-slots or \ set this bit + TO pci-device-slots \ and write it back +; + +\ Update pci-next-mmio to be 1MB aligned and set the mmio-base register +\ and set the Limit register to the maximum available address space +\ needed for scanning possible devices behind the bridge +: pci-bridge-set-mmio-base ( addr -- ) + pci-next-mmio @ 100000 #aligned \ read the current Value and align to 1MB boundary + dup 100000 + pci-next-mmio ! \ and write back with 1MB for bridge + 10 rshift \ mmio-base reg is only the upper 16 bits + pci-max-mmio @ 1- FFFF0000 and or \ and Insert mmio Limit (set it to max) + swap 20 + rtas-config-l! \ and write it into the bridge +; + +\ Update pci-next-mmio to be 1MB aligned and set the mmio-limit register +\ The Limit Value is one less then the upper boundary +\ If the limit is less than the base the mmio is disabled +: pci-bridge-set-mmio-limit ( addr -- ) + pci-next-mmio @ 100000 #aligned \ fetch current value and align to 1MB + dup pci-next-mmio ! \ and write it back + 1- FFFF0000 and \ make it one less and keep upper 16 bits + over 20 + rtas-config-l@ 0000FFFF and \ fetch original value + or swap 20 + rtas-config-l! \ and write it into the Reg +; + +\ Update pci-next-mem to be 1MB aligned and set the mem-base and mem-base-upper register +\ and set the Limit register to the maximum available address space +\ needed for scanning possible devices behind the bridge +: pci-bridge-set-mem-base ( addr -- ) + pci-next-mem @ 100000 #aligned \ read the current Value and align to 1MB boundary + dup 100000 + pci-next-mem ! \ and write back with 1MB for bridge + over 24 + rtas-config-w@ \ check if 64bit support + 1 and IF \ IF 64 bit support + 2dup 20 rshift \ | keep upper 32 bits + swap 28 + rtas-config-l! \ | and write it into the Base-Upper32-bits + pci-max-mem @ 20 rshift \ | fetch max Limit address and keep upper 32 bits + 2 pick 2C + rtas-config-l! \ | and set the Limit + THEN \ FI + 10 rshift \ keep upper 16 bits + pci-max-mem @ 1- FFFF0000 and or \ and Insert mmem Limit (set it to max) + swap 24 + rtas-config-l! \ and write it into the bridge +; + +\ Update pci-next-mem to be 1MB aligned and set the mem-limit register +\ The Limit Value is one less then the upper boundary +\ If the limit is less than the base the mem is disabled +: pci-bridge-set-mem-limit ( addr -- ) + pci-next-mem @ 100000 #aligned \ read the current Value and align to 1MB boundary + dup pci-next-mem ! \ and write it back + 1- \ make limit one less than boundary + over 24 + rtas-config-w@ \ check if 64bit support + 1 and IF \ IF 64 bit support + 2dup 20 rshift \ | keep upper 32 bits + swap 2C + rtas-config-l! \ | and write it into the Limit-Upper32-bits + THEN \ FI + FFFF0000 and \ keep upper 16 bits + over 24 + rtas-config-l@ 0000FFFF and \ fetch original Value + or swap 24 + rtas-config-l! \ and write it into the bridge +; + +\ Update pci-next-io to be 4KB aligned and set the io-base and io-base-upper register +\ and set the Limit register to the maximum available address space +\ needed for scanning possible devices behind the bridge +: pci-bridge-set-io-base ( addr -- ) + pci-next-io @ 1000 #aligned \ read the current Value and align to 4KB boundary + dup 1000 + pci-next-io ! \ and write back with 4K for bridge + over 1C + rtas-config-l@ \ check if 32bit support + 1 and IF \ IF 32 bit support + 2dup 10 rshift \ | keep upper 16 bits + pci-max-io @ FFFF0000 and or \ | insert upper 16 bits of Max-Limit + swap 30 + rtas-config-l! \ | and write it into the Base-Upper16-bits + THEN \ FI + 8 rshift 000000FF and \ keep upper 8 bits + pci-max-io @ 1- 0000FF00 and or \ insert upper 8 bits of Max-Limit + over rtas-config-l@ FFFF0000 and \ fetch original Value + or swap 1C + rtas-config-l! \ and write it into the bridge +; + +\ Update pci-next-io to be 4KB aligned and set the io-limit register +\ The Limit Value is one less then the upper boundary +\ If the limit is less than the base the io is disabled +: pci-bridge-set-io-limit ( addr -- ) + pci-next-io @ 1000 #aligned \ read the current Value and align to 4KB boundary + dup pci-next-io ! \ and write it back + 1- \ make limit one less than boundary + over 1D + rtas-config-b@ \ check if 32bit support + 1 and IF \ IF 32 bit support + 2dup FFFF0000 and \ | keep upper 16 bits + over 30 + rtas-config-l@ \ | fetch original Value + or swap 30 + rtas-config-l! \ | and write it into the Limit-Upper16-bits + THEN \ FI + 0000FF00 and \ keep upper 8 bits + over 1C + rtas-config-l@ FFFF00FF and \ fetch original Value + or swap 1C + rtas-config-l! \ and write it into the bridge +; + +\ set up all base registers to the current variable Values +: pci-bridge-set-bases ( addr -- ) + dup pci-bridge-set-mmio-base + dup pci-bridge-set-mem-base + pci-bridge-set-io-base +; + +\ set up all limit registers to the current variable Values +: pci-bridge-set-limits ( addr -- ) + dup pci-bridge-set-mmio-limit + dup pci-bridge-set-mem-limit + pci-bridge-set-io-limit +; + +\ ---------------------------------------------------------- +\ ****************** PCI Scan functions ****************** +\ ---------------------------------------------------------- + +\ define function pointer as forward declaration of pci-probe-bus +DEFER func-pci-probe-bus +DEFER func-pci-bridge-range-props + +\ Setup the Base and Limits in the Bridge +\ and scan the bus(es) beyond that Bridge +: pci-bridge-probe ( addr -- ) + dup pci-bridge-set-bases \ SetUp all Base Registers + dup func-pci-bridge-range-props \ Setup temporary "range + pci-bus-number 1+ TO pci-bus-number \ increase number of busses found + pci-device-vec-len 1+ TO pci-device-vec-len \ increase the device-slot vector depth + dup \ stack config-addr for pci-bus! + FF swap \ Subordinate Bus Number ( for now to max to open all subbusses ) + pci-bus-number swap \ Secondary Bus Number ( the new busnumber ) + dup pci-addr2bus swap \ Primary Bus Number ( the current bus ) + pci-bus! \ and set them into the bridge + pci-enable \ enable mem/IO transactions + dup pci-bus-scnd@ func-pci-probe-bus \ and probe the secondary bus + dup pci-bus-number swap pci-bus-subo! \ set SubOrdinate Bus Number to current number of busses + pci-device-vec-len 1- TO pci-device-vec-len \ decrease the device-slot vector depth + dup pci-bridge-set-limits \ SetUp all Limit Registers + drop \ forget the config-addr +; + +\ set up the pci-device +: pci-device-setup ( addr -- ) + drop \ since the config-addr is coded in my-space, drop it here + s" pci-device.fs" included \ and setup the device as node in the device tree +; + +\ set up the pci bridge +: pci-bridge-setup ( addr -- ) + drop \ since the config-addr is coded in my-space, drop it here + s" pci-bridge.fs" included \ and setup the bridge as node in the device tree +; + +\ add the new found device/bridge to the device tree and set it up +: pci-add-device ( addr -- ) + new-device \ create a new device-tree node + dup set-space \ set the config addr for this device tree entry + dup pci-set-slot \ set the slot bit + dup pci-htype@ \ read HEADER-Type + 7f and \ Mask bit 7 - multifunction device + CASE + 0 OF pci-device-setup ENDOF \ | set up the device + 1 OF pci-bridge-setup ENDOF \ | set up the bridge + dup OF dup pci-htype@ pci-out ENDOF + ENDCASE + finish-device \ and close the device-tree node +; + +\ check for multifunction and for each function +\ (dependig from header type) call device or bridge setup +: pci-setup-device ( addr -- ) + dup pci-htype@ \ read HEADER-Type + 80 and IF 8 ELSE 1 THEN \ check for multifunction + 0 DO \ LOOP over all possible functions (either 8 or only 1) + dup + i 8 lshift + \ calc device-function-config-addr + dup pci-vendor@ \ check if valid function + FFFF = IF + drop \ non-valid so forget the address + ELSE + pci-device-number 1+ \ increase the number of devices + TO pci-device-number \ and store it + pci-add-device \ and add the device to the device tree and set it up + THEN + LOOP \ next function + drop \ forget the device-addr +; + +\ check if a device is plugged into this bus at this device number +: pci-probe-device ( busnr devicenr -- ) + pci-bus2addr \ calc pci-address + dup pci-vendor@ \ fetch Vendor-ID + FFFF = IF \ check if valid + drop \ if not forget it + ELSE + pci-setup-device \ if valid setup the device + THEN +; + +\ walk through all 32 possible pci devices on this bus and probe them +: pci-probe-bus ( busnr -- ) + 0 TO pci-device-slots \ reset slot array to unpoppulated + 20 0 DO + dup + i pci-probe-device + LOOP + drop +; + +\ setup the function pointer used in pci-bridge-setup +' pci-probe-bus TO func-pci-probe-bus + +\ ---------------------------------------------------------- +\ ****************** System functions ******************** +\ ---------------------------------------------------------- +\ Setup the whole system for pci devices +\ start with the bus-min and try all busses +\ until at least 1 device was found +\ ( needed for HostBridges that don't start with Bus 0 ) +: pci-probe-all ( bus-max bus-min -- ) \ Check all busses from bus-min up to bus-max if needed + 0 TO pci-device-vec-len \ reset the device-slot vector + DO + i TO pci-bus-number \ set current Busnumber + 0 TO pci-device-number \ reset Device Number + pci-bus-number pci-probe-bus \ and probe this bus + pci-device-number 0 > IF LEAVE THEN \ if we found a device we're done + LOOP \ else next bus +; + +: (probe-pci-host-bridge) ( bus-max bus-min -- ) + 0d emit ." Adapters on " puid 10 0.r cr \ print the puid we're looking at + ( bus-max bus-min ) pci-probe-all \ and walk the bus + pci-device-number 0= IF \ IF no devices found + 15 spaces \ | indent the output + ." None" cr \ | tell the world our result + THEN \ FI +; + +\ probe the hostbridge that is specified in my-puid +\ for the mmio mem and io addresses: +\ base is the least available address +\ max is the highest available address +: probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- ) + puid >r TO puid \ save puid and set the new + pci-next-io ! \ save the next io-base address + pci-max-io ! \ save the max io-space address + pci-next-mem ! \ save the next mem-base address + pci-max-mem ! \ save the max mem-space address + pci-next-mmio ! \ save the next mmio-base address + pci-max-mmio ! \ save the max mmio-space address + (probe-pci-host-bridge) + r> TO puid \ restore puid +; + +\ provide the device-alias definition words +#include <pci-aliases.fs> + +\ provide all words for the interrupts settings +#include <pci-interrupts.fs> + +\ provide all words for the pci capabilities init +#include <pci-capabilities.fs> + +\ provide all words needed to generate the properties and/or assign BAR values +#include "pci-properties.fs" + +\ setup the function pointer for bridge ranges +' pci-bridge-range-props TO func-pci-bridge-range-props diff --git a/qemu/roms/SLOF/slof/fs/preprocessor.fs b/qemu/roms/SLOF/slof/fs/preprocessor.fs new file mode 100644 index 000000000..a13fb3004 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/preprocessor.fs @@ -0,0 +1,41 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: ([IF]) + BEGIN + BEGIN parse-word dup 0= WHILE + 2drop refill + REPEAT + + 2dup s" [IF]" str= IF 1 throw THEN + 2dup s" [ELSE]" str= IF 2 throw THEN + 2dup s" [THEN]" str= IF 3 throw THEN + s" \" str= IF linefeed parse 2drop THEN + AGAIN + ; + +: [IF] ( flag -- ) + IF exit THEN + 1 BEGIN + ['] ([IF]) catch + CASE + 1 OF 1+ ENDOF + 2 OF dup 1 = if 1- then ENDOF + 3 OF 1- ENDOF + ENDCASE + dup 0 <= + UNTIL drop +; immediate + +: [ELSE] 0 [COMPILE] [IF] ; immediate +: [THEN] ; immediate + diff --git a/qemu/roms/SLOF/slof/fs/property.fs b/qemu/roms/SLOF/slof/fs/property.fs new file mode 100644 index 000000000..cb99fbe9d --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/property.fs @@ -0,0 +1,192 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Properties 5.3.5 + +\ Words on the property list for a node are actually executable words, +\ that return the address and length of the property's data. Special +\ nodes like /options can have their properties use specialized code to +\ dynamically generate their data; most nodes just use a 2CONSTANT. + +\ Put the type as byte before the property +\ { int = 1, bytes = 2, string = 3 } +\ This is used by .properties for pretty print + +\ Flag for type encoding, encode-* resets, set-property set the flag +true value encode-first? + +: decode-int over >r 4 /string r> 4c@ swap 2swap swap bljoin ; +: decode-64 decode-int -rot decode-int -rot 2swap swap lxjoin ; +: decode-string ( prop-addr1 prop-len1 -- prop-addr2 prop-len2 str len ) + dup 0= IF 2dup EXIT THEN \ string properties with zero length + over BEGIN dup c@ 0= IF 1+ -rot swap 2 pick over - rot over - -rot 1- + EXIT THEN 1+ AGAIN ; + +\ Remove a word from a wordlist. +: (prune) ( name len head -- ) + dup >r (find) ?dup IF r> BEGIN dup @ WHILE 2dup @ = IF + >r @ r> ! EXIT THEN @ REPEAT 2drop ELSE r> drop THEN ; +: prune ( name len -- ) last (prune) ; + +: set-property ( data dlen name nlen phandle -- ) + true to encode-first? + get-current >r node>properties @ set-current + 2dup prune $2CONSTANT r> set-current ; +: delete-property ( name nlen -- ) + get-node get-current >r node>properties @ set-current + prune r> set-current ; +: property ( data dlen name nlen -- ) get-node set-property ; +: get-property ( str len phandle -- true | data dlen false ) + ?dup 0= IF cr cr cr ." get-property for " type ." on zero phandle" + cr cr true EXIT THEN + node>properties @ voc-find dup IF link> execute false ELSE drop true THEN ; +: get-package-property ( str len phandle -- true | data dlen false ) + get-property ; +: get-my-property ( str len -- true | data dlen false ) + my-self ihandle>phandle get-property ; +: get-parent-property ( str len -- true | data dlen false ) + my-parent ihandle>phandle get-property ; + +: get-inherited-property ( str len -- true | data dlen false ) + my-self ihandle>phandle + BEGIN + 3dup get-property 0= IF + \ Property found + rot drop rot drop rot drop false EXIT + THEN + parent dup 0= IF + \ Root node has been reached, but property has not been found + 3drop true EXIT + THEN + AGAIN +; + +\ Print out properties. + +20 CONSTANT indent-prop + +: .prop-int ( str len -- ) + space + 400 min 0 + ?DO + i over + dup ( str act-addr act-addr ) + c@ 2 0.r 1+ dup c@ 2 0.r 1+ dup c@ 2 0.r 1+ c@ 2 0.r ( str ) + i c and c = IF \ check for multipleof 16 bytes + cr indent @ indent-prop + 1+ 0 \ linefeed + indent + DO + space \ print spaces + LOOP + ELSE + space space \ print two spaces + THEN + 4 +LOOP + drop +; + +: .prop-bytes ( str len -- ) + 2dup -4 and .prop-int ( str len ) + + dup 3 and dup IF ( str len len%4 ) + >r -4 and + r> ( str' len%4 ) + bounds ( str' str'+len%4 ) + DO + i c@ 2 0.r \ Print last 3 bytes + LOOP + ELSE + 3drop + THEN +; + +: .prop-string ( str len ) + 2dup space type + cr indent @ indent-prop + 0 DO space LOOP \ Linefeed + .prop-bytes +; + +: .propbytes ( xt -- ) + execute dup + IF + over cell- @ execute + ELSE + 2drop + THEN +; +: .property ( lfa -- ) + cr indent @ 0 + ?DO + space + LOOP + link> dup >name name>string 2dup type nip ( len ) + indent-prop swap - ( xt 20-len ) + dup 0< IF drop 0 THEN 0 ( xt number-of-space 0 ) + ?DO + space + LOOP + .propbytes +; +: (.properties) ( phandle -- ) + node>properties @ cell+ @ BEGIN dup WHILE dup .property @ REPEAT drop ; +: .properties ( -- ) + get-node (.properties) ; + +: next-property ( str len phandle -- false | str' len' true ) + ?dup 0= IF device-tree @ THEN \ XXX: is this line required? + node>properties @ + >r 2dup 0= swap 0= or IF 2drop r> cell+ ELSE r> voc-find THEN + @ dup IF link>name name>string true THEN ; + + +\ encode-* words and all helpers + +\ Start a encoded property string +: encode-start ( -- prop 0 ) + ['] .prop-int compile, + false to encode-first? + here 0 +; + +: encode-int ( val -- prop prop-len ) + encode-first? IF + ['] .prop-int compile, \ Execution token for print + false to encode-first? + THEN + here swap lbsplit c, c, c, c, /l +; +: encode-bytes ( str len -- prop-addr prop-len ) + encode-first? IF + ['] .prop-bytes compile, \ Execution token for print + false to encode-first? + THEN + here over 2dup 2>r allot swap move 2r> +; +: encode-string ( str len -- prop-addr prop-len ) + encode-first? IF + ['] .prop-string compile, \ Execution token for print + false to encode-first? + THEN + encode-bytes 0 c, char+ +; + +: encode+ ( prop1-addr prop1-len prop2-addr prop2-len -- prop-addr prop-len ) + nip + ; +: encode-int+ encode-int encode+ ; +: encode-64 xlsplit encode-int rot encode-int+ ; +: encode-64+ encode-64 encode+ ; + + +\ Helpers for common nodes. Should perhaps remove "compatible", as it's +\ not typically a single string. +: device-name encode-string s" name" property ; +: device-type encode-string s" device_type" property ; +: model encode-string s" model" property ; +: compatible encode-string s" compatible" property ; diff --git a/qemu/roms/SLOF/slof/fs/quiesce.fs b/qemu/roms/SLOF/slof/fs/quiesce.fs new file mode 100644 index 000000000..47006e44d --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/quiesce.fs @@ -0,0 +1,58 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +100 CONSTANT quiesce-xt# + +\ The array with the quiesce execution tokens: +CREATE quiesce-xts quiesce-xt# cells allot +quiesce-xts quiesce-xt# cells erase + +0 VALUE quiesce-done? + + +\ Add a token to the quiesce execution token array: +: add-quiesce-xt ( xt -- ) + quiesce-xt# 0 DO + quiesce-xts I cells + ( xt arrayptr ) + dup @ 0= ( xt arrayptr true|false ) + IF + ! UNLOOP EXIT + ELSE ( xt arrayptr ) + over swap ( xt xt arrayptr ) + @ = \ xt already stored ? + IF + drop UNLOOP EXIT + THEN ( xt ) + THEN + LOOP + drop ( xt -- ) + ." Warning: quiesce xt list is full." cr +; + + +\ The quiesce call asserts that the firmware and all hardware +\ is in a sane state (e.g. assert that no background DMA is +\ running anymore) +: quiesce ( -- ) + quiesce-done? IF EXIT THEN + true to quiesce-done? + quiesce-xt# 0 DO + quiesce-xts I cells + ( arrayptr ) + @ dup IF ( xt ) + EXECUTE + ELSE + drop UNLOOP EXIT + THEN + LOOP +; + diff --git a/qemu/roms/SLOF/slof/fs/rmove.fs b/qemu/roms/SLOF/slof/fs/rmove.fs new file mode 100644 index 000000000..c28dba9c4 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/rmove.fs @@ -0,0 +1,53 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +defer '(r@) +defer '(r!) +1 VALUE /(r) + + +\ The rest of the code already implemented in prim.in +\ In the end all of this should be moved over there and this file terminated + +: (rfill) ( addr size pattern 'r! /r -- ) + to /(r) to '(r!) ff and + dup 8 lshift or dup 10 lshift or dup 20 lshift or + -rot bounds ?do dup i '(r!) /(r) +loop drop +; + +: (fwrmove) ( src dest size -- ) + >r 0 -rot r> bounds ?do + dup '(r@) i '(r!) /(r) dup +loop 2drop +; + +\ Move from main to device memory +: mrmove ( src dest size -- ) + 3dup or or 7 AND CASE + 0 OF ['] x@ ['] rx! /x ENDOF + 4 OF ['] l@ ['] rl! /l ENDOF + 2 OF ['] w@ ['] rw! /w ENDOF + dup OF ['] c@ ['] rb! /c ENDOF + ENDCASE + ( We already know that source and destination do not overlap ) + to /(r) to '(r!) to '(r@) (fwrmove) +; + +: rfill ( addr size pattern -- ) + 3dup drop or 7 AND CASE + 0 OF ['] rx! /x ENDOF + 4 OF ['] rl! /l ENDOF + 2 OF ['] rw! /w ENDOF + dup OF ['] rb! /c ENDOF + ENDCASE (rfill) +; + + + diff --git a/qemu/roms/SLOF/slof/fs/romfs.fs b/qemu/roms/SLOF/slof/fs/romfs.fs new file mode 100644 index 000000000..7d7e4637e --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/romfs.fs @@ -0,0 +1,123 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +STRUCT + cell field romfs>file-header + cell field romfs>data + cell field romfs>data-size + cell field romfs>flags + +CONSTANT /romfs-lookup-control-block + +CREATE romfs-lookup-cb /romfs-lookup-control-block allot +romfs-lookup-cb /romfs-lookup-control-block erase + +: create-filename ( string -- string\0 ) + here >r dup 8 + allot + r@ over 8 + erase + r@ zplace r> ; + +: romfs-lookup ( fn-str fn-len -- data size | false ) + create-filename romfs-base + romfs-lookup-cb romfs-lookup-entry call-c + 0= IF romfs-lookup-cb dup romfs>data @ swap romfs>data-size @ ELSE + false THEN ; + +: ibm,romfs-lookup ( fn-str fn-len -- data-high data-low size | 0 0 false ) + romfs-lookup dup + 0= if drop 0 0 false else + swap dup 20 rshift swap ffffffff and then ; + +\ FIXME For a short time ... +: romfs-lookup-client ibm,romfs-lookup ; + +\ Fixme temp implementation + +STRUCT + cell field romfs>next-off + cell field romfs>size + cell field romfs>flags + cell field romfs>data-off + cell field romfs>name + +CONSTANT /romfs-cb + +: romfs-map-file ( fn-str fn-len -- file-addr file-size ) + romfs-base >r + BEGIN 2dup r@ romfs>name zcount string=ci not WHILE + ( fn-str fn-len ) ( R: rom-cb-file-addr ) + r> romfs>next-off dup @ dup 0= IF 1 THROW THEN + >r REPEAT + ( fn-str fn-len ) ( R: rom-cb-file-addr ) + 2drop r@ romfs>data-off @ r@ + r> romfs>size @ ; + +\ returns address of romfs-header file +: flash-header ( -- address | false ) + get-flash-base 28 + \ prepare flash header file address + dup rx@ \ fetch "magic123" + 6d61676963313233 <> IF \ IF flash is not valid + drop \ | forget address + false \ | return false + THEN \ FI +; + +CREATE bdate-str 10 allot +: bdate2human ( -- addr len ) + flash-header 40 + rx@ (.) + drop dup 0 + bdate-str 6 + 4 move + dup 4 + bdate-str 0 + 2 move + dup 6 + bdate-str 3 + 2 move + dup 8 + bdate-str b + 2 move + a + bdate-str e + 2 move + 2d bdate-str 2 + c! + 2d bdate-str 5 + c! + 20 bdate-str a + c! + 3a bdate-str d + c! + bdate-str 10 +; + + +\ Look up a file in the ROM file system and evaluate it + +: included ( fn fn-len -- ) + 2dup >r >r romfs-lookup dup IF + r> drop r> drop evaluate + ELSE + drop ." Cannot open file : " r> r> type cr + THEN +; + +: include ( " fn " -- ) + parse-word included +; + +: ?include ( flag " fn " -- ) + parse-word rot IF included ELSE 2drop THEN +; + +: include? ( nargs flag " fn " -- ) + parse-word rot IF + rot drop included + ELSE + 2drop 0 ?DO drop LOOP + THEN +; + + +\ List files in ROMfs + +: (print-romfs-file-info) ( file-addr -- ) + 9 emit dup b 0.r 2 spaces dup 8 + @ 6 0.r 2 spaces 20 + zcount type cr +; + +: romfs-list ( -- ) + romfs-base 0 cr BEGIN + dup (print-romfs-file-info) dup @ dup 0= UNTIL 2drop +; diff --git a/qemu/roms/SLOF/slof/fs/root.fs b/qemu/roms/SLOF/slof/fs/root.fs new file mode 100644 index 000000000..21c710951 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/root.fs @@ -0,0 +1,84 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ this creates the root and common branches of the device tree + +defer (client-exec) +defer client-exec + +\ defined in slof/fs/client.fs +defer callback +defer continue-client + +0 VALUE chosen-node + +: chosen + chosen-node dup 0= IF + drop s" /chosen" find-node dup to chosen-node + THEN +; + +: set-chosen ( prop len name len -- ) + chosen set-property ; + +: get-chosen ( name len -- [ prop len ] success ) + chosen get-property 0= ; + +\ Look for an exising root, create one if needed +" /" find-node dup 0= IF + drop + new-device + s" /" device-name +ELSE + extend-device +THEN + +\ Create /chosen if it doesn't exist +" /chosen" find-node dup 0= IF + drop + new-device + s" chosen" device-name + s" " encode-string s" bootargs" property + s" " encode-string s" bootpath" property + finish-device +ELSE + drop +THEN + +\ Create /aliases +new-device + s" aliases" device-name +finish-device + +\ Create /options +new-device + s" options" device-name +finish-device + +\ Create /openprom +new-device + s" openprom" device-name + 0 0 s" relative-addressing" property +finish-device + +\ Create /packages +new-device +#include <packages.fs> +finish-device + +: open true ; +: close ; +#include <archsupport.fs> + +\ Finish root +finish-device + diff --git a/qemu/roms/SLOF/slof/fs/rtas/rtas-cpu.fs b/qemu/roms/SLOF/slof/fs/rtas/rtas-cpu.fs new file mode 100644 index 000000000..c133abc40 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/rtas/rtas-cpu.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: rtas-start-cpu ( pid loc r3 -- status ) + [ s" start-cpu" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 3 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args2 l! + rtas-cb rtas>args1 l! + rtas-cb rtas>args0 l! + 0 rtas-cb rtas>args3 l! + enter-rtas + rtas-cb rtas>args3 l@ +; diff --git a/qemu/roms/SLOF/slof/fs/rtas/rtas-flash.fs b/qemu/roms/SLOF/slof/fs/rtas/rtas-flash.fs new file mode 100644 index 000000000..f8abeaaf0 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/rtas/rtas-flash.fs @@ -0,0 +1,46 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: rtas-ibm-update-flash-64-and-reboot ( block-list -- status ) + [ s" ibm,update-flash-64-and-reboot" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 1 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args1 l@ +; + +: rtas-ibm-manage-flash-image ( image-to-commit -- status ) + [ s" ibm,manage-flash-image" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 1 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args1 l@ +; + +: rtas-set-flashside ( flashside -- status ) + [ s" rtas-set-flashside" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 1 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args1 l@ +; + +: rtas-get-flashside ( -- status ) + [ s" rtas-get-flashside" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 0 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + enter-rtas + rtas-cb rtas>args0 l@ +; diff --git a/qemu/roms/SLOF/slof/fs/rtas/rtas-init.fs b/qemu/roms/SLOF/slof/fs/rtas/rtas-init.fs new file mode 100644 index 000000000..8451cfde7 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/rtas/rtas-init.fs @@ -0,0 +1,121 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ (rtas-size) determines the size required for RTAS. +\ It looks at the rtas binary in the flash and reads the rtas-size from +\ its header at offset 8. +: (rtas-size) ( -- rtas-size ) + s" rtas" romfs-lookup dup 0= + ABORT" romfs-lookup for rtas failed" + drop 8 + @ +; + +(rtas-size) CONSTANT rtas-size + +: instantiate-rtas ( adr -- entry ) + dup rtas-size erase + s" rtas" romfs-lookup 0= + ABORT" romfs-lookup for rtas failed" + rtas-config swap start-rtas ; + +here fff + fffffffffffff000 and here - allot +here rtas-size allot CONSTANT rtas-start-addr + +rtas-start-addr instantiate-rtas CONSTANT rtas-entry-point + +: drone-rtas + rtas-start-addr + dup rtas-size erase + 2000000 start-rtas to rtas-entry-point +; + + +\ ffffffffffffffff CONSTANT rtas-entry-point + +\ rtas control block + +STRUCT + /l field rtas>token + /l field rtas>nargs + /l field rtas>nret + /l field rtas>args0 + /l field rtas>args1 + /l field rtas>args2 + /l field rtas>args3 + /l field rtas>args4 + /l field rtas>args5 + /l field rtas>args6 + /l field rtas>args7 + /l C * field rtas>args + /l field rtas>bla + +CONSTANT /rtas-control-block + +CREATE rtas-cb /rtas-control-block allot +rtas-cb /rtas-control-block erase + +\ call-c ( p0 p1 p2 entry -- ret ) + +: enter-rtas ( -- ) + rtas-cb rtas-start-addr 0 rtas-entry-point call-c drop ; + + +\ This is the structure of the RTAS function jump table in the C code: +STRUCT + cell FIELD rtasfunctab>name + cell FIELD rtasfunctab>func + cell FIELD rtasfunctab>flags +CONSTANT rtasfunctab-size + +\ Create RTAS token properties by analyzing the jump table in the C code: +: rtas-create-token-properties ( -- ) + rtas-start-addr 10 + @ rtas-start-addr + \ Get pointer to jump table + rtas-start-addr 18 + @ rtas-start-addr + l@ \ Get the number of entries + 0 DO + dup rtasfunctab>func @ 0<> \ function pointer must not be NULL + over rtasfunctab>flags @ 1 and 0= \ Check the only-internal flag + and + IF + i 1+ encode-int \ Create the token value + 2 pick rtasfunctab>name @ zcount \ Create the token name string + property \ Create the property + THEN + rtasfunctab-size + \ Proceed to the next entry + LOOP + drop +; + +\ Get the RTAS token that corresponds to an RTAS property name: +: rtas-get-token ( str len -- token|0 ) + rtas-start-addr 10 + @ rtas-start-addr + \ Get pointer to jump table + rtas-start-addr 18 + @ rtas-start-addr + l@ \ Get the number of entries + 0 DO + dup rtasfunctab>name @ \ Get pointer to function name + dup 0<> \ function name must not be NULL + over zcount 5 pick = nip and \ Check if both strings have same length + IF + 3 pick 3 pick \ Make a copy of the token name string + comp 0= + IF + drop 2drop + i 1+ \ If the name matched, return the token + UNLOOP EXIT + THEN + ELSE + drop + THEN + rtasfunctab-size + \ Proceed to the next entry + LOOP + drop + ." RTAS token not found: " type cr + 0 +; diff --git a/qemu/roms/SLOF/slof/fs/rtas/rtas-reboot.fs b/qemu/roms/SLOF/slof/fs/rtas/rtas-reboot.fs new file mode 100644 index 000000000..a9539ecc1 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/rtas/rtas-reboot.fs @@ -0,0 +1,33 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: rtas-power-off ( x y -- status ) + [ s" power-off" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 2 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + rtas-cb rtas>args1 l! + enter-rtas + rtas-cb rtas>args2 l@ +; + +: power-off ( -- ) 0 0 rtas-power-off ; + + +: rtas-system-reboot ( -- status ) + [ s" system-reboot" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 0 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args1 l@ +; diff --git a/qemu/roms/SLOF/slof/fs/rtas/rtas-vpd.fs b/qemu/roms/SLOF/slof/fs/rtas/rtas-vpd.fs new file mode 100644 index 000000000..7fb4b547d --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/rtas/rtas-vpd.fs @@ -0,0 +1,33 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: rtas-read-vpd ( offset length data -- status ) + [ s" msg-read-vpd" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 3 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args2 l! + rtas-cb rtas>args1 l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args3 l@ +; + +: rtas-write-vpd ( offset length data -- status ) + [ s" msg-write-vpd" rtas-get-token ] LITERAL rtas-cb rtas>token l! + 3 rtas-cb rtas>nargs l! + 1 rtas-cb rtas>nret l! + rtas-cb rtas>args2 l! + rtas-cb rtas>args1 l! + rtas-cb rtas>args0 l! + enter-rtas + rtas-cb rtas>args3 l@ +; diff --git a/qemu/roms/SLOF/slof/fs/scsi-disk.fs b/qemu/roms/SLOF/slof/fs/scsi-disk.fs new file mode 100644 index 000000000..197847147 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/scsi-disk.fs @@ -0,0 +1,324 @@ +\ ***************************************************************************** +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Create new VSCSI child device + +\ Create device +new-device + +\ Set name +s" disk" device-name + +s" block" device-type + +false VALUE scsi-disk-debug? + +\ Get SCSI bits +scsi-open + +\ Send SCSI commands to controller + +: execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) + ( ... [ sense-buf sense-len ] stat ) + " execute-scsi-command" $call-parent +; + +: retry-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len #retries -- ... ) + ( ... 0 | [ sense-buf sense-len ] stat ) + " retry-scsi-command" $call-parent +; + +\ ---------------------------------\ +\ Common SCSI Commands and helpers \ +\ ---------------------------------\ + +0 INSTANCE VALUE block-size +0 INSTANCE VALUE max-transfer +0 INSTANCE VALUE max-block-num +0 INSTANCE VALUE is_cdrom +INSTANCE VARIABLE deblocker + +\ This scratch area is made global for now as we only +\ use it for small temporary commands such as inquiry +\ read-capacity or media events +CREATE scratch 100 allot +CREATE cdb 10 allot + +: dump-scsi-error ( sense-buf sense-len stat name namelen -- ) + ." SCSI-DISK: " my-self instance>path type ." ," type ." failed" cr + ." SCSI-DISK: Status " dup . .status-text + 0<> IF + ." Sense " scsi-get-sense-data dup . .sense-text + ." ASC " . ." ASCQ " . cr + ELSE drop THEN +; + +: read-blocks ( addr block# #blocks -- #read ) + scsi-disk-debug? IF + ." SCSI-DISK: read-blocks " .s cr + THEN + + \ Bound check. This should probably be done by deblocker + \ but it doesn't at this point so do it here + 2dup + max-block-num > IF + ." SCSI-DISK: Access beyond end of device ! " cr + drop + dup max-block-num > IF + drop drop 0 EXIT + THEN + dup max-block-num swap - + THEN + + dup block-size * ( addr block# #blocks len ) + >r rot r> ( block# #blocks addr len ) + 2swap ( addr len block# #blocks ) + dup >r + cdb scsi-build-read-10 ( addr len ) + r> -rot ( #blocks addr len ) + scsi-dir-read cdb scsi-param-size 10 + retry-scsi-command + ( #blocks [ sense-buf sense-len ] stat ) + dup 0<> IF " read-blocks" dump-scsi-error -65 throw ELSE drop THEN +; + +: (inquiry) ( size -- buffer | NULL ) + dup cdb scsi-build-inquiry + \ 16 retries for inquiry to flush out any UAs + scratch swap scsi-dir-read cdb scsi-param-size 10 retry-scsi-command + \ Success ? + 0= IF scratch ELSE 2drop 0 THEN +; + +: inquiry ( -- buffer | NULL ) + scsi-disk-debug? IF + ." SCSI-DISK: inquiry " .s cr + THEN + d# 36 (inquiry) 0= IF 0 EXIT THEN + scratch inquiry-data>add-length c@ 5 + + (inquiry) +; + +: read-capacity ( -- blocksize #blocks ) + \ Now issue the read-capacity command + scsi-disk-debug? IF + ." SCSI-DISK: read-capacity " .s cr + THEN + \ Make sure that there are zeros in the buffer in case something goes wrong: + scratch 10 erase + cdb scsi-build-read-cap-10 scratch scsi-length-read-cap-10-data scsi-dir-read + cdb scsi-param-size 1 retry-scsi-command + \ Success ? + dup 0<> IF " read-capacity" dump-scsi-error 0 0 EXIT THEN + drop scratch scsi-get-capacity-10 1 + +; + +100 CONSTANT test-unit-retries + +\ SCSI test-unit-read +: test-unit-ready ( true | [ ascq asc sense-key false ] ) + scsi-disk-debug? IF + ." SCSI-DISK: test-unit-ready " .s cr + THEN + cdb scsi-build-test-unit-ready + 0 0 0 cdb scsi-param-size test-unit-retries retry-scsi-command + \ stat == 0, return + 0= IF true EXIT THEN + \ check sense len, no sense -> return HW error + 0= IF drop 0 0 4 false EXIT THEN + \ get sense + scsi-get-sense-data false +; + + +: start-stop-unit ( state# -- true | false ) + scsi-disk-debug? IF + ." SCSI-DISK: start-stop-unit " .s cr + THEN + cdb scsi-build-start-stop-unit + 0 0 0 cdb scsi-param-size 10 retry-scsi-command + \ Success ? + 0= IF true ELSE 2drop false THEN +; + +: compare-sense ( ascq asc key ascq2 asc2 key2 -- true | false ) + 3 pick = ( ascq asc key ascq2 asc2 keycmp ) + swap 4 pick = ( ascq asc key ascq2 keycmp asccmp ) + rot 5 pick = ( ascq asc key keycmp asccmp ascqcmp ) + and and nip nip nip +; + +\ -------------------------\ +\ CDROM specific functions \ +\ -------------------------\ + +0 CONSTANT CDROM-READY +1 CONSTANT CDROM-NOT-READY +2 CONSTANT CDROM-NO-DISK +3 CONSTANT CDROM-TRAY-OPEN +4 CONSTANT CDROM-INIT-REQUIRED +5 CONSTANT CDROM-TRAY-MAYBE-OPEN + +: cdrom-try-close-tray ( -- ) + scsi-const-load start-stop-unit drop +; + +: cdrom-must-close-tray ( -- ) + scsi-const-load start-stop-unit not IF + ." Tray open !" cr -65 throw + THEN +; + +: get-media-event ( -- true | false ) + scsi-disk-debug? IF + ." SCSI-DISK: get-media-event " .s cr + THEN + cdb scsi-build-get-media-event + scratch scsi-length-media-event scsi-dir-read cdb scsi-param-size 1 retry-scsi-command + \ Success ? + 0= IF true ELSE 2drop false THEN +; + +: cdrom-status ( -- status ) + test-unit-ready + IF CDROM-READY EXIT THEN + + scsi-disk-debug? IF + ." TestUnitReady sense: " 3dup . . . cr + THEN + + 3dup 1 4 2 compare-sense IF + 3drop CDROM-NOT-READY EXIT + THEN + + get-media-event IF + scratch w@ 4 >= IF + scratch 2 + c@ 04 = IF + scratch 5 + c@ + dup 02 and 0<> IF drop 3drop CDROM-READY EXIT THEN + dup 01 and 0<> IF drop 3drop CDROM-TRAY-OPEN EXIT THEN + drop 3drop CDROM-NO-DISK EXIT + THEN + THEN + THEN + + 3dup 2 4 2 compare-sense IF + 3drop CDROM-INIT-REQUIRED EXIT + THEN + over 4 = over 2 = and IF + \ Format in progress... what do we do ? Just ignore + 3drop CDROM-READY EXIT + THEN + over 3a = IF + 3drop CDROM-NO-DISK EXIT + THEN + + \ Other error... + 3drop CDROM-TRAY-MAYBE-OPEN +; + +: prep-cdrom ( -- ready? ) + 5 0 DO + cdrom-status CASE + CDROM-READY OF UNLOOP true EXIT ENDOF + CDROM-NO-DISK OF ." No medium !" cr UNLOOP false EXIT ENDOF + CDROM-TRAY-OPEN OF cdrom-must-close-tray ENDOF + CDROM-INIT-REQUIRED OF cdrom-try-close-tray ENDOF + CDROM-TRAY-MAYBE-OPEN OF cdrom-try-close-tray ENDOF + ENDCASE + d# 1000 ms + LOOP + ." Drive not ready !" cr false +; + +\ ------------------------\ +\ Disk specific functions \ +\ ------------------------\ + +: prep-disk ( -- ready? ) + test-unit-ready not IF + ." SCSI-DISK: Disk not ready ! " + ." Sense " dup .sense-text ." [" . ." ]" + ." ASC " . ." ASCQ " . cr + false EXIT THEN true +; + +\ --------------------------\ +\ Standard device interface \ +\ --------------------------\ + +: open ( -- true | false ) + scsi-disk-debug? IF + ." SCSI-DISK: open [" .s ." ] unit is " my-unit . . ." [" .s ." ]" cr + THEN + my-unit " set-address" $call-parent + + inquiry dup 0= IF drop false EXIT THEN + scsi-disk-debug? IF + ." ---- inquiry: ----" cr + dup 100 dump cr + ." ------------------" cr + THEN + + \ Skip devices with PQ != 0 + dup inquiry-data>peripheral c@ e0 and 0 <> IF + ." SCSI-DISK: Unsupported PQ != 0" cr + false EXIT + THEN + + inquiry-data>peripheral c@ CASE + 5 OF true to is_cdrom ENDOF + 7 OF true to is_cdrom ENDOF + ENDCASE + + scsi-disk-debug? IF + is_cdrom IF + ." SCSI-DISK: device treated as CD-ROM" cr + ELSE + ." SCSI-DISK: device treated as disk" cr + THEN + THEN + + is_cdrom IF prep-cdrom ELSE prep-disk THEN + not IF false EXIT THEN + + " max-transfer" $call-parent to max-transfer + + read-capacity to max-block-num to block-size + max-block-num 0= block-size 0= OR IF + ." SCSI-DISK: Failed to get disk capacity!" cr + FALSE EXIT + THEN + + scsi-disk-debug? IF + ." Capacity: " max-block-num . ." blocks of " block-size . cr + THEN + + 0 0 " deblocker" $open-package dup deblocker ! dup IF + " disk-label" find-package IF + my-args rot interpose + THEN + THEN 0<> +; + +: close ( -- ) + deblocker @ close-package ; + +: seek ( pos.lo pos.hi -- status ) + s" seek" deblocker @ $call-method ; + +: read ( addr len -- actual ) + s" read" deblocker @ $call-method ; + +\ Get rid of SCSI bits +scsi-close + +finish-device diff --git a/qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs b/qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs new file mode 100644 index 000000000..579ce37f9 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/scsi-host-helpers.fs @@ -0,0 +1,127 @@ +\ This file is meant to be included by SCSI hosts to provide +\ helpers such as retry-scsi-command + +\ Returns 1 for retry, 0 for return with no error and +\ -1 for return with an error +\ +: check-retry-sense? ( sense-buf sense-len -- retry? ) + \ Check if the sense-len is at least 8 bytes + 8 < IF -1 EXIT THEN + + \ Fixed sense record, look for filemark etc... + dup sense-data>response-code c@ 7e and 70 = IF + dup sense-data>sense-key c@ e0 and IF drop -1 EXIT THEN + THEN + + \ Get sense data + scsi-get-sense-data? IF ( ascq asc sense-key ) + \ No sense or recoverable, return success + dup 2 < IF 3drop 0 EXIT THEN + \ not ready and unit attention, retry + dup 2 = swap 6 = or nip nip IF 1 EXIT THEN + THEN + \ Return failure + -1 +; + +\ This is almost as the standard retry-command but returns +\ additionally the length of the returned sense information +\ +\ The hw-err? field is gone, stat is -1 for a HW error, and +\ the sense data is provided iff stat is CHECK_CONDITION (02) +\ +\ Additionally we wait 10ms between retries +\ +0 INSTANCE VALUE rcmd-buf-addr +0 INSTANCE VALUE rcmd-buf-len +0 INSTANCE VALUE rcmd-dir +0 INSTANCE VALUE rcmd-cmd-addr +0 INSTANCE VALUE rcmd-cmd-len + +: retry-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len #retries -- ... ) + ( ... 0 | [ sense-buf sense-len ] stat ) + >r \ stash #retries + to rcmd-cmd-len to rcmd-cmd-addr to rcmd-dir to rcmd-buf-len to rcmd-buf-addr + 0 \ dummy status & sense + r> \ retreive #retries ( stat #retries ) + 0 DO + \ drop previous status & sense + 0<> IF 2drop THEN + + \ Restore arguments + rcmd-buf-addr + rcmd-buf-len + rcmd-dir + rcmd-cmd-addr + rcmd-cmd-len + + \ Send command + execute-scsi-command ( [ sense-buf sense-len ] stat ) + + \ Success ? + dup 0= IF LEAVE THEN + + \ HW error ? + dup -1 = IF LEAVE THEN + + \ Check condition ? + dup 2 = IF ( sense-buf sense-len stat ) + >r \ stash stat ( sense-buf sense len ) + 2dup + check-retry-sense? ( sense-buf sense-len retry? ) + r> swap \ unstash stat ( sense-buf sense-len stat retry? ) + \ Check retry? result + CASE + 0 OF 3drop 0 LEAVE ENDOF \ Swallow error, return 0 + -1 OF LEAVE ENDOF \ No retry + ENDCASE + ELSE \ Anything other than busy -> exit + dup 8 <> IF LEAVE THEN + THEN + a ms + LOOP +; + +\ ----------------------------------------------------------- +\ Some command helpers +\ ----------------------------------------------------------- +\ +\ TODO: Get rid of global "sector" and instead return an +\ allocated block for the caller to free + +CREATE sector d# 512 allot +CREATE cdb 10 allot + +: (inquiry) ( size -- buffer | NULL ) + dup cdb scsi-build-inquiry + \ 16 retries for inquiry to flush out any UAs + sector swap scsi-dir-read cdb scsi-param-size 10 retry-scsi-command + \ Success ? + 0= IF sector ELSE 2drop 0 THEN +; + +\ Read the initial 36bytes and then decide how much more is to be read +: inquiry ( -- buffer | NULL ) + d# 36 (inquiry) 0= IF 0 EXIT THEN + sector inquiry-data>add-length c@ 5 + + (inquiry) +; + +: report-luns ( -- [ sector ] true | false ) + 200 cdb scsi-build-report-luns + \ 16 retries to flush out any UAs + sector 200 scsi-dir-read cdb scsi-param-size 10 retry-scsi-command + \ Success ? + 0= IF sector true ELSE drop false THEN +; + +\ This routine creates a disk alias for the first found disk/cdrom +: make-disk-alias ( $name srplun -- ) + >r 2dup r> -rot ( $name srplun $name) + find-alias 0<> IF 4drop exit THEN + get-node node>path + 20 allot + " /disk@" string-cat ( $name srplun npath npathl ) + rot base @ >r hex (u.) r> base ! string-cat ( $name $diskpath ) + set-alias +; diff --git a/qemu/roms/SLOF/slof/fs/scsi-loader.fs b/qemu/roms/SLOF/slof/fs/scsi-loader.fs new file mode 100644 index 000000000..fec1f78dc --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/scsi-loader.fs @@ -0,0 +1,77 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ************************************** +\ Last change: MiR 13.11.2007 10:55:57 +\ ************************************** + +: .ansi-attr-off 1b emit ." [0m" ; \ ESC Sequence: all terminal attributes off +: .ansi-blue 1b emit ." [34m" ; \ ESC Sequence: foreground-color = blue +: .ansi-green 1b emit ." [32m" ; \ ESC Sequence: foreground-color = green +: .ansi-red 1b emit ." [31m" ; \ ESC Sequence: foreground-color = green +: .ansi-bold 1b emit ." [1m" ; \ ESC Sequence: foreground-color bold + +false VALUE scsi-supp-present? + +: scsi-xt-err ." SCSI-ERROR (Intern) " ; +' scsi-xt-err VALUE scsi-open-xt \ preset with an invalid token + +\ ************************************* +\ utility to show all active word-lists +\ ************************************* +: .wordlists ( -- ) + .ansi-red + get-order ( -- wid1 .. widn n ) + dup space 28 emit .d ." word lists : " + 0 DO + . 08 emit 2c emit + LOOP + 08 emit \ 'bs' + 29 emit \ ')' + cr space 28 emit + ." Context: " context dup . + @ 5b emit . 8 emit 5d emit + space + ." / Current: " current . + .ansi-attr-off + cr +; + +\ ************************************* +\ utility to show first word-lists +\ ************************************* +: .context ( num -- ) + .ansi-red + space + 5b emit + 23 emit . 3a emit + context @ + . 8 emit 5d emit space + .ansi-attr-off +; + +\ **************************************************************************** +\ open scsi-support by adding a new word list on top of search path +\ first check if scsi-support.fs must be included (first call) +\ when open use execution pointer to access version in new word list +\ **************************************************************************** +: scsi-open ( -- ) + scsi-supp-present? NOT + IF + s" scsi-support.fs" included ( xt-open ) + to scsi-open-xt ( ) + true to scsi-supp-present? + THEN + scsi-open-xt execute +; + + diff --git a/qemu/roms/SLOF/slof/fs/scsi-probe-helpers.fs b/qemu/roms/SLOF/slof/fs/scsi-probe-helpers.fs new file mode 100644 index 000000000..6aec8b159 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/scsi-probe-helpers.fs @@ -0,0 +1,95 @@ +\ This file is meant to be included by SCSI hosts to provide +\ probing helpers - scsi-find-disks + +: wrapped-inquiry ( -- true | false ) + inquiry 0= IF false EXIT THEN + \ Skip devices with PQ != 0 + sector inquiry-data>peripheral c@ e0 and 0 = +; + +: scsi-read-lun ( addr -- lun true | false ) + dup c@ C0 AND CASE + 40 OF w@-be 3FFF AND TRUE ENDOF + 0 OF w@-be TRUE ENDOF + dup dup OF ." Unsupported LUN format = " . cr FALSE ENDOF + ENDCASE +; + +: vscsi-report-luns ( -- array ndev ) + \ array of pointers, up to 8 devices + dev-max-target 3 << alloc-mem dup + 0 ( devarray devcur ndev ) + dev-max-target 0 DO + i 0 dev-generate-srplun (set-target) + report-luns nip IF + sector l@ ( devarray devcur ndev size ) + sector 8 + swap ( devarray devcur ndev lunarray size ) + dup 8 + dup alloc-mem ( devarray devcur ndev lunarray size size+ mem ) + dup rot 0 fill ( devarray devcur ndev lunarray size mem ) + dup >r swap move r> ( devarray devcur ndev mem ) + dup sector l@ 3 >> 0 ?DO ( devarray devcur ndev mem memcur ) + dup dup scsi-read-lun IF + j swap dev-generate-srplun swap x! 8 + + ELSE + 2drop + THEN + LOOP drop + rot ( devarray ndev mem devcur ) + dup >r x! r> 8 + ( devarray ndev devcur ) + swap 1 + + ELSE + dev-max-target 1 = IF + \ Some USB MSC devices do not implement report + \ luns. That will stall the bulk pipe. These devices are + \ single lun devices, report it accordingly + + ( devarray devcur ndev ) + 16 alloc-mem ( devarray devcur ndev mem ) + dup 16 0 fill ( devarray devcur ndev mem ) + dup 0 0 dev-generate-srplun swap x! ( devarray devcur ndev mem ) + rot x! ( devarray ndev ) + 1 + + UNLOOP EXIT + THEN + THEN + LOOP + nip +; + +: make-media-alias ( $name srplun -- ) + >r + get-next-alias ?dup IF + r> make-disk-alias + ELSE + r> drop + THEN +; + +: scsi-find-disks ( -- ) + ." SCSI: Looking for devices" cr + vscsi-report-luns + 0 ?DO + dup x@ + BEGIN + dup x@ + dup 0= IF drop TRUE ELSE + (set-target) wrapped-inquiry IF + ." " current-target (u.) type ." " + \ XXX FIXME: Check top bits to ignore unsupported units + \ and maybe provide better printout & more cases + \ XXX FIXME: Actually check for LUNs + sector inquiry-data>peripheral c@ CASE + 0 OF ." DISK : " " disk" current-target make-media-alias ENDOF + 5 OF ." CD-ROM : " " cdrom" current-target make-media-alias ENDOF + 7 OF ." OPTICAL : " " cdrom" current-target make-media-alias ENDOF + e OF ." RED-BLOCK: " " disk" current-target make-media-alias ENDOF + dup dup OF ." ? (" . 8 emit 29 emit 5 spaces ENDOF + ENDCASE + sector .inquiry-text cr + THEN + 8 + FALSE + THEN + UNTIL drop + 8 + + LOOP drop +; diff --git a/qemu/roms/SLOF/slof/fs/scsi-support.fs b/qemu/roms/SLOF/slof/fs/scsi-support.fs new file mode 100644 index 000000000..3e65c8781 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/scsi-support.fs @@ -0,0 +1,847 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ************************************************ +\ create a new scsi word-list named 'scsi-words' +\ ************************************************ +vocabulary scsi-words \ create new word list named 'scsi-words' +also scsi-words definitions \ place next definitions into new list + +\ for some commands specific parameters are used, which normally +\ need not to be altered. These values are preset at include time +\ or explicit by a call of 'scsi-supp-init' +false value scsi-param-debug \ common debugging flag +d# 0 value scsi-param-size \ length of CDB processed last +h# 0 value scsi-param-control \ control word for CDBs as defined in SAM-4 +d# 0 value scsi-param-errors \ counter for detected errors + +\ utility to increment error counter +: scsi-inc-errors + scsi-param-errors 1 + to scsi-param-errors +; + +\ *************************************************************************** +\ SCSI-Command: TEST UNIT READY +\ Type: Primary Command (SPC-3 clause 6.33) +\ *************************************************************************** +\ Forth Word: scsi-build-test-unit-ready ( cdb -- ) +\ *************************************************************************** +\ checks if a device is ready to receive commands +\ *************************************************************************** +\ command code: +00 CONSTANT scsi-cmd-test-unit-ready +\ CDB structure: +STRUCT + /c FIELD test-unit-ready>operation-code \ 00h + 4 FIELD test-unit-ready>reserved \ unused + /c FIELD test-unit-ready>control \ control byte as specified in SAM-4 +CONSTANT scsi-length-test-unit-ready + +\ cdb build: +\ all fields are zeroed +: scsi-build-test-unit-ready ( cdb -- ) + dup scsi-length-test-unit-ready erase ( cdb ) + scsi-param-control swap test-unit-ready>control c! ( ) + scsi-length-test-unit-ready to scsi-param-size \ update CDB length +; + +\ *************************************************************************** +\ SCSI-Command: REPORT LUNS +\ Type: Primary Command +\ *************************************************************************** +\ Forth Word: scsi-build-report-luns ( cdb -- ) +\ *************************************************************************** +\ report all LUNs supported by a device +\ *************************************************************************** +\ command code: +a0 CONSTANT scsi-cmd-report-luns +\ CDB structure: +STRUCT + /c FIELD report-luns>operation-code \ a0h + 1 FIELD report-luns>reserved \ unused + /c FIELD report-luns>select-report \ report select byte + 3 FIELD report-luns>reserved2 \ unused + /l FIELD report-luns>alloc-length \ report length + 1 FIELD report-luns>reserved3 \ unused + /c FIELD report-luns>control \ control byte +CONSTANT scsi-length-report-luns + +\ cdb build: +\ all fields are zeroed +: scsi-build-report-luns ( alloc-len cdb -- ) + dup scsi-length-report-luns erase \ 12 bytes CDB + scsi-cmd-report-luns over ( alloc-len cdb cmd cdb ) + report-luns>operation-code c! ( alloc-len cdb ) + scsi-param-control over report-luns>control c! ( alloc-len cdb ) + report-luns>alloc-length l! \ size of Data-In Buffer + scsi-length-report-luns to scsi-param-size \ update CDB length +; + +\ *************************************************************************** +\ SCSI-Command: REQUEST SENSE +\ Type: Primary Command (SPC-3 clause 6.27) +\ *************************************************************************** +\ Forth Word: scsi-build-request-sense ( cdb -- ) +\ *************************************************************************** +\ for return data a buffer of at least 252 bytes must be present! +\ see spec: SPC-3 (r23) / clauses 4.5 and 6.27 +\ *************************************************************************** +\ command code: +03 CONSTANT scsi-cmd-request-sense +\ CDB structure: +STRUCT + /c FIELD request-sense>operation-code \ 03h + 3 FIELD request-sense>reserved \ unused + /c FIELD request-sense>allocation-length \ buffer-length for data response + /c FIELD request-sense>control \ control byte as specified in SAM-4 +CONSTANT scsi-length-request-sense + +\ cdb build: +: scsi-build-request-sense ( alloc-len cdb -- ) + >r ( alloc-len ) ( R: -- cdb ) + r@ scsi-length-request-sense erase ( alloc-len ) + scsi-cmd-request-sense r@ ( alloc-len cmd cdb ) + request-sense>operation-code c! ( alloc-len ) + dup d# 252 > \ buffer length too big ? + IF + scsi-inc-errors + drop d# 252 \ replace with 252 + ELSE + dup d# 18 < \ allocated buffer too small ? + IF + scsi-inc-errors + drop 0 \ reject return data + THEN + THEN ( alloclen ) + r@ request-sense>allocation-length c! ( ) + scsi-param-control r> request-sense>control c! ( alloc-len cdb ) ( R: cdb -- ) + scsi-length-request-sense to scsi-param-size \ update CDB length +; + +\ ---------------------------------------- +\ SCSI-Response: SENSE_DATA +\ ---------------------------------------- +70 CONSTANT scsi-response(request-sense-0) +71 CONSTANT scsi-response(request-sense-1) + +STRUCT + /c FIELD sense-data>response-code \ 70h (current errors) or 71h (deferred errors) + /c FIELD sense-data>obsolete + /c FIELD sense-data>sense-key \ D3..D0 = sense key, D7 = EndOfMedium + /l FIELD sense-data>info + /c FIELD sense-data>alloc-length \ <= 244 (for max size) + /l FIELD sense-data>command-info + /c FIELD sense-data>asc \ additional sense key + /c FIELD sense-data>ascq \ additional sense key qualifier + /c FIELD sense-data>unit-code + 3 FIELD sense-data>key-specific + /c FIELD sense-data>add-sense-bytes \ start of appended extra bytes +CONSTANT scsi-length-sense-data + +\ ---------------------------------------- +\ get from SCSI response block: +\ - Additional Sense Code Qualifier +\ - Additional Sense Code +\ - sense-key +\ ---------------------------------------- +\ Forth Word: scsi-get-sense-data ( addr -- ascq asc sense-key ) +\ ---------------------------------------- +: scsi-get-sense-data ( addr -- ascq asc sense-key ) + >r ( R: -- addr ) + r@ sense-data>response-code c@ 7f and 72 >= IF + r@ 3 + c@ ( ascq ) + r@ 2 + c@ ( ascq asc ) + r> 1 + c@ 0f and ( ascq asc sense-key ) + ELSE + r@ sense-data>ASCQ c@ ( ascq ) + r@ sense-data>ASC c@ ( ascq asc ) + r> sense-data>sense-key c@ 0f and ( ascq asc sense-key ) ( R: addr -- ) + THEN +; + +\ -------------------------------------------------------------------------- +\ Forth Word: scsi-get-sense-data? ( addr -- false | ascq asc sense-key true ) +\ -------------------------------------------------------------------------- +: scsi-get-sense-data? ( addr -- false | ascq asc sense-key true ) + dup + sense-data>response-code c@ + 7e AND dup 70 = swap 72 = or \ Response code (some devices have MSB set) + IF + scsi-get-sense-data TRUE + ELSE + drop FALSE \ drop addr + THEN + +; + +\ -------------------------------------------------------------------------- +\ Forth Word: scsi-get-sense-ID? ( addr -- false | sense-ID true ) +\ same as scsi-get-sense-data? but returns +\ a single word composed of: sense-key<<16 | asc<<8 | ascq +\ -------------------------------------------------------------------------- +: scsi-get-sense-ID? ( addr -- false | ascq asc sense-key true ) + dup + sense-data>response-code c@ + 7e AND 70 = \ Response code (some devices have MSB set) + IF + scsi-get-sense-data ( ascq asc sense-key ) + 10 lshift ( ascq asc sense-key16 ) + swap 8 lshift or ( ascq sense-key+asc ) + swap or \ 24-bit sense-ID ( sense-key+asc+ascq ) + TRUE + ELSE + drop FALSE \ drop addr + THEN +; + +\ *************************************************************************** +\ SCSI-Command: INQUIRY +\ Type: Primary Command (SPC-3 clause 6.4) +\ *************************************************************************** +\ Forth Word: scsi-build-inquiry ( alloc-len cdb -- ) +\ *************************************************************************** +\ command code: +12 CONSTANT scsi-cmd-inquiry + +\ CDB structure +STRUCT + /c FIELD inquiry>operation-code \ 0x12 + /c FIELD inquiry>reserved \ + EVPD-Bit (vital product data) + /c FIELD inquiry>page-code \ page code for vital product data (if used) + /w FIELD inquiry>allocation-length \ length of Data-In-Buffer + /c FIELD inquiry>control \ control byte as specified in SAM-4 +CONSTANT scsi-length-inquiry + +\ Setup command INQUIRY +: scsi-build-inquiry ( alloc-len cdb -- ) + dup scsi-length-inquiry erase \ 6 bytes CDB + scsi-cmd-inquiry over ( alloc-len cdb cmd cdb ) + inquiry>operation-code c! ( alloc-len cdb ) + scsi-param-control over inquiry>control c! ( alloc-len cdb ) + inquiry>allocation-length w! \ size of Data-In Buffer + scsi-length-inquiry to scsi-param-size \ update CDB length +; + +\ ---------------------------------------- +\ block structure of inquiry return data: +\ ---------------------------------------- +STRUCT + /c FIELD inquiry-data>peripheral \ qualifier and device type + /c FIELD inquiry-data>reserved1 + /c FIELD inquiry-data>version \ supported SCSI version (1,2,3) + /c FIELD inquiry-data>data-format + /c FIELD inquiry-data>add-length \ total block length - 4 + /c FIELD inquiry-data>flags1 + /c FIELD inquiry-data>flags2 + /c FIELD inquiry-data>flags3 + d# 8 FIELD inquiry-data>vendor-ident \ vendor string + d# 16 FIELD inquiry-data>product-ident \ device string + /l FIELD inquiry-data>product-revision \ revision string + d# 20 FIELD inquiry-data>vendor-specific \ optional params +\ can be increased by vendor specific fields +CONSTANT scsi-length-inquiry-data + +\ *************************************************************************** +\ SCSI-Command: READ CAPACITY (10) +\ Type: Block Command (SBC-3 clause 5.12) +\ *************************************************************************** +\ Forth Word: scsi-build-read-capacity-10 ( cdb -- ) +\ *************************************************************************** +25 CONSTANT scsi-cmd-read-capacity-10 \ command code + +STRUCT \ SCSI 10-byte CDB structure + /c FIELD read-cap-10>operation-code + /c FIELD read-cap-10>reserved1 + /l FIELD read-cap-10>lba + /w FIELD read-cap-10>reserved2 + /c FIELD read-cap-10>reserved3 + /c FIELD read-cap-10>control +CONSTANT scsi-length-read-cap-10 + +\ Setup READ CAPACITY (10) command +: scsi-build-read-cap-10 ( cdb -- ) + dup scsi-length-read-cap-10 erase ( cdb ) + scsi-cmd-read-capacity-10 over ( cdb cmd cdb ) + read-cap-10>operation-code c! ( cdb ) + scsi-param-control swap read-cap-10>control c! ( ) + scsi-length-read-cap-10 to scsi-param-size \ update CDB length +; + +\ ---------------------------------------- +\ get from SCSI response block: +\ - Additional Sense Code Qualifier +\ - Additional Sense Code +\ - sense-key +\ ---------------------------------------- +\ Forth Word: scsi-get-capacity-10 ( addr -- block-size #blocks ) +\ ---------------------------------------- +\ Block structure +STRUCT + /l FIELD read-cap-10-data>max-lba + /l FIELD read-cap-10-data>block-size +CONSTANT scsi-length-read-cap-10-data + +\ get data-block +: scsi-get-capacity-10 ( addr -- block-size #blocks ) + >r ( addr -- ) ( R: -- addr ) + r@ read-cap-10-data>block-size l@ ( block-size ) + r> read-cap-10-data>max-lba l@ ( block-size #blocks ) ( R: addr -- ) +; + +\ *************************************************************************** +\ SCSI-Command: READ CAPACITY (16) +\ Type: Block Command (SBC-3 clause 5.13) +\ *************************************************************************** +\ Forth Word: scsi-build-read-capacity-16 ( cdb -- ) +\ *************************************************************************** +9e CONSTANT scsi-cmd-read-capacity-16 \ command code + +STRUCT \ SCSI 16-byte CDB structure + /c FIELD read-cap-16>operation-code + /c FIELD read-cap-16>service-action + /l FIELD read-cap-16>lba-high + /l FIELD read-cap-16>lba-low + /l FIELD read-cap-16>allocation-length \ should be 32 + /c FIELD read-cap-16>reserved + /c FIELD read-cap-16>control +CONSTANT scsi-length-read-cap-16 + +\ Setup READ CAPACITY (16) command +: scsi-build-read-cap-16 ( cdb -- ) + >r r@ ( R: -- cdb ) + scsi-length-read-cap-16 erase ( ) + scsi-cmd-read-capacity-16 ( code ) + r@ read-cap-16>operation-code c! ( ) + 10 r@ read-cap-16>service-action c! + d# 32 \ response size 32 bytes + r@ read-cap-16>allocation-length l! ( ) + scsi-param-control r> read-cap-16>control c! ( R: cdb -- ) + scsi-length-read-cap-16 to scsi-param-size \ update CDB length +; + +\ ---------------------------------------- +\ get from SCSI response block: +\ - Block Size (in Bytes) +\ - Number of Blocks +\ ---------------------------------------- +\ Forth Word: scsi-get-capacity-16 ( addr -- block-size #blocks ) +\ ---------------------------------------- +\ Block structure for return data +STRUCT + /l FIELD read-cap-16-data>max-lba-high \ upper quadlet of Max-LBA + /l FIELD read-cap-16-data>max-lba-low \ lower quadlet of Max-LBA + /l FIELD read-cap-16-data>block-size \ logical block length in bytes + /c FIELD read-cap-16-data>protect \ type of protection (4 bits) + /c FIELD read-cap-16-data>exponent \ logical blocks per physical blocks + /w FIELD read-cap-16-data>lowest-aligned \ first LBA of a phsy. block + 10 FIELD read-cap-16-data>reserved \ 16 reserved bytes +CONSTANT scsi-length-read-cap-16-data \ results in 32 + +\ get data-block +: scsi-get-capacity-16 ( addr -- block-size #blocks ) + >r ( R: -- addr ) + r@ read-cap-16-data>block-size l@ ( block-size ) + r@ read-cap-16-data>max-lba-high l@ ( block-size #blocks-high ) + d# 32 lshift ( block-size #blocks-upper ) + r> read-cap-16-data>max-lba-low l@ + ( block-size #blocks ) ( R: addr -- ) +; + +\ *************************************************************************** +\ SCSI-Command: MODE SENSE (10) +\ Type: Primary Command (SPC-3 clause 6.10) +\ *************************************************************************** +\ Forth Word: scsi-build-mode-sense-10 ( alloc-len subpage page cdb -- ) +\ *************************************************************************** +5a CONSTANT scsi-cmd-mode-sense-10 + +\ CDB structure +STRUCT + /c FIELD mode-sense-10>operation-code + /c FIELD mode-sense-10>res-llbaa-dbd-res + /c FIELD mode-sense-10>pc-page-code \ page code + page control + /c FIELD mode-sense-10>sub-page-code + 3 FIELD mode-sense-10>reserved2 + /w FIELD mode-sense-10>allocation-length + /c FIELD mode-sense-10>control +CONSTANT scsi-length-mode-sense-10 + +: scsi-build-mode-sense-10 ( alloc-len subpage page cdb -- ) + >r ( alloc-len subpage page ) ( R: -- cdb ) + r@ scsi-length-mode-sense-10 erase \ 10 bytes CDB + scsi-cmd-mode-sense-10 ( alloc-len subpage page cmd ) + r@ mode-sense-10>operation-code c! ( alloc-len subpage page ) + 10 r@ mode-sense-10>res-llbaa-dbd-res c! \ long LBAs accepted + r@ mode-sense-10>pc-page-code c! ( alloc-len subpage ) + r@ mode-sense-10>sub-page-code c! ( alloc-len ) + r@ mode-sense-10>allocation-length w! ( ) + + scsi-param-control r> mode-sense-10>control c! ( R: cdb -- ) + scsi-length-mode-sense-10 to scsi-param-size \ update CDB length +; + +\ return data processing +\ (see spec: SPC-3 clause 7.4.3) + +STRUCT + /w FIELD mode-sense-10-data>head-length + /c FIELD mode-sense-10-data>head-medium + /c FIELD mode-sense-10-data>head-param + /c FIELD mode-sense-10-data>head-longlba + /c FIELD mode-sense-10-data>head-reserved + /w FIELD mode-sense-10-data>head-descr-len +CONSTANT scsi-length-mode-sense-10-data + +\ **************************************** +\ This function shows the mode page header +\ helpful for further analysis +\ **************************************** +: .mode-sense-data ( addr -- ) + cr + dup mode-sense-10-data>head-length + w@ ." Mode Length: " .d space + dup mode-sense-10-data>head-medium + c@ ." / Medium Type: " .d space + dup mode-sense-10-data>head-longlba + c@ ." / Long LBA: " .d space + mode-sense-10-data>head-descr-len + w@ ." / Descr. Length: " .d +; + +\ *************************************************************************** +\ SCSI-Command: READ (6) +\ Type: Block Command (SBC-3 clause 5.7) +\ *************************************************************************** +\ Forth Word: scsi-build-read-6 ( block# #blocks cdb -- ) +\ *************************************************************************** +\ this SCSI command uses 21 bits to represent start LBA +\ and 8 bits to specify the numbers of blocks to read +\ The value of 0 blocks is interpreted as 256 blocks +\ +\ command code +08 CONSTANT scsi-cmd-read-6 + +\ CDB structure +STRUCT + /c FIELD read-6>operation-code \ 08h + /c FIELD read-6>block-address-msb \ upper 5 bits + /w FIELD read-6>block-address \ lower 16 bits + /c FIELD read-6>length \ number of blocks to read + /c FIELD read-6>control \ CDB control +CONSTANT scsi-length-read-6 + +: scsi-build-read-6 ( block# #blocks cdb -- ) + >r ( block# #blocks ) ( R: -- cdb ) + r@ scsi-length-read-6 erase \ 6 bytes CDB + scsi-cmd-read-6 r@ read-6>operation-code c! ( block# #blocks ) + + \ check block count to read (#blocks) + dup d# 255 > \ #blocks exceeded limit ? + IF + scsi-inc-errors + drop 1 \ replace with any valid number + THEN + r@ read-6>length c! \ set #blocks to read + + \ check starting block number (block#) + dup 1fffff > \ check address upper limit + IF + scsi-inc-errors + drop \ remove original block# + 1fffff \ replace with any valid address + THEN + dup d# 16 rshift + r@ read-6>block-address-msb c! \ set upper 5 bits + ffff and + r@ read-6>block-address w! \ set lower 16 bits + scsi-param-control r> read-6>control c! ( R: cdb -- ) + scsi-length-read-6 to scsi-param-size \ update CDB length +; + +\ *************************************************************************** +\ SCSI-Command: READ (10) +\ Type: Block Command (SBC-3 clause 5.8) +\ *************************************************************************** +\ Forth Word: scsi-build-read-10 ( block# #blocks cdb -- ) +\ *************************************************************************** +\ command code +28 CONSTANT scsi-cmd-read-10 + +\ CDB structure +STRUCT + /c FIELD read-10>operation-code + /c FIELD read-10>protect + /l FIELD read-10>block-address \ logical block address (32bits) + /c FIELD read-10>group + /w FIELD read-10>length \ transfer length (16-bits) + /c FIELD read-10>control +CONSTANT scsi-length-read-10 + +: scsi-build-read-10 ( block# #blocks cdb -- ) + >r ( block# #blocks ) ( R: -- cdb ) + r@ scsi-length-read-10 erase \ 10 bytes CDB + scsi-cmd-read-10 r@ read-10>operation-code c! ( block# #blocks ) + r@ read-10>length w! ( block# ) + r@ read-10>block-address l! ( ) + scsi-param-control r> read-10>control c! ( R: cdb -- ) + scsi-length-read-10 to scsi-param-size \ update CDB length +; + +\ *************************************************************************** +\ SCSI-Command: READ (12) +\ Type: Block Command (SBC-3 clause 5.9) +\ *************************************************************************** +\ Forth Word: scsi-build-read-12 ( block# #blocks cdb -- ) +\ *************************************************************************** +\ command code +a8 CONSTANT scsi-cmd-read-12 + +\ CDB structure +STRUCT + /c FIELD read-12>operation-code \ code: a8 + /c FIELD read-12>protect \ RDPROTECT, DPO, FUA, FUA_NV + /l FIELD read-12>block-address \ lba + /l FIELD read-12>length \ transfer length (32bits) + /c FIELD read-12>group \ group number + /c FIELD read-12>control +CONSTANT scsi-length-read-12 + +: scsi-build-read-12 ( block# #blocks cdb -- ) + >r ( block# #blocks ) ( R: -- cdb ) + r@ scsi-length-read-12 erase \ 12 bytes CDB + scsi-cmd-read-12 r@ read-12>operation-code c! ( block# #blocks ) + r@ read-12>length l! ( block# ) + r@ read-12>block-address l! ( ) + scsi-param-control r> read-12>control c! ( R: cdb -- ) + scsi-length-read-12 to scsi-param-size \ update CDB length +; + +\ *************************************************************************** +\ SCSI-Command: READ with autodetection of required command +\ read(10) or read(12) depending on parameter size +\ (read(6) removed because obsolete in some cases (USB)) +\ Type: Block Command +\ *************************************************************************** +\ Forth Word: scsi-build-read? ( block# #blocks cdb -- ) +\ +\ +----------------+---------------------------| +\ | block# (lba) | #block (transfer-length) | +\ +-----------+----------------+---------------------------| +\ | read-6 | 16-Bits | 8 Bits | +\ | read-10 | 32-Bits | 16 Bits | +\ | read-12 | 32-Bits | 32 Bits | +\ *************************************************************************** +: scsi-build-read? ( block# #blocks cdb -- length ) + over ( block# #blocks cdb #blocks ) + fffe > \ tx-length (#blocks) exceeds 16-bit limit ? + IF + scsi-build-read-12 ( block# #blocks cdb -- ) + scsi-length-read-12 ( length ) + ELSE ( block# #blocks cdb ) + scsi-build-read-10 ( block# #blocks cdb -- ) + scsi-length-read-10 ( length ) + THEN +; + +\ *************************************************************************** +\ SCSI-Command: START STOP UNIT +\ Type: Block Command (SBC-3 clause 5.19) +\ *************************************************************************** +\ Forth Word: scsi-build-start-stop-unit ( state# cdb -- ) +\ *************************************************************************** +\ command code +1b CONSTANT scsi-cmd-start-stop-unit + +\ CDB structure +STRUCT + /c FIELD start-stop-unit>operation-code + /c FIELD start-stop-unit>immed + /w FIELD start-stop-unit>reserved + /c FIELD start-stop-unit>pow-condition + /c FIELD start-stop-unit>control +CONSTANT scsi-length-start-stop-unit + +\ START/STOP constants +\ (see spec: SBC-3 clause 5.19) +f1 CONSTANT scsi-const-active-power \ param used for start-stop-unit +f2 CONSTANT scsi-const-idle-power \ param used for start-stop-unit +f3 CONSTANT scsi-const-standby-power \ param used for start-stop-unit +3 CONSTANT scsi-const-load \ param used for start-stop-unit +2 CONSTANT scsi-const-eject \ param used for start-stop-unit +1 CONSTANT scsi-const-start +0 CONSTANT scsi-const-stop + +: scsi-build-start-stop-unit ( state# cdb -- ) + >r ( state# ) ( R: -- cdb ) + r@ scsi-length-start-stop-unit erase \ 6 bytes CDB + scsi-cmd-start-stop-unit r@ start-stop-unit>operation-code c! + dup 3 > + IF + 4 lshift \ shift to upper nibble + THEN ( state ) + r@ start-stop-unit>pow-condition c! ( ) + scsi-param-control r> start-stop-unit>control c! ( R: cdb -- ) + scsi-length-start-stop-unit to scsi-param-size \ update CDB length +; + +\ *************************************************************************** +\ SCSI-Command: SEEK(10) +\ Type: Block Command (obsolete) +\ *************************************************************************** +\ Forth Word: scsi-build-seek ( state# cdb -- ) +\ Obsolete function (last listed in spec SBC / Nov. 1997) +\ implemented only for the sake of completeness +\ *************************************************************************** +\ command code +2b CONSTANT scsi-cmd-seek + +\ CDB structure +STRUCT + /c FIELD seek>operation-code + /c FIELD seek>reserved1 + /l FIELD seek>lba + 3 FIELD seek>reserved2 + /c FIELD seek>control +CONSTANT scsi-length-seek + +: scsi-build-seek ( lba cdb -- ) + >r ( lba ) ( R: -- cdb ) + r@ scsi-length-seek erase \ 10 bytes CDB + scsi-cmd-seek r@ seek>operation-code c! + r> seek>lba l! ( ) ( R: cdb -- ) + scsi-length-seek to scsi-param-size \ update CDB length +; + +\ **************************************************************************** +\ CDROM media event stuff +\ **************************************************************************** + +STRUCT + /w FIELD media-event-data-len + /c FIELD media-event-nea-class + /c FIELD media-event-supp-class + /l FIELD media-event-data +CONSTANT scsi-length-media-event + +: scsi-build-get-media-event ( cdb -- ) + dup c erase ( cdb ) + 4a over c! ( cdb ) + 01 over 1 + c! + 10 over 4 + c! + 08 over 8 + c! + drop +; + + + +\ *************************************************************************** +\ SCSI-Utility: .sense-code +\ *************************************************************************** +\ this utility prints a string associated to the sense code +\ see specs: SPC-3/r23 clause 4.5.6 +\ *************************************************************************** +: .sense-text ( scode -- ) + case + 0 OF s" OK" ENDOF + 1 OF s" RECOVERED ERR" ENDOF + 2 OF s" NOT READY" ENDOF + 3 OF s" MEDIUM ERROR" ENDOF + 4 OF s" HARDWARE ERR" ENDOF + 5 OF s" ILLEGAL REQUEST" ENDOF + 6 OF s" UNIT ATTENTION" ENDOF + 7 OF s" DATA PROTECT" ENDOF + 8 OF s" BLANK CHECK" ENDOF + 9 OF s" VENDOR SPECIFIC" ENDOF + a OF s" COPY ABORTED" ENDOF + b OF s" ABORTED COMMAND" ENDOF + d OF s" VOLUME OVERFLOW" ENDOF + e OF s" MISCOMPARE" ENDOF + dup OF s" UNKNOWN" ENDOF + endcase + 5b emit type 5d emit +; + +\ *************************************************************************** +\ SCSI-Utility: .status-code +\ *************************************************************************** +\ this utility prints a string associated to the status code +\ see specs: SAM-3/r14 clause 5.3 +\ *************************************************************************** +: .status-text ( stat -- ) + case + 00 OF s" GOOD" ENDOF + 02 OF s" CHECK CONDITION" ENDOF + 04 OF s" CONDITION MET" ENDOF + 08 OF s" BUSY" ENDOF + 18 OF s" RESERVATION CONFLICT" ENDOF + 28 OF s" TASK SET FULL" ENDOF + 30 OF s" ACA ACTIVE" ENDOF + 40 OF s" TASK ABORTED" ENDOF + dup OF s" UNKNOWN" ENDOF + endcase + 5b emit type 5d emit +; + +\ *************************************************************************** +\ SCSI-Utility: .capacity-text +\ *************************************************************************** +\ utility that shows total capacity on screen by use of the return data +\ from read-capacity calculation is SI conform (base 10) +\ *************************************************************************** +\ sub function to print a 3 digit decimal +\ number with 2 post decimal positions xxx.yy +: .dec3-2 ( prenum postnum -- ) + swap + base @ >r \ save actual base setting + decimal \ show decimal values + 4 .r 2e emit + dup 9 <= IF 30 emit THEN .d \ 3 pre-decimal, right aligned + r> base ! \ restore base +; + +: .capacity-text ( block-size #blocks -- ) + scsi-param-debug \ debugging flag set ? + IF \ show additional info + 2dup + cr + ." LBAs: " .d \ highest logical block number + ." / Block-Size: " .d + ." / Total Capacity: " + THEN + * \ calculate total capacity + dup d# 1000000000000 >= \ check terabyte limit + IF + d# 1000000000000 /mod + swap + d# 10000000000 / \ limit remainder to two digits + .dec3-2 ." TB" \ show terabytes as xxx.yy + ELSE + dup d# 1000000000 >= \ check gigabyte limit + IF + d# 1000000000 /mod + swap + d# 10000000 / + .dec3-2 ." GB" \ show gigabytes as xxx.yy + ELSE + dup d# 1000000 >= + IF + d# 1000000 /mod \ check mega byte limit + swap + d# 10000 / + .dec3-2 ." MB" \ show megabytes as xxx.yy + ELSE + dup d# 1000 >= \ check kilo byte limit + IF + d# 1000 /mod + swap + d# 10 / + .dec3-2 ." kB" + ELSE + .d ." Bytes" + THEN + THEN + THEN + THEN +; + +\ *************************************************************************** +\ SCSI-Utility: .inquiry-text ( addr -- ) +\ *************************************************************************** +\ utility that shows: +\ vendor-ident product-ident and revision +\ from an inquiry return data block (addr) +\ *************************************************************************** +: .inquiry-text ( addr -- ) + 22 emit \ enclose text with " + dup inquiry-data>vendor-ident 8 type space + dup inquiry-data>product-ident 10 type space + inquiry-data>product-revision 4 type + 22 emit +; + +\ *************************************************************************** +\ SCSI-Utility: scsi-supp-init ( -- ) +\ *************************************************************************** +\ utility that helps to ensure that parameters are set to valid values +: scsi-supp-init ( -- ) + false to scsi-param-debug \ no debug strings + h# 0 to scsi-param-size + h# 0 to scsi-param-control \ common CDB control byte + d# 0 to scsi-param-errors \ local errors (param limits) +; + +\ *************************************************************************** +\ Constants used by SCSI controller's execute-scsi-command +\ *************************************************************************** +true CONSTANT scsi-dir-read +false CONSTANT scsi-dir-write + + +\ *************************************************************************** +\ scsi loader +\ *************************************************************************** +0 VALUE scsi-context \ addr of word list on top + + +\ **************************************************************************** +\ open scsi-support by adding a new word list on top of search path +\ precondition: scsi-support.fs must have been included +\ **************************************************************************** +: scsi-init ( -- ) + also scsi-words \ append scsi word-list + context to scsi-context \ save for close process + scsi-supp-init \ preset all scsi-param-xxx values + scsi-param-debug + IF + space ." SCSI-SUPPORT OPENED" cr + .wordlists + THEN +; + +\ **************************************************************************** +\ close scsi-session and remove scsi word list (if exists) +\ **************************************************************************** +\ if 'previous' is used without a preceding 'also' all forth words are lost ! +\ **************************************************************************** +: scsi-close ( -- ) +\ FIXME This only works if scsi-words is the last vocabulary on the stack +\ Instead we could use get-order to find us on the "wordlist stack", +\ remove us and write the wordlist stack back with set-order. +\ BUT: Is this worth the effort? + + scsi-param-debug + IF + space ." Closing SCSI-SUPPORT .. " cr + THEN + context scsi-context = \ scsi word list still active ? + IF + scsi-param-errors 0<> \ any errors occurred ? + IF + cr ." ** WARNING: " scsi-param-errors .d + ." SCSI Errors occurred ** " cr + THEN + previous \ remove scsi word list on top + 0 to scsi-context \ prevent from being misinterpreted + ELSE + cr ." ** WARNING: Trying to close non-open SCSI-SUPPORT (1) ** " cr + THEN + scsi-param-debug + IF + .wordlists + THEN +; + + +s" scsi-init" $find drop \ return execution pointer, when included + +previous \ remove scsi word list from search path +definitions \ place next definitions into previous list + diff --git a/qemu/roms/SLOF/slof/fs/search.fs b/qemu/roms/SLOF/slof/fs/search.fs new file mode 100644 index 000000000..3acca2f11 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/search.fs @@ -0,0 +1,89 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +\ +\ Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +\ + + +\ stuff we should already have: + +: linked ( var -- ) here over @ , swap ! ; + +HEX + +\ \ \ +\ \ \ Wordlists +\ \ \ + +VARIABLE wordlists forth-wordlist wordlists ! + +\ create a new wordlist +: wordlist ( -- wid ) here wordlists linked 0 , ; + + +\ \ \ +\ \ \ Search order +\ \ \ + +10 CONSTANT max-in-search-order \ should define elsewhere +\ CREATE search-order max-in-search-order cells allot \ stack of wids \ is in engine now +\ search-order VALUE context \ top of stack \ is in engine now + +: also ( -- ) clean-hash context dup cell+ dup to context >r @ r> ! ; +: previous ( -- ) clean-hash context cell- to context ; +: only ( -- ) clean-hash search-order to context ( minimal-wordlist search-order ! ) ; +: seal ( -- ) clean-hash context @ search-order dup to context ! ; + +: get-order ( -- wid_n .. wid_1 n ) + context >r search-order BEGIN dup r@ u<= WHILE + dup @ swap cell+ REPEAT r> drop + search-order - cell / ; +: set-order ( wid_n .. wid_1 n -- ) \ XXX: special cases for 0, -1 + clean-hash 1- cells search-order + dup to context + BEGIN dup search-order u>= WHILE + dup >r ! r> cell- REPEAT drop ; + + +\ \ \ +\ \ \ Compilation wordlist +\ \ \ + +: get-current ( -- wid ) current ; +: set-current ( wid -- ) to current ; + +: definitions ( -- ) context @ set-current ; + + +\ \ \ +\ \ \ Vocabularies +\ \ \ + +: VOCABULARY ( C: "name" -- ) ( -- ) CREATE wordlist drop DOES> clean-hash context ! ; +\ : VOCABULARY ( C: "name" -- ) ( -- ) wordlist CREATE , DOES> @ context ! ; +\ XXX we'd like to swap forth and forth-wordlist around (for .voc 's sake) +: FORTH ( -- ) clean-hash forth-wordlist context ! ; + +: .voc ( wid -- ) \ display name for wid \ needs work ( body> or something like that ) + dup cell- @ ['] vocabulary ['] forth within IF + 2 cells - >name name>string type ELSE u. THEN space ; +: vocs ( -- ) \ display all wordlist names + cr wordlists BEGIN @ dup WHILE dup .voc REPEAT drop ; +: order ( -- ) + cr ." context: " get-order 0 ?DO .voc LOOP + cr ." current: " get-current .voc ; + + + + +\ some handy helper +: voc-find ( wid -- 0 | link ) + clean-hash cell+ @ (find) clean-hash ; diff --git a/qemu/roms/SLOF/slof/fs/slof-logo.fs b/qemu/roms/SLOF/slof/fs/slof-logo.fs new file mode 100644 index 000000000..53d318447 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/slof-logo.fs @@ -0,0 +1,20 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: .slof-logo + cr ." ..`. .. ....... .. ...... ......." + cr ." ..`...`''.`'. .''``````..''. .`''```''`. `''``````" + cr ." .`` .:' ': `''..... .''. ''` .''..''......." + cr ." ``.':.';. ``````''`.''. .''. ''``''`````'`" + cr ." ``.':':` .....`''.`'`...... `'`.....`''.`'` " + cr ." .`.`'`` .'`'`````. ``'''''' ``''`'''`. `'` " +; diff --git a/qemu/roms/SLOF/slof/fs/sms/sms-load.fs b/qemu/roms/SLOF/slof/fs/sms/sms-load.fs new file mode 100644 index 000000000..8e4db8060 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/sms/sms-load.fs @@ -0,0 +1,70 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +false VALUE (sms-loaded?) + +false value (sms-available?) + +s" sms.fs" romfs-lookup IF true to (sms-available?) drop THEN + +(sms-available?) [IF] + +#include "packages/sms.fs" + +\ Initialize SMS NVRAM handling. +#include "sms-nvram.fs" + +\ Dynamically load sms code from the romfs file +\ Assumption is that skeleton sms package already exists +\ but aside of open & close, all other methods are in a romfs file (sms.fs) +\ Here we open the package and load the rest of the functionality + +\ After that, one needs to find-device and execute sms-start method +\ The shorthand for that is given as (global) sms-start word + +: $sms-node s" /packages/sms" ; + +: (sms-init-package) ( -- true|false ) + (sms-loaded?) ?dup IF EXIT THEN + $sms-node ['] find-device catch IF 2drop false EXIT THEN + s" sms.fs" [COMPILE] included + device-end + true dup to (sms-loaded?) +; + +\ External wrapper for sms package method +: (sms-evaluate) ( addr len -- ) + (sms-init-package) not IF + cr ." SMS is not available." cr 2drop exit + THEN + + s" Entering SMS ..." type + disable-watchdog + reset-dual-emit + + \ if we only had execute-device-method... + 2>r $sms-node find-device + 2r> evaluate + device-end + vpd-boot-import +; + +: sms-start ( -- ) s" sms-start" (sms-evaluate) ; +: sms-fru-replacement ( -- ) s" sms-fru-replacement" (sms-evaluate) ; + +[ELSE] + +: sms-start ( -- ) cr ." SMS is not available." cr ; +: sms-fru-replacement ( -- ) cr ." SMS FRU replacement is not available." cr ; + +[THEN] + diff --git a/qemu/roms/SLOF/slof/fs/sms/sms-nvram.fs b/qemu/roms/SLOF/slof/fs/sms/sms-nvram.fs new file mode 100644 index 000000000..4f5d6ddd5 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/sms/sms-nvram.fs @@ -0,0 +1,124 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Initialize SMS NVRAM handling. + +: sms-init-nvram ( -- ) + nvram-partition-type-sms get-nvram-partition IF + cr ." Could not find SMS partition in NVRAM - " + nvram-partition-type-sms s" SMS" d# 1024 new-nvram-partition + ABORT" Failed to create SMS NVRAM partition" + 2dup erase-nvram-partition drop + + 2dup s" lang" s" 1" internal-set-env drop + + 2dup s" tftp-retries" s" 5" internal-set-env drop + 2dup s" tftp-blocksize" s" 512" internal-set-env drop + 2dup s" bootp-retries" s" 255" internal-set-env drop + 2dup s" client" s" 000.000.000.000" internal-set-env drop + 2dup s" server" s" 000.000.000.000" internal-set-env drop + 2dup s" gateway" s" 000.000.000.000" internal-set-env drop + 2dup s" netmask" s" 255.255.255.000" internal-set-env drop + 2dup s" net-protocol" s" 0" internal-set-env drop + 2dup s" net-flags" s" 0" internal-set-env drop + 2dup s" net-device" s" 0" internal-set-env drop + 2dup s" net-client-name" s" " internal-set-env drop + + 2dup s" scsi-spinup" s" 6" internal-set-env drop + 2dup s" scsi-id-0" s" 7" internal-set-env drop + 2dup s" scsi-id-1" s" 7" internal-set-env drop + 2dup s" scsi-id-2" s" 7" internal-set-env drop + 2dup s" scsi-id-3" s" 7" internal-set-env drop + ." created" cr + THEN + s" sms-nvram-partition" $2constant +; + +sms-init-nvram + +: sms-add-env ( "name" "value" -- ) sms-nvram-partition 2rot 2rot internal-add-env drop ; +: sms-set-env ( "name" "value" -- ) sms-nvram-partition 2rot 2rot internal-set-env drop ; +: sms-get-env ( "name" -- "value" TRUE | FALSE) sms-nvram-partition 2swap internal-get-env ; + +: sms-get-net-device ( -- n ) s" net-device" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ; +: sms-set-net-device ( n -- ) (.d) s" net-device" 2swap sms-set-env ; + +: sms-get-net-flags ( -- n ) s" net-flags" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ; +: sms-set-net-flags ( n -- ) (.d) s" net-flags" 2swap sms-set-env ; + +: sms-get-net-protocol ( -- n ) s" net-protocol" sms-get-env IF $dnumber IF 0 THEN ELSE 0 THEN ; +: sms-set-net-protocol ( n -- ) (.d) s" net-protocol" 2swap sms-set-env ; + +: sms-get-lang ( -- n ) s" lang" sms-get-env IF $dnumber IF 1 THEN ELSE 1 THEN ; +: sms-set-lang ( n -- ) (.d) s" lang" 2swap sms-set-env ; + +: sms-get-bootp-retries ( -- n ) s" bootp-retries" sms-get-env IF $dnumber IF 255 THEN ELSE 255 THEN ; +: sms-set-bootp-retries ( n -- ) (.d) s" bootp-retries" 2swap sms-set-env ; + +: sms-get-tftp-retries ( -- n ) s" tftp-retries" sms-get-env IF $dnumber IF 5 THEN ELSE 5 THEN ; +: sms-set-tftp-retries ( n -- ) (.d) s" tftp-retries" 2swap sms-set-env ; + +: sms-get-tftp-blocksize ( -- n ) s" tftp-blocksize" sms-get-env IF $dnumber IF 5 THEN ELSE 5 THEN ; +: sms-set-tftp-blocksize ( n -- ) (.d) s" tftp-blocksize" 2swap sms-set-env ; + +: sms-get-client ( -- FALSE | n1 n2 n3 n4 TRUE ) s" client" sms-get-env IF (ipaddr) ELSE false THEN ; +: sms-set-client ( n1 n2 n3 n4 -- ) (ipformat) s" client" 2swap sms-set-env ; + +: sms-get-server ( -- FALSE | n1 n2 n3 n4 TRUE ) s" server" sms-get-env IF (ipaddr) ELSE false THEN ; +: sms-set-server ( n1 n2 n3 n4 -- ) (ipformat) s" server" 2swap sms-set-env ; + +: sms-get-gateway ( -- FALSE | n1 n2 n3 n4 TRUE ) s" gateway" sms-get-env IF (ipaddr) ELSE false THEN ; +: sms-set-gateway ( n1 n2 n3 n4 -- ) (ipformat) s" gateway" 2swap sms-set-env ; + +: sms-get-subnet ( -- FALSE | n1 n2 n3 n4 TRUE ) s" netmask" sms-get-env IF (ipaddr) ELSE false THEN ; +: sms-set-subnet ( n1 n2 n3 n4 -- ) (ipformat) s" netmask" 2swap sms-set-env ; + +: sms-get-client-name ( -- FALSE | addr len TRUE ) s" net-client-name" sms-get-env ; +: sms-set-client-name ( addr len -- ) s" net-client-name" 2swap sms-set-env ; + +: sms-get-scsi-spinup ( -- n ) s" scsi-spinup" sms-get-env IF $dnumber IF 6 THEN ELSE 6 THEN ; +: sms-set-scsi-spinup ( n -- ) (.d) s" scsi-spinup" 2swap sms-set-env ; + +: sms-get-scsi-id ( n -- id ) s" scsi-id-" rot (.) $cat sms-get-env IF $dnumber IF 6 THEN ELSE 6 THEN ; +: sms-set-scsi-id ( id n -- ) swap (.d) rot s" scsi-id-" rot (.) $cat sms-set-env ; + + +\ generates the boot-file part of the boot string + +: sms-get-net-boot-file ( -- addr len ) + \ the format is + \ :[bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries + \ we choose dhcp as a default! + s" net" sms-get-net-device (.) $cat + s" :dhcp," $cat + sms-get-server IF (ipformat) $cat THEN + s" ," $cat + sms-get-client-name IF $cat THEN + s" ," $cat + sms-get-client IF (ipformat) $cat THEN + s" ," $cat + sms-get-gateway IF (ipformat) $cat THEN + s" ," $cat + \ If the number of retries is 255 (max), assume default timeout (10min) + sms-get-bootp-retries dup ff <> IF (.) $cat ELSE drop THEN + s" ," $cat + sms-get-tftp-retries (.) $cat + \ now write the string to the boot path + dup IF + \ This could be considered a memory leak, but it is only + \ executed once for booting so it is not a problem + strdup ( s" :" 2swap $cat strdup ) + THEN +; + +' sms-get-net-boot-file to furnish-boot-file + diff --git a/qemu/roms/SLOF/slof/fs/stack.fs b/qemu/roms/SLOF/slof/fs/stack.fs new file mode 100644 index 000000000..0f7e097bf --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/stack.fs @@ -0,0 +1,57 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ Example: +\ +\ To get a 30 element stack, go: +\ +\ 0 > 30 new-stack my-stack +\ 0 > my-stack +\ 0 > 20 push 30 push +\ 0 > pop pop .s + +0 value current-stack + +: new-stack ( cells <>name -- ) + create >r here ( here R: cells ) + dup r@ 2 + cells ( here here bytes R: cells ) + dup allot erase ( here R: cells) + cell+ r> ( here+1cell cells ) + swap ! ( ) + DOES> to current-stack +; + +: reset-stack ( -- ) + 0 current-stack ! +; + +: stack-depth ( -- depth ) + current-stack @ +; + +: push ( value -- ) + current-stack @ + current-stack cell+ @ over <= ABORT" Stack overflow" + cells + 1 current-stack +! + current-stack 2 cells + + ! +; + +: pop ( -- value ) + current-stack @ 0= ABORT" Stack underflow" + current-stack @ cells + current-stack + cell+ @ + -1 current-stack +! +; + + diff --git a/qemu/roms/SLOF/slof/fs/start-up.fs b/qemu/roms/SLOF/slof/fs/start-up.fs new file mode 100644 index 000000000..f1488fa38 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/start-up.fs @@ -0,0 +1,171 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: (boot) ( -- ) + s" Executing following boot-command: " + boot-command $cat nvramlog-write-string-cr + s" boot-command" evaluate \ get boot command + ['] evaluate catch ?dup IF \ and execute it + ." boot attempt returned: " + abort"-str @ count type cr + nip nip \ drop string from 1st evaluate + throw + THEN +; + +\ Note: The following ESC sequences has to be handled: +\ 1B 4F 50 +\ 1B 5B 31 31 7E + +\ Reads and converts the function key. +\ key = F1 -- n = 1 +: (function-key) ( -- n ) + key? IF + key CASE + 50 OF 1 ENDOF + 7e OF 1 ENDOF + dup OF 0 ENDOF + ENDCASE + THEN +; + +\ Checks if an ESC sequence occurs. +: (esc-sequence) ( -- n ) + key? IF + key CASE + 4f OF (function-key) ENDOF + 5b OF + key key (function-key) ENDOF + dup OF 0 ENDOF + ENDCASE + THEN +; + +: (s-pressed) ( -- ) + s" An 's' has been pressed. Entering Open Firmware Prompt" + nvramlog-write-string-cr +; + +: (boot?) ( -- ) + of-prompt? not auto-boot? and IF + (boot) + THEN +; + + +#include "sms/sms-load.fs" + + +\ Watchdog will be rearmed during load if use-load-watchdog variable is TRUE +TRUE VALUE use-load-watchdog? + +1 value my-boot-dev +1 value digit-val +0 value boot-dev-no + +: boot-selected + 1 to my-boot-dev + BEGIN parse-word dup WHILE + boot-dev-no my-boot-dev = IF + s" boot " 2swap $cat + ['] evaluate catch ?dup IF \ and execute it + ." boot attempt returned: " + abort"-str @ count type cr + throw + THEN + 0 0 load-list 2! + UNLOOP EXIT + ELSE + 2drop + THEN + my-boot-dev 1 + to my-boot-dev + REPEAT 2drop 0 0 load-list 2! + + (boot) +; + +: boot-start + \ Remove multiple F12 key presses if any + BEGIN key? WHILE + key drop + REPEAT + + decimal + BEGIN parse-word dup WHILE + my-boot-dev (u.) s" . " $cat type 2dup type ." : " de-alias type cr + my-boot-dev 1 + to my-boot-dev + REPEAT 2drop 0 0 load-list 2! + + cr BEGIN KEY dup emit + dup isdigit IF + dup 30 - to digit-val + boot-dev-no a * digit-val + to boot-dev-no + THEN + d = UNTIL + + boot-dev-no my-boot-dev < IF + s" boot-selected " s" $bootdev" evaluate $cat strdup evaluate + ELSE + ." Invalid choice!" cr + THEN + hex +; + +: boot-menu-start + ." Select boot device:" cr cr + s" boot-start " s" $bootdev" evaluate $cat strdup evaluate +; + +: boot-menu-enabled? ( -- true|false ) + s" qemu,boot-menu" get-chosen IF + decode-int 1 = IF + 2drop TRUE EXIT + THEN + 2drop + THEN + FALSE +; + +: f12-pressed? + 34 = >r 32 = r> and IF + TRUE + ELSE + FALSE + THEN +; + +: start-it ( -- ) + key? IF + key CASE + [char] s OF (s-pressed) ENDOF + 1b OF + (esc-sequence) CASE + 1 OF + console-clean-fifo + f12-pressed? boot-menu-enabled? and IF + boot-menu-start + ELSE + (boot?) + THEN + ENDOF + dup OF (boot?) ENDOF + ENDCASE + ENDOF + dup OF (boot?) ENDOF + ENDCASE + ELSE + (boot?) + THEN + + disable-watchdog FALSE to use-load-watchdog? + .banner +; diff --git a/qemu/roms/SLOF/slof/fs/term-io.fs b/qemu/roms/SLOF/slof/fs/term-io.fs new file mode 100644 index 000000000..52ce12a5b --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/term-io.fs @@ -0,0 +1,97 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +: input ( dev-str dev-len -- ) + open-dev ?dup IF + \ Close old stdin: + s" stdin" get-chosen IF + decode-int nip nip ?dup IF close-dev THEN + THEN + \ Now set the new stdin: + encode-int s" stdin" set-chosen + THEN +; + +: output ( dev-str dev-len -- ) + open-dev ?dup IF + \ Close old stdout: + s" stdout" get-chosen IF + decode-int nip nip ?dup IF close-dev THEN + THEN + \ Now set the new stdout: + encode-int s" stdout" set-chosen + THEN +; + +: io ( dev-str dev-len -- ) + 2dup input output +; + + +1 BUFFER: (term-io-char-buf) + +: term-io-key ( -- char ) + s" stdin" get-chosen IF + decode-int nip nip dup 0= IF 0 EXIT THEN + >r BEGIN + (term-io-char-buf) 1 s" read" r@ $call-method + 0 > + UNTIL + (term-io-char-buf) c@ + r> drop + ELSE + [ ' key behavior compile, ] + THEN +; + +' term-io-key to key + +\ this word will check what the current chosen input device is: +\ - if it is a serial device, it will use serial-key? to check for available input +\ - if it is a keyboard, it will check if the "key-available?" method is implemented (i.e. for usb-keyboard) and use that +\ - if it's an hv console, use hvterm-key? +\ otherwise it will always return false +: term-io-key? ( -- true|false ) + s" stdin" get-chosen IF + decode-int nip nip dup 0= IF drop 0 EXIT THEN \ return false and exit if no stdin set + >r \ store ihandle on return stack + s" device_type" r@ ihandle>phandle ( propstr len phandle ) + get-property ( true | data dlen false ) + IF + \ device_type not found, return false and exit + false + ELSE + 1 - \ remove 1 from length to ignore null-termination char + \ device_type found, check wether it is serial or keyboard + 2dup s" serial" str= IF + 2drop serial-key? r> drop EXIT + THEN \ call serial-key, cleanup return-stack, exit + 2dup s" keyboard" str= IF + 2drop ( ) + \ keyboard found, check for key-available? method, execute it or return false + s" key-available?" r@ ihandle>phandle find-method IF + drop s" key-available?" r@ $call-method + ELSE + false + THEN + r> drop EXIT \ cleanup return-stack, exit + THEN + 2drop r> drop false EXIT \ unknown device_type cleanup return-stack, return false + THEN + ELSE + \ stdin not set, return false + false + THEN +; + +' term-io-key? to key? diff --git a/qemu/roms/SLOF/slof/fs/terminal.fs b/qemu/roms/SLOF/slof/fs/terminal.fs new file mode 100644 index 000000000..582bedeb3 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/terminal.fs @@ -0,0 +1,212 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ \\\\\\\\\\\\\\ Global Data + +0 VALUE line# +0 VALUE column# +false VALUE inverse? +false VALUE inverse-screen? +18 VALUE #lines +50 VALUE #columns + +false VALUE cursor +false VALUE saved-cursor + + +\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods + +defer draw-character \ 2B inited by display driver +defer reset-screen \ 2B inited by display driver +defer toggle-cursor \ 2B inited by display driver +defer erase-screen \ 2B inited by display driver +defer blink-screen \ 2B inited by display driver +defer invert-screen \ 2B inited by display driver +defer insert-characters \ 2B inited by display driver +defer delete-characters \ 2B inited by display driver +defer insert-lines \ 2B inited by display driver +defer delete-lines \ 2B inited by display driver +defer draw-logo \ 2B inited by display driver + +: nop-toggle-cursor ( nop ) ; +' nop-toggle-cursor to toggle-cursor + +\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous) +\ * +\ * +: (cursor-off) ( -- ) cursor dup to saved-cursor + IF toggle-cursor false to cursor THEN ; +: (cursor-on) ( -- ) cursor dup to saved-cursor + 0= IF toggle-cursor true to cursor THEN ; +: restore-cursor ( -- ) saved-cursor dup cursor + <> IF toggle-cursor to cursor ELSE drop THEN ; + +' (cursor-off) to cursor-off +' (cursor-on) to cursor-on + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ Generic device methods: +\ * + + +\ \\\\\\\\\\\\\\ Exported Interface: +\ * +\ * + +false VALUE esc-on +false VALUE csi-on +defer esc-process +0 VALUE esc-num-parm +0 VALUE esc-num-parm2 +0 VALUE saved-line# +0 VALUE saved-column# + +: get-esc-parm ( default -- value ) + esc-num-parm dup 0> IF nip ELSE drop THEN 0 to esc-num-parm ; +: get-esc-parm2 ( default -- value ) + esc-num-parm2 dup 0> IF nip ELSE drop THEN 0 to esc-num-parm2 ; +: set-esc-parm ( newdigit -- ) [char] 0 - esc-num-parm a * + to esc-num-parm ; + +: reverse-cursor ( oldpos -- newpos) dup IF 1 get-esc-parm - THEN ; +: advance-cursor ( bound oldpos -- newpos) tuck > IF 1 get-esc-parm + THEN ; +: erase-in-line #columns column# - dup 0> IF delete-characters ELSE drop THEN ; + +: terminal-line++ ( -- ) + line# 1+ dup #lines = IF 1- 0 to line# 1 delete-lines THEN + to line# +; + +0 VALUE dang +0 VALUE blipp +false VALUE stopcsi +0 VALUE term-background +7 VALUE term-foreground + +: set-term-color + dup d# 30 d# 39 between IF dup d# 30 - to term-foreground THEN + dup d# 40 d# 49 between IF dup d# 40 - to term-background THEN + 0 = IF + 0 to term-background + 7 to term-foreground + THEN + term-foreground term-background <= to inverse? +; + +: ansi-esc ( char -- ) + csi-on IF + dup [char] 0 [char] 9 between IF set-esc-parm + ELSE true to stopcsi CASE + [char] A OF line# reverse-cursor to line# ENDOF + [char] B OF #lines line# advance-cursor to line# ENDOF + [char] C OF #columns column# advance-cursor to column# ENDOF + [char] D OF column# reverse-cursor to column# ENDOF + [char] E OF ( FIXME: Cursor Next Line - No idea what does it mean ) + #lines line# advance-cursor to line# + ENDOF + [char] f OF + 1 get-esc-parm2 to line# column# get-esc-parm to column# + ENDOF + [char] H OF + 1 get-esc-parm2 to line# column# get-esc-parm to column# + ENDOF + ( second parameter delimiter for f and H commands ) + [char] ; OF false to stopcsi 0 get-esc-parm to esc-num-parm2 ENDOF + [char] ? OF false to stopcsi ENDOF ( FIXME: Ignore that for now ) + [char] l OF ENDOF ( FIXME: ?25l should hide cursor ) + [char] h OF ENDOF ( FIXME: ?25h should show cursor ) + [char] J OF + #lines line# - dup 0> IF + line# 1+ to line# delete-lines line# 1- to line# + ELSE drop THEN + erase-in-line + ENDOF + [char] K OF erase-in-line ENDOF + [char] L OF 1 get-esc-parm insert-lines ENDOF + [char] M OF 1 get-esc-parm delete-lines ENDOF + [char] @ OF 1 get-esc-parm insert-characters ENDOF + [char] P OF 1 get-esc-parm delete-characters ENDOF + [char] m OF 0 get-esc-parm set-term-color ENDOF + ( These are non-ANSI commands recommended by OpenBoot ) + [char] p OF inverse-screen? IF false to inverse-screen? + inverse? 0= to inverse? invert-screen + THEN + ENDOF + [char] q OF inverse-screen? 0= IF true to inverse-screen? + inverse? 0= to inverse? invert-screen + THEN + ENDOF +\ [char] s OF reset-screen ENDOF ( FIXME: this conflicts w. ANSI ) +\ [char] s OF line# to saved-line# column# to saved-column# ENDOF + [char] u OF saved-line# to line# saved-column# to column# ENDOF + dup dup to dang OF blink-screen ENDOF + ENDCASE stopcsi IF false to csi-on + false to esc-on 0 to esc-num-parm 0 to esc-num-parm2 THEN + THEN + ELSE CASE + ( DEV VT compatibility stuff used by accept.fs ) + [char] 7 OF line# to saved-line# column# to saved-column# ENDOF + [char] 8 OF saved-line# to line# saved-column# to column# ENDOF + [char] [ OF true to csi-on ENDOF + dup dup OF false to esc-on to blipp ENDOF + ENDCASE + csi-on 0= IF false to esc-on THEN 0 to esc-num-parm 0 to esc-num-parm2 + THEN +; + +' ansi-esc to esc-process +CREATE twtracebuf 4000 allot twtracebuf 4000 erase +twtracebuf VALUE twbp +0 VALUE twbc + +: twtrace + twbc 4000 = IF 0 to twbc twtracebuf to twbp THEN + dup twbp c! twbp 1+ to twbp twbc 1+ to twbc +; + +: terminal-write ( addr len -- actual-len ) + cursor-off + tuck bounds ?DO i c@ + twtrace + esc-on IF esc-process + ELSE CASE + 1B OF true to esc-on ENDOF + carret OF 0 to column# ENDOF + linefeed OF terminal-line++ ENDOF + bell OF blink-screen ENDOF + 9 ( TAB ) OF column# 7 + -8 and dup #columns < IF + to column# + ELSE drop THEN + ENDOF + B ( VT ) OF line# ?dup IF 1- to line# THEN ENDOF + C ( FF ) OF 0 to line# 0 to column# erase-screen ENDOF + bs OF column# 1- dup 0< IF + line# IF + line# 1- to line# + drop #columns 1- + ELSE drop column# + THEN + THEN + to column# ( bl draw-character ) + ENDOF + dup OF + i c@ draw-character + column# 1+ dup #columns >= IF + drop 0 terminal-line++ + THEN + to column# + ENDOF + ENDCASE + THEN + LOOP + restore-cursor +; diff --git a/qemu/roms/SLOF/slof/fs/timebase.fs b/qemu/roms/SLOF/slof/fs/timebase.fs new file mode 100644 index 000000000..00a0bd203 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/timebase.fs @@ -0,0 +1,24 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +\ Define all timebase related words + +: tb@ ( -- tb ) + BEGIN tbu@ tbl@ tbu@ rot over <> WHILE 2drop REPEAT + 20 lshift swap ffffffff and or +; + +: milliseconds ( -- ms ) tb@ d# 1000 * tb-frequency / ; +: microseconds ( -- us ) tb@ d# 1000000 * tb-frequency / ; + +: ms ( ms-to-wait -- ) milliseconds + BEGIN milliseconds over >= UNTIL drop ; +: get-msecs ( -- n ) milliseconds ; +: us ( us-to-wait -- ) microseconds + BEGIN microseconds over >= UNTIL drop ; diff --git a/qemu/roms/SLOF/slof/fs/translate.fs b/qemu/roms/SLOF/slof/fs/translate.fs new file mode 100644 index 000000000..9654f242f --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/translate.fs @@ -0,0 +1,150 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ this is a C-to-Forth translation from the translate +\ address code in the client +\ with extensions to handle different sizes of #size-cells + +\ this tries to figure out if it is a PCI device what kind of +\ translation is wanted +\ if prop_type is 0, "reg" property is used, otherwise "assigned-addresses" +: pci-address-type ( node address prop_type -- type ) + -rot 2 pick ( prop_type node address prop_type ) + 0= IF + swap s" reg" rot get-property ( prop_type address data dlen false ) + ELSE + swap s" assigned-addresses" rot get-property ( prop_type address data dlen false ) + THEN + IF 2drop -1 EXIT THEN 4 / 5 / + \ advance (phys-addr(3) size(2)) steps + 0 DO + \ BARs and Expansion ROM must be in assigned-addresses... + \ so if prop_type is 0 ("reg") and a config space offset is set + \ we skip this entry... + dup l@ FF AND 0<> ( prop_type address data cfgspace_offset? ) + 3 pick 0= ( prop_type address data cfgspace_offset? reg_prop? ) + AND NOT IF + 2dup 4 + ( prop_type address data address data' ) + 2dup @ 2 pick 8 + @ + <= -rot @ >= and IF + l@ 03000000 and 18 rshift nip + ( prop_type type ) + swap drop ( type ) + UNLOOP EXIT + THEN + THEN + \ advance in 4 byte steps and (phys-addr(3) size(2)) steps + 4 5 * + + LOOP + 3drop -1 +; + +: (range-read-cells) ( range-addr #cells -- range-value ) + \ if number of cells != 1; do 64bit read; else a 32bit read + 1 = IF l@ ELSE @ THEN +; + +\ this functions tries to find a mapping for the given address +\ it assumes that if we have #address-cells == 3 that we are trying +\ to do a PCI translation + +\ nac - #address-cells +\ nsc - #size-cells +\ pnac - parent #address-cells + +: (map-one-range) ( type range pnac nsc nac address -- address true | address false ) + \ only check for the type if nac == 3 (PCI) + over 3 = 5 pick l@ 3000000 and 18 rshift 7 pick <> and IF + >r 2drop 3drop r> false EXIT + THEN + \ get size + 4 pick 4 pick 3 pick + 4 * + + \ get nsc + 3 pick + \ read size + ( type range pnac nsc nac address range nsc ) + (range-read-cells) + ( type range pnac nsc nac address size ) + \ skip type if PCI + 5 pick 3 pick 3 = IF + 4 + + THEN + \ get nac + 3 pick + ( type range pnac nsc nac address size range nac ) + \ read child-mapping + (range-read-cells) + ( type range pnac nsc nac address size child-mapping ) + dup >r dup 3 pick > >r + over <= r> or IF + \ address is not inside the mapping range + >r 2drop 3drop r> r> drop false EXIT + THEN + dup r> - + ( type range pnac nsc nac address offset ) + \ add the offset on the parent mapping + 5 pick 5 pick 3 = IF + \ skip type if PCI + 4 + + THEN + 3 pick 4 * + + ( type range pnac nsc nac address offset parent-mapping-address ) + \ get pnac + 5 pick + \ read parent mapping + (range-read-cells) + ( type range pnac nsc nac address offset parent-mapping ) + + >r 3drop 3drop r> true +; + +\ this word translates the given address starting from the node specified +\ in node; the word will return to the node it was started from +: translate-address ( node address -- address ) + \ check for address type in "assigned-addresses" + 2dup 1 pci-address-type ( node address type ) + dup -1 = IF + \ not found in "assigned-addresses", check in "reg" + drop 2dup 0 pci-address-type ( node address type ) + THEN + rot parent BEGIN + \ check if it is the root node + dup parent 0= IF 2drop EXIT THEN + ( address type parent ) + s" #address-cells" 2 pick get-property 2drop l@ >r \ nac + s" #size-cells" 2 pick get-property 2drop l@ >r \ nsc + s" #address-cells" 2 pick parent get-property 2drop l@ >r \ pnac + -rot ( node address type ) + s" ranges" 4 pick get-property IF + 3drop + ABORT" no ranges property; not translatable" + THEN + r> r> r> 3 roll + ( node address type ranges pnac nsc nac length ) + 4 / >r 3dup + + >r 5 roll r> r> swap / 0 ?DO + ( node type ranges pnac nsc nac address ) + 6dup (map-one-range) IF + nip leave + THEN + nip + \ advance ranges + 4 roll + ( node type pnac nsc nac address ranges ) + 4 pick 4 pick 4 pick + + 4 * + 4 -roll + LOOP + >r 2drop 2drop r> ( node type address ) + swap rot parent ( address type node ) + dup 0= + UNTIL +; + +\ this words translates the given address starting from the current node +: translate-my-address ( address -- address' ) + get-node swap translate-address +; diff --git a/qemu/roms/SLOF/slof/fs/update_flash.fs b/qemu/roms/SLOF/slof/fs/update_flash.fs new file mode 100644 index 000000000..e04869d77 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/update_flash.fs @@ -0,0 +1,110 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Set by update-flash -f to true, preventing update-flash -c +false value flash-new + +: update-flash-help ( -- ) + cr ." update-flash tool to flash host FW " cr + ." -f <filename> : Flash from file (e.g. net:\boot_rom.bin)" cr + ." -l : Flash from load-base" cr + ." -d : Flash from old load base (used by drone)" cr + ." -c : Flash from temp to perm" cr + ." -r : Flash from perm to temp" cr +; + +: flash-read-temp ( -- success? ) + get-flashside 1 = IF flash-addr get-load-base over flash-image-size rmove true + ELSE + false + THEN +; + +: flash-read-perm ( -- success? ) + get-flashside 0= IF + flash-addr get-load-base over flash-image-size rmove true + ELSE + false + THEN +; + +: flash-switch-side ( side -- success? ) + set-flashside 0<> IF + s" Cannot change flashside" type cr false + ELSE + true + THEN +; + +: flash-ensure-temp ( -- success? ) + get-flashside 0= IF + cr ." Cannot flash perm! Switching to temp side!" + 1 flash-switch-side + ELSE + true + THEN +; + +\ update-flash -f <filename> +\ -l +\ -c +\ -r + +: update-flash ( "text" ) + get-flashside >r \ Save old flashside + parse-word ( str len ) \ Parse first string + drop dup c@ ( str first-char ) + [char] - <> IF + update-flash-help r> 2drop EXIT + THEN + + 1+ c@ ( second-char ) + CASE + [char] f OF + parse-word cr s" do-load" evaluate + flash-ensure-temp TO flash-new + ENDOF + [char] l OF + flash-ensure-temp + ENDOF + [char] d OF + flash-load-base get-load-base 200000 move + flash-ensure-temp + ENDOF + [char] c OF + flash-read-temp 0= flash-new or IF + ." Cannot commit temp, need to boot on temp first " cr false + ELSE + 0 flash-switch-side + THEN + ENDOF + [char] r OF + flash-read-perm 0= IF + ." Cannot commit perm, need to boot on perm first " cr false + ELSE + 1 flash-switch-side + THEN + ENDOF + dup OF + false + ENDOF + ENDCASE + + ( true| false ) + + 0= IF + update-flash-help r> drop EXIT + THEN + + get-load-base flash-write 0= IF ." Flash write failed !! " cr THEN + r> set-flashside drop \ Restore old flashside +; diff --git a/qemu/roms/SLOF/slof/fs/usb/dev-hci.fs b/qemu/roms/SLOF/slof/fs/usb/dev-hci.fs new file mode 100644 index 000000000..5fb25b8b6 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/dev-hci.fs @@ -0,0 +1,71 @@ +\ ***************************************************************************** +\ * Copyright (c) 2006, 2012, 2013 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ +\ * +\ * [OEX]HCI functions +\ * +\ **************************************************************************** + +\ ( num $name type ) + +VALUE usb_type \ USB type + +\ Open Firmware Properties +device-type +" usb" 2dup device-name + +rot +VALUE usb_num \ controller number +usb_num $cathex strdup \ create alias name +2dup find-alias 0= IF + get-node node>path set-alias +ELSE 3drop THEN + +/hci-dev BUFFER: hcidev +usb_num hcidev usb-setup-hcidev +TRUE VALUE first-time-init? +0 VALUE open-count + +false VALUE dev-hci-debug? + +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +\ converts physical address to text unit string +: encode-unit ( port -- unit-str unit-len ) 1 hex-encode-unit ; + +\ Converts text unit string to phyical address +: decode-unit ( addr len -- port ) 1 hex-decode-unit ; + +: get-hci-dev ( -- hcidev ) + hcidev +; + +: hc-cleanup ( -- ) + my-phandle set-node + dev-hci-debug? IF ." USB-HCI: Cleaning up " pwd cr THEN + hcidev USB-HCD-EXIT + 0 set-node +; + +: open ( -- true | false ) + true +; + +: close +; + +\ create a new entry to cleanup and suspend HCI +\ after first init +first-time-init? IF + ['] hc-cleanup add-quiesce-xt + false to first-time-init? +THEN diff --git a/qemu/roms/SLOF/slof/fs/usb/dev-hub.fs b/qemu/roms/SLOF/slof/fs/usb/dev-hub.fs new file mode 100644 index 000000000..ba0b33437 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/dev-hub.fs @@ -0,0 +1,32 @@ +new-device + +VALUE sudev + +s" slofdev.fs" included +sudev slof-dev>port l@ dup set-unit encode-phys " reg" property +sudev slof-dev>udev @ VALUE udev + +s" hub" device-name + +s" dev-parent-calls.fs" included + +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property +: decode-unit 1 hex-decode-unit ; +: encode-unit 1 hex-encode-unit ; + +: usb-hub-init ( usbdev -- true | false ) + udev USB-HUB-INIT +; + +: open ( -- true | false ) + TRUE +; + +: close +; + +." USB HUB " cr +usb-hub-init drop + +finish-device diff --git a/qemu/roms/SLOF/slof/fs/usb/dev-keyb.fs b/qemu/roms/SLOF/slof/fs/usb/dev-keyb.fs new file mode 100644 index 000000000..db9e23ef1 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/dev-keyb.fs @@ -0,0 +1,54 @@ +new-device + +VALUE sudev +false VALUE usb-keyb-debug? + +s" slofdev.fs" included +sudev slof-dev>port l@ dup set-unit encode-phys " reg" property +sudev slof-dev>udev @ VALUE udev + +s" usb-keyboard" device-name +s" keyboard" device-type +s" EN" encode-string s" language" property +s" keyboard" get-node node>path set-alias + +s" dev-parent-calls.fs" included + +0 VALUE open-count + +: open ( -- true | false ) + usb-keyb-debug? IF ." USB-KEYB: Opening (count is " open-count . ." )" cr THEN + open-count 0= IF + udev USB-HID-INIT 0= IF + ." USB keyboard setup failed " pwd cr false EXIT + THEN + THEN + open-count 1 + to open-count + true +; + +: close + usb-keyb-debug? IF ." USB-KEYB: Closing (count is " open-count . ." )" cr THEN + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + my-phandle set-node + udev USB-HID-EXIT drop + 0 set-node + THEN + THEN +; + +\ method to check if a key is present in output buffer +\ used by 'term-io.fs' +: key-available? ( -- true|false ) + udev USB-KEY-AVAILABLE IF TRUE ELSE FALSE THEN +; + +: read ( addr len -- actual ) + 0= IF drop 0 EXIT THEN + udev USB-READ-KEYB ?dup IF swap c! 1 ELSE 0 swap c! 0 then +; + +." USB Keyboard " cr +finish-device diff --git a/qemu/roms/SLOF/slof/fs/usb/dev-mouse.fs b/qemu/roms/SLOF/slof/fs/usb/dev-mouse.fs new file mode 100644 index 000000000..f6acd7e28 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/dev-mouse.fs @@ -0,0 +1,20 @@ +new-device + +VALUE sudev +s" slofdev.fs" included +sudev slof-dev>port l@ dup set-unit encode-phys " reg" property +sudev slof-dev>udev @ VALUE udev + +s" usb-mouse" device-name + +\ .S cr +\ dup slof-dev>udev dup . @ . cr +\ dup slof-dev>port dup . l@ . cr +\ dup slof-dev>devaddr dup . l@ . cr +\ dup slof-dev>hcitype dup . l@ . cr +\ dup slof-dev>num dup . l@ . cr +\ dup slof-dev>devtype dup . l@ . cr + +." USB mouse " cr + +finish-device diff --git a/qemu/roms/SLOF/slof/fs/usb/dev-parent-calls.fs b/qemu/roms/SLOF/slof/fs/usb/dev-parent-calls.fs new file mode 100644 index 000000000..57fa8ebdc --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/dev-parent-calls.fs @@ -0,0 +1,15 @@ +\ ****************************************************************************/ +\ * Copyright (c) 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +get-node CONSTANT my-phandle + +s" dma-function.fs" included diff --git a/qemu/roms/SLOF/slof/fs/usb/dev-storage.fs b/qemu/roms/SLOF/slof/fs/usb/dev-storage.fs new file mode 100644 index 000000000..94f8421d3 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/dev-storage.fs @@ -0,0 +1,361 @@ +\ ***************************************************************************** +\ * Copyright (c) 2013 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ( usbdev -- ) + +new-device + +VALUE usbdev + +s" slofdev.fs" included + +false VALUE usb-disk-debug? + +usbdev slof-dev>port l@ dup set-unit encode-phys " reg" property +s" storage" device-name + +s" dev-parent-calls.fs" included + +2 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +: decode-unit 2 hex64-decode-unit ; +: encode-unit 2 hex64-encode-unit ; + +0 CONSTANT USB_PIPE_OUT +1 CONSTANT USB_PIPE_IN + +\ ----------------------------------------------------------- +\ Specific properties +\ ----------------------------------------------------------- + +usbdev slof-dev>udev @ VALUE udev +usbdev slof-dev>port l@ VALUE port +usbdev slof-dev>hcitype l@ VALUE hcitype + +0 INSTANCE VALUE lun +10000 VALUE dev-max-transfer +0 VALUE resp-buffer +0 VALUE resp-size +0f CONSTANT SCSI-COMMAND-OFFSET + +\ ------------------------------------------------------- +\ DMA-able buffers +\ ------------------------------------------------------- + +STRUCT + dev-max-transfer FIELD usb>data + 40 FIELD usb>cmd + 20 FIELD usb>csw +CONSTANT /dma-buf + +0 VALUE dma-buf +0 VALUE dma-buf-phys +0 VALUE td-buf +0 VALUE td-buf-phys +1000 CONSTANT /td-buf + +: (dma-buf-init) ( -- ) + /dma-buf dma-alloc TO dma-buf + dma-buf /dma-buf 0 dma-map-in TO dma-buf-phys + /td-buf dma-alloc TO td-buf + td-buf /td-buf 0 dma-map-in TO td-buf-phys +; + +: (dma-buf-free) ( -- ) + td-buf td-buf-phys /td-buf dma-map-out + td-buf /td-buf dma-free + 0 TO td-buf + 0 TO td-buf-phys + dma-buf dma-buf-phys /dma-buf dma-map-out + dma-buf /dma-buf dma-free + 0 TO dma-buf + 0 TO dma-buf-phys +; + + +scsi-open + +\ ----------------------------------------------------------- +\ Perform SCSI commands +\ ----------------------------------------------------------- + +0 INSTANCE VALUE current-target + +\ SCSI command. We do *NOT* implement the "standard" execute-command +\ because that doesn't have a way to return the sense buffer back, and +\ we do have auto-sense with some hosts. Instead we implement a made-up +\ do-scsi-command. +\ +\ Note: stat is -1 for "hw error" (ie, error queuing the command or +\ getting the response). +\ +\ A sense buffer is returned whenever the status is non-0 however +\ if sense-len is 0 then no sense data is actually present +\ + +: do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE ) + TO resp-size + TO resp-buffer + udev USB_PIPE_OUT td-buf td-buf-phys dma-buf-phys usb>cmd 1F + usb-transfer-bulk IF \ transfer CBW + resp-size IF + d# 125 us + udev USB_PIPE_IN td-buf td-buf-phys resp-buffer resp-size + usb-transfer-bulk 1 = not IF \ transfer data + usb-disk-debug? IF ." Data phase failed " cr THEN + \ FALSE EXIT + \ in case of a stall/halted endpoint we clear the halt + \ Fall through and try reading the CSW + THEN + THEN + d# 125 us + udev USB_PIPE_IN td-buf td-buf-phys dma-buf-phys usb>csw 0D + usb-transfer-bulk \ transfer CSW + ELSE + FALSE EXIT + THEN +; + +STRUCT \ cbw + /l FIELD cbw>sig + /l FIELD cbw>tag + /l FIELD cbw>len + /c FIELD cbw>flags + /c FIELD cbw>lun \ 0:3 bits + /c FIELD cbw>cblen \ 0:4 bits +CONSTANT cbw-length + +STRUCT \ csw + /l FIELD csw>sig + /l FIELD csw>tag + /l FIELD csw>data-residue + /c FIELD csw>status +CONSTANT cbw-length + +0 VALUE cbw-addr +0 VALUE csw-addr + +: build-cbw ( tag xfer-len dir lun cmd-len addr -- ) + TO cbw-addr ( tag xfer-len dir lun cmd-len ) + cbw-addr cbw-length erase ( tag xfer-len dir lun cmd-len ) + cbw-addr cbw>cblen c! ( tag xfer-len dir lun ) + cbw-addr cbw>lun c! ( tag xfer-len dir ) + \ dir is true or false + \ bmCBWFlags + \ BIT 7 Direction + \ 0 - OUT + \ 1 - IN + IF 80 ELSE 0 THEN + cbw-addr cbw>flags c! ( tag xfer-len ) + cbw-addr cbw>len l!-le ( tag ) + cbw-addr cbw>tag l!-le ( ) + 43425355 cbw-addr cbw>sig l!-le +; + +0 INSTANCE VALUE usb-buf-addr +0 INSTANCE VALUE usb-buf-len +0 INSTANCE VALUE usb-dir +0 INSTANCE VALUE usb-cmd-addr +0 INSTANCE VALUE usb-cmd-len +1 VALUE tag + +: execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... ) + ( ... [ sense-buf sense-len ] stat ) + \ Cleanup virtio request and response + to usb-cmd-len to usb-cmd-addr to usb-dir to usb-buf-len to usb-buf-addr + + dma-buf usb>cmd 40 0 fill + dma-buf usb>csw 20 0 fill + + tag usb-buf-len usb-dir lun usb-cmd-len dma-buf usb>cmd + ( tag transfer-len dir lun cmd-len addr ) + build-cbw + 1 tag + to tag + + usb-cmd-addr + dma-buf usb>cmd SCSI-COMMAND-OFFSET + + usb-cmd-len + move + + \ Send it + dma-buf-phys usb>data usb-buf-len + do-bulk-command IF + dma-buf usb>data usb-buf-addr usb-buf-len move + ELSE + ." USB-DISK: Bulk commad failed!" cr + 0 0 -1 EXIT + THEN + + dma-buf usb>csw to csw-addr + csw-addr csw>sig l@ 55534253 <> IF + ." USB-DISK: CSW signature invalid " cr + 0 0 -1 EXIT + THEN + + csw-addr csw>status c@ CASE + 0 OF ENDOF \ Good + 1 OF + usb-disk-debug? IF + ." USB-DISK: CSW Data residue: " + csw-addr csw>data-residue l@-le . cr + THEN + 0 0 8 EXIT ENDOF \ Command failed, Retry + dup OF 0 0 -1 EXIT ENDOF \ Anything else -> HW error + ENDCASE + + \ Other error status + csw-addr csw>status c@ dup 0<> IF + usb-disk-debug? IF + over scsi-get-sense-data + ." USB-DISK: Sense key [ " dup . ." ] " .sense-text + ." ASC,ASCQ: " . . cr + THEN + rot + THEN +; + +\ -------------------------------- +\ Include the generic host helpers +\ -------------------------------- + +" scsi-host-helpers.fs" included + +0 VALUE open-count + +: usb-storage-init ( -- TRUE ) + td-buf 0= IF + usb-disk-debug? IF ." USB-DISK: Allocating buffer " cr THEN + (dma-buf-init) + udev USB-MSC-INIT 0= IF + ." USB-DISK: Unable to initialize MSC " cr + FALSE + ELSE + TRUE + THEN + THEN +; + +: usb-storage-cleanup + td-buf 0<> IF + usb-disk-debug? IF ." USB-DISK: Freeing buffer " cr THEN + (dma-buf-free) + udev USB-MSC-EXIT 0= IF ." USB-DISK: Unable to exit MSC " cr THEN + THEN +; + +: open + usb-disk-debug? IF ." USB-DISK: Opening (count is " open-count . ." )" cr THEN + + open-count 0= IF + usb-storage-init IF + 1 to open-count true + ELSE ." USB-DISK initialization failed !" cr false THEN + ELSE + open-count 1 + to open-count + true + THEN +; + +: close + usb-disk-debug? IF ." USB-DISK: Closing (count is " open-count . ." )" cr THEN + + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + usb-storage-cleanup + THEN + THEN +; + +\ ----------------------------------------------------------- +\ SCSI scan at boot and child device support +\ ----------------------------------------------------------- + +\ We use SRP luns of the form 01000000 | (target << 8) | lun +\ in the top 32 bits of the 64-bit LUN +: (set-target) + dup 20 >> FFFF and to lun + dup 30 >> FF and to port + to current-target + usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN +; + +: dev-generate-srplun ( target lun-id -- srplun ) + swap drop port 0100 or 10 << or 20 << +; + +\ FIXME: Check max transfer coming from virtio config +: max-transfer ( -- n ) + dev-max-transfer +; + +\ We obtain here a unit address on the stack, since our #address-cells +\ is 2, the 64-bit srplun is split in two cells that we need to join +\ +\ Note: This diverges a bit from the original OF scsi spec as the two +\ cells are the 2 words of a 64-bit SRP LUN +: set-address ( srplun.lo srplun.hi -- ) + lxjoin (set-target) + usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN +; + +1 CONSTANT #target +: dev-max-target ( -- #target ) + #target +; + +" scsi-probe-helpers.fs" included + +scsi-close \ no further scsi words required + +\ Set scsi alias if none is set yet +: setup-alias + s" scsi" find-alias 0= IF + s" scsi" get-node node>path set-alias + ELSE + drop + THEN +; + +: usb-storage-init-and-scan ( -- ) + usb-disk-debug? IF ." Initializing usb-disk: udev " udev . cr THEN + + \ Create instance for scanning: + 0 0 get-node open-node ?dup 0= IF EXIT THEN + my-self >r + dup to my-self + + hcitype + CASE + 1 OF 4000 TO dev-max-transfer ENDOF \ OHCI + 2 OF 10000 TO dev-max-transfer ENDOF \ EHCI + 3 OF F000 TO dev-max-transfer ENDOF \ XHCI + ENDCASE + usb-storage-init + scsi-find-disks + setup-alias + usb-storage-cleanup + \ Close the temporary instance: + close-node + r> to my-self +; + +." USB Storage " cr +: usb-scsi-add-disk + " scsi-disk.fs" included +; + +usb-scsi-add-disk +usb-storage-init-and-scan + +finish-device diff --git a/qemu/roms/SLOF/slof/fs/usb/slofdev.fs b/qemu/roms/SLOF/slof/fs/usb/slofdev.fs new file mode 100644 index 000000000..d6e20fdcd --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/slofdev.fs @@ -0,0 +1,8 @@ +STRUCT + /n FIELD slof-dev>udev + /l FIELD slof-dev>port + /l FIELD slof-dev>devaddr + /l FIELD slof-dev>hcitype + /l FIELD slof-dev>num + /l FIELD slof-dev>devtype +CONSTANT slof-usb-dev diff --git a/qemu/roms/SLOF/slof/fs/usb/usb-static.fs b/qemu/roms/SLOF/slof/fs/usb/usb-static.fs new file mode 100644 index 000000000..47db7276a --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/usb/usb-static.fs @@ -0,0 +1,70 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011, 2013 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Load dev hci +: load-dev-hci ( num name-str name-len ) + s" dev-hci.fs" INCLUDED +; + +0 VALUE ohci-init +0 VALUE ehci-init +0 VALUE xhci-init +0 VALUE usb-alias-num + +: get-usb-alias-num + usb-alias-num dup 1+ to usb-alias-num +; + +\ create a new ohci device alias for the current node +: set-ohci-alias ( -- ) + 1 to ohci-init + get-usb-alias-num ( num ) + s" ohci" 1 load-dev-hci +; + +\ create a new ehci device alias for the current node +: set-ehci-alias ( -- ) + 1 to ehci-init + get-usb-alias-num ( num ) + s" ehci" 2 load-dev-hci +; + +\ create a new xhci device alias for the current node +: set-xhci-alias ( -- ) + 1 to xhci-init + get-usb-alias-num ( num ) + s" xhci" 3 load-dev-hci +; + +: usb-enumerate ( hcidev -- ) + USB-HCD-INIT +; + +: usb-scan ( -- ) + ." Scanning USB " cr + ohci-init 1 = IF USB-OHCI-REGISTER THEN + ehci-init 1 = IF USB-EHCI-REGISTER THEN + xhci-init 1 = IF USB-XHCI-REGISTER THEN + + usb-alias-num 0 ?DO + " usb" i $cathex find-device + " get-hci-dev" get-node find-method + IF + execute usb-enumerate + ELSE + ." get-base-address method not found for usb@" i . + ." Device type: " + " device_type" get-node get-property 0= IF decode-string type cr 2drop THEN + THEN + LOOP + 0 set-node \ FIXME Setting it back +; diff --git a/qemu/roms/SLOF/slof/fs/vpd-bootlist.fs b/qemu/roms/SLOF/slof/fs/vpd-bootlist.fs new file mode 100644 index 000000000..5a082156f --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/vpd-bootlist.fs @@ -0,0 +1,134 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +4 CONSTANT vpd-bootlist-size + +\ Bootable devices +00 CONSTANT FLOPPY +01 CONSTANT USB +02 CONSTANT SAS +03 CONSTANT SATA +04 CONSTANT ISCSI +05 CONSTANT ISCSICRITICAL +06 CONSTANT NET +07 CONSTANT NOTSPECIFIED +08 CONSTANT HDD0 +09 CONSTANT HDD1 +0a CONSTANT HDD2 +0b CONSTANT HDD3 +0c CONSTANT CDROM +0e CONSTANT HDD4 +10 CONSTANT SCSI + +: check-bootlist ( -- true | false ) + vpd-bootlist l@ + dup 0= IF + ( bootlist == 0 means that probably nothing from vpd has been received ) + s" Boot list could not be read from VPD" log-string cr + s" Boot watchdog has been rearmed" log-string cr + 2 set-watchdog + EXIT + THEN + + FFFFFFFF = IF + ( bootlist all FFs means that the vpd has no useful information ) + .banner + -6b boot-exception-handler + \ The next message is duplicate, but sent w. log-string + s" Boot list successfully read from VPD but no useful information received" log-string cr + s" Please specify the boot device in the management module" log-string cr + s" Specified Boot Sequence not valid" mm-log-warning + false + EXIT + THEN + + true +; + +\ the following words are necessary for vpd-boot-import +defer set-boot-device +defer add-boot-device + +\ select-install? is a flag which is used in the SMS panel #20 +\ "Select/Install Boot Devices". +\ This panel can be used to temporarily override the boot device. +false VALUE select-install? + +\ select/install-path stores string address and string length of the +\ device node chosen in the SMS panel #20 "Select/Install Boot Devices" +\ This device node is prepended to the boot path if select-install? is +\ true. +CREATE select/install-path 2 cells allot + +\ Import boot device list from VPD +\ If none, keep the existing list in NVRAM +\ This word can be used to overwrite read-bootlist if wanted + +: vpd-boot-import ( -- ) + 0 0 set-boot-device + + select-install? IF + select/install-path 2@ add-boot-device + THEN + + vpd-read-bootlist + check-bootlist IF + 4 0 DO vpd-bootlist i + c@ + CASE + 6 OF \ cr s" 2B Booting from Network" log-string cr + furnish-boot-file strdup add-boot-device + ENDOF + + HDD0 OF \ cr s" 2B Booting from hdd0" log-string cr + s" disk hdd0" add-boot-device ENDOF + + HDD1 OF \ cr s" 2B Booting from hdd1" log-string cr + s" hdd1" add-boot-device ENDOF + + HDD2 OF \ cr s" 2B Booting from hdd2" log-string cr + s" hdd2" add-boot-device ENDOF + + HDD3 OF \ cr s" 2B Booting from hdd3" log-string cr + s" hdd3" add-boot-device ENDOF + + CDROM OF \ cr s" 2B Booting from CDROM" log-string cr + s" cdrom" add-boot-device ENDOF + + HDD4 OF \ cr s" 2B Booting from hdd4" log-string cr + s" hdd4" add-boot-device ENDOF + + F OF \ cr s" 2B Booting from SAS - w. Timeout" log-string cr + s" sas" add-boot-device ENDOF + + SCSI OF \ cr s" 2B Booting from SAS - Continuous Retry" log-string cr + s" sas" add-boot-device ENDOF + + ENDCASE + LOOP + bootdevice 2@ nip + IF 0 + ELSE + \ Check for all no device -> use boot-device + vpd-bootlist l@ 07070707 = IF 0 ELSE -6b THEN + THEN + ELSE -6a THEN + boot-exception-handler +; + +: vpd-bootlist-restore-default ( -- ) + NOTSPECIFIED vpd-bootlist 0 + c! + NOTSPECIFIED vpd-bootlist 1 + c! + NOTSPECIFIED vpd-bootlist 2 + c! + HDD0 vpd-bootlist 3 + c! + vpd-write-bootlist +; + diff --git a/qemu/roms/SLOF/slof/fs/xmodem.fs b/qemu/roms/SLOF/slof/fs/xmodem.fs new file mode 100644 index 000000000..122192212 --- /dev/null +++ b/qemu/roms/SLOF/slof/fs/xmodem.fs @@ -0,0 +1,120 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +01 CONSTANT XM-SOH \ Start of header +04 CONSTANT XM-EOT \ End-of-transmission +06 CONSTANT XM-ACK \ Acknowledge +15 CONSTANT XM-NAK \ Neg. acknowledge + +0 VALUE xm-retries \ Retry count +0 VALUE xm-block# + + +\ * +\ * Internal function: +\ * wait <timeout> seconds for a new character +\ * +: xmodem-get-byte ( timeout -- byte|-1 ) + d# 1000 * + 0 DO + key? IF key UNLOOP EXIT THEN + 1 ms + LOOP + -1 +; + + +\ * +\ * Internal function: +\ * Receive one XMODEM packet, check block number and check sum. +\ * +: xmodem-rx-packet ( address -- success? ) + 1 xmodem-get-byte \ Get block number + dup 0 < IF + 2drop false EXIT \ Timeout + THEN + 1 xmodem-get-byte \ Get neg. block number + dup 0 < IF + 3drop false EXIT \ Timeout + THEN + rot 0 ( blk# ~blk# address chksum ) + 80 0 DO + 1 xmodem-get-byte dup 0 < IF ( blk# ~blk# address chksum byte ) + 3drop 2drop UNLOOP FALSE EXIT + THEN + dup 3 pick c! ( blk# ~blk# address chksum byte ) + + swap 1+ swap ( blk# ~blk# address+1 chksum' ) + LOOP + ( blk# ~blk# address chksum ) + \ Check sum: + 0ff and + 1 xmodem-get-byte <> IF + \ CRC failed! + 3drop FALSE EXIT + THEN + drop ( blk# ~blk# ) + \ finally check if block numbers are ok: + over xm-block# <> IF + \ Wrong block number! + 2drop FALSE EXIT + THEN ( blk# ~blk# ) + ff xor = +; + + +\ * +\ * Internal function: +\ * Load file to given address via XMODEM protocol +\ * +: (xmodem-load) ( address -- bytes ) + 1 to xm-block# + 0 to xm-retries + dup + BEGIN + d# 10 xmodem-get-byte dup >r + CASE + XM-SOH OF + dup xmodem-rx-packet IF + \ A packet has been received successfully + XM-ACK emit + 80 + ( start-addr next-addr R: rx-byte ) + 0 to xm-retries \ Reset retry count + xm-block# 1+ ff and to xm-block# \ Increase current block# + ELSE + \ Error while receiving packet + XM-NAK emit + xm-retries 1+ to xm-retries \ Increase retry count + THEN + ENDOF + XM-EOT OF + XM-ACK emit + ENDOF + dup OF + XM-NAK emit + xm-retries 1+ to xm-retries \ Increase retry count + ENDOF + ENDCASE + r> XM-EOT = + xm-retries d# 10 >= OR + UNTIL ( start-address end-address ) + swap - ( bytes received ) +; + + +\ * +\ * Load file to load-base via XMODEM protocol +\ * +: xmodem-load ( -- bytes ) + cr ." Waiting for start of XMODEM upload..." cr + get-load-base (xmodem-load) +; diff --git a/qemu/roms/SLOF/slof/helpers.c b/qemu/roms/SLOF/slof/helpers.c new file mode 100644 index 000000000..d7c1888b4 --- /dev/null +++ b/qemu/roms/SLOF/slof/helpers.c @@ -0,0 +1,136 @@ +/****************************************************************************** + * Copyright (c) 2007, 2012, 2013 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +/* + * All functions concerning interface to slof + */ + +#include <stdio.h> +#include <string.h> +#include <cpu.h> +#include "helpers.h" +#include "paflof.h" + +/** + * get msec-timer value + * access to HW register + * overrun will occur if boot exceeds 1.193 hours (49 days) + * + * @param - + * @return actual timer value in ms as 32bit + */ +uint32_t SLOF_GetTimer(void) +{ + forth_eval("get-msecs"); + return (uint32_t) forth_pop(); +} + +void SLOF_msleep(uint32_t time) +{ + time = SLOF_GetTimer() + time; + while (time > SLOF_GetTimer()) + cpu_relax(); +} + +void SLOF_usleep(uint32_t time) +{ + forth_push(time); + forth_eval("us"); +} + +void *SLOF_dma_alloc(long size) +{ + forth_push(size); + forth_eval("dma-alloc"); + return (void *)forth_pop(); +} + +void SLOF_dma_free(void *virt, long size) +{ + forth_push((long)virt); + forth_push(size); + forth_eval("dma-free"); +} + +void *SLOF_alloc_mem(long size) +{ + forth_push(size); + forth_eval("alloc-mem"); + return (void *)forth_pop(); +} + +void *SLOF_alloc_mem_aligned(long size, long align) +{ + unsigned long addr = (unsigned long)SLOF_alloc_mem(size + align - 1); + addr = addr + align - 1; + addr = addr & ~(align - 1); + + return (void *)addr; +} + +void SLOF_free_mem(void *addr, long size) +{ + forth_push((long)addr); + forth_push(size); + forth_eval("free-mem"); +} + +long SLOF_dma_map_in(void *virt, long size, int cacheable) +{ + forth_push((long)virt); + forth_push(size); + forth_push(cacheable); + forth_eval("dma-map-in"); + return forth_pop(); +} + +void SLOF_dma_map_out(long phys, void *virt, long size) +{ + forth_push((long)virt); + forth_push((long)phys); + forth_push(size); + forth_eval("dma-map-out"); +} + +long SLOF_pci_config_read32(long offset) +{ + forth_push(offset); + forth_eval("config-l@"); + return forth_pop(); +} + +long SLOF_pci_config_read16(long offset) +{ + forth_push(offset); + forth_eval("config-w@"); + return forth_pop(); +} + +void SLOF_pci_config_write32(long offset, long value) +{ + forth_push(value); + forth_push(offset); + forth_eval("config-l!"); +} + +void SLOF_pci_config_write16(long offset, long value) +{ + forth_push(value); + forth_push(offset); + forth_eval("config-w!"); +} + +void *SLOF_translate_my_address(void *addr) +{ + forth_push((long)addr); + forth_eval("translate-my-address"); + return (void *)forth_pop(); +} diff --git a/qemu/roms/SLOF/slof/lowmem.S b/qemu/roms/SLOF/slof/lowmem.S new file mode 100644 index 000000000..9aaa9f75c --- /dev/null +++ b/qemu/roms/SLOF/slof/lowmem.S @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> +#include <xvect.h> + + .globl _start + /* All exception vectors *******************/ +_start: + .org 0x100 + /* check if Master / Slave *****************/ + /* Master will go to XVECT_M_HANDLER */ + /* Slave will go to XVECT_S_HANDLER */ +#ifdef SECONDARY_CPUS_STOPPED + ld r3,XVECT_S_HANDLER(0) + mfspr r0, PIR + cmpwi r0, 0 + bne 0f +#endif + ld r3,XVECT_M_HANDLER(0) +0: + mtctr r3 + li r0,0x100 + bctr + + /* FIXME: Also need 0280, 0380, 0f20, etc. */ + + .irp i, 0x0200,0x0280,0x0300,0x0380,0x0400,0x0480,0x0500,0x0600,0x0700, \ + 0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00,0x0e00,0x0f00, \ + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \ + 0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \ + 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \ + 0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00,0x2f00 + .org \i + + /* enable this if you get exceptions before the console works */ + /* this will allow using the hardware debugger to see where */ + /* it traps, and with what register values etc. */ + // b $ + + mtsprg 0,r0 + mfctr r0 + mtsprg 2,r0 + mflr r0 + mtsprg 3,r0 + ld r0, XVECT_M_HANDLER(0) + mtctr r0 + li r0,\i + bctr + .endr + + + .org XVECT_M_HANDLER + .quad 0 + + .org XVECT_S_HANDLER + .quad 0 + + .org XVECT_TOPADDR + .byte 0x36 # to fill out to exactly 16kB diff --git a/qemu/roms/SLOF/slof/ofw.S b/qemu/roms/SLOF/slof/ofw.S new file mode 100644 index 000000000..14e1e9d2b --- /dev/null +++ b/qemu/roms/SLOF/slof/ofw.S @@ -0,0 +1,59 @@ +/****************************************************************************** + * Copyright (c) 2004, 2011 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> +#include <xvect.h> + + .section ".slof.loader","ax" + + /* this only works if paflof is running below 4GB */ + lis r31, fdt_start@h /* save address of */ + ori r31, r31, fdt_start@l /* flattened device */ + std r3, 0(r31) /* tree */ + + /* this only works if paflof is running below 4GB */ + lis r31, romfs_base@h /* save address of */ + ori r31, r31, romfs_base@l /* the romfs */ + std r4, 0(r31) + + /* this only works if paflof is running below 4GB */ + lis r31, epapr_magic@h /* if it is an epapr compliant */ + ori r31, r31, epapr_magic@l /* low level firmware; then r6 */ + std r6, 0(r31) /* contains the epapr magic */ + + /* this only works if paflof is running below 4GB */ + lis r31, epapr_ima_size@h + ori r31, r31, epapr_ima_size@l + std r7, 0(r31) /* r7 contains the IMA size */ + + /* fill in handler address */ + + /* this only works if paflof is running below 4GB */ + mfmsr r0 + mtsrr1 r0 + lis r3, _slof_text@h + ori r3, r3, _slof_text@l + ld r3, 0(r3) + std r3, XVECT_M_HANDLER(0) + +#ifdef BROKEN_SC1 + /* Patch potentially broken sc 1 instructions */ + lis r3, _slof_text@h + ori r3, r3, _slof_text@l + lis r4, _slof_text_end@h + ori r4, r4, _slof_text_end@l + li r5, 0 + bl .patch_broken_sc1 +#endif + + /* GO! */ + ba 0x100 diff --git a/qemu/roms/SLOF/slof/paflof.c b/qemu/roms/SLOF/slof/paflof.c new file mode 100644 index 000000000..624955fba --- /dev/null +++ b/qemu/roms/SLOF/slof/paflof.c @@ -0,0 +1,116 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +// +// Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +// + + +#define XSTR(x) #x +#define ISTR(x,y) XSTR(x.y) +#undef unix + +#include "paflof.h" +#include <string.h> +#include <stdint.h> +#include <ctype.h> +#include <cache.h> +#include <allocator.h> + +#include ISTR(TARG,h) + +#define LAST_ELEMENT(x) x[sizeof x / sizeof x[0] - 1] + +/* Hack to get around static inline issues */ +#include "../lib/libhvcall/libhvcall.h" + + +extern char _start_OF[]; + +unsigned long fdt_start; +unsigned long romfs_base; +unsigned long epapr_magic; +unsigned long epapr_ima_size; // ePAPR initially mapped area size +unsigned char hash_table[HASHSIZE*CELLSIZE]; + +#include ISTR(TARG,c) + +// the actual engine +long engine(int mode, long param_1, long param_2) +{ + // For Exceptions: + // mode = ENGINE_MODE_PARAM_1 | MODE_PARAM_2 + // (param_1 = error, param_2 = reason) + // + // For Push: + // mode = ENGINE_MODE_PARAM_1 | ENGINE_MODE_NOP + // + // For Pop: + // mode = ENGINE_MODE_NOP | ENGINE_MODE_POP + // + // For Evaluate: + // mode = ENGINE_MODE_PARAM_1 | MODE_PARAM_2 | ENGINE_MODE_EVAL + // (param_1 = strlen(string), param_2 = string) + + cell *restrict ip; + cell *restrict cfa; + static cell handler_stack[160]; + static cell c_return[2]; + static cell dummy; + + #include "prep.h" + #include "dict.xt" + + static int init_engine = 0; + if (init_engine == 0) { + // one-time initialisation + init_engine = 1; + LAST_ELEMENT(xt_FORTH_X2d_WORDLIST).a = xt_LASTWORD; + + // stack-pointers + dp = the_data_stack - 1; + rp = handler_stack - 1; + + // return-address for "evaluate" personality + dummy.a = &&over; + c_return[1].a = &dummy; + } + + if (mode & ENGINE_MODE_PARAM_2) { + (++dp)->n = param_2; + } + if (mode & ENGINE_MODE_PARAM_1) { + (++dp)->n = param_1; + } + + if (mode & ENGINE_MODE_NOP ) { + goto over; + } + + if (mode & ENGINE_MODE_EVAL) { + (++rp)->a = c_return; + ip = xt_EVALUATE + 2 + ((10 + CELLSIZE - 1) / CELLSIZE); + } else { + ip = xt_SYSTHROW; + } + + #include "prim.code" + #include "board.code" + #include ISTR(TARG,code) + + + // Only reached in case of non-exception call +over: if (mode & ENGINE_MODE_POP) { + return ((dp--)->n); + } else { + return 0; + } +} diff --git a/qemu/roms/SLOF/slof/paflof.h b/qemu/roms/SLOF/slof/paflof.h new file mode 100644 index 000000000..885c9487b --- /dev/null +++ b/qemu/roms/SLOF/slof/paflof.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +// +// Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +// + + +extern long engine(int, long, long); + +#define TIBSIZE 256 + +#define POCKETSIZE 256 +#define NUMPOCKETS 16 + +#define HASHSIZE 0x1000 + +// engine mode bits +#define ENGINE_MODE_PARAM_1 0x0001 +#define ENGINE_MODE_PARAM_2 0x0002 +#define ENGINE_MODE_NOP 0x0004 +#define ENGINE_MODE_EVAL 0x0008 +#define ENGINE_MODE_POP 0x0010 + +// engine calls +#define forth_eval(s) engine(ENGINE_MODE_PARAM_1|ENGINE_MODE_PARAM_2|ENGINE_MODE_EVAL, \ + strlen((s)), (long)(s)) +#define forth_eval_pop(s) engine(ENGINE_MODE_PARAM_1|ENGINE_MODE_PARAM_2|ENGINE_MODE_EVAL|ENGINE_MODE_POP, \ + strlen((s)), (long)(s)) + +#define forth_push(v) engine(ENGINE_MODE_PARAM_1|ENGINE_MODE_NOP, v, 0) + +#define forth_pop() engine(ENGINE_MODE_NOP|ENGINE_MODE_POP, 0, 0) diff --git a/qemu/roms/SLOF/slof/ppc64.c b/qemu/roms/SLOF/slof/ppc64.c new file mode 100644 index 000000000..20d927069 --- /dev/null +++ b/qemu/roms/SLOF/slof/ppc64.c @@ -0,0 +1,110 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> + +/* the exception frame should be page aligned + * the_exception_frame is used by the handler to store a copy of all + * registers after an exception; this copy can then be used by paflof's + * exception handler to printout a register dump */ +cell the_exception_frame[0x400 / CELLSIZE] __attribute__ ((aligned(PAGE_SIZE)));; + +/* the_client_frame is the register save area when starting a client */ +cell the_client_frame[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100))); +cell the_client_stack[0x8000 / CELLSIZE] __attribute__ ((aligned(0x100))); +/* THE forth stack */ +cell the_data_stack[0x2000 / CELLSIZE] __attribute__ ((aligned(0x100))); +/* the forth return stack */ +cell the_return_stack[0x2000 / CELLSIZE] __attribute__ ((aligned(0x100))); + +/* forth stack and return-stack pointers */ +cell *restrict dp; +cell *restrict rp; + +/* terminal input buffer */ +cell the_tib[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100))); +/* temporary string buffers */ +char the_pockets[NUMPOCKETS * POCKETSIZE] __attribute__ ((aligned(0x100))); + +cell the_comp_buffer[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100))); + +cell the_heap[HEAP_SIZE / CELLSIZE] __attribute__ ((aligned(0x1000))); +cell *the_heap_start = &the_heap[0]; +cell *the_heap_end = &the_heap[HEAP_SIZE / CELLSIZE]; + +extern void io_putchar(unsigned char); + + +static unsigned long __attribute__((noinline)) +call_c(cell arg0, cell arg1, cell arg2, cell entry) +{ + register unsigned long r3 asm("r3") = arg0.u; + register unsigned long r4 asm("r4") = arg1.u; + register unsigned long r5 asm("r5") = arg2.u; + register unsigned long r6 = entry.u ; + + asm volatile("mflr 31 ; mtctr %4 ; bctrl ; mtlr 31" + : "=r" (r3) + : "r" (r3), "r" (r4), "r" (r5), "r" (r6) + : "ctr", "r6", "r7", "r8", "r9", "r10", "r11", + "r12", "r13", "r31", "lr", "cc"); + + return r3; +} + + +long +writeLogByte_wrapper(long x, long y) +{ + unsigned long result; + + SET_CI; + result = writeLogByte(x, y); + CLR_CI; + + return result; +} + + +/** + * Standard write function for the libc. + * + * @param fd file descriptor (should always be 1 or 2) + * @param buf pointer to the array with the output characters + * @param count number of bytes to be written + * @return the number of bytes that have been written successfully + */ +int +write(int fd, const void *buf, int count) +{ + int i; + char *ptr = (char *)buf; + + if (fd != 1 && fd != 2) + return 0; + + for (i = 0; i < count; i++) { + if (*ptr == '\n') + io_putchar('\r'); + io_putchar(*ptr++); + } + + return i; +} + +/* This should probably be temporary until a better solution is found */ +void +asm_cout(long Character, long UART, long NVRAM __attribute__((unused))) +{ + if (UART) + io_putchar(Character); +} diff --git a/qemu/roms/SLOF/slof/ppc64.code b/qemu/roms/SLOF/slof/ppc64.code new file mode 100644 index 000000000..94069a296 --- /dev/null +++ b/qemu/roms/SLOF/slof/ppc64.code @@ -0,0 +1,274 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +// This file contains the implementation of the Forth code words specific +// to PowerPC64. Some of this is 970-only. + +// 970-specific CPU registers. +// Don't use on P7 ! +PRIM(HID0_X21) + unsigned long hid0 = TOS.u; + asm volatile("sync ; mtspr 1008,%0 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008 ; mfspr %0,1008" : "+r"(hid0)); + POP; +MIRP + +PRIM(HID0_X40) + PUSH; + asm volatile("mfspr %0,1008" : "=r"(TOS)); +MIRP + +PRIM(HID1_X21) + unsigned long hid1 = TOS.u; + asm volatile("mtspr 1009,%0 ; mtspr 1009,%0 ; isync" : : "r"(hid1)); + POP; +MIRP + +PRIM(HID1_X40) + PUSH; + asm volatile("mfspr %0,1009" : "=r"(TOS)); +MIRP + +PRIM(HID4_X21) + unsigned long hid4 = TOS.u; + asm volatile("sync ; mtspr 1012,%0 ; isync" : : "r"(hid4)); + POP; +MIRP + +PRIM(HID4_X40) + PUSH; + asm volatile("mfspr %0,1012" : "=r"(TOS)); +MIRP + +PRIM(HID5_X21) + unsigned long hid5 = TOS.u; + asm volatile("mtspr 1014,%0" : : "r"(hid5)); + POP; +MIRP + +PRIM(HID5_X40) + PUSH; + asm volatile("mfspr %0,1014" : "=r"(TOS)); +MIRP + +// PowerPC special registers. +PRIM(MSR_X21) + unsigned long msr = TOS.u; + asm volatile("mtmsrd %0" : : "r"(msr)); + POP; +MIRP + +PRIM(MSR_X40) + PUSH; + asm volatile("mfmsr %0" : "=r"(TOS)); +MIRP + +PRIM(SDR1_X21) + unsigned long sdr1 = TOS.u; + asm volatile("mtsdr1 %0" : : "r"(sdr1)); + POP; +MIRP + +PRIM(SDR1_X40) + PUSH; + asm volatile("mfsdr1 %0" : "=r"(TOS)); +MIRP + +PRIM(PVR_X40) + PUSH; + asm volatile("mfpvr %0" : "=r"(TOS)); +MIRP + +PRIM(PIR_X40) + PUSH; + asm volatile("mfspr %0,1023" : "=r"(TOS)); +MIRP + +PRIM(TBL_X40) + PUSH; + asm volatile("mftbl %0" : "=r"(TOS)); +MIRP + +PRIM(TBU_X40) + PUSH; + asm volatile("mftbu %0" : "=r"(TOS)); +MIRP + +PRIM(DABR_X21) + unsigned long dabr = TOS.u; + asm volatile("mtspr 1013,%0" : : "r"(dabr)); + POP; +MIRP + +PRIM(DABR_X40) + PUSH; + asm volatile("mfspr %0,1013" : "=r"(TOS)); +MIRP + +PRIM(HIOR_X21) + unsigned long dabr = TOS.u; + asm volatile("mtspr 311,%0" : : "r"(dabr)); + POP; +MIRP + +PRIM(HIOR_X40) + PUSH; + asm volatile("mfspr %0,311" : "=r"(TOS)); +MIRP + + + +PRIM(SPRG0_X21) + unsigned long sprg0 = TOS.u; + asm volatile("mtsprg0 %0" : "+r"(sprg0)); + POP; +MIRP + +PRIM(SPRG0_X40) + PUSH; + asm volatile("mfsprg0 %0" : "=r"(TOS)); +MIRP + +PRIM(SPRG1_X21) + unsigned long sprg1 = TOS.u; + asm volatile("mtsprg1 %0" : "+r"(sprg1)); + POP; +MIRP + +PRIM(SPRG1_X40) + PUSH; + asm volatile("mfsprg1 %0" : "=r"(TOS)); +MIRP + +PRIM(SPRG2_X21) + unsigned long sprg2 = TOS.u; + asm volatile("mtsprg2 %0" : "+r"(sprg2)); + POP; +MIRP + +PRIM(SPRG2_X40) + PUSH; + asm volatile("mfsprg2 %0" : "=r"(TOS)); +MIRP + +PRIM(SPRG3_X21) + unsigned long sprg3 = TOS.u; + asm volatile("mtsprg3 %0" : "+r"(sprg3)); + POP; +MIRP + +PRIM(SPRG3_X40) + PUSH; + asm volatile("mfsprg3 %0" : "=r"(TOS)); +MIRP + +PRIM(HSPRG0_X21) + unsigned long hsprg0 = TOS.u; + asm volatile("mtspr 304,%0" : "+r"(hsprg0)); + POP; +MIRP + +PRIM(HSPRG0_X40) + PUSH; + asm volatile("mfspr %0,304" : "=r"(TOS)); +MIRP + +PRIM(HSPRG1_X21) + unsigned long hsprg1 = TOS.u; + asm volatile("mtspr 305,%0" : "+r"(hsprg1)); + POP; +MIRP + +PRIM(HSPRG1_X40) + PUSH; + asm volatile("mfspr %0,305" : "=r"(TOS)); +MIRP + + +PRIM(MMCR0_X21) + unsigned long mmcr0 = TOS.u; + asm volatile("sync ; mtspr 795,%0 ; isync" : : "r"(mmcr0)); + POP; +MIRP + +PRIM(PMC1_X40) + PUSH; + asm volatile("sync ; mfspr %0,787" : "=r"(TOS)); +MIRP + +PRIM(ICBI) + asm volatile("dcbst 0,%0 ; sync ; icbi 0,%0 ; sync ; isync" : : "r"(TOS)); + POP; +MIRP + +// Call into the client program. +PRIM(JUMP_X2d_CLIENT) + TOS.u = call_client(TOS); +MIRP + + +// Hang. Useful for debugging, believe it or not. +PRIM(CRASH) + for (;;) ; +MIRP + +PRIM(START_X2d_RTAS) + cell e = TOS; POP; + cell p1 = TOS; POP; + cell p0 = TOS; + TOS.u = call_c(p0, p1, (cell)0UL, e); +MIRP + +PRIM(CALL_X2d_C) + cell e = TOS; POP; + cell p2 = TOS; POP; + cell p1 = TOS; POP; + cell p0 = TOS; + TOS.u = call_c(p0, p1, p2, e); +MIRP + +PRIM(FLUSHCACHE) + type_u n = TOS.u; POP; + unsigned char* p = TOS.a; POP; + flush_cache(p, n); +MIRP + +PRIM(DEC_X21) + unsigned long dec = TOS.u; + asm volatile("mtdec %0" : "+r"(dec)); + POP; +MIRP + +PRIM(DEC_X40) + PUSH; + asm volatile("mfdec %0" : "=r"(TOS)); +MIRP + +PRIM(BM_X2d_ALLOCATOR_X2d_INIT) + unsigned long blocksize = TOS.u; POP; + unsigned long size = TOS.u; POP; + unsigned long start = TOS.u; + TOS.u = SLOF_bm_allocator_init(start, size, blocksize); +MIRP + +PRIM(BM_X2d_ALLOC) + unsigned long size = TOS.u; POP; + unsigned long handle = TOS.u; + TOS.u = SLOF_bm_alloc(handle, size); +MIRP + +PRIM(BM_X2d_FREE) + unsigned long size = TOS.u; POP; + unsigned long addr = TOS.u; POP; + unsigned long handle = TOS.u; POP; + SLOF_bm_free(handle, addr, size); +MIRP
\ No newline at end of file diff --git a/qemu/roms/SLOF/slof/ppc64.h b/qemu/roms/SLOF/slof/ppc64.h new file mode 100644 index 000000000..59a1b906d --- /dev/null +++ b/qemu/roms/SLOF/slof/ppc64.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <cpu.h> +#include "types.h" + +#define PAGE_SIZE 4096 +#define HEAP_SIZE 0x800000 + +#ifdef CPU_PPC970 +#define SET_CI set_ci() +#define CLR_CI clr_ci() +#else +#define SET_CI +#define CLR_CI +#endif + +// The big Forth source file that contains everything but the core engine. +// We include it as a hunk of data into the C part of SLOF; at startup +// time, this will be EVALUATE'd. +extern char _binary_OF_fsi_start[], _binary_OF_fsi_end[]; + +extern cell the_mem[]; /* Space for the dictionary / the HERE pointer */ + +extern cell *restrict dp; +extern cell *restrict rp; + +void client_entry_point(); + +extern unsigned long call_client(cell); +extern long c_romfs_lookup(long, long, void *); +extern long writeLogByte(long, long); diff --git a/qemu/roms/SLOF/slof/ppc64.in b/qemu/roms/SLOF/slof/ppc64.in new file mode 100644 index 000000000..b533c68c4 --- /dev/null +++ b/qemu/roms/SLOF/slof/ppc64.in @@ -0,0 +1,96 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +// The Forth code words (primitives) that are specific to PowerPC64. + +// CPU register accesses. +cod(HID0!) +cod(HID0@) +cod(HID1!) +cod(HID1@) +cod(HID4!) +cod(HID4@) +cod(HID5!) +cod(HID5@) +cod(MSR@) +cod(MSR!) +cod(SDR1@) +cod(SDR1!) +cod(PVR@) +cod(PIR@) +cod(TBL@) +cod(TBU@) +cod(DABR@) +cod(DABR!) +cod(HIOR@) +cod(HIOR!) +cod(SPRG0@) +cod(SPRG0!) +cod(SPRG1@) +cod(SPRG1!) +cod(SPRG2@) +cod(SPRG2!) +cod(SPRG3@) +cod(SPRG3!) +cod(HSPRG0@) +cod(HSPRG0!) +cod(HSPRG1@) +cod(HSPRG1!) +cod(DEC@) +cod(DEC!) + +cod(MMCR0!) +cod(PMC1@) + +cod(ICBI) + + +// The start address of a binary payload. +//con(PAYLOAD (type_u)_binary_payload_start) + +// Calling the client program. +con(CLIENT-ENTRY-POINT (type_u)client_entry_point) +cod(JUMP-CLIENT) +dfr(CLIENTINTERFACE) + + +con(ROMFS-LOOKUP-ENTRY (type_u) c_romfs_lookup) + +// not very elegant... but the only way it works for me +con(.WRITE-LOG-BYTE-ENTRY (type_u) writeLogByte_wrapper) +col(WRITE-LOG-BYTE-ENTRY .WRITE-LOG-BYTE-ENTRY @) + +cod(CALL-C) +cod(START-RTAS) + + +cod(FLUSHCACHE) +// Bit map allocator +cod(BM-ALLOCATOR-INIT) +cod(BM-ALLOC) +cod(BM-FREE) + +// Hang. +cod(CRASH) + +var(DAAR 0x00f00000) +col(DUMBER DAAR @ C! LIT(1) DAAR +!) + +dfr(BOOT-EXCEPTION-HANDLER) + +col(NICEINIT DOTICK DROP DOTO EMIT DOTICK ((FIND)) DOTO (FIND) DOTICK 2DROP DOTO (REVEAL) LIT((type_u)_binary_OF_fsi_start) LIT((type_u)_binary_OF_fsi_end) OVER - DOTICK EVALUATE CATCH BOOT-EXCEPTION-HANDLER) + +static cell xt_SYSTHROW[] = { _0 RDEPTH_X21 DUP LIT(0x100) _X3d _0BRANCH(5) SWAP DROP NICEINIT BRANCH(7) DUP LIT(0x3800) _X3d _0BRANCH(1) CLIENTINTERFACE PRINT_X2d_STATUS QUIT }; + +// sentinel, leave it here! +col(LASTWORD ) + diff --git a/qemu/roms/SLOF/slof/prep.h b/qemu/roms/SLOF/slof/prep.h new file mode 100644 index 000000000..03950ba2d --- /dev/null +++ b/qemu/roms/SLOF/slof/prep.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +// +// Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +// + + +#define _N(_n) { .n = _n }, +#define _O(_n) { .n = CELLSIZE * (_n) }, +#define _C(_c) { .c = _c }, +#define _A(_a) { .a = _a }, + +#define ref(_xt, _nname) _A(xt_ ## _xt + _nname) +#define header(_xt, _header...) static cell xt_ ## _xt[] = { _header +#define def(_xts...) _xts }; +#define lab(_xt) _A(&&code_ ## _xt) + +#define DOCOL lab(DOCOL) +#define DODOES lab(DODOES) +#define DODEFER lab(DODEFER) +#define DOALIAS lab(DOALIAS) +#define DOCON lab(DOCON) +#define DOVAL lab(DOVAL) +#define DOFIELD lab(DOFIELD) +#define DOVAR lab(DOVAR) +#define DOBUFFER_X3a lab(DOBUFFER_X3a) + +#define cod(_xt) def(lab(_xt)) +#define col(_xt, _def...) def(DOCOL _def SEMICOLON) +#define con(_xt, _def) def(DOCON _N(_def)) +#define dfr(_xt) def(DODEFER _N(0)) +#define val(_xt, _def) def(DOVAL _N(_def)) +#define var(_xt, _def) def(DOVAR _N(_def)) + + +#define raw(_xt, _def) def(_def) +#define str(_xt, _def...) def(_def) diff --git a/qemu/roms/SLOF/slof/prim.code b/qemu/roms/SLOF/slof/prim.code new file mode 100644 index 000000000..9fbed7168 --- /dev/null +++ b/qemu/roms/SLOF/slof/prim.code @@ -0,0 +1,592 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +// +// Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +// + + +#define NEXT00 goto *cfa->a +#define NEXT0 cfa = ip->a; NEXT00 +#define NEXT ip++; NEXT0 + +#define PRIM(name) code_##name: { \ + asm volatile ("#### " #name : : : "memory"); \ + void *w = (cfa = (++ip)->a)->a; +#define MIRP goto *w; } + + + + // start interpreting + NEXT0; + + + +// These macros could be replaced to allow for TOS caching etc. +#define TOS (*dp) +#define NOS (*(dp-1)) +#define POP dp-- +#define PUSH dp++ + +#define RTOS (*rp) +#define RNOS (*(rp-1)) +#define RPOP rp-- +#define RPUSH rp++ + + + + +// For terminal input. +PRIM(TIB) PUSH; TOS.a = the_tib; MIRP + +// For pockets (temporary string buffers). +PRIM(POCKETS) PUSH; TOS.a = the_pockets; MIRP + +// exception register area +PRIM(EREGS) PUSH; TOS.a = the_exception_frame; MIRP + +// client register area +PRIM(CIREGS) PUSH; TOS.a = the_client_frame; MIRP + +// Client stack +// (According to the PowerPC ABI the stack-pointer points to the +// lowest **USED** value. +// I.e. it is decremented before a new element is stored on the +// stack.) +PRIM(CISTACK) PUSH; TOS.a = the_client_stack + + (sizeof(the_client_stack) / CELLSIZE); MIRP + +// compile-in-interpret buffer +PRIM(COMP_X2d_BUFFER) PUSH; TOS.a = the_comp_buffer; MIRP + +// Paflof base address +PRIM(PAFLOF_X2d_START) PUSH; TOS.a = _start_OF; MIRP + +// Heap pointers +PRIM(HEAP_X2d_START) PUSH; TOS.a = the_heap_start; MIRP +PRIM(HEAP_X2d_END) PUSH; TOS.a = the_heap_end; MIRP + +// FDT pointer +PRIM(FDT_X2d_START) PUSH; TOS.u = fdt_start; MIRP + +// romfs-base +PRIM(ROMFS_X2d_BASE) PUSH; TOS.u = romfs_base; MIRP + +// if the low level firmware is epapr compliant it will put the +// epapr magic into r6 before starting paflof +// epapr-magic is a copy of r6 +PRIM(EPAPR_X2d_MAGIC) PUSH; TOS.u = epapr_magic; MIRP + +// Initially mapped area size (for ePAPR compliant LLFW) +PRIM(EPAPR_X2d_IMA_X2d_SIZE) PUSH; TOS.u = epapr_ima_size; MIRP + +// Codefields. +code_DOCOL: + { + RPUSH; RTOS.a = ip; + ip = cfa; + NEXT; + } +code_DODOES: + { + RPUSH; RTOS.a = ip; + ip = (cfa + 1)->a; + PUSH; TOS.a = cfa + 2; + NEXT0; + } +code_DODEFER: + { + cfa = (cfa + 1)->a; + NEXT00; + } +code_DOALIAS: + { + cfa = (cfa + 1)->a; + NEXT00; + } +code_DOCON: + { + PUSH; + TOS = *(cfa + 1); + NEXT; + } +code_DOVAL: + { + PUSH; + TOS = *(cfa + 1); + NEXT; + } +code_DOFIELD: + { + dp->n += (cfa + 1)->n; + NEXT; + } +code_DOVAR: + { + (++dp)->a = cfa + 1; + NEXT; + } +code_DOBUFFER_X3a: + { + (++dp)->a = cfa + 1; + NEXT; + } + + + + + +// branching +code_BRANCH: + { + type_n dis = (++ip)->n; + ip = (cell *)((type_u)ip + dis); + NEXT; + } +code_0BRANCH: + { + type_n dis = (++ip)->n; + if (TOS.u == 0) + ip = (cell *)((type_u)ip + dis); + POP; + NEXT; + } + +// Jump to "defer BP" +code_BREAKPOINT: + { + RPUSH; RTOS.a = ip; + ip = (cell * ) xt_BP+2; + NEXT; + } + + +// literals +code_LIT: + { + PUSH; + TOS = *++ip; + NEXT; + } +code_DOTICK: + { + PUSH; + TOS = *++ip; + NEXT; + } + + + +// 1.1 +PRIM(DUP) cell x = TOS; PUSH; TOS = x; MIRP +PRIM(OVER) cell x = NOS; PUSH; TOS = x; MIRP +PRIM(PICK) TOS = *(dp - TOS.n - 1); MIRP + +// 1.2 +PRIM(DROP) POP; MIRP + +// 1.3 +PRIM(SWAP) cell x = NOS; NOS = TOS; TOS = x; MIRP + +// 1.4 +PRIM(_X3e_R) RPUSH; RTOS = TOS; POP; MIRP +PRIM(R_X3e) PUSH; TOS = RTOS; RPOP; MIRP +PRIM(R_X40) PUSH; TOS = RTOS; MIRP + +// 1.5 +PRIM(DEPTH) PUSH; TOS.u = dp - the_data_stack; MIRP +PRIM(DEPTH_X21) dp = the_data_stack + TOS.u - 1; MIRP +PRIM(RDEPTH) PUSH; TOS.u = rp - the_return_stack + 1; MIRP +PRIM(RDEPTH_X21) rp = the_return_stack + TOS.u - 1; POP; MIRP +PRIM(RPICK) TOS = *(rp - TOS.n); MIRP + +// 2.1 +PRIM(_X2b) NOS.u += TOS.u; POP; MIRP +PRIM(_X2d) NOS.u -= TOS.u; POP; MIRP +PRIM(_X2a) NOS.u *= TOS.u; POP; MIRP + +// 2.2 +PRIM(LSHIFT) NOS.u <<= TOS.u; POP; MIRP +PRIM(RSHIFT) NOS.u >>= TOS.u; POP; MIRP +PRIM(ASHIFT) NOS.n >>= TOS.u; POP; MIRP +PRIM(AND) NOS.u &= TOS.u; POP; MIRP +PRIM(OR) NOS.u |= TOS.u; POP; MIRP +PRIM(XOR) NOS.u ^= TOS.u; POP; MIRP + +// 3.1 +#define GET_TYPE1(t) { \ + t *restrict a = (t *restrict)(TOS.a); \ + t b; + +#define GET_TYPE2(t) \ + b = *a; + +#define GET_TYPE3(t) \ + TOS.u = b; \ +} + +#define PUT_TYPE1(t) { \ + t *restrict a = TOS.a; \ + t b = NOS.u; \ + POP; \ + POP; + +#define PUT_TYPE2(t) \ + *a = b; \ +} + +#define GET_CELL1 GET_TYPE1(type_u) +#define PUT_CELL1 PUT_TYPE1(type_u) +#define GET_CHAR1 GET_TYPE1(type_c) +#define PUT_CHAR1 PUT_TYPE1(type_c) +#define GET_WORD1 GET_TYPE1(type_w) +#define PUT_WORD1 PUT_TYPE1(type_w) +#define GET_LONG1 GET_TYPE1(type_l) +#define PUT_LONG1 PUT_TYPE1(type_l) +#define GET_XONG1 GET_TYPE1(type_u) +#define PUT_XONG1 PUT_TYPE1(type_u) + +#define GET_CELL2 GET_TYPE2(type_u) +#define PUT_CELL2 PUT_TYPE2(type_u) +#define GET_CHAR2 GET_TYPE2(type_c) +#define PUT_CHAR2 PUT_TYPE2(type_c) +#define GET_WORD2 GET_TYPE2(type_w) +#define PUT_WORD2 PUT_TYPE2(type_w) +#define GET_LONG2 GET_TYPE2(type_l) +#define PUT_LONG2 PUT_TYPE2(type_l) +#define GET_XONG2 GET_TYPE2(type_u) +#define PUT_XONG2 PUT_TYPE2(type_u) + +#define GET_CELL3 GET_TYPE3(type_u) +#define GET_CHAR3 GET_TYPE3(type_c) +#define GET_WORD3 GET_TYPE3(type_w) +#define GET_LONG3 GET_TYPE3(type_l) +#define GET_XONG3 GET_TYPE3(type_u) + +#define GET_CELL GET_CELL1 GET_CELL2 GET_CELL3 +#define PUT_CELL PUT_CELL1 PUT_CELL2 +#define GET_CHAR GET_CHAR1 GET_CHAR2 GET_CHAR3 +#define PUT_CHAR PUT_CHAR1 PUT_CHAR2 +#define GET_WORD GET_WORD1 GET_WORD2 GET_WORD3 +#define PUT_WORD PUT_WORD1 PUT_WORD2 +#define GET_LONG GET_LONG1 GET_LONG2 GET_LONG3 +#define PUT_LONG PUT_LONG1 PUT_LONG2 +#define GET_XONG GET_XONG1 GET_XONG2 GET_XONG3 +#define PUT_XONG PUT_XONG1 PUT_XONG2 + + PRIM(_X40) GET_CELL; MIRP + PRIM(_X21) PUT_CELL; MIRP + PRIM(C_X40) GET_CHAR; MIRP + PRIM(C_X21) PUT_CHAR; MIRP + PRIM(W_X40) GET_WORD; MIRP + PRIM(W_X21) PUT_WORD; MIRP + PRIM(L_X40) GET_LONG; MIRP + PRIM(L_X21) PUT_LONG; MIRP + PRIM(X_X40) GET_XONG; MIRP + PRIM(X_X21) PUT_XONG; MIRP + + +#define UGET_TYPE1(t) { \ + type_c *restrict a = (type_c *restrict)(TOS.a); \ + t b; \ + type_c *restrict c = (type_c *restrict)&b; + +#define UGET_TYPE2(t) \ + *c++ = *a++; \ + *c++ = *a++; + +#define UGET_TYPE3(t) \ + TOS.u = b; \ +} + +#define UPUT_TYPE1(t) { \ + type_c *restrict a = (type_c *restrict)(TOS.a); \ + t b = NOS.u; \ + type_c *restrict c = (type_c *restrict)&b; \ + POP; \ + POP; + +#define UPUT_TYPE2(t) \ + *a++ = *c++; \ + *a++ = *c++; + +#define UPUT_TYPE3(t) } + +#define UGET_WORD1 UGET_TYPE1(type_w) +#define UPUT_WORD1 UPUT_TYPE1(type_w) +#define UGET_WORD2 UGET_TYPE2(type_w) +#define UPUT_WORD2 UPUT_TYPE2(type_w) +#define UGET_WORD3 UGET_TYPE3(type_w) +#define UPUT_WORD3 UPUT_TYPE3(type_w) +#define UGET_LONG1 UGET_TYPE1(type_l) +#define UPUT_LONG1 UPUT_TYPE1(type_l) +#define UGET_LONG2 UGET_TYPE2(type_l) +#define UPUT_LONG2 UPUT_TYPE2(type_l) +#define UGET_LONG3 UGET_TYPE3(type_l) +#define UPUT_LONG3 UPUT_TYPE3(type_l) + +#define UGET_WORD UGET_WORD1 UGET_WORD2 UGET_WORD3 +#define UPUT_WORD UPUT_WORD1 UPUT_WORD2 UPUT_WORD3 +#define UGET_LONG UGET_LONG1 UGET_LONG2 UGET_LONG2 UGET_LONG3 +#define UPUT_LONG UPUT_LONG1 UPUT_LONG2 UPUT_LONG2 UPUT_LONG3 + + PRIM(UNALIGNED_X2d_W_X40) UGET_WORD; MIRP + PRIM(UNALIGNED_X2d_W_X21) UPUT_WORD; MIRP + PRIM(UNALIGNED_X2d_L_X40) UGET_LONG; MIRP + PRIM(UNALIGNED_X2d_L_X21) UPUT_LONG; MIRP + + +// 6 +PRIM(_X3c) NOS.n = -(NOS.n < TOS.n); POP; MIRP +PRIM(U_X3c) NOS.n = -(NOS.u < TOS.u); POP; MIRP +PRIM(0_X3c) TOS.n = -(TOS.n < 0); MIRP +PRIM(_X3d) NOS.n = -(NOS.u == TOS.u); POP; MIRP +PRIM(0_X3d) TOS.n = -(TOS.u == 0); MIRP + + + + + + +// 8.4 +PRIM(DODO) RPUSH; RTOS = NOS; RPUSH; RTOS = TOS; POP; POP; MIRP +code_DO_X3f_DO: + { + cell i = *dp--; + cell n = *dp--; + type_n dis = (++ip)->n; + if (i.n == n.n) + ip = (cell *restrict)((type_c *restrict)ip + dis); + else { + *(rp + 1) = n; + *(rp += 2) = i; + } + NEXT; + } +code_DOLOOP: + { + type_n dis = (++ip)->n; + rp->n++; + if (rp->n == (rp - 1)->n) + rp -= 2; + else + ip = (cell *restrict)((type_c *restrict)ip + dis); + NEXT; + } +code_DO_X2b_LOOP: + { + type_u lo, hi; + type_n inc; + type_n dis = (++ip)->n; + lo = rp->u; + inc = (dp--)->n; + rp->n += inc; + if (inc >= 0) + hi = rp->u; + else { + hi = lo; + lo = rp->u; + } + if ((type_u)((rp - 1)->n - 1 - lo) < hi - lo) + rp -= 2; + else + ip = (cell *restrict)((type_c *restrict)ip + dis); + NEXT; + } +code_DOLEAVE: + { + type_n dis = (++ip)->n; + rp -= 2; + ip = (cell *restrict)((type_c *restrict)ip + dis); + NEXT; + } +code_DO_X3f_LEAVE: + { + type_n dis = (++ip)->n; + if ((dp--)->n) { + rp -= 2; + ip = (cell *restrict)((type_c *restrict)ip + dis); + } + NEXT; + } + + + + + + +// 8.5 +code_EXIT: + { + ip = (rp--)->a; + NEXT; + } + +code_SEMICOLON: + { + ip = (rp--)->a; + NEXT; + } + +code_EXECUTE: // don't need this as prim + { + cfa = (dp--)->a; + NEXT00; + } + + +PRIM(MOVE) + type_u n = TOS.u; POP; + unsigned char *q = TOS.a; POP; + unsigned char *p = TOS.a; POP; + + _FASTMOVE(p, q, n); +MIRP + +code_FILL: + { + unsigned char c = (dp--)->u; + type_n size = ((dp--)->n); + unsigned char *d = (unsigned char *)((dp--)->u); + type_u fill_v=c | c <<8; + + fill_v |= fill_v << 16; + switch (((type_u)d | (type_u)size) & (sizeof(type_u)-1)) { + case 0: { + type_u *up = (type_u *)d; +#if (__LONG_MAX__ > 2147483647L) + fill_v |= fill_v << 32; +#endif + while ((size-=sizeof(type_u)) >= 0) + *up++ = fill_v; + } + case sizeof(type_l): { + type_l *lp = (type_l *)d; + + while ((size-=sizeof(type_l)) >= 0) + *lp++ = (type_l)fill_v; + } + case sizeof(type_w): { + type_w *wp = (type_w *)d; + + while ((size-=sizeof(type_w)) >= 0) + *wp++ = (type_w)fill_v; + } + default: + while (size-- > 0) + *d++ = (unsigned char)c; + } + NEXT; + } + +code_COMP: + { + type_n len = ((dp--)->n); + unsigned char *addr2 = (unsigned char *)((dp--)->u); + unsigned char *addr1 = (unsigned char *)((dp--)->u); + + while (len-- > 0) { + if (*addr1 > *addr2) { + (++dp)->n = 1; + NEXT; + } + else if (*addr1 < *addr2) { + (++dp)->n = -1; + NEXT; + } + addr1 += 1; + addr2 += 1; + } + (++dp)->n = 0; + NEXT; + } + + +PRIM(RMOVE) + type_u size = ((dp--)->u); + type_u *d = (type_u *)((dp--)->u); + type_u *s = (type_u *)((dp--)->u); + _FASTRMOVE(s, d, size); + + MIRP + + +// String compare, case insensitive: +// : string=ci ( str1 len1 str2 len2 -- equal? ) +PRIM(STRING_X3d_CI) + type_u l2 = TOS.u; POP; + unsigned char *p2 = TOS.a; POP; + type_u l1 = TOS.u; POP; + unsigned char *p1 = TOS.a; + + if (l1 == l2) { + TOS.n = -1; /* Default to TRUE */ + while (l1 > 0) { + if (toupper(*p1) != toupper(*p2)) { + TOS.n = 0; + break; + } + ++p1; ++p2; + --l1; + } + } + else { + TOS.n = 0; + } +MIRP + +// bool dependend pick +// ?PICK ( v1 v2 bool -- v1|v2 ) +PRIM(_X3f_PICK) + type_u b = TOS.u; POP; + if (b) { NOS = TOS; } + POP; +MIRP + +/* zcount ( zstr -- str len ) */ +PRIM(ZCOUNT) + type_u len = strlen(TOS.a); + PUSH; TOS.u = len; +MIRP + +PRIM(CLEAN_X2d_HASH) + memset(hash_table, 0, sizeof(hash_table)); +MIRP + +PRIM(HASH_X2d_TABLE) + PUSH; + TOS.a = hash_table; +MIRP + +/* hash ( str len -- hash ) + * this word is used in find-hash.fs to create + * a hash to accelerate word lookup */ +PRIM(HASH) + type_u len = TOS.u; POP; + unsigned char *str = TOS.a; + type_u tmp = len; + type_u hash = 0; + while(len--) { + hash <<= 1; + hash ^= tolower(*str); + hash ^= tmp; + str++; + } + /* we only want hash values which size is smaller + * than HASHSIZE */ + hash &= HASHSIZE - 1; + /* access the hash table in steps of CELLSIZE */ + hash *= CELLSIZE; + /* return a pointer for this hash in the hash table */ + TOS.a = hash_table + hash; +MIRP diff --git a/qemu/roms/SLOF/slof/prim.in b/qemu/roms/SLOF/slof/prim.in new file mode 100644 index 000000000..7a0d6a2ed --- /dev/null +++ b/qemu/roms/SLOF/slof/prim.in @@ -0,0 +1,113 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +// +// Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +// + +cod(TIB) +cod(POCKETS) +cod(EREGS) +cod(CIREGS) +cod(CISTACK) +// compile buffer for the "structure words in interpret mode" OF extension +cod(COMP-BUFFER) + +cod(PAFLOF-START) +cod(HEAP-START) +cod(HEAP-END) +// flattened device tree start address +cod(FDT-START) +// romfs start address +cod(ROMFS-BASE) +// if the low level firmware is epapr compliant it will put the +// epapr magic into r6 before starting paflof +// epapr-magic is a copy of r6 +cod(EPAPR-MAGIC) +// ePAPR Initially mapped area size +cod(EPAPR-IMA-SIZE) + +cod(BRANCH) _ADDING _O +cod(0BRANCH) _ADDING _O +dfr(BP) +cod(BREAKPOINT) + +cod(LIT) _ADDING _N +cod(DOTICK) + +cod(DUP) +cod(OVER) +cod(PICK) +cod(DROP) +cod(SWAP) + +cod(>R) +cod(R>) +cod(R@) +cod(RPICK) + +cod(DEPTH) +cod(DEPTH!) +cod(RDEPTH) +cod(RDEPTH!) + +cod(+) +cod(-) +cod(*) +cod(LSHIFT) +cod(RSHIFT) +cod(ASHIFT) +cod(AND) +cod(OR) +cod(XOR) + +cod(@) +cod(!) +cod(C@) +cod(C!) +cod(W@) +cod(W!) +cod(L@) +cod(L!) +cod(X@) +cod(X!) + +cod(UNALIGNED-W@) +cod(UNALIGNED-W!) +cod(UNALIGNED-L@) +cod(UNALIGNED-L!) + +cod(<) +cod(U<) +cod(0<) +cod(=) +cod(0=) + +cod(DODO) +cod(DO?DO) _ADDING _O +cod(DOLOOP) _ADDING _O +cod(DO+LOOP) _ADDING _O +cod(DOLEAVE) _ADDING _O +cod(DO?LEAVE) _ADDING _O + +cod(EXIT) +cod(SEMICOLON) +cod(EXECUTE) + +cod(MOVE) +// cod(RMOVE64) +cod(RMOVE) +cod(ZCOUNT) +con(HASH-SIZE HASHSIZE) +cod(HASH) +cod(CLEAN-HASH) +cod(HASH-TABLE) diff --git a/qemu/roms/SLOF/slof/ref.pl b/qemu/roms/SLOF/slof/ref.pl new file mode 100644 index 000000000..b21f13901 --- /dev/null +++ b/qemu/roms/SLOF/slof/ref.pl @@ -0,0 +1,148 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ +#!/usr/bin/perl + +# +# Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +# + + +use Getopt::Std; +use Data::Dumper; + +$CELLSIZE = length(sprintf "%x", ~0) / 2; +$CELLSIZE = 8; +$DEBUG = 0; + +sub usage +{ + printf STDERR "Usage: ref.pl [ -s 32|64 ] [ -d ] \n"; + printf STDERR " ref.pl -h\n"; + exit 0; +} + +sub string +{ + my ($s, $extra) = @_; + + $DEBUG and printf STDERR "\nstring:[%s][%02x]\n", $s, ord $extra; + $s = sprintf "%s%c%s", $extra, length($s), $s; + @s = ($s =~ /(.{1,$CELLSIZE})/gs); + do { s/([\x00-\x1f\x22\x5c\x7f-\xff])/sprintf "\\%03o", ord $1/egs } for @s; + my @reut = ("{ .c = \"" . (join "\" }, { .c = \"", @s) . "\" },", scalar @s); + # $DEBUG and print STDERR Dumper \@reut; + return @reut; +} + +sub forth_to_c_name +{ + ($_, my $numeric) = @_; + s/([^a-zA-Z0-9])/sprintf("_X%02x_", ord($1))/ge; + s/__/_/g; +# s/^_//; + s/_$//; + s/^(\d)/_$1/ if $numeric; + return $_; +} + +sub special_forth_to_c_name +{ + ($_, my $numeric) = @_; + + $DEBUG and print STDERR "\tasked for $_ [[numeric is $numeric]]\n"; + my ($name, $arg) = (/^([^(]+)(.*)$/); + # $DEBUG and print STDERR "\tname is $name -- arg is $arg\n"; + if ($special{$name} == 1) { + $_ = forth_to_c_name($name, $numeric) . $arg; + } elsif ($special{$name} != 2) { + $_ = forth_to_c_name($_, $numeric); + } + # $DEBUG and print STDERR "\tmaking it $_\n"; + return $_; +} + +getopts('dhs:') or die "Invalid option!\n"; + +$opt_h and usage(); +$opt_d and $DEBUG=1; +$opt_s and $opt_s != 32 and $opt_s != 64 and die("Only -s32 or -s64 allowed"); + +$opt_s and $opt_s == 32 and $CELLSIZE=4; + +$DEBUG and printf STDERR "Cell size set to $CELLSIZE;\n"; + +$link = "0"; +%special = ( _N => 2, _O => 2, _C => 2, _A => 2 ); + +$DEBUG and print STDERR "Compiling:"; +while ($line = <>) { + if ($line =~ /^([a-z]{3})\(([^ ]+)./) { + $typ = $1; + $name = $2; + + $DEBUG and print STDERR "\n\t\t$name###\n"; + + $name =~ s/\)$// if $line =~ /\)\s+_ADDING.*$/; + # $DEBUG and print STDERR " $name"; + $cname = forth_to_c_name($name, 1); + $par = ''; + $add = ''; + $extra = "\0"; + if ($typ eq "imm") { + $typ = "col"; + $extra = "\1"; + } +# if ($typ eq "com") { +# $typ = "col"; +# $extra = "\3"; +# } + ($str, $strcells) = (string $name, $extra); + if ($line =~ /^str\([^"]*"([^"]*)"/) { + # $DEBUG and print STDERR "[[[$1]]]\n"; + ($s) = (string $1); + $line =~ s/"[^"]*"/$s/; + } + if ($line =~ /_ADDING +(.*)$/) { + $special{$name} = 1; + @typ = (split /\s+/, $1); + $count = 0; + $par = "(" . (join ", ", map { $count++; "_x$count" } @typ) . ")"; + $count = 0; + $add = join " ", map { $count++; "$_(_x$count)" } @typ; + $line =~ s/\s+_ADDING.*$//; + } + # $DEBUG and print STDERR $line; + ($body) = ($line =~ /^...\((.*)\)$/); + @body = split " ", $body; + # $DEBUG and print STDERR "\n"; + # $DEBUG and print STDERR "BODY WAS: ", (join " ", @body), "\n"; + if ($typ ne "str" and $typ ne "con") { + @body = map { special_forth_to_c_name($_, $typ eq "col") } @body; + } else { + $body[0] = special_forth_to_c_name($body[0]); + } + # $DEBUG and print STDERR "BODY IS: ", (join " ", @body), "\n"; + $body = join " ", @body; + $body =~ s/ /, /; + # $DEBUG and print STDERR "===> $body\n"; + + print "header($cname, { .a = $link }, $str) "; + $link = "xt_$cname"; + print "$typ($body)\n"; + print "#define $cname$par ref($cname, $strcells+1) $add\n"; + (my $xxcname) = ($cname =~ /^_?(.*)/); + $add and print "#define DO$xxcname ref($cname, $strcells+1)\n"; + } else { + print $line; + } +} +$DEBUG and print STDERR "\n"; diff --git a/qemu/roms/SLOF/slof/types.h b/qemu/roms/SLOF/slof/types.h new file mode 100644 index 000000000..e347cc3cf --- /dev/null +++ b/qemu/roms/SLOF/slof/types.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ +// +// Copyright 2002,2003,2004 Segher Boessenkool <segher@kernel.crashing.org> +// + + +#ifndef _TYPES_H +#define _TYPES_H + +#if 0 +#include <stdint.h> + +typedef uint8_t type_c; // 1 byte +typedef uint16_t type_w; // 2 bytes +typedef uint32_t type_l; // 4 bytes +typedef intptr_t type_n; // cell size +typedef uintptr_t type_u; // cell size +#else +typedef unsigned char type_c; // 1 byte +typedef unsigned short type_w; // 2 bytes +typedef unsigned int type_l; // 4 bytes +typedef long type_n; // cell size +typedef unsigned long type_u; // cell size +#endif + +//#define CELLSIZE (sizeof(type_u) / sizeof(type_c)) +#define CELLSIZE sizeof(type_u) + +typedef union cell { + type_n n; + type_u u; + void *a; + type_c c[CELLSIZE]; + type_w w[CELLSIZE/2]; + type_l l[CELLSIZE/4]; +} cell; + + +#endif /* _TYPES_H */ diff --git a/qemu/roms/SLOF/tools/.gitignore b/qemu/roms/SLOF/tools/.gitignore new file mode 100644 index 000000000..e45841399 --- /dev/null +++ b/qemu/roms/SLOF/tools/.gitignore @@ -0,0 +1 @@ +gen_reloc_table diff --git a/qemu/roms/SLOF/tools/Makefile b/qemu/roms/SLOF/tools/Makefile new file mode 100644 index 000000000..6de8fe645 --- /dev/null +++ b/qemu/roms/SLOF/tools/Makefile @@ -0,0 +1,33 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +include ../make.rules + +all: gen_reloc_table + +%.o: %.c + $(HOSTCC) -W $(HOSTCFLAGS) -c $^ + +elf2tst: elf2tst.o + $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ + +gen_reloc_table: gen_reloc_table.o + $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ + +clean_here: + rm -f elf2tst *.o gen_reloc_table + +clean: clean_here + + +distclean: clean_here + diff --git a/qemu/roms/SLOF/tools/create_reloc_table.sh b/qemu/roms/SLOF/tools/create_reloc_table.sh new file mode 100755 index 000000000..8cacb742a --- /dev/null +++ b/qemu/roms/SLOF/tools/create_reloc_table.sh @@ -0,0 +1,60 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ +#!/bin/sh + + +CROSSTMP=`grep ^CROSS $(dirname $0)/../make.rules | cut -d\ -f2` + +CROSS=${CROSS-$CROSSTMP} + +# Set defaults: +LD="${CROSS}ld" +LDFLAGS="-nostdlib" +LDSFILE="" +OBJCOPY="${CROSS}objcopy" + +DIRNAME=`dirname $0` + +# Parse parameters: +while [ $# -gt 0 ] ; do + case "$1" in + --ld) LD=$2 ; shift 2 ;; + --ldflags) LDFLAGS=$2 ; shift 2 ;; + --lds) LDSFILE=$2 ; shift 2 ;; + --objcopy) OBJCOPY=$2 ; shift 2 ;; + *.o|*.a|-l*|-L*) OBJFILES="$OBJFILES $1" ; shift ;; + *) echo "$0:" ; echo " Unsupported argument: $1"; exit -1 ;; + esac +done + +if [ -z $LDSFILE ]; then + echo "Please specifiy an lds file with the --lds option" + exit 42 +fi + +TMP1=`mktemp` +TMP2=`mktemp` + +# Now create the two object files: +$LD $LDFLAGS -T $LDSFILE -o $TMP1.o $OBJFILES || exit -1 +$LD $LDFLAGS -T $LDSFILE -o $TMP2.o $OBJFILES --section-start .text=0x4000000000000000 || exit -1 + +$OBJCOPY -O binary $TMP1.o $TMP1.bin || exit -1 +$OBJCOPY -O binary $TMP2.o $TMP2.bin || exit -1 + +# Create the relocation table with gen_reloc_table: +$DIRNAME/gen_reloc_table $TMP1.bin $TMP2.bin reloc_table.bin + +$LD -o reloc_table.o -bbinary reloc_table.bin -e0 || exit -1 +$OBJCOPY --rename-section .data=.reloc reloc_table.o reloc_table.o || exit -1 + +rm -f $TMP1.o $TMP2.o $TMP1.bin $TMP2.bin reloc_table.bin diff --git a/qemu/roms/SLOF/tools/gen_reloc_table.c b/qemu/roms/SLOF/tools/gen_reloc_table.c new file mode 100644 index 000000000..b15ce9d00 --- /dev/null +++ b/qemu/roms/SLOF/tools/gen_reloc_table.c @@ -0,0 +1,95 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +static int reloc_64_cnt; + +static int reloc_64[4096]; + +static void +output_int(FILE *output_file, int i) +{ + fputc((i>>24) & 0xff, output_file); + fputc((i>>16) & 0xff, output_file); + fputc((i>>8) & 0xff, output_file); + fputc(i & 0xff, output_file); +} + +static void +output_reloc_table(FILE * output_file, int reloc_cnt, int reloc[]) +{ + int i; + for (i=0; i < reloc_cnt; i++) + { +#ifdef DEBUG + printf ("reloc %x\n", reloc[i]); +#endif + output_int (output_file, reloc[i]); + } + if ((reloc_cnt & 1) == 0) + output_int (output_file, 0); +} + +int +main(int argc, char *argv[]) +{ + int cnt_a, cnt_b, offset = -1; + unsigned char a, b; + FILE *orig, *other, *output_file; + + if (argc != 4) + { + fprintf (stderr, "reloc_diff orig_file other_file output_file\n"); + exit(-1); + } + + orig = fopen(argv[1], "rb"); + other = fopen(argv[2], "rb"); + output_file = fopen(argv[3], "wb"); + if(orig == NULL || other == NULL || output_file == NULL) { + printf("Could not open file.\n"); + return -1; + } + + while (1) + { + cnt_a = fread(&a, 1, 1, orig); + cnt_b = fread(&b, 1, 1, other); + offset ++; + if (cnt_a != cnt_b) + { + fprintf (stderr, "Files >%s< and >%s< have not the same length\n",argv[1],argv[2]); + exit(-1); + } + + if (cnt_a == 0) + break; + + if (a == b) continue; + + if (a + 0x40 == b) + { + reloc_64[reloc_64_cnt++] = offset; + } + else + { + fprintf(stderr, "Unknown relocation"); + fprintf(stderr, "Offset %x: %02x %02x\n", offset, a, b); + break; + } + } + + output_reloc_table(output_file, reloc_64_cnt, reloc_64); + return 0; +} |