├── .github └── workflows │ └── build_check.yml ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── Makefile ├── README.md ├── adb-devprobe.sh ├── autoversion.sh ├── bin ├── fel-sdboot.sunxi ├── jtag-loop.sunxi ├── ramboot.scr ├── ramboot.uboot-sh └── uart0-helloworld-sdboot.sunxi ├── boot_head.S ├── boot_head.lds ├── bootinfo.c ├── common.h ├── fel-gpio ├── fel-remotefunc-compiler.rb ├── fel-remotefunc-spi-data-transfer.c ├── fel-remotefunc-spi-data-transfer.h ├── fel-sdboot.S ├── fel-sdboot.lds ├── fel-spiflash.c ├── fel-spiflash.h ├── fel.c ├── fel_lib.c ├── fel_lib.h ├── fexc.c ├── fexc.h ├── find-arm-gcc.sh ├── fit_image.c ├── fit_image.h ├── include ├── list.h ├── portable_endian.h └── types.h ├── jtag-loop.S ├── jtag-loop.c ├── jtag-loop.lds ├── meminfo.c ├── nand-common.h ├── nand-image-builder.c ├── nand-part-a10.h ├── nand-part-a20.h ├── nand-part-main.c ├── nand-part.c ├── phoenix_info.c ├── pio.c ├── progress.c ├── progress.h ├── script.c ├── script.h ├── script_bin.c ├── script_bin.h ├── script_extractor.c ├── script_fex.c ├── script_fex.h ├── script_uboot.c ├── script_uboot.h ├── soc_info.c ├── soc_info.h ├── sunxi-fel.1 ├── tests ├── Makefile ├── fextest.sh ├── test_all_fex.sh ├── test_bin2fex_corner_cases.sh ├── test_fex2bin_corner_cases.sh └── unify-fex.c ├── thunks ├── Makefile ├── README.md ├── clrsetbits.S ├── clrsetbits.h ├── fel-to-spl-thunk.S ├── fel-to-spl-thunk.h ├── memcpy.S ├── memcpy.h ├── objdump_to_h.awk ├── readl_writel.S ├── readl_writel.h ├── rmr-thunk.S ├── rmr-thunk.h ├── sid_read_root.S └── sid_read_root.h ├── uart0-helloworld-sdboot.c └── uart0-helloworld-sdboot.lds /.github/workflows/build_check.yml: -------------------------------------------------------------------------------- 1 | name: Build host tools 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Install prerequisites 17 | run: sudo apt-get install -y libusb-1.0-0-dev zlib1g-dev libfdt-dev 18 | - name: make 19 | run: make tools misc 20 | - name: make check 21 | run: make check 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin2fex 2 | fex2bin 3 | sunxi-bootinfo 4 | sunxi-fel 5 | sunxi-fexc 6 | sunxi-nand-part 7 | sunxi-pio 8 | version.h 9 | *.o 10 | *.swp 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # use container-based infrastructure 2 | sudo: false 3 | 4 | language: c 5 | 6 | # treat all warnings as errors, fake cross-toolchain (build everything on host) 7 | env: 8 | - CFLAGS="-g -O2 -Werror" CROSS_COMPILE="" 9 | 10 | os: 11 | - linux 12 | - osx 13 | compiler: 14 | - gcc 15 | - clang 16 | 17 | # OSX uses Apple's flavor of clang anyway, so there's no point in trying "gcc". 18 | # This excludes the "gcc" compiler from the build matrix for OSX: 19 | matrix: 20 | exclude: 21 | - os: osx 22 | compiler: gcc 23 | 24 | # take care of the libusb dependency for Linux 25 | addons: 26 | apt: 27 | packages: 28 | - libusb-1.0-0-dev 29 | 30 | # take care of the libusb dependency for Mac OS X; select make/install target 31 | before_install: 32 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then 33 | brew update; 34 | brew install libusb; 35 | export TARGET=tools; 36 | else 37 | export TARGET=all; 38 | fi 39 | 40 | # build (and test) using the Makefile, with a single overall status 41 | script: 42 | - make ${TARGET} && make misc && make check 43 | 44 | # run/simulate a test install 45 | after_success: 46 | - make install-${TARGET} install-misc DESTDIR=/tmp PREFIX=/sunxi-tools 47 | 48 | # turn off email notifications 49 | notifications: 50 | - email: false 51 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Alejandro Mery 2 | # Copyright (C) 2012,2013 Henrik Nordstrom 3 | # Copyright (C) 2013 Patrick Wood 4 | # Copyright (C) 2013 Pat Wood 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | # Windows predefines OS in the environment (to "Windows_NT"), otherwise use uname 20 | OS ?= $(shell uname) 21 | 22 | CC ?= gcc 23 | DEFAULT_CFLAGS := -std=c99 24 | DEFAULT_CFLAGS += -Wall -Wextra -Wno-unused-result 25 | 26 | DEFAULT_CFLAGS += -D_POSIX_C_SOURCE=200112L 27 | # Define _BSD_SOURCE, necessary to expose all endian conversions properly. 28 | # See http://linux.die.net/man/3/endian 29 | DEFAULT_CFLAGS += -D_BSD_SOURCE 30 | # glibc 2.20+ also requires _DEFAULT_SOURCE 31 | DEFAULT_CFLAGS += -D_DEFAULT_SOURCE 32 | ifeq ($(OS),NetBSD) 33 | # add explicit _NETBSD_SOURCE, see https://github.com/linux-sunxi/sunxi-tools/pull/22 34 | DEFAULT_CFLAGS += -D_NETBSD_SOURCE 35 | endif 36 | 37 | DEFAULT_CFLAGS += -Iinclude/ 38 | 39 | PKG_CONFIG ?= pkg-config 40 | 41 | # Tools useful on host and target 42 | TOOLS = sunxi-fexc sunxi-bootinfo sunxi-fel sunxi-nand-part sunxi-pio 43 | 44 | # Symlinks to sunxi-fexc 45 | FEXC_LINKS = bin2fex fex2bin 46 | 47 | # Tools which are only useful on the target 48 | TARGET_TOOLS = sunxi-meminfo 49 | 50 | # Misc tools (of more "exotic" nature) not part of our default build / install 51 | MISC_TOOLS = phoenix_info sunxi-nand-image-builder 52 | 53 | # ARM binaries and images 54 | # Note: To use this target, set/adjust CROSS_COMPILE and MKSUNXIBOOT if needed 55 | BINFILES = jtag-loop.sunxi fel-sdboot.sunxi uart0-helloworld-sdboot.sunxi 56 | 57 | MKSUNXIBOOT ?= mksunxiboot 58 | PATH_DIRS := $(shell echo $$PATH | sed -e 's/:/ /g') 59 | # Try to guess a suitable default ARM cross toolchain 60 | CROSS_DEFAULT := arm-none-eabi- 61 | CROSS_COMPILE ?= $(or $(shell ./find-arm-gcc.sh),$(CROSS_DEFAULT)) 62 | CROSS_CC := $(CROSS_COMPILE)gcc 63 | 64 | DESTDIR ?= 65 | PREFIX ?= /usr/local 66 | BINDIR ?= $(PREFIX)/bin 67 | MANDIR ?= $(PREFIX)/share/man/man1 68 | 69 | .PHONY: all clean tools target-tools install install-tools install-target-tools 70 | .PHONY: check 71 | 72 | tools: $(TOOLS) $(FEXC_LINKS) 73 | target-tools: $(TARGET_TOOLS) 74 | 75 | all: tools target-tools 76 | 77 | misc: $(MISC_TOOLS) 78 | 79 | binfiles: $(BINFILES) 80 | 81 | install: install-tools 82 | install-all: install-tools install-target-tools 83 | 84 | install-tools: $(TOOLS) 85 | install -d $(DESTDIR)$(BINDIR) 86 | @set -ex ; for t in $^ ; do \ 87 | install -m0755 $$t $(DESTDIR)$(BINDIR)/$$t ; \ 88 | done 89 | @set -ex ; for l in $(FEXC_LINKS) ; do \ 90 | ln -nfs sunxi-fexc $(DESTDIR)$(BINDIR)/$$l ; \ 91 | done 92 | install -D -m0644 -t $(DESTDIR)$(MANDIR) sunxi-fel.1 93 | 94 | install-target-tools: $(TARGET_TOOLS) 95 | install -d $(DESTDIR)$(BINDIR) 96 | @set -ex ; for t in $^ ; do \ 97 | install -m0755 $$t $(DESTDIR)$(BINDIR)/$$t ; \ 98 | done 99 | 100 | install-misc: $(MISC_TOOLS) 101 | install -d $(DESTDIR)$(BINDIR) 102 | @set -ex ; for t in $^ ; do \ 103 | install -m0755 $$t $(DESTDIR)$(BINDIR)/$$t ; \ 104 | done 105 | 106 | 107 | clean: 108 | make -C tests/ clean 109 | @rm -vf $(TOOLS) $(FEXC_LINKS) $(TARGET_TOOLS) $(MISC_TOOLS) 110 | @rm -vf version.h *.o *.elf *.sunxi *.bin *.nm *.orig 111 | 112 | $(TOOLS) $(TARGET_TOOLS) $(MISC_TOOLS): Makefile common.h version.h 113 | 114 | fex2bin bin2fex: sunxi-fexc 115 | ln -nsf $< $@ 116 | 117 | sunxi-fexc: fexc.h script.h script.c \ 118 | script_uboot.h script_uboot.c \ 119 | script_bin.h script_bin.c \ 120 | script_fex.h script_fex.c 121 | 122 | LIBUSB = libusb-1.0 123 | LIBUSB_CFLAGS ?= `$(PKG_CONFIG) --cflags $(LIBUSB)` 124 | LIBUSB_LIBS ?= `$(PKG_CONFIG) --libs $(LIBUSB)` 125 | 126 | ZLIB = zlib 127 | ZLIB_CFLAGS ?= `$(PKG_CONFIG) --cflags $(ZLIB)` 128 | ZLIB_LIBS ?= `$(PKG_CONFIG) --libs $(ZLIB)` 129 | 130 | ifeq ($(OS),Windows_NT) 131 | # Windows lacks mman.h / mmap() 132 | DEFAULT_CFLAGS += -DNO_MMAP 133 | # portable_endian.h relies on winsock2 134 | LIBS += -lws2_32 135 | endif 136 | 137 | HOST_CFLAGS = $(DEFAULT_CFLAGS) $(CFLAGS) 138 | 139 | PROGRESS := progress.c progress.h 140 | SOC_INFO := soc_info.c soc_info.h 141 | FEL_LIB := fel_lib.c fel_lib.h 142 | SPI_FLASH:= fel-spiflash.c fel-spiflash.h fel-remotefunc-spi-data-transfer.h 143 | 144 | sunxi-fel: fel.c fit_image.c thunks/fel-to-spl-thunk.h $(PROGRESS) $(SOC_INFO) $(FEL_LIB) $(SPI_FLASH) 145 | $(CC) $(HOST_CFLAGS) $(LIBUSB_CFLAGS) $(ZLIB_CFLAGS) $(LDFLAGS) -o $@ \ 146 | $(filter %.c,$^) $(LIBS) $(LIBUSB_LIBS) $(ZLIB_LIBS) -lfdt 147 | 148 | sunxi-nand-part: nand-part-main.c nand-part.c nand-part-a10.h nand-part-a20.h 149 | $(CC) $(HOST_CFLAGS) -c -o nand-part-main.o nand-part-main.c 150 | $(CC) $(HOST_CFLAGS) -c -o nand-part-a10.o nand-part.c -D A10 151 | $(CC) $(HOST_CFLAGS) -c -o nand-part-a20.o nand-part.c -D A20 152 | $(CC) $(LDFLAGS) -o $@ nand-part-main.o nand-part-a10.o nand-part-a20.o $(LIBS) 153 | 154 | sunxi-%: %.c 155 | $(CC) $(HOST_CFLAGS) $(LDFLAGS) -o $@ $(filter %.c,$^) $(LIBS) 156 | phoenix_info: phoenix_info.c 157 | $(CC) $(HOST_CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) 158 | 159 | %.bin: %.elf 160 | $(CROSS_COMPILE)objcopy -O binary $< $@ 161 | 162 | %.sunxi: %.bin 163 | $(MKSUNXIBOOT) $< $@ 164 | 165 | ARM_ELF_FLAGS = -Os -marm -fpic -Wall 166 | ARM_ELF_FLAGS += -fno-common -fno-builtin -ffreestanding -nostdinc -fno-strict-aliasing 167 | ARM_ELF_FLAGS += -mno-thumb-interwork -fno-stack-protector -fno-toplevel-reorder 168 | ARM_ELF_FLAGS += -Wstrict-prototypes -Wno-format-nonliteral -Wno-format-security 169 | 170 | jtag-loop.elf: jtag-loop.c jtag-loop.lds 171 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T jtag-loop.lds -Wl,-N 172 | 173 | fel-sdboot.elf: fel-sdboot.S fel-sdboot.lds 174 | $(CROSS_CC) -march=armv5te -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T fel-sdboot.lds -Wl,-N 175 | 176 | uart0-helloworld-sdboot.elf: uart0-helloworld-sdboot.c uart0-helloworld-sdboot.lds 177 | $(CROSS_CC) -march=armv5te -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T uart0-helloworld-sdboot.lds -Wl,-N 178 | 179 | boot_head_sun3i.elf: boot_head.S boot_head.lds 180 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T boot_head.lds -Wl,-N -DMACHID=0x1094 181 | 182 | boot_head_sun4i.elf: boot_head.S boot_head.lds 183 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T boot_head.lds -Wl,-N -DMACHID=0x1008 184 | 185 | boot_head_sun5i.elf: boot_head.S boot_head.lds 186 | $(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T boot_head.lds -Wl,-N -DMACHID=0x102A 187 | 188 | sunxi-bootinfo: bootinfo.c 189 | 190 | # "preprocessed" .h files for inclusion of ARM thunk code 191 | headers: 192 | make -C thunks/ CROSS_COMPILE=$(CROSS_COMPILE) 193 | 194 | 195 | # target tools 196 | TARGET_CFLAGS = $(DEFAULT_CFLAGS) -static $(CFLAGS) 197 | sunxi-meminfo: meminfo.c 198 | $(CROSS_CC) $(TARGET_CFLAGS) -o $@ $< 199 | sunxi-script_extractor: script_extractor.c 200 | $(CROSS_CC) $(TARGET_CFLAGS) -o $@ $< 201 | 202 | version.h: 203 | @./autoversion.sh > $@ 204 | 205 | .gitignore: Makefile 206 | @for x in $(TOOLS) $(FEXC_LINKS) $(TARGET_TOOLS) version.h '*.o' '*.swp'; do \ 207 | echo "$$x"; \ 208 | done | sort -V > $@ 209 | 210 | check: $(FEXC_LINKS) 211 | make -C tests/ 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sunxi-tools 2 | [![License](http://img.shields.io/badge/License-GPL-green.svg)](LICENSE.md) 3 | [![Build Status](https://travis-ci.org/linux-sunxi/sunxi-tools.svg?branch=master)](https://travis-ci.org/linux-sunxi/sunxi-tools) 4 | [![Releases](https://img.shields.io/github/release/linux-sunxi/sunxi-tools.svg)](https://github.com/linux-sunxi/sunxi-tools/releases) 5 | [![Commits](https://img.shields.io/github/commits-since/linux-sunxi/sunxi-tools/v1.4.svg)](https://github.com/linux-sunxi/sunxi-tools/compare/v1.4...master) 6 | 7 | Copyright (C) 2012 Alejandro Mery 8 |
For a full list of contributors, see 9 | [this link](https://github.com/linux-sunxi/sunxi-tools/contributors) 10 | or use the command `git shortlog -se --no-merges`. 11 | 12 | Command line utilities to work with devices based on [Allwinner SoC]s: 13 | sun4i, sun5i, ... - that's why the 'x' in the package name. 14 | 15 | ### sunxi-fexc 16 | `.fex` file (de)compiler 17 | 18 | Usage: ./sunxi-fexc [-vq] [-I ] [-O ] [ []] 19 | 20 | infmt: fex, bin (default:fex) 21 | outfmt: fex, bin (default:bin) 22 | 23 | ### bin2fex 24 | compatibility shortcut to call `sunxi-fexc` to decompile a _script.bin_ 25 | blob back into `.fex` format used by Allwinner's SDK to configure 26 | the boards. 27 | 28 | ### fex2bin 29 | compatiblity shortcut to call `sunxi-fexc` to compile a `.fex` file 30 | into the binary form used by the legacy 3.4 kernel ("linux-sunxi"). 31 | 32 | ### sunxi-fel 33 | script interface for USB communication with the FEL handler built in to 34 | the CPU. You usually activate [FEL mode] by pushing the _uboot_ / _recovery_ 35 | button at poweron, or by having your device "fail over" to FEL when no other 36 | boot option is available. See http://linux-sunxi.org/FEL/USBBoot for a detailed 37 | usage guide. 38 | 39 | When called with no arguments, _sunxi-fel_ will display a short usage summary. 40 | 41 | _Note:_ Unless you select a specific device using the `--dev` or `--sid` 42 | options, the tool will access the first Allwinner device (in FEL mode) that it 43 | finds. You can print a list of all FEL devices currently connected/detected 44 | with `./sunxi-fel --list --verbose`. 45 | 46 | ### fel-gpio 47 | Simple wrapper (script) around `sunxi-pio` and `sunxi-fel` 48 | to allow GPIO manipulations via FEL 49 | 50 | ### fel-sdboot 51 | ARM native sdcard bootloader forcing the device into FEL mode 52 | 53 | ### uart0-helloworld-sdboot 54 | ARM native sdcard bootloader, which is only printing a short "hello" 55 | message to the UART0 serial console. Because it relies on runtime 56 | SoC type detection, this single image is bootable on a wide range of 57 | Allwinner devices and can be used for testing. Additionally, it may 58 | serve as a template/example for developing simple bare metal code 59 | (LED blinking and other similar GPIO related things). 60 | 61 | ### sunxi-pio 62 | Manipulate PIO registers/dumps 63 | 64 | ### sunxi-nand-part 65 | Tool for manipulating Allwinner NAND partition tables 66 | 67 | ### sunxi-nand-image-builder 68 | Tool used to create raw NAND images (including boot0 images) 69 | 70 | ### jtag-loop.sunxi 71 | ARM native boot helper to force the SD port into JTAG and then stop, 72 | to ease debugging of bootloaders. 73 | 74 | ### sunxi-bootinfo 75 | Dump information from Allwinner boot files (_boot0_ / _boot1_) 76 | 77 | --type=sd include SD boot info 78 | --type=nand include NAND boot info (not implemented) 79 | 80 | ### phoenix_info 81 | gives information about a phoenix image created by the 82 | phoenixcard utility and optionally extracts the embedded boot 83 | code & firmware file from their hidden partitions. 84 | 85 | ### sunxi-meminfo 86 | Tool for reading DRAM settings from registers. Compiled as a 87 | static binary for use on android and other OSes. 88 | To build this, get a toolchain and run: 89 | 90 | make CROSS_COMPILE=arm-linux-gnueabihf- sunxi-meminfo 91 | 92 | ### sunxi-script_extractor 93 | A simple tool, which can be executed on a rooted Android device 94 | to dump the _script.bin_ blob from RAM via reading _/dev/mem_. 95 | To build this, get a toolchain and run: 96 | 97 | make CROSS_COMPILE=arm-linux-gnueabihf- sunxi-script_extractor 98 | --- 99 | 100 | ## Building 101 | 102 | Compilation requires the development version of *libusb-1.0* (include header 103 | and library) to be installed for `sunxi-fel`. Unless you explicitly pass 104 | *LIBUSB_CFLAGS* and *LIBUSB_LIBS* to the make utility, `pkg-config` is also 105 | needed. Development versions of zlib and libfdt are also required. 106 | 107 | To install the dependencies on Ubuntu 20.04 using package manager: 108 | 109 | ```bash 110 | sudo apt install libusb-1.0-0-dev libz-dev libfdt-dev 111 | ``` 112 | 113 | Available build targets: 114 | 115 | * `make tools` 116 | builds tools that are useful on the host. This is what most people will want, 117 | and our default target (when simply using `make`). 118 | 119 | * `make target-tools` 120 | builds tools that are intended for the target (Allwinner SoC), using a 121 | cross-compiler. The Makefile will try to auto-detect a suitable toolchain 122 | prefix, and falls back to `arm-none-eabi-` otherwise. 123 | If needed, you may override this by explicitly setting *CROSS_COMPILE*. 124 |
_Hint:_ When compiling 'natively' on the target platform you may 125 | simply use an empty toolchain prefix here (`make target-tools CROSS_COMPILE=` 126 | or `make all CROSS_COMPILE=`). 127 | 128 | * `make all` 129 | builds both *tools* and *target-tools*. 130 | 131 | * `make install-tools` 132 | builds *tools* and then copies/installs them to a filesystem location. The 133 | destination is affected by settings for `DESTDIR`, `PREFIX` and possibly 134 | `BINDIR`. For details, please refer to the *Makefile*. 135 | You may use `make install` as a shortcut for this. 136 | 137 | * `make install-target-tools` 138 | builds *target-tools* and then copies/installs them to a filesystem location 139 | selected by `DESTDIR`, `PREFIX` and possibly `BINDIR` - see `make install-tools` 140 | above. 141 | 142 | * `make install-all` 143 | builds and installs both *tools* and *target-tools*. 144 | 145 | * `make misc` 146 | builds miscellaneous (host) utilities that are not part of our 'standard' suite. 147 | Currently this means `phoenix_info` and `sunxi-nand-image-builder`. 148 | 149 | * `make install-misc` 150 | builds *misc* and installs the resulting binaries. 151 | 152 | ## License 153 | This software is licensed under the terms of GPLv2+ as defined by the 154 | Free Software Foundation, details can be read in the [LICENSE.md](LICENSE.md) 155 | file. 156 | 157 | [allwinner soc]: http://linux-sunxi.org/Allwinner_SoC_Family 158 | [fel mode]: http://linux-sunxi.org/FEL 159 | -------------------------------------------------------------------------------- /adb-devprobe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (C) 2012 Henrik Nordstrom 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | adb shell insmod /vendor/modules/sunxi-dbgreg.ko >/dev/null 24 | 25 | dump_io() 26 | { 27 | module=$1 28 | addr=$2 29 | len=$3 30 | 31 | for ((i = 0; i < len; i+=4)) { 32 | printf "%x %s " $((addr + i)) $module 33 | adb shell "echo `printf %x $((addr + i))` > /sys/devices/virtual/misc/sunxi-reg/rw/address; cat /sys/devices/virtual/misc/sunxi-reg/rw/value" 34 | echo 35 | } 36 | } 37 | 38 | dump_io SRAM 0xf1c00000 0x100 39 | dump_io DRAM 0xf1c01000 0x400 40 | dump_io CCM 0xf1c20000 0x400 41 | dump_io PIO 0xf1c20800 0x400 42 | 43 | dump_pmu() 44 | { 45 | for ((i = 0; i <0x100; i+=2)) { 46 | adb shell "echo `printf 0x%x $i` > /sys/bus/i2c/devices/0-0034/axp20_reg; cat /sys/bus/i2c/devices/0-0034/axp20_regs" 47 | } 48 | } 49 | 50 | dump_pmu 51 | -------------------------------------------------------------------------------- /autoversion.sh: -------------------------------------------------------------------------------- 1 | # 2 | # This script auto-updates a VERSION string definition. 3 | # It outputs informational messages to stderr, while the actual 4 | # output (on stdout) can easily be redirected to a file. 5 | # 6 | 7 | LATEST_RELEASE="v1.4.2" 8 | 9 | if VER=`git describe --tags --dirty --always`; then 10 | echo "Setting version information: ${VER}" >&2 11 | else 12 | VER=${LATEST_RELEASE} 13 | echo "Unable to determine current version (using \"${VER}\" as fallback)" >&2 14 | fi 15 | echo >&2 16 | 17 | echo "/* Auto-generated information. DO NOT EDIT */" 18 | echo "#define VERSION \"${VER}\"" 19 | -------------------------------------------------------------------------------- /bin/fel-sdboot.sunxi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-sunxi/sunxi-tools/7540cb235691be94ac5ef0181a73dd929949fc4e/bin/fel-sdboot.sunxi -------------------------------------------------------------------------------- /bin/jtag-loop.sunxi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-sunxi/sunxi-tools/7540cb235691be94ac5ef0181a73dd929949fc4e/bin/jtag-loop.sunxi -------------------------------------------------------------------------------- /bin/ramboot.scr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-sunxi/sunxi-tools/7540cb235691be94ac5ef0181a73dd929949fc4e/bin/ramboot.scr -------------------------------------------------------------------------------- /bin/ramboot.uboot-sh: -------------------------------------------------------------------------------- 1 | # U-boot RAM boot script 2 | ramdisk= 3 | if iminfo 0x4c000000; then 4 | ramdisk=0x4c000000 5 | fi 6 | setenv bootargs console=ttyS0,115200 rdinit=/sbin/init panic=10 7 | bootm 0x44000000 $ramdisk 8 | -------------------------------------------------------------------------------- /bin/uart0-helloworld-sdboot.sunxi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linux-sunxi/sunxi-tools/7540cb235691be94ac5ef0181a73dd929949fc4e/bin/uart0-helloworld-sdboot.sunxi -------------------------------------------------------------------------------- /boot_head.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Boot header to work around broken Allwinner A1x boot loaders 3 | * 4 | * Copyright (C) 2012 Henrik Nordstrom 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License as 8 | * published by the Free Software Foundation; either version 2 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 19 | * MA 02111-1307 USA 20 | * 21 | * 22 | * This file is a workaround to broken bootloaders on Allwinner A1x 23 | * platform who do not provide correct machid or atags address 24 | * 25 | * Usage: 26 | * load the header at 0x40007000 and change the entry point of your 27 | * boot process to 0x40007000 28 | * 29 | * Detailed memory map: 30 | * 0x40000100 atags 31 | * 0x40007000 boot_head (entry point) 32 | * 0x40008000 kernel 33 | * 0x43000000 script.bin 34 | * If you have a ramdisk then load it at some higher address 35 | */ 36 | 37 | _start: 38 | ldr r0, =0 39 | ldr r1, =MACHID 40 | ldr r2, =0x40000100 41 | ldr lr, =0x40008000 42 | bx lr 43 | -------------------------------------------------------------------------------- /boot_head.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x40007000; 21 | .text : { *(.text) } 22 | /DISCARD/ : { *(.dynstr*) } 23 | /DISCARD/ : { *(.dynamic*) } 24 | /DISCARD/ : { *(.plt*) } 25 | /DISCARD/ : { *(.interp*) } 26 | /DISCARD/ : { *(.gnu*) } 27 | /DISCARD/ : { *(.note*) } 28 | } 29 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_COMMON_H 18 | #define _SUNXI_TOOLS_COMMON_H 19 | 20 | #include /* offsetof */ 21 | 22 | #include "version.h" /* auto-generated VERSION string */ 23 | 24 | /** flag function argument as unused */ 25 | #ifdef UNUSED 26 | #elif defined(__GNUC__) 27 | # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) 28 | #else 29 | # define UNUSED(x) UNUSED_ ## x 30 | #endif 31 | 32 | /** finds the parent of an struct member */ 33 | #ifndef container_of 34 | #define container_of(P,T,M) (T *)((char *)(P) - offsetof(T, M)) 35 | #endif 36 | 37 | /** calculate number of elements of an array */ 38 | #ifndef ARRAY_SIZE 39 | #define ARRAY_SIZE(A) (sizeof(A)/sizeof((A)[0])) 40 | #endif 41 | 42 | /** shortcut to "printf to stderr" */ 43 | #define pr_error(...) fprintf(stderr, __VA_ARGS__) 44 | /** like pr_error(), but also exit program */ 45 | #define pr_fatal(...) \ 46 | do { pr_error(__VA_ARGS__); exit(EXIT_FAILURE); } while (0); 47 | 48 | #endif /* _SUNXI_TOOLS_COMMON_H */ 49 | -------------------------------------------------------------------------------- /fel-gpio: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Copyright (C) 2012,2013 Henrik Nordstrom 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | pio_base=0x01c20800 24 | pio_size=0x228 25 | sram_addr=0x3000 26 | 27 | # read PIO 28 | ./sunxi-fel memmove $sram_addr $pio_base $pio_size 29 | ./sunxi-fel read $sram_addr $pio_size pio.reg 30 | ./sunxi-pio -i pio.reg print > pio.old 31 | cat pio.old | fgrep -v '<0><0><0><0>' 32 | 33 | while read cmd; do 34 | ./sunxi-pio -i pio.reg -o pio.reg $cmd 35 | # write PIO 36 | ./sunxi-fel write $sram_addr pio.reg 37 | ./sunxi-fel memmove $pio_base $sram_addr $pio_size 38 | # (re-)read PIO 39 | ./sunxi-fel memmove $sram_addr $pio_base $pio_size 40 | ./sunxi-fel read $sram_addr $pio_size pio.reg 41 | ./sunxi-pio -i pio.reg print > pio.new 42 | diff -U0 pio.old pio.new || true 43 | mv -f pio.new pio.old 44 | done 45 | -------------------------------------------------------------------------------- /fel-remotefunc-compiler.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # (C) Copyright 2016 Siarhei Siamashka 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | if ARGV.size < 2 20 | printf("Usage: #{$PROGRAM_NAME} [c_source_input] [marshalled_header_output]\n\n") 21 | 22 | printf("This script uses an ARM toolchain to compile native ARM code, and then\n") 23 | printf("automatically generates the necessary wrapper code for calling it from\n") 24 | printf("the sunxi-fel tool. Executing such compiled pieces of code natively on\n") 25 | printf("the device may be needed for the performance critical parts.\n") 26 | 27 | printf("\nExample input file:\n\n") 28 | printf(" unsigned sum(unsigned a, unsigned b)\n") 29 | printf(" {\n") 30 | printf(" return a + b;\n") 31 | printf(" }\n") 32 | printf("\n") 33 | printf("Using this example code inside of sunxi-fel:\n") 34 | printf("\n") 35 | printf(" uint32_t a = 1, b = 2, c;\n") 36 | printf(" aw_fel_remotefunc_prepare_sum(dev, a, b);\n") 37 | printf(" aw_fel_remotefunc_execute(dev, &c);\n") 38 | printf(" printf(\"%%d + %%d = %%d\\n\", a, b, c);\n\n") 39 | 40 | printf("If the returned result is not needed (a void function), then the second\n") 41 | printf("argument to the 'aw_fel_remotefunc_execute' function can be NULL.\n\n") 42 | exit(1) 43 | end 44 | 45 | def tool_exists(tool_name) 46 | `which #{tool_name} > /dev/null 2>&1` 47 | return $?.to_i == 0 48 | end 49 | 50 | def parse_stack_usage(filename) 51 | return unless File.exist?(filename) 52 | File.read(filename).strip.split("\n").map do |l| 53 | if l =~ /\:([^\:\s]+)\s+(\d+)\s+(\S+)/ 54 | if $3 != "static" 55 | abort sprintf("Non-static stack usage for function '%s'\n", $1) 56 | end 57 | {function_name: $1, stack_usage: $2.to_i} 58 | else 59 | abort sprintf("Failed to parse stack usage information '%s'\n", l.strip) 60 | end 61 | end 62 | end 63 | 64 | toolchains = [ 65 | "arm-none-eabi-", 66 | "arm-linux-gnueabihf-", 67 | "arm-none-linux-gnueabi-", 68 | "armv7a-hardfloat-linux-gnueabi-", 69 | ] 70 | 71 | toolchain = toolchains.find { |toolchain| tool_exists("#{toolchain}gcc") } 72 | abort "Can't find any usable ARM crosscompiler.\n" unless toolchain 73 | 74 | # Compile the source file 75 | system("#{toolchain}gcc -c -Os -marm -march=armv5te -mfloat-abi=soft -fstack-usage -fpic -o #{ARGV[0]}.o #{ARGV[0]}") 76 | exit($?.to_i) if $?.to_i != 0 77 | 78 | # Read the stack usage information 79 | stack_usage = parse_stack_usage("#{ARGV[0]}.su") 80 | if stack_usage.size != 1 81 | abort sprintf("Expected only one function in the source file, but got %s.\n", 82 | stack_usage.map {|a| "'" + a[:function_name] + "()'" }.join(", ")) 83 | end 84 | 85 | `#{toolchain}size -A #{ARGV[0]}.o`.each_line do |l| 86 | if l =~ /(\S+)\s+(\S+)/ 87 | if ($1 == ".data" || $1 == ".bss" || $1 == ".rodata") && $2.to_i > 0 88 | abort "Can't have non-empty '.data', '.bss' or '.rodata' section." 89 | end 90 | end 91 | end 92 | 93 | `#{toolchain}objdump -t #{ARGV[0]}.o`.each_line do |l| 94 | if l =~ /\*UND\*/ 95 | abort "External references are not allowed: '#{l.strip}'.\n" 96 | end 97 | end 98 | 99 | function_name = stack_usage[0][:function_name] 100 | 101 | # Read the source file and strip multiline C comments 102 | sourcefile = File.read(ARGV[0]).gsub(/\/\*.*?\*\//m, "") 103 | 104 | # Try to find the function and its arguments 105 | unless sourcefile =~ /#{function_name}\((.*?)\)/m 106 | abort sprintf("Can't find the function '%s()' in the source file.\n", 107 | function_name) 108 | end 109 | 110 | # Extract the function argument names 111 | function_args = $1.split(",").map {|a| if a.strip =~ /([^\*\s]+)$/ then $1 end } 112 | 113 | # Check if there is any return value 114 | have_retval = !(sourcefile =~ /void\s+#{function_name}/m) 115 | 116 | ############################################################################### 117 | # Generate output file 118 | ############################################################################### 119 | 120 | out = File.open(ARGV[1], "w") 121 | 122 | out.printf("/* Automatically generated, do not edit! */\n\n") 123 | 124 | out.printf("static void\n") 125 | funcdecl = sprintf("aw_fel_remotefunc_prepare_#{function_name}(feldev_handle *dev,") 126 | out.printf("%s\n", funcdecl) 127 | out.printf("%s", function_args.map {|a| 128 | " " * funcdecl.index("(") + " uint32_t " + a }.join(",\n")) 129 | out.printf(")\n{\n") 130 | 131 | out.printf("\tstatic uint8_t arm_code[] = {\n") 132 | `#{toolchain}objdump -d #{ARGV[0]}.o`.each_line {|l| 133 | next unless l =~ /(\h+)\:\s+(\h+)\s+(\S+)\s+([^;]*)/ 134 | addr = $1 135 | opcode = $2 136 | p1 = $3 137 | p2 = $4.strip 138 | opcode = opcode.scan(/../).map {|a| "0x" + a }.reverse.join(", ") 139 | out.printf("\t\t%s, /* %4s: %-8s %-34s \x2a/\n", opcode, addr, p1, p2) 140 | } 141 | out.printf("\t};\n") 142 | 143 | out.printf("\tuint32_t args[] = {\n\t\t") 144 | out.printf("%s\n\t};\n", function_args.join(",\n\t\t")) 145 | 146 | out.printf("\taw_fel_remotefunc_prepare(dev, %d, arm_code, sizeof(arm_code), %d, args);\n", 147 | stack_usage[0][:stack_usage], function_args.size) 148 | 149 | out.printf("}\n") 150 | -------------------------------------------------------------------------------- /fel-remotefunc-spi-data-transfer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2016 Siarhei Siamashka 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice (including the next 12 | * paragraph) shall be included in all copies or substantial portions of the 13 | * Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | * DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | typedef unsigned int u32; 25 | typedef unsigned char u8; 26 | 27 | #define readl(addr) (*((volatile u32 *)(addr))) 28 | #define writel(v, addr) (*((volatile u32 *)(addr)) = (u32)(v)) 29 | #define readb(addr) (*((volatile u8 *)(addr))) 30 | #define writeb(v, addr) (*((volatile u8 *)(addr)) = (u8)(v)) 31 | 32 | /* 33 | * This is a basic full-duplex SPI data transfer function (we are sending a 34 | * block of data and receiving the same amount of data back), doing the job 35 | * without any help from DMA. And because we can be running in some rather 36 | * adverse conditions (with default PMIC settings, low CPU clock speed and 37 | * CPU caches disabled), it is necessary to use 32-bit accesses to read/write 38 | * the FIFO buffers. As a result, Allwinner A13 with the default 408MHz CPU 39 | * clock speed can successfully handle at least 12 MHz SPI clock speed. 40 | * 41 | * Supports both sun4i and sun6i variants of the SPI controller (they only 42 | * need different hardware register addresses passed as arguments). 43 | */ 44 | static void inline __attribute((always_inline)) spi_data_transfer(void *buf, 45 | u32 bufsize, 46 | void *spi_ctl_reg, 47 | u32 spi_ctl_xch_bitmask, 48 | void *spi_fifo_reg, 49 | void *spi_tx_reg, 50 | void *spi_rx_reg, 51 | void *spi_bc_reg, 52 | void *spi_tc_reg, 53 | void *spi_bcc_reg) 54 | { 55 | u32 cnt; 56 | u32 rxsize = bufsize; 57 | u32 txsize = bufsize; 58 | u8 *rxbuf8 = buf; 59 | u8 *txbuf8 = buf; 60 | u32 *rxbuf; 61 | u32 *txbuf; 62 | u32 cpsr; 63 | 64 | /* sun6i uses 3 registers, sun4i only needs 2 */ 65 | writel(bufsize, spi_bc_reg); 66 | writel(bufsize, spi_tc_reg); 67 | if (spi_bcc_reg) 68 | writel(bufsize, spi_bcc_reg); 69 | 70 | /* Fill the TX buffer with some initial data */ 71 | cnt = (-(u32)txbuf8 & 3) + 60; 72 | if (cnt > txsize) 73 | cnt = txsize; 74 | while (cnt-- > 0) { 75 | writeb(*txbuf8++, spi_tx_reg); 76 | txsize--; 77 | } 78 | 79 | /* Temporarily disable IRQ & FIQ */ 80 | asm volatile("mrs %0, cpsr" : "=r" (cpsr)); 81 | asm volatile("msr cpsr_c, %0" :: "r" (cpsr | 0xC0)); 82 | 83 | /* Start the data transfer */ 84 | writel(readl(spi_ctl_reg) | spi_ctl_xch_bitmask, spi_ctl_reg); 85 | 86 | /* Read the initial unaligned part of the data */ 87 | cnt = (-(u32)rxbuf8 & 3); 88 | if (cnt > rxsize) 89 | cnt = rxsize; 90 | while (cnt > 0) { 91 | u32 fiforeg = readl(spi_fifo_reg); 92 | int rxfifo = fiforeg & 0x7F; 93 | if (rxfifo > 0) { 94 | *rxbuf8++ = readb(spi_rx_reg); 95 | cnt--; 96 | rxsize--; 97 | } 98 | } 99 | 100 | /* Fast processing of the aligned part (read/write 32-bit at a time) */ 101 | rxbuf = (u32 *)rxbuf8; 102 | txbuf = (u32 *)txbuf8; 103 | while (rxsize >= 4) { 104 | u32 fiforeg = readl(spi_fifo_reg); 105 | int rxfifo = fiforeg & 0x7F; 106 | int txfifo = (fiforeg >> 16) & 0x7F; 107 | if (rxfifo >= 4) { 108 | *rxbuf++ = readl(spi_rx_reg); 109 | rxsize -= 4; 110 | } 111 | if (txfifo < 60 && txsize >= 4) { 112 | writel(*txbuf++, spi_tx_reg); 113 | txsize -= 4; 114 | } 115 | } 116 | 117 | /* Handle the trailing part pf the data */ 118 | rxbuf8 = (u8 *)rxbuf; 119 | txbuf8 = (u8 *)txbuf; 120 | while (rxsize >= 1) { 121 | u32 fiforeg = readl(spi_fifo_reg); 122 | int rxfifo = fiforeg & 0x7F; 123 | int txfifo = (fiforeg >> 16) & 0x7F; 124 | if (rxfifo >= 1) { 125 | *rxbuf8++ = readb(spi_rx_reg); 126 | rxsize -= 1; 127 | } 128 | if (txfifo < 60 && txsize >= 1) { 129 | writeb(*txbuf8++, spi_tx_reg); 130 | txsize -= 1; 131 | } 132 | } 133 | 134 | /* Restore CPSR */ 135 | asm volatile("msr cpsr_c, %0" :: "r" (cpsr)); 136 | } 137 | 138 | void spi_batch_data_transfer(u8 *buf, 139 | void *spi_ctl_reg, 140 | u32 spi_ctl_xch_bitmask, 141 | void *spi_fifo_reg, 142 | void *spi_tx_reg, 143 | void *spi_rx_reg, 144 | void *spi_bc_reg, 145 | void *spi_tc_reg, 146 | void *spi_bcc_reg) 147 | { 148 | u8 wait_for_completion_cmd[2]; 149 | u8 *backup_buf; 150 | u32 bufsize; 151 | 152 | while (1) { 153 | u32 code = (buf[0] << 8) | buf[1]; 154 | 155 | /* End of data */ 156 | if (code == 0) 157 | return; 158 | 159 | if (code == 0xFFFF) { 160 | /* Wait for completion, part 1 */ 161 | backup_buf = buf; 162 | buf = wait_for_completion_cmd; 163 | wait_for_completion_cmd[0] = 0x05; 164 | bufsize = 2; 165 | } else { 166 | /* Normal buffer */ 167 | buf += 2; 168 | bufsize = code; 169 | } 170 | 171 | spi_data_transfer(buf, bufsize, spi_ctl_reg, spi_ctl_xch_bitmask, 172 | spi_fifo_reg, spi_tx_reg, spi_rx_reg, 173 | spi_bc_reg, spi_tc_reg, spi_bcc_reg); 174 | buf += bufsize; 175 | 176 | if (code == 0xFFFF) { 177 | /* Wait for completion, part 2 */ 178 | buf = backup_buf; 179 | if (wait_for_completion_cmd[1] & 1) { 180 | /* Still busy */ 181 | continue; 182 | } 183 | /* Advance to the next code */ 184 | buf = backup_buf + 2; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /fel-sdboot.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Bernhard Nortmann 3 | * 4 | * Based on previous works 5 | * Copyright (C) 2016 Siarhei Siamashka 6 | * Copyright (C) 2012 Henrik Nordstrom 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of 11 | * the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 | * MA 02111-1307 USA 22 | * 23 | */ 24 | 25 | /* 26 | * This file is a utility stub (bootloader code) to force the device into 27 | * FEL mode, by jumping directly to the corresponding (N-)BROM entry point. 28 | * 29 | * Build instructions: 30 | * make fel-sdboot.sunxi 31 | * 32 | * If needed, adjust CROSS_COMPILE and MKSUNXIBOOT according to your 33 | * toolchain, e.g. 34 | * make fel-sdboot.sunxi CROSS_COMPILE=armv7a-hardfloat-linux-gnueabi- \ 35 | * MKSUNXIBOOT=/usr/local/bin/mksunxiboot 36 | * 37 | * 38 | * Install instructions: 39 | * dd if=fel-sdboot.sunxi of=/dev/sdX bs=1024 seek=8 40 | */ 41 | 42 | SCTRL .req r0 43 | .equ V_BIT, (1 << 13) 44 | 45 | .equ BROM_ENTRY_LOW, 0x00000020 46 | .equ BROM_ENTRY_HIGH, 0xFFFF0020 47 | 48 | /* 49 | * In cases where insufficient padding is added by an old mksunxiboot, 50 | * _start may be 0x20, which means that the instruction at 0x28 could get 51 | * corrupted by the BROM - see https://patchwork.ozlabs.org/patch/622173/ 52 | * 53 | * Apply a workaround to avoid (= skip over) that memory location. 54 | * _main would be at 0x30 in that particular case. With newer (properly 55 | * fixed) versions of mksunxiboot, this code ends up at higher addresses 56 | * and will be moot, but harmless. 57 | */ 58 | _start: 59 | b _main 60 | nop 61 | nop 62 | nop 63 | 64 | _main: 65 | mrc p15, 0, SCTRL, c1, c0, 0 66 | tst SCTRL, #V_BIT @ test SCTRL.V 67 | moveq lr, #BROM_ENTRY_LOW 68 | ldrne lr, =BROM_ENTRY_HIGH 69 | bx lr 70 | -------------------------------------------------------------------------------- /fel-sdboot.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x0030; 21 | .text : { *(.text) } 22 | /DISCARD/ : { *(.dynstr*) } 23 | /DISCARD/ : { *(.dynamic*) } 24 | /DISCARD/ : { *(.plt*) } 25 | /DISCARD/ : { *(.interp*) } 26 | /DISCARD/ : { *(.gnu*) } 27 | /DISCARD/ : { *(.note*) } 28 | } 29 | -------------------------------------------------------------------------------- /fel-spiflash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2016 Siarhei Siamashka 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef _SUNXI_TOOLS_FEL_SPIFLASH_H 19 | #define _SUNXI_TOOLS_FEL_SPIFLASH_H 20 | 21 | #include "fel_lib.h" 22 | #include "progress.h" 23 | 24 | void aw_fel_spiflash_read(feldev_handle *dev, 25 | uint32_t offset, void *buf, size_t len, 26 | progress_cb_t progress); 27 | void aw_fel_spiflash_write(feldev_handle *dev, 28 | uint32_t offset, void *buf, size_t len, 29 | progress_cb_t progress); 30 | void aw_fel_spiflash_info(feldev_handle *dev); 31 | void aw_fel_spiflash_help(void); 32 | void aw_fel_spi0_init(feldev_handle *dev); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /fel_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Bernhard Nortmann 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_FEL_LIB_H 18 | #define _SUNXI_TOOLS_FEL_LIB_H 19 | 20 | #include 21 | #include 22 | #include "progress.h" 23 | #include "soc_info.h" 24 | 25 | /* USB identifiers for Allwinner device in FEL mode */ 26 | #define AW_USB_VENDOR_ID 0x1F3A 27 | #define AW_USB_PRODUCT_ID 0xEFE8 28 | 29 | typedef struct _felusb_handle felusb_handle; /* opaque data type */ 30 | 31 | /* More general FEL "device" handle, including version data and SoC info */ 32 | typedef struct { 33 | felusb_handle *usb; 34 | struct aw_fel_version soc_version; 35 | soc_name_t soc_name; 36 | soc_info_t *soc_info; 37 | } feldev_handle; 38 | 39 | /* list_fel_devices() will return an array of this type */ 40 | typedef struct { 41 | int busnum, devnum; 42 | struct aw_fel_version soc_version; 43 | soc_name_t soc_name; 44 | soc_info_t *soc_info; 45 | uint32_t SID[4]; 46 | } feldev_list_entry; 47 | 48 | /* FEL device management */ 49 | 50 | void feldev_init(void); 51 | void feldev_done(feldev_handle *dev); 52 | 53 | feldev_handle *feldev_open(int busnum, int devnum, 54 | uint16_t vendor_id, uint16_t product_id); 55 | void feldev_close(feldev_handle *dev); 56 | 57 | feldev_list_entry *list_fel_devices(size_t *count); 58 | 59 | /* FEL functions */ 60 | 61 | void aw_fel_read(feldev_handle *dev, uint32_t offset, void *buf, size_t len); 62 | void aw_fel_write(feldev_handle *dev, const void *buf, uint32_t offset, size_t len); 63 | void aw_fel_write_buffer(feldev_handle *dev, const void *buf, uint32_t offset, 64 | size_t len, bool progress); 65 | void aw_fel_execute(feldev_handle *dev, uint32_t offset); 66 | 67 | void fel_readl_n(feldev_handle *dev, uint32_t addr, uint32_t *dst, size_t count); 68 | void fel_writel_n(feldev_handle *dev, uint32_t addr, uint32_t *src, size_t count); 69 | 70 | void fel_memmove(feldev_handle *dev, 71 | uint32_t dst_addr, uint32_t src_addr, size_t size); 72 | 73 | void fel_clrsetbits_le32(feldev_handle *dev, 74 | uint32_t addr, uint32_t clrbits, uint32_t setbits); 75 | #define fel_clrbits_le32(dev, addr, value) \ 76 | fel_clrsetbits_le32(dev, addr, value, 0) 77 | #define fel_setbits_le32(dev, addr, value) \ 78 | fel_clrsetbits_le32(dev, addr, 0, value) 79 | 80 | int fel_read_sid(feldev_handle *dev, uint32_t *result, 81 | unsigned int offset, unsigned int length, 82 | bool force_workaround); 83 | 84 | bool aw_fel_remotefunc_prepare(feldev_handle *dev, 85 | size_t stack_size, 86 | void *arm_code, 87 | size_t arm_code_size, 88 | size_t num_args, 89 | uint32_t *args); 90 | bool aw_fel_remotefunc_execute(feldev_handle *dev, uint32_t *result); 91 | 92 | #endif /* _SUNXI_TOOLS_FEL_LIB_H */ 93 | -------------------------------------------------------------------------------- /fexc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "fexc.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #ifndef NO_MMAP 25 | #include 26 | #endif 27 | #include 28 | #include 29 | #include 30 | 31 | #define pr_info(...) pr_error("fexc: " __VA_ARGS__) 32 | #define pr_err(...) pr_error("E: fexc: " __VA_ARGS__) 33 | 34 | enum script_format { 35 | FEX_SCRIPT_FORMAT, 36 | BIN_SCRIPT_FORMAT, 37 | UBOOT_HEADER_FORMAT, 38 | }; 39 | 40 | /* 41 | */ 42 | static inline char *read_all(int fd, const char *filename, size_t *size) 43 | { 44 | size_t buf_size = 4096, count = 0; 45 | char *p, *buf = malloc(buf_size); 46 | if (!buf) { 47 | pr_err("%s: %s\n", "malloc", strerror(errno)); 48 | return NULL; 49 | } 50 | p = buf; 51 | while (1) { 52 | ssize_t rc = read(fd, p, buf_size-count); 53 | if (rc == 0) 54 | break; 55 | else if (rc > 0) { 56 | count += rc; 57 | p += rc; 58 | 59 | if (count == buf_size) { 60 | char *new; 61 | buf_size *= 2; 62 | new = realloc(buf, buf_size); 63 | if (!new) { 64 | pr_err("%s: %s\n", "realloc", 65 | strerror(errno)); 66 | free(buf); 67 | return NULL; 68 | } else if (new != buf) { 69 | buf = new; 70 | p = buf + count; 71 | } 72 | } 73 | } else if (errno != EAGAIN && errno != EINTR) { 74 | pr_err("%s: %s: %s\n", filename, 75 | "read", strerror(errno)); 76 | free(buf); 77 | return NULL; 78 | } 79 | } 80 | 81 | *size = count; 82 | return buf; 83 | } 84 | 85 | /* 86 | */ 87 | static inline int script_parse(enum script_format format, 88 | const char *filename, 89 | struct script *script) 90 | { 91 | int ret = 0; 92 | switch (format) { 93 | case FEX_SCRIPT_FORMAT: { 94 | FILE *in = stdin; 95 | if (!filename) 96 | filename = ""; 97 | else if ((in = fopen(filename, "r")) == NULL) { 98 | pr_err("%s: %s\n", filename, strerror(errno)); 99 | break; 100 | } 101 | ret = script_parse_fex(in, filename, script); 102 | fclose(in); 103 | }; break; 104 | case BIN_SCRIPT_FORMAT: { 105 | int in = 0; /* stdin */ 106 | struct stat sb; 107 | void *bin = NULL; 108 | size_t bin_size; 109 | int allocated = 1; 110 | 111 | if (!filename) 112 | filename = ""; 113 | else if ((in = open(filename, O_RDONLY)) < 0) { 114 | pr_err("%s: %s\n", filename, strerror(errno)); 115 | break; 116 | } 117 | 118 | if (fstat(in, &sb) == -1) { 119 | pr_err("%s: %s: %s\n", filename, 120 | "fstat", strerror(errno)); 121 | goto bin_close; 122 | #ifndef NO_MMAP 123 | } else if (S_ISREG(sb.st_mode)) { 124 | /* regular file, mmap it */ 125 | bin = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, in, 0); 126 | if (bin == MAP_FAILED) { 127 | pr_err("%s: %s: %s\n", filename, 128 | "mmap", strerror(errno)); 129 | goto bin_close; 130 | } 131 | bin_size = sb.st_size; 132 | allocated = 0; 133 | #endif 134 | } else { 135 | /* something else... just read it all! */ 136 | bin = read_all(in, filename, &bin_size); 137 | if (bin == NULL) 138 | goto bin_close; 139 | allocated = 1; 140 | } 141 | 142 | ret = script_decompile_bin(bin, bin_size, filename, script); 143 | if (allocated) 144 | free(bin); 145 | #ifndef NO_MMAP 146 | else if (munmap(bin, bin_size) == -1) { 147 | pr_err("%s: %s: %s\n", filename, 148 | "munmap", strerror(errno)); 149 | } 150 | #endif 151 | bin_close: 152 | close(in); 153 | }; break; 154 | case UBOOT_HEADER_FORMAT: /* not valid input */ 155 | ; 156 | } 157 | return ret; 158 | } 159 | static inline int script_generate(enum script_format format, 160 | const char *filename, 161 | struct script *script) 162 | { 163 | int ret = 0; 164 | static int (*text_gen[3]) (FILE *, const char *, struct script *) = { 165 | [FEX_SCRIPT_FORMAT] = script_generate_fex, 166 | [UBOOT_HEADER_FORMAT] = script_generate_uboot, 167 | }; 168 | 169 | if (text_gen[format]) { 170 | FILE *out = stdout; 171 | 172 | if (!filename) 173 | filename = ""; 174 | else if ((out = fopen(filename, "w")) == NULL) { 175 | pr_err("%s: %s\n", filename, strerror(errno)); 176 | goto done; 177 | } 178 | 179 | ret = text_gen[format](out, filename, script); 180 | fclose(out); 181 | } else { 182 | int out = 1; /* stdout */ 183 | size_t sections, entries, bin_size; 184 | void *bin; 185 | 186 | if (!filename) 187 | filename = ""; 188 | else if ((out = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { 189 | pr_err("%s: %s\n", filename, strerror(errno)); 190 | goto done; 191 | } 192 | 193 | bin_size = script_bin_size(script, §ions, &entries); 194 | bin = calloc(1, bin_size); 195 | if (!bin) 196 | pr_err("%s: %s\n", "malloc", strerror(errno)); 197 | else if (script_generate_bin(bin, bin_size, script, sections, entries)) { 198 | char *p = bin; 199 | while(bin_size) { 200 | ssize_t wc = write(out, p, bin_size); 201 | 202 | if (wc>0) { 203 | p += wc; 204 | bin_size -= wc; 205 | } else if (wc < 0 && errno != EINTR) { 206 | pr_err("%s: %s: %s\n", filename, 207 | "write", strerror(errno)); 208 | break; 209 | } 210 | } 211 | ret = (bin_size == 0); 212 | } 213 | free(bin); 214 | close(out); 215 | } 216 | done: 217 | return ret; 218 | } 219 | 220 | /* 221 | */ 222 | static inline void app_usage(const char *arg0, int mode) 223 | { 224 | fputs("sunxi-fexc " VERSION "\n\n", stderr); 225 | pr_error("Usage: %s [-vq]%s[ []]\n", arg0, 226 | mode ? " " : " [-I ] [-O ] "); 227 | 228 | if (mode == 0) 229 | fputs("\ninfmt: fex, bin (default:fex)" 230 | "\noutfmt: fex, bin, uboot (default:bin)\n", 231 | stderr); 232 | } 233 | 234 | static inline int app_choose_mode(char *arg0) 235 | { 236 | const char *name = basename(arg0); 237 | if (strcmp(name, "fex2bin") == 0) 238 | return 1; 239 | else if (strcmp(name, "bin2fex") == 0) 240 | return 2; 241 | else 242 | return 0; 243 | } 244 | 245 | /* 246 | */ 247 | int main(int argc, char *argv[]) 248 | { 249 | static const char *formats[] = { "fex", "bin", "uboot", NULL }; 250 | enum script_format infmt=FEX_SCRIPT_FORMAT; 251 | enum script_format outfmt=BIN_SCRIPT_FORMAT; 252 | const char *filename[] = { NULL /*stdin*/, NULL /*stdout*/}; 253 | struct script *script; 254 | 255 | int app_mode = app_choose_mode(argv[0]); 256 | 257 | const char *opt_string = "I:O:vq?"; 258 | if (app_mode != 0) opt_string += 4; /* disallow -I and -O */ 259 | int opt, ret = 1; 260 | int verbose = 0; 261 | 262 | if (app_mode == 2) { /* bin2fex */ 263 | infmt = BIN_SCRIPT_FORMAT; 264 | outfmt = FEX_SCRIPT_FORMAT; 265 | } 266 | 267 | while ((opt = getopt(argc, argv, opt_string)) != -1) { 268 | switch (opt) { 269 | case 'I': 270 | infmt=0; 271 | for (const char **f = formats; *f; f++, infmt++) { 272 | if (strcmp(*f, optarg) == 0) 273 | break; 274 | } 275 | switch (infmt) { 276 | case FEX_SCRIPT_FORMAT: 277 | case BIN_SCRIPT_FORMAT: 278 | break; 279 | default: 280 | pr_error("%s: invalid format -- \"%s\"\n", 281 | argv[0], optarg); 282 | goto show_usage; 283 | } 284 | break; 285 | case 'O': 286 | outfmt=0; 287 | for (const char **f = formats; *f; f++, outfmt++) { 288 | if (strcmp(*f, optarg) == 0) 289 | break; 290 | } 291 | if (!formats[outfmt]) { 292 | pr_error("%s: invalid format -- \"%s\"\n", 293 | argv[0], optarg); 294 | goto show_usage; 295 | } 296 | break; 297 | case 'v': 298 | verbose++; 299 | break; 300 | case 'q': 301 | verbose--; 302 | break; 303 | default: 304 | show_usage: 305 | app_usage(argv[0], app_mode); 306 | goto done; 307 | } 308 | } 309 | 310 | switch (argc - optind) { 311 | case 2: 312 | filename[1] = argv[optind+1]; /* out */ 313 | /* fall-through */ 314 | case 1: 315 | if (strcmp(argv[optind], "-") != 0) 316 | filename[0] = argv[optind]; /* in */ 317 | case 0: 318 | break; 319 | default: 320 | goto show_usage; 321 | } 322 | 323 | if (verbose>0) 324 | pr_error("%s: from %s:%s to %s:%s\n", argv[0], 325 | formats[infmt], filename[0]?filename[0]:"", 326 | formats[outfmt], filename[1]?filename[1]:""); 327 | 328 | if ((script = script_new()) == NULL) { 329 | perror("malloc"); 330 | goto done; 331 | } else if (script_parse(infmt, filename[0], script) && 332 | script_generate(outfmt, filename[1], script)) { 333 | ret = 0; 334 | } 335 | script_delete(script); 336 | done: 337 | return ret; 338 | } 339 | -------------------------------------------------------------------------------- /fexc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_FEXC_H 18 | #define _SUNXI_TOOLS_FEXC_H 19 | 20 | #include "common.h" 21 | 22 | #include 23 | #include 24 | 25 | #include "script.h" 26 | #include "script_bin.h" 27 | #include "script_fex.h" 28 | #include "script_uboot.h" 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /find-arm-gcc.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Try to locate suitable ARM cross compilers available via $PATH 3 | # If any are found, this function will output them as a TAB-delimited list 4 | # 5 | scan_path () { 6 | IFS=":" 7 | for path in $PATH; do 8 | find "$path" -maxdepth 1 -executable -name 'arm*-gcc' -printf '%f\t' 2>/dev/null 9 | done 10 | } 11 | 12 | # Use only the first field from result, and convert it to a toolchain prefix 13 | scan_path | cut -f 1 | sed -e 's/-gcc/-/' 14 | -------------------------------------------------------------------------------- /fit_image.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Andre Przywara 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; under version 2 of the License. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "common.h" 22 | #include "fel_lib.h" 23 | #include "fit_image.h" 24 | 25 | /* defined in fel.c */ 26 | extern bool verbose; 27 | 28 | #define IH_ARCH_INVALID 0 29 | #define IH_ARCH_ARM 2 30 | #define IH_ARCH_ARM64 22 31 | 32 | #define IH_OS_INVALID 0 33 | #define IH_OS_LINUX 5 34 | #define IH_OS_U_BOOT 17 35 | #define IH_OS_ARM_TRUSTED_FIRMWARE 25 36 | #define IH_OS_EFI 28 37 | 38 | struct fit_image_info { 39 | const char *description; 40 | const char *data; 41 | uint32_t data_size; 42 | uint32_t load_addr; 43 | uint32_t entry_point; 44 | uint8_t os; 45 | uint8_t arch; 46 | }; 47 | 48 | static int fit_parse_os(const char *value) 49 | { 50 | if (!value || !*value) 51 | return IH_OS_INVALID; 52 | 53 | if (!strcmp(value, "u-boot")) 54 | return IH_OS_U_BOOT; 55 | if (!strcmp(value, "linux")) 56 | return IH_OS_LINUX; 57 | if (!strcmp(value, "arm-trusted-firmware")) 58 | return IH_OS_ARM_TRUSTED_FIRMWARE; 59 | if (!strcmp(value, "efi")) 60 | return IH_OS_EFI; 61 | 62 | return IH_OS_INVALID; 63 | } 64 | 65 | static int fit_parse_arch(const char *value) 66 | { 67 | if (!value || !*value) 68 | return IH_ARCH_INVALID; 69 | 70 | if (!strcmp(value, "arm")) 71 | return IH_ARCH_ARM; 72 | if (!strcmp(value, "arm64")) 73 | return IH_ARCH_ARM64; 74 | 75 | return IH_ARCH_INVALID; 76 | } 77 | 78 | static uint32_t fdt_getprop_u32(const void *fdt, int node, const char *name) 79 | { 80 | const fdt32_t *val; 81 | 82 | val = fdt_getprop(fdt, node, name, NULL); 83 | if (!val) 84 | return ~0U; 85 | 86 | return fdt32_to_cpu(*val); 87 | } 88 | 89 | static const char *fdt_getprop_str(const void *fdt, int node, const char *name) 90 | { 91 | const struct fdt_property *prop; 92 | 93 | prop = fdt_get_property(fdt, node, name, NULL); 94 | if (!prop) 95 | return NULL; 96 | 97 | return prop->data; 98 | } 99 | 100 | /* 101 | * Find the image with the given name under the /images node, and parse 102 | * its information into the fit_image_info struct. 103 | * Returns 0 on success, and a negative error value otherwise. 104 | */ 105 | static int fit_get_image_info(const void *fit, const char *name, 106 | struct fit_image_info *info) 107 | { 108 | int node; 109 | const char *str; 110 | uint32_t data_offset; 111 | 112 | node = fdt_path_offset(fit, "/images"); 113 | if (node < 0) 114 | return -1; 115 | node = fdt_subnode_offset(fit, node, name); 116 | if (node < 0) 117 | return -1; 118 | 119 | info->load_addr = fdt_getprop_u32(fit, node, "load"); 120 | info->entry_point = fdt_getprop_u32(fit, node, "entry"); 121 | info->description = fdt_getprop_str(fit, node, "description"); 122 | /* properties used for FIT images with external data */ 123 | info->data_size = fdt_getprop_u32(fit, node, "data-size"); 124 | data_offset = fdt_getprop_u32(fit, node, "data-offset"); 125 | 126 | /* check for embedded data (when invalid external data properties) */ 127 | if (info->data_size == ~0U || data_offset == ~0U) { 128 | const struct fdt_property *prop; 129 | int len; 130 | 131 | prop = fdt_get_property(fit, node, "data", &len); 132 | info->data_size = len; 133 | info->data = prop->data; 134 | } else { 135 | /* external data is appended at the end of the FIT DTB blob */ 136 | info->data = (const char *)fit + ((fdt_totalsize(fit) + 3) & ~3U); 137 | info->data += data_offset; 138 | } 139 | 140 | info->os = fit_parse_os(fdt_getprop_str(fit, node, "os")); 141 | info->arch = fit_parse_arch(fdt_getprop_str(fit, node, "arch")); 142 | 143 | str = fdt_getprop_str(fit, node, "compression"); 144 | /* The current SPL does not support compression either. */ 145 | if (str && strcmp(str, "none")) { 146 | printf("compression \"%s\" not supported for image \"%s\"\n", 147 | str, info->description); 148 | return -2; 149 | } 150 | 151 | return 0; 152 | } 153 | 154 | static int entry_arch; 155 | static uint32_t dtb_addr; 156 | 157 | /* 158 | * Upload the image described by its fit_image_info struct to the board. 159 | * Detect if an image contains an entry point and return that. 160 | * Set entry_arch to arm or arm64 on the way. Also detect the image 161 | * containing U-Boot and record its end address, so that the DTB can be 162 | * appended later on. 163 | * Returns the entry point if any is specified, or 0 otherwise. 164 | */ 165 | static uint32_t fit_load_image(feldev_handle *dev, struct fit_image_info *img) 166 | { 167 | uint32_t ret = 0; 168 | 169 | if (verbose) 170 | printf("loading image \"%s\" (%d bytes) to 0x%x\n", 171 | img->description, img->data_size, img->load_addr); 172 | aw_fel_write_buffer(dev, img->data, 173 | img->load_addr, img->data_size, true); 174 | 175 | if (img->entry_point != ~0U) { 176 | ret = img->entry_point; 177 | entry_arch = img->arch; 178 | } 179 | /* either explicitly marked as U-Boot, or the first invalid one */ 180 | if (img->os == IH_OS_U_BOOT || 181 | (!dtb_addr && img->os == IH_OS_INVALID)) 182 | dtb_addr = img->load_addr + img->data_size; 183 | 184 | return ret; 185 | } 186 | 187 | uint32_t load_fit_images(feldev_handle *dev, const void *fit, 188 | const char *dt_name, bool *use_aarch64) 189 | { 190 | const struct fdt_property *prop; 191 | struct fit_image_info img; 192 | const char *str; 193 | int node, len; 194 | uint32_t entry_point = 0; 195 | 196 | node = fdt_path_offset(fit, "/configurations"); 197 | if (node < 0) { 198 | pr_error("invalid FIT image, no /configurations node\n"); 199 | return 0; 200 | } 201 | 202 | /* 203 | * Find the right configuration node, either by using the provided 204 | * DT name as an identifier, falling back to the node titled "default", 205 | * or by using just the first node. 206 | */ 207 | if (dt_name) { 208 | for (node = fdt_first_subnode(fit, node); 209 | node >= 0; 210 | node = fdt_next_subnode(fit, node)) { 211 | prop = fdt_get_property(fit, node, "description", NULL); 212 | if (prop && !strcmp(prop->data, dt_name)) 213 | break; 214 | } 215 | if (node < 0) { 216 | pr_error("no matching FIT configuration node for \"%s\"\n", 217 | dt_name); 218 | return 0; 219 | } 220 | } else { 221 | prop = fdt_get_property(fit, node, "default", NULL); 222 | if (!prop) 223 | node = fdt_first_subnode(fit, node); 224 | else 225 | node = fdt_subnode_offset(fit, node, prop->data); 226 | if (node < 0) { 227 | pr_error("no default FIT configuration node\n"); 228 | return 0; 229 | } 230 | } 231 | 232 | entry_arch = IH_ARCH_INVALID; 233 | dtb_addr = 0; 234 | 235 | /* Load the image described as "firmware". */ 236 | str = fdt_getprop_str(fit, node, "firmware"); 237 | if (str && !fit_get_image_info(fit, str, &img)) { 238 | uint32_t addr = fit_load_image(dev, &img); 239 | 240 | if (addr != 0) 241 | entry_point = addr; 242 | } else { 243 | printf("WARNING: no valid \"firmware\" image entry in FIT\n"); 244 | } 245 | 246 | /* load all loadables, at their respective load addresses */ 247 | prop = fdt_get_property(fit, node, "loadables", &len); 248 | for (str = prop ? prop->data : NULL; 249 | prop && (str - prop->data) < len && *str; 250 | str += strlen(str) + 1) { 251 | uint32_t addr; 252 | 253 | if (fit_get_image_info(fit, str, &img)) { 254 | printf("Can't load loadable \"%s\", skipping.\n", str); 255 | continue; 256 | } 257 | addr = fit_load_image(dev, &img); 258 | if (addr != 0) 259 | entry_point = addr; 260 | } 261 | 262 | if (use_aarch64) 263 | *use_aarch64 = (entry_arch == IH_ARCH_ARM64); 264 | 265 | if (!dtb_addr) { 266 | printf("Warning: no U-Boot image found, not loading DTB\n"); 267 | return entry_point; 268 | } 269 | 270 | /* load .dtb right after the U-Boot image (appended DTB) */ 271 | str = fdt_getprop_str(fit, node, "fdt"); 272 | if (!str || fit_get_image_info(fit, str, &img)) { 273 | printf("Warning: no FDT found in FIT image\n"); 274 | return entry_point; 275 | } 276 | if (verbose) 277 | printf("loading DTB \"%s\" (%d bytes)\n", img.description, 278 | img.data_size); 279 | aw_fel_write_buffer(dev, img.data, dtb_addr, img.data_size, false); 280 | 281 | return entry_point; 282 | } 283 | -------------------------------------------------------------------------------- /fit_image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020 Andre Przywara 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; under version 2 of the License. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | */ 16 | 17 | #ifndef __FIT_IMAGE_H__ 18 | #define __FIT_IMAGE_H__ 19 | 20 | #include 21 | #include "fel_lib.h" 22 | 23 | /* 24 | * Load all images referenced in the given U-Boot FIT image. @dt_name will 25 | * be used to select one of the configurations. @use_aarch64 contains the 26 | * target architecture of the entry point. 27 | * Returns the entry point address of the image to be started. 28 | */ 29 | uint32_t load_fit_images(feldev_handle *dev, const void *fit, 30 | const char *dt_name, bool *use_aarch64); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_LIST_H 18 | #define _SUNXI_TOOLS_LIST_H 19 | 20 | /* 21 | * list 22 | */ 23 | 24 | /** a list hook */ 25 | struct list_entry { 26 | struct list_entry *prev; 27 | struct list_entry *next; 28 | }; 29 | 30 | /** initialize an empty list hook */ 31 | static inline void list_init(struct list_entry *self) 32 | { 33 | self->prev = self->next = self; 34 | } 35 | 36 | /** puts an entry between two other on a list */ 37 | static inline void list_inject(struct list_entry *l, 38 | struct list_entry *prev, 39 | struct list_entry *next) 40 | { 41 | l->prev = prev; 42 | l->next = next; 43 | 44 | next->prev = l; 45 | prev->next = l; 46 | } 47 | 48 | #define list_insert(H, E) list_inject((E), (H), (H)->next) 49 | #define list_append(H, E) list_inject((E), (H)->prev, (H)) 50 | 51 | /** removes an entry for the list where it's contained */ 52 | static inline void list_remove(struct list_entry *l) 53 | { 54 | struct list_entry *prev = l->prev, *next = l->next; 55 | next->prev = prev; 56 | prev->next = next; 57 | } 58 | 59 | /** returns first element of a list */ 60 | static inline struct list_entry *list_first(struct list_entry *l) 61 | { 62 | return (l->next == l) ? NULL : l->next; 63 | } 64 | 65 | /** returns last element of a list */ 66 | static inline struct list_entry *list_last(struct list_entry *l) 67 | { 68 | return (l->prev == l) ? NULL : l->prev; 69 | } 70 | 71 | /** returns next element on a list */ 72 | static inline struct list_entry *list_next(struct list_entry *l, 73 | struct list_entry *e) 74 | { 75 | return (e->next == l) ? NULL : e->next; 76 | } 77 | 78 | /** is list empty? */ 79 | static inline int list_empty(struct list_entry *l) 80 | { 81 | return (l->prev == l); 82 | } 83 | 84 | #endif /* _SUNXI_TOOLS_LIST_H */ 85 | -------------------------------------------------------------------------------- /include/portable_endian.h: -------------------------------------------------------------------------------- 1 | // "License": Public Domain 2 | // I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. 3 | // In case there are jurisdictions that don't support putting things in the public domain you can also consider it to 4 | // be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it 5 | // an example on how to get the endian conversion functions on different platforms. 6 | 7 | #ifndef PORTABLE_ENDIAN_H__ 8 | #define PORTABLE_ENDIAN_H__ 9 | 10 | #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) 11 | 12 | # define __WINDOWS__ 13 | 14 | #endif 15 | 16 | #if defined(__linux__) || defined(__CYGWIN__) 17 | 18 | # include 19 | 20 | #elif defined(__APPLE__) 21 | 22 | # include 23 | 24 | # define htobe16(x) OSSwapHostToBigInt16(x) 25 | # define htole16(x) OSSwapHostToLittleInt16(x) 26 | # define be16toh(x) OSSwapBigToHostInt16(x) 27 | # define le16toh(x) OSSwapLittleToHostInt16(x) 28 | 29 | # define htobe32(x) OSSwapHostToBigInt32(x) 30 | # define htole32(x) OSSwapHostToLittleInt32(x) 31 | # define be32toh(x) OSSwapBigToHostInt32(x) 32 | # define le32toh(x) OSSwapLittleToHostInt32(x) 33 | 34 | # define htobe64(x) OSSwapHostToBigInt64(x) 35 | # define htole64(x) OSSwapHostToLittleInt64(x) 36 | # define be64toh(x) OSSwapBigToHostInt64(x) 37 | # define le64toh(x) OSSwapLittleToHostInt64(x) 38 | 39 | # define __BYTE_ORDER BYTE_ORDER 40 | # define __BIG_ENDIAN BIG_ENDIAN 41 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 42 | # define __PDP_ENDIAN PDP_ENDIAN 43 | 44 | #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) 45 | 46 | # include 47 | 48 | /* For functions still missing, try to substitute 'historic' OpenBSD names */ 49 | #ifndef be16toh 50 | # define be16toh(x) betoh16(x) 51 | #endif 52 | #ifndef le16toh 53 | # define le16toh(x) letoh16(x) 54 | #endif 55 | #ifndef be32toh 56 | # define be32toh(x) betoh32(x) 57 | #endif 58 | #ifndef le32toh 59 | # define le32toh(x) letoh32(x) 60 | #endif 61 | #ifndef be64toh 62 | # define be64toh(x) betoh64(x) 63 | #endif 64 | #ifndef le64toh 65 | # define le64toh(x) letoh64(x) 66 | #endif 67 | 68 | #elif defined(__WINDOWS__) 69 | 70 | # include 71 | # include 72 | 73 | # if BYTE_ORDER == LITTLE_ENDIAN 74 | 75 | # define htobe16(x) htons(x) 76 | # define htole16(x) (x) 77 | # define be16toh(x) ntohs(x) 78 | # define le16toh(x) (x) 79 | 80 | # define htobe32(x) htonl(x) 81 | # define htole32(x) (x) 82 | # define be32toh(x) ntohl(x) 83 | # define le32toh(x) (x) 84 | 85 | # define htobe64(x) htonll(x) 86 | # define htole64(x) (x) 87 | # define be64toh(x) ntohll(x) 88 | # define le64toh(x) (x) 89 | 90 | # elif BYTE_ORDER == BIG_ENDIAN 91 | 92 | /* that would be xbox 360 */ 93 | # define htobe16(x) (x) 94 | # define htole16(x) __builtin_bswap16(x) 95 | # define be16toh(x) (x) 96 | # define le16toh(x) __builtin_bswap16(x) 97 | 98 | # define htobe32(x) (x) 99 | # define htole32(x) __builtin_bswap32(x) 100 | # define be32toh(x) (x) 101 | # define le32toh(x) __builtin_bswap32(x) 102 | 103 | # define htobe64(x) (x) 104 | # define htole64(x) __builtin_bswap64(x) 105 | # define be64toh(x) (x) 106 | # define le64toh(x) __builtin_bswap64(x) 107 | 108 | # else 109 | 110 | # error byte order not supported 111 | 112 | # endif 113 | 114 | # define __BYTE_ORDER BYTE_ORDER 115 | # define __BIG_ENDIAN BIG_ENDIAN 116 | # define __LITTLE_ENDIAN LITTLE_ENDIAN 117 | # define __PDP_ENDIAN PDP_ENDIAN 118 | 119 | #else 120 | 121 | # error platform not supported 122 | 123 | #endif 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2012 Henrik Nordstrom 3 | * (C) Copyright 2012 Alejandro Mery 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | */ 20 | 21 | #ifndef SUNXI_TYPES_H 22 | #define SUNXI_TYPES_H 23 | 24 | #include 25 | 26 | #define __s8 int8_t 27 | #define __s16 int16_t 28 | #define __s32 int32_t 29 | #define __s64 int64_t 30 | 31 | #define s8 int8_t 32 | #define s16 int16_t 33 | #define s32 int32_t 34 | #define s64 int64_t 35 | 36 | #define __u8 uint8_t 37 | #define __u16 uint16_t 38 | #define __u32 uint32_t 39 | #define __u64 uint64_t 40 | 41 | #define u8 uint8_t 42 | #define u16 uint16_t 43 | #define u32 uint32_t 44 | #define u64 uint64_t 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /jtag-loop.S: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2012 Jens Andersen 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17 | * MA 02111-1307 USA 18 | */ 19 | 20 | /* 21 | 22 | Build instructions: 23 | 24 | arm-none-linux-gnueabi-gcc -g -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder jtag-loop.S -c 25 | 26 | arm-none-linux-gnueabi-objcopy -O binary jtag-loop.o jtag-loop.bin 27 | 28 | mksunxiboot jtag-loop.bin jtag-loop.sunxi 29 | */ 30 | 31 | .file "fel-loop.S" 32 | .global entry 33 | .text 34 | .code 32 35 | .section ".start", "ax" 36 | 37 | entry: 38 | ldr r0,=0x01c208b4 39 | ldr r1,=0x00444444 40 | str r1, [r0] 41 | b . 42 | -------------------------------------------------------------------------------- /jtag-loop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2012 Jens Andersen 3 | * (C) Copyright 2012 Henrik Nordstrom 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | */ 20 | 21 | /* 22 | 23 | Build instructions: 24 | 25 | arm-none-linux-gnueabi-gcc -g -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder -Os jtag-loop.c -c 26 | 27 | arm-none-linux-gnueabi-objcopy -O binary jtag-loop.o jtag-loop.bin 28 | 29 | mksunxiboot jtag-loop.bin jtag-loop.sunxi 30 | */ 31 | 32 | void _start(void) 33 | { 34 | *(volatile unsigned long *)0x01c208b4 = 0x00444444; 35 | while(1); 36 | } 37 | -------------------------------------------------------------------------------- /jtag-loop.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x0030; 21 | .text : { *(.text) } 22 | /DISCARD/ : { *(.dynstr*) } 23 | /DISCARD/ : { *(.dynamic*) } 24 | /DISCARD/ : { *(.plt*) } 25 | /DISCARD/ : { *(.interp*) } 26 | /DISCARD/ : { *(.gnu*) } 27 | /DISCARD/ : { *(.note*) } 28 | } 29 | -------------------------------------------------------------------------------- /nand-common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2013 3 | * Patrick H Wood, All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | * 20 | */ 21 | 22 | #include "types.h" 23 | 24 | extern int nand_part_a10 (int argc, char **argv, const char *cmd, int fd, int force); 25 | extern int nand_part_a20 (int argc, char **argv, const char *cmd, int fd, int force); 26 | extern int checkmbrs_a10 (int fd); 27 | extern int checkmbrs_a20 (int fd); 28 | extern void usage (const char *cmd); 29 | extern __u32 calc_crc32(void * buffer, __u32 length); 30 | -------------------------------------------------------------------------------- /nand-part-a10.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/block/sun4i_nand/nfd/mbr.h 3 | * 4 | * (C) Copyright 2007-2012 5 | * Allwinner Technology Co., Ltd. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 | * MA 02111-1307 USA 21 | */ 22 | 23 | #ifndef __MBR_H__ 24 | #define __MBR_H__ 25 | 26 | #include "types.h" 27 | 28 | #define MBR_MAGIC "softw311" 29 | #define MBR_VERSION 0x100 30 | #define nand_part nand_part_a10 31 | #define checkmbrs checkmbrs_a10 32 | 33 | #define MAX_PART_COUNT 15 //max part count 34 | #define MBR_COPY_NUM 4 //mbr backup count 35 | 36 | #define MBR_START_ADDRESS 0x0 //mbr start address 37 | #define MBR_SIZE 1024 //mbr size 38 | #define MBR_RESERVED (MBR_SIZE - 20 - (MAX_PART_COUNT * 64)) //mbr reserved space 39 | 40 | // extern struct __NandDriverGlobal_t NandDriverInfo; 41 | 42 | // extern struct __NandStorageInfo_t NandStorageInfo; 43 | 44 | #define DiskSize (SECTOR_CNT_OF_SINGLE_PAGE * PAGE_CNT_OF_PHY_BLK * BLOCK_CNT_OF_DIE * \ 45 | DIE_CNT_OF_CHIP * NandStorageInfo.ChipCnt / 1024 * DATA_BLK_CNT_OF_ZONE) 46 | 47 | 48 | struct nand_disk{ 49 | unsigned long size; 50 | unsigned long offset; 51 | unsigned char type; 52 | }; 53 | 54 | /* part info */ 55 | typedef struct tag_PARTITION{ 56 | __u32 addrhi; //start address high 32 bit 57 | __u32 addrlo; //start address low 32 bit 58 | __u32 lenhi; //size high 32 bit 59 | __u32 lenlo; //size low 32 bit 60 | __u8 classname[12]; //major device name 61 | __u8 name[12]; //minor device name 62 | unsigned int user_type; //标志当前盘符所属于的用户 63 | unsigned int ro; //标志当前盘符的读写属性 64 | __u8 res[16]; //reserved 65 | }PARTITION; 66 | 67 | /* mbr info */ 68 | typedef struct tag_MBR{ 69 | __u32 crc32; // crc, from byte 4 to mbr tail 70 | __u32 version; // version 71 | __u8 magic[8]; // magic number 72 | __u8 copy; // mbr backup count 73 | __u8 index; // current part no 74 | __u16 PartCount; // part counter 75 | PARTITION array[MAX_PART_COUNT];// part info 76 | __u8 res[MBR_RESERVED]; // reserved space 77 | }MBR; 78 | 79 | int mbr2disks(struct nand_disk* disk_array); 80 | 81 | #endif //__MBR_H__ 82 | -------------------------------------------------------------------------------- /nand-part-a20.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/block/sun4i_nand/nfd/mbr.h 3 | * 4 | * (C) Copyright 2007-2012 5 | * Allwinner Technology Co., Ltd. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of 10 | * the License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 | * MA 02111-1307 USA 21 | */ 22 | 23 | #ifndef __MBR_H__ 24 | #define __MBR_H__ 25 | 26 | #include "types.h" 27 | 28 | #define MBR_MAGIC "softw411" 29 | #define MBR_VERSION 0x200 30 | #define nand_part nand_part_a20 31 | #define checkmbrs checkmbrs_a20 32 | 33 | #define MAX_PART_COUNT 120 //max part count 34 | #define MBR_COPY_NUM 4 //mbr backup count 35 | 36 | #define MBR_START_ADDRESS 0x0 //mbr start address 37 | #define MBR_SIZE 1024*16 //mbr size 38 | #define MBR_RESERVED (MBR_SIZE - 32 - (MAX_PART_COUNT * 128)) //mbr reserved space 39 | 40 | // extern struct __NandDriverGlobal_t NandDriverInfo; 41 | 42 | // extern struct __NandStorageInfo_t NandStorageInfo; 43 | 44 | #define DiskSize (SECTOR_CNT_OF_SINGLE_PAGE * PAGE_CNT_OF_PHY_BLK * BLOCK_CNT_OF_DIE * \ 45 | DIE_CNT_OF_CHIP * NandStorageInfo.ChipCnt / 1024 * DATA_BLK_CNT_OF_ZONE) 46 | 47 | 48 | struct nand_disk{ 49 | unsigned long size; 50 | unsigned long offset; 51 | unsigned char type; 52 | }; 53 | 54 | /* part info */ 55 | typedef struct nand_tag_PARTITION{ 56 | unsigned int addrhi; //起始地址, 以扇区为单位 57 | unsigned int addrlo; // 58 | unsigned int lenhi; //长度 59 | unsigned int lenlo; // 60 | unsigned char classname[16]; //次设备名 61 | unsigned char name[16]; //主设备名 62 | unsigned int user_type; //用户类型 63 | unsigned int keydata; //关键数据,要求量产不丢失 64 | unsigned int ro; //读写属性 65 | unsigned char res[68]; //保留数据,匹配分区信息128字节 66 | }__attribute__ ((packed))PARTITION; 67 | 68 | /* mbr info */ 69 | typedef struct nand_tag_MBR{ 70 | unsigned int crc32; // crc 1k - 4 71 | unsigned int version; // 版本信息, 0x00000100 72 | unsigned char magic[8]; //"softw411" 73 | unsigned int copy; //分数 74 | unsigned int index; //第几个MBR备份 75 | unsigned int PartCount; //分区个数 76 | unsigned int stamp[1]; //对齐 77 | PARTITION array[MAX_PART_COUNT]; // 78 | unsigned char res[MBR_RESERVED]; 79 | }__attribute__ ((packed)) MBR; 80 | 81 | int mbr2disks(struct nand_disk* disk_array); 82 | 83 | #endif //__MBR_H__ 84 | -------------------------------------------------------------------------------- /nand-part-main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2013 3 | * Patrick H Wood, All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License as 7 | * published by the Free Software Foundation; either version 2 of 8 | * the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 18 | * MA 02111-1307 USA 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "nand-common.h" 27 | #include "common.h" 28 | 29 | void usage(const char *cmd) 30 | { 31 | puts("sunxi-nand-part " VERSION "\n"); 32 | printf("usage: %s [-f a10|a20] nand-device\n", cmd); 33 | printf(" %s nand-device 'name2 len2 [usertype2]' ['name3 len3 [usertype3]'] ...\n", cmd); 34 | printf(" %s [-f a10|a20] nand-device start1 'name1 len1 [usertype1]' ['name2 len2 [usertype2]'] ...\n", cmd); 35 | } 36 | 37 | typedef struct tag_CRC32_DATA 38 | { 39 | __u32 CRC; //int的大小是32位 40 | __u32 CRC_32_Tbl[256]; //用来保存码表 41 | }CRC32_DATA_t; 42 | 43 | __u32 calc_crc32(void * buffer, __u32 length) 44 | { 45 | __u32 i, j; 46 | CRC32_DATA_t crc32; // 47 | __u32 CRC32 = 0xffffffff; //设置初始值 48 | crc32.CRC = 0; 49 | 50 | for( i = 0; i < 256; ++i)//用++i以提高效率 51 | { 52 | crc32.CRC = i; 53 | for( j = 0; j < 8 ; ++j) 54 | { 55 | //这个循环实际上就是用"计算法"来求取CRC的校验码 56 | if(crc32.CRC & 1) 57 | crc32.CRC = (crc32.CRC >> 1) ^ 0xEDB88320; 58 | else //0xEDB88320就是CRC-32多项表达式的值 59 | crc32.CRC >>= 1; 60 | } 61 | crc32.CRC_32_Tbl[i] = crc32.CRC; 62 | } 63 | 64 | CRC32 = 0xffffffff; //设置初始值 65 | for( i = 0; i < length; ++i) 66 | { 67 | CRC32 = crc32.CRC_32_Tbl[(CRC32^((unsigned char*)buffer)[i]) & 0xff] ^ (CRC32>>8); 68 | } 69 | //return CRC32; 70 | return CRC32^0xffffffff; 71 | } 72 | 73 | int main (int argc, char **argv) 74 | { 75 | char *nand = "/dev/nand"; 76 | const char *cmd = argv[0]; 77 | int fd; 78 | int force = 0; // force write even if magics and CRCs don't match 79 | 80 | argc--; 81 | argv++; 82 | 83 | if (argc > 1) { 84 | if (!strcmp(argv[0], "-f")) { 85 | if (!strcasecmp(argv[1], "a10")) 86 | force = 10; 87 | else if (!strcasecmp(argv[1], "a20")) 88 | force = 20; 89 | else { 90 | usage(cmd); 91 | return -1; 92 | } 93 | argc -= 2; 94 | argv += 2; 95 | } 96 | } 97 | 98 | if (argc > 0) { 99 | nand = argv[0]; 100 | argc--; 101 | argv++; 102 | } 103 | fd = open(nand, O_RDWR); 104 | if (fd < 0) { 105 | usage(cmd); 106 | return -2; 107 | } 108 | if (force == 10) 109 | return nand_part_a10 (argc, argv, cmd, fd, force); 110 | if (force == 20) 111 | return nand_part_a20 (argc, argv, cmd, fd, force); 112 | 113 | if (checkmbrs_a10(fd)) 114 | return nand_part_a10 (argc, argv, cmd, fd, force); 115 | if (checkmbrs_a20(fd)) 116 | return nand_part_a20 (argc, argv, cmd, fd, force); 117 | } 118 | -------------------------------------------------------------------------------- /nand-part.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mbr.c 3 | * (C) Copyright 2012 4 | * Patrick H Wood, All rights reserved. 5 | * Heavily modified from the Allwinner file drivers/block/sun4i_nand/nfd/mbr.c. 6 | * (Allwinner copyright block retained below.) 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of 11 | * the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 | * MA 02111-1307 USA 22 | * 23 | */ 24 | 25 | /* 26 | * drivers/block/sun4i_nand/nfd/mbr.c 27 | * (C) Copyright 2007-2012 28 | * Allwinner Technology Co., Ltd. 29 | * 30 | * This program is free software; you can redistribute it and/or 31 | * modify it under the terms of the GNU General Public License as 32 | * published by the Free Software Foundation; either version 2 of 33 | * the License, or (at your option) any later version. 34 | * 35 | * This program is distributed in the hope that it will be useful, 36 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | * GNU General Public License for more details. 39 | * 40 | * You should have received a copy of the GNU General Public License 41 | * along with this program; if not, write to the Free Software 42 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 43 | * MA 02111-1307 USA 44 | */ 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #ifdef __linux__ 54 | # include 55 | # include /* BLKRRPART */ 56 | #endif 57 | #include "nand-common.h" 58 | 59 | // so far, only known formats are for A10 and A20 60 | #if defined(A10) 61 | # include "nand-part-a10.h" 62 | #elif defined(A20) 63 | # include "nand-part-a20.h" 64 | #endif 65 | 66 | #define MAX_NAME 16 67 | 68 | static void printmbrheader(MBR *mbr) 69 | { 70 | printf("mbr: version 0x%08x, magic %8.8s\n", mbr->version, mbr->magic); 71 | } 72 | 73 | static MBR *_get_mbr(int fd, int mbr_num, int force) 74 | { 75 | MBR *mbr; 76 | 77 | /*request mbr space*/ 78 | mbr = malloc(sizeof(MBR)); 79 | if(mbr == NULL) 80 | { 81 | printf("%s : request memory fail\n",__FUNCTION__); 82 | return NULL; 83 | } 84 | 85 | /*get mbr from nand device*/ 86 | lseek(fd,MBR_START_ADDRESS + MBR_SIZE*mbr_num,SEEK_SET); 87 | if(read(fd,mbr,MBR_SIZE) == MBR_SIZE) 88 | { 89 | /*checksum*/ 90 | printf("check partition table copy %d: ", mbr_num); 91 | printmbrheader(mbr); 92 | if (force) { 93 | memcpy(mbr->magic, MBR_MAGIC, 8); 94 | mbr->version = MBR_VERSION; 95 | return mbr; 96 | } 97 | if(strncmp((char *)mbr->magic, MBR_MAGIC, 8)) 98 | { 99 | printf("magic %8.8s is not %8s\n", mbr->magic, MBR_MAGIC); 100 | return NULL; 101 | } 102 | if(mbr->version != MBR_VERSION) 103 | { 104 | printf("version 0x%08x is not 0x%08x\n", mbr->version, MBR_VERSION); 105 | return NULL; 106 | } 107 | if(*(__u32 *)mbr == calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4)) 108 | { 109 | printf("OK\n"); 110 | return mbr; 111 | } 112 | printf("BAD!\n"); 113 | } 114 | return NULL; 115 | } 116 | 117 | static __s32 _free_mbr(MBR *mbr) 118 | { 119 | if(mbr) 120 | { 121 | free(mbr); 122 | mbr = 0; 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | static void printmbr(MBR *mbr) 129 | { 130 | unsigned int part_cnt; 131 | 132 | printmbrheader(mbr); 133 | printf("%d partitions\n", mbr->PartCount); 134 | for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++) 135 | { 136 | printf("partition %2d: class = %12s, name = %12s, partition start = %8d, partition size = %8d user_type=%d\n", 137 | part_cnt + 1, 138 | mbr->array[part_cnt].classname, 139 | mbr->array[part_cnt].name, 140 | mbr->array[part_cnt].addrlo, 141 | mbr->array[part_cnt].lenlo, 142 | mbr->array[part_cnt].user_type); 143 | } 144 | } 145 | int checkmbrs(int fd) 146 | { 147 | int i; 148 | MBR *mbrs[MBR_COPY_NUM]; 149 | MBR *mbr = NULL; 150 | 151 | memset((void *) mbrs, 0, sizeof(mbrs)); 152 | for (i = 0; i < MBR_COPY_NUM; i++) { 153 | mbrs[i] = _get_mbr(fd, i, 0); 154 | if (mbrs[i]) 155 | mbr = mbrs[i]; 156 | } 157 | if (!mbr) { 158 | printf("all partition tables are bad!\n"); 159 | for (i = 0; i < MBR_COPY_NUM; i++) { 160 | if (mbrs[i]) 161 | _free_mbr(mbrs[i]); 162 | } 163 | return 0; 164 | } 165 | 166 | printmbr(mbr); 167 | for (i = 0; i < MBR_COPY_NUM; i++) { 168 | if (mbrs[i]) 169 | _free_mbr(mbrs[i]); 170 | } 171 | return 1; 172 | } 173 | 174 | static int writembrs(int fd, char names[][MAX_NAME], __u32 start, __u32 *lens, unsigned int *user_types, int nparts, int partoffset, int force) 175 | { 176 | unsigned int part_cnt = 0; 177 | int i; 178 | char yn = 'n'; 179 | MBR *mbrs[MBR_COPY_NUM]; 180 | MBR *mbr = NULL; 181 | FILE *backup; 182 | 183 | memset((void *) mbrs, 0, sizeof(mbrs)); 184 | for (i = 0; i < MBR_COPY_NUM; i++) { 185 | mbrs[i] = _get_mbr(fd, i, force); 186 | if (mbrs[i]) 187 | mbr = mbrs[i]; 188 | } 189 | if (!mbr) { 190 | printf("all partition tables are bad!\n"); 191 | for (i = 0; i < MBR_COPY_NUM; i++) { 192 | if (mbrs[i]) 193 | _free_mbr(mbrs[i]); 194 | } 195 | return 0; 196 | } 197 | // back up mbr data 198 | backup = fopen("nand_mbr.backup", "w"); 199 | if (!backup) { 200 | printf("can't open nand_mbr.backup to back up mbr data\n"); 201 | for (i = 0; i < MBR_COPY_NUM; i++) { 202 | if (mbrs[i]) 203 | _free_mbr(mbrs[i]); 204 | } 205 | return 0; 206 | } 207 | 208 | fprintf(backup, "%d ", mbr->array[0].addrlo); 209 | for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++) 210 | { 211 | fprintf(backup, "'%s %d %d' ", mbr->array[part_cnt].name, 212 | mbr->array[part_cnt].lenlo, mbr->array[part_cnt].user_type); 213 | } 214 | fprintf(backup, "\n"); 215 | fclose(backup); 216 | 217 | mbr->PartCount = nparts + partoffset; 218 | if (partoffset) 219 | start = mbr->array[0].addrlo + mbr->array[0].lenlo; 220 | for(i = 0; i < nparts; i++) { 221 | strcpy((char *)mbr->array[i+partoffset].name, names[i]); 222 | strcpy((char *)mbr->array[i+partoffset].classname, "DISK"); 223 | memset((void *) mbr->array[i+partoffset].res, 0, sizeof(mbr->array[i+partoffset].res)); 224 | mbr->array[i+partoffset].user_type = user_types[i]; 225 | mbr->array[i+partoffset].ro = 0; 226 | mbr->array[i+partoffset].addrhi = 0; 227 | mbr->array[i+partoffset].lenhi = 0; 228 | mbr->array[i+partoffset].addrlo = start; 229 | mbr->array[i+partoffset].lenlo = lens[i]; 230 | start += lens[i]; 231 | } 232 | 233 | printf("\nready to write new partition tables:\n"); 234 | printmbr(mbr); 235 | for (i = 0; i < MBR_COPY_NUM; i++) { 236 | if (mbrs[i]) 237 | _free_mbr(mbrs[i]); 238 | } 239 | printf("\nwrite new partition tables? (Y/N)\n"); 240 | read(0, &yn, 1); 241 | if (yn != 'Y' && yn != 'y') { 242 | printf("aborting\n"); 243 | return 0; 244 | } 245 | 246 | for (i = 0; i < MBR_COPY_NUM; i++) { 247 | mbr->index = i; 248 | // calculate new checksum 249 | *(__u32 *)mbr = calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4); 250 | lseek(fd,MBR_START_ADDRESS + MBR_SIZE*i,SEEK_SET); 251 | write(fd,mbr,MBR_SIZE); 252 | } 253 | 254 | #ifdef __linux__ 255 | if (ioctl(fd, BLKRRPART, NULL)) 256 | perror("Failed rereading partition table"); 257 | #endif 258 | 259 | return 1; 260 | } 261 | 262 | int nand_part (int argc, char **argv, const char *cmd, int fd, int force) 263 | { 264 | int partoffset = 0; 265 | int i; 266 | char names[MAX_PART_COUNT][MAX_NAME]; 267 | __u32 lens[MAX_PART_COUNT]; 268 | unsigned int user_types[MAX_PART_COUNT]; 269 | __u32 start; 270 | 271 | 272 | // parse name/len arguments 273 | memset((void *) user_types, 0, sizeof(user_types)); 274 | if (argc > 0) { 275 | if (sscanf(argv[0], "%u", &start) != 1) { 276 | partoffset++; 277 | if (force) { 278 | printf("if using -f, must set info for first partition\n"); 279 | usage(cmd); 280 | close(fd); 281 | return -3; 282 | } 283 | } 284 | else { 285 | argc--; 286 | argv++; 287 | } 288 | 289 | if (start < MBR_SIZE * MBR_COPY_NUM / 512) { 290 | printf("Partition 1 starting offset must be at least %d\n", MBR_SIZE * MBR_COPY_NUM / 512); 291 | close(fd); 292 | return -3; 293 | } 294 | 295 | for (i = 0; i < argc; i++) { 296 | if (sscanf(argv[i], "%s %d %d", names[i], &lens[i], &user_types[i]) < 2) { 297 | printf("bad 'name len' argument\n"); 298 | usage(cmd); 299 | close(fd); 300 | return -3; 301 | } 302 | } 303 | } 304 | 305 | checkmbrs(fd); 306 | 307 | if (argc > MAX_PART_COUNT - partoffset) { 308 | printf("too many partitions specified (MAX 14)\n"); 309 | usage(cmd); 310 | close(fd); 311 | return -2; 312 | } 313 | 314 | 315 | if (argc > 0) { 316 | if (writembrs(fd, names, start, lens, user_types, argc, partoffset, force)) { 317 | printf("\nverifying new partition tables:\n"); 318 | checkmbrs(fd); 319 | #ifdef __linux__ 320 | printf("rereading partition table... returned %d\n", ioctl(fd, BLKRRPART, 0)); 321 | #endif 322 | } 323 | } 324 | close(fd); 325 | 326 | return 0; 327 | } 328 | -------------------------------------------------------------------------------- /phoenix_info.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Henrik Nordstrom 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "common.h" 24 | #include "portable_endian.h" 25 | 26 | struct phoenix_ptable { 27 | char signature[16]; /* "PHOENIX_CARD_IMG" */ 28 | unsigned int unknown1; /* 0x00200100 */ 29 | unsigned short parts; /* Number of partitions */ 30 | unsigned short unknown2; /* 0x0001 */ 31 | unsigned char pad[8]; 32 | struct phoenix_entry { 33 | unsigned int start; /* 512 bytes blocks */ 34 | unsigned int size; /* bytes */ 35 | unsigned int unknown; /* ???? */ 36 | unsigned int sig; /* "add\0" */ 37 | } part[62]; 38 | } ptable; 39 | 40 | static int save_part(struct phoenix_ptable *ptable, int part, const char *dest, FILE *in) 41 | { 42 | int l = strlen(dest) + 16; 43 | char outname[l]; 44 | FILE *out = stdout; 45 | char *buf = NULL; 46 | int ret = 0; 47 | snprintf(outname, l, dest, part); 48 | if (part > ptable->parts) { 49 | fprintf(stderr, "ERROR: Part index out of range\n"); 50 | return -1; 51 | } 52 | buf = malloc(ptable->part[part].size); 53 | if (!buf) 54 | goto err; 55 | if (strcmp(outname, "-") != 0) 56 | out = fopen(outname, "wb"); 57 | if (!out) 58 | goto err; 59 | if (fseek(in, ptable->part[part].start * 0x200, SEEK_SET) == -1) 60 | goto err; 61 | if (fread(buf, ptable->part[part].size, 1, in) != 1) 62 | goto err; 63 | if (fwrite(buf, ptable->part[part].size, 1, out) != 1) 64 | goto err; 65 | ret = 0; 66 | _exit: 67 | if (buf) 68 | free(buf); 69 | if (out != stdout) 70 | fclose(out); 71 | return ret; 72 | err: 73 | perror(NULL); 74 | ret = -1; 75 | goto _exit; 76 | } 77 | 78 | static void usage(char **argv) 79 | { 80 | puts("phoenix-info " VERSION "\n"); 81 | printf("Usage: %s [options] [phoenix_image]\n" 82 | " -v verbose\n" 83 | " -q quiet\n" 84 | " -p N part number\n" 85 | " -o X destination directory, file or pattern (%%d for part number)\n" 86 | " -s save all parts\n" 87 | , argv[0] 88 | ); 89 | } 90 | 91 | int main(int argc, char **argv) 92 | { 93 | int i; 94 | FILE *in = stdin; 95 | int verbose = 1; 96 | int save_parts = 0; 97 | int part = -1; 98 | int opt; 99 | const char *dest = "%d.img"; 100 | 101 | while ((opt = getopt(argc, argv, "vqso:p:?")) != -1) { 102 | switch(opt) { 103 | case 'v': 104 | verbose++; 105 | break; 106 | case 'q': 107 | if (verbose) 108 | verbose--; 109 | break; 110 | case 'o': 111 | dest = optarg; 112 | save_parts = 1; 113 | break; 114 | case 'p': 115 | save_parts = 1; 116 | part = atoi(optarg); 117 | break; 118 | case 's': 119 | save_parts = 1; 120 | break; 121 | default: 122 | usage(argv); 123 | exit(1); 124 | break; 125 | } 126 | } 127 | if (save_parts && !strchr(dest, '%')) { 128 | const char *t = dest; 129 | if (!*t) 130 | t = "./"; 131 | if (t[strlen(t)-1] == '/' || !part) { 132 | int l = strlen(t) + strlen("/%d.img") + 1; 133 | char *tmp = malloc(l); 134 | snprintf(tmp, l, "%s/%%d.img", optarg); 135 | t = tmp; 136 | } 137 | dest = t; 138 | } 139 | if (argc > optind + 1) { 140 | usage(argv); 141 | exit(1); 142 | } 143 | if (optind < argc ) { 144 | in = fopen(argv[optind], "rb"); 145 | } 146 | fseek(in, 0x1C00, SEEK_CUR); 147 | fread(&ptable, 1, 0x400, in); 148 | if (strncmp(ptable.signature, "PHOENIX_CARD_IMG", 16) != 0) { 149 | fprintf(stderr, "ERROR: Not a phoenix image\n"); 150 | exit(1); 151 | } 152 | if (verbose > 1) { 153 | printf("???? : %08x\n", le32toh(ptable.unknown1)); 154 | printf("Parts : %d\n", le16toh(ptable.parts)); 155 | printf("???? : %08x\n", le16toh(ptable.unknown2)); 156 | printf("pad : %02x%02x%02x%02x%02x%02x%02x%02x\n", ptable.pad[0], ptable.pad[1], ptable.pad[2], ptable.pad[3], ptable.pad[4], ptable.pad[5], ptable.pad[6], ptable.pad[7]); 157 | printf("\n"); 158 | } 159 | for (i = 0; i < le16toh(ptable.parts); i++) { 160 | if (verbose && (part == -1 || part == i)) { 161 | printf("part %d:\n", i); 162 | printf("\tstart: 0x%08x (%u / 0x%08x)\n", le32toh(ptable.part[i].start)*512, le32toh(ptable.part[i].start), le32toh(ptable.part[i].start)); 163 | printf("\tsize : %u\n", le32toh(ptable.part[i].size)); 164 | printf("\t?????: %08x\n", le32toh(ptable.part[i].unknown)); 165 | if (verbose > 1 || le32toh(ptable.part[i].sig) != 0x00646461) 166 | printf("\tsig??: %08x\n", le32toh(ptable.part[i].sig)); 167 | printf("\n"); 168 | } 169 | if (save_parts && (part == -1 || part == i)) { 170 | save_part(&ptable, i, dest, in); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /progress.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bernhard Nortmann 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #include "progress.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | /* Less reliable than clock_gettime, but does not require linking with -lrt */ 24 | inline double gettime(void) 25 | { 26 | struct timeval tv; 27 | gettimeofday(&tv, NULL); 28 | return tv.tv_sec + (double)tv.tv_usec / 1000000.; 29 | } 30 | 31 | /* Calculate transfer rate (in bytes per second) */ 32 | inline double rate(size_t transferred, double elapsed) 33 | { 34 | if (elapsed > 0) 35 | return (double)transferred / elapsed; 36 | return 0.; 37 | } 38 | 39 | /* Estimate remaining time ("ETA") for given transfer rate */ 40 | inline double estimate(size_t remaining, double rate) 41 | { 42 | if (rate > 0) 43 | return (double)remaining / rate; 44 | return 0.; 45 | } 46 | 47 | /* Return ETA (in seconds) as string, formatted to minutes and seconds */ 48 | const char *format_ETA(double remaining) 49 | { 50 | static char result[6] = ""; 51 | 52 | int seconds = remaining + 0.5; /* simplistic round() */ 53 | if (seconds >= 0 && seconds < 6000) { 54 | snprintf(result, sizeof(result), 55 | "%02d:%02d", seconds / 60, seconds % 60); 56 | return result; 57 | } 58 | return "--:--"; 59 | } 60 | 61 | /* Private progress state variable */ 62 | 63 | typedef struct { 64 | progress_cb_t callback; 65 | size_t total; 66 | size_t done; 67 | double start; /* start point (timestamp) for rate and ETA calculation */ 68 | } progress_private_t; 69 | 70 | static progress_private_t progress = { 71 | .callback = NULL, 72 | .start = 0. 73 | }; 74 | 75 | /* 'External' API */ 76 | 77 | void progress_start(progress_cb_t callback, size_t expected_total) 78 | { 79 | progress.callback = callback; 80 | progress.total = expected_total; 81 | progress.done = 0; 82 | progress.start = gettime(); /* reset start time */ 83 | } 84 | 85 | /* Update progress status, passing information to the callback function. */ 86 | void progress_update(size_t bytes_done) 87 | { 88 | progress.done += bytes_done; 89 | if (progress.callback) 90 | progress.callback(progress.total, progress.done); 91 | } 92 | 93 | /* Return relative / "elapsed" time, since progress_start() */ 94 | static inline double progress_elapsed(void) 95 | { 96 | if (progress.start != 0.) 97 | return gettime() - progress.start; 98 | return 0.; 99 | } 100 | 101 | /* Callback function implementing a simple progress bar written to stdout */ 102 | void progress_bar(size_t total, size_t done) 103 | { 104 | static const int WIDTH = 48; /* # of characters to use for progress bar */ 105 | 106 | float ratio = total > 0 ? (float)done / total : 0; 107 | int i, pos = WIDTH * ratio; 108 | double speed = rate(done, progress_elapsed()); 109 | double eta = estimate(total - done, speed); 110 | 111 | printf("\r%3.0f%% [", ratio * 100); /* current percentage */ 112 | for (i = 0; i < pos; i++) putchar('='); 113 | for (i = pos; i < WIDTH; i++) putchar(' '); 114 | if (done < total) 115 | printf("]%6.1f kB/s, ETA %s ", kilo(speed), format_ETA(eta)); 116 | else 117 | /* transfer complete, output totals plus a newline */ 118 | printf("] %5.0f kB, %6.1f kB/s\n", kilo(done), kilo(speed)); 119 | 120 | fflush(stdout); 121 | } 122 | 123 | /* 124 | * Progress callback that emits percentage numbers, each on a separate line. 125 | * The output is suitable for piping it into "dialog --gauge". 126 | * 127 | * sunxi-fel multiwrite-with-gauge <...> \ 128 | * | dialog --title "FEL upload progress" \ 129 | * --gauge "" 5 70 130 | */ 131 | void progress_gauge(size_t total, size_t done) 132 | { 133 | if (total > 0) { 134 | printf("%.0f\n", (float)done / total * 100); 135 | fflush(stdout); 136 | } 137 | } 138 | 139 | /* 140 | * A more sophisticated version of progress_gauge() that also updates the 141 | * prompt (caption) with additional information. This uses a feature of 142 | * the dialog utility that parses "XXX" delimiters - see 'man dialog'. 143 | * 144 | * sunxi-fel multiwrite-with-xgauge <...> \ 145 | * | dialog --title "FEL upload progress" \ 146 | * --backtitle "Please wait..." \ 147 | * --gauge "" 6 70 148 | */ 149 | void progress_gauge_xxx(size_t total, size_t done) 150 | { 151 | if (total > 0) { 152 | double speed = rate(done, progress_elapsed()); 153 | double eta = estimate(total - done, speed); 154 | printf("XXX\n"); 155 | printf("%.0f\n", (float)done / total * 100); 156 | if (done < total) 157 | printf("%zu of %zu, %.1f kB/s, ETA %s\n", 158 | done, total, kilo(speed), format_ETA(eta)); 159 | else 160 | printf("Done: %.1f kB, at %.1f kB/s\n", 161 | kilo(done), kilo(speed)); 162 | printf("XXX\n"); 163 | fflush(stdout); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /progress.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Bernhard Nortmann 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_PROGRESS_H 18 | #define _SUNXI_TOOLS_PROGRESS_H 19 | 20 | #include 21 | 22 | /* function pointer type for a progress callback / notification */ 23 | typedef void (*progress_cb_t)(size_t total, size_t done); 24 | 25 | /* conversion helper macros */ 26 | #define kilo(value) ((double)(value) / 1000.) /* SI prefix "k" */ 27 | #define kibi(value) ((double)(value) / 1024.) /* binary prefix "Ki", "K" */ 28 | 29 | double gettime(void); 30 | double rate(size_t transferred, double elapsed); 31 | double estimate(size_t remaining, double rate); 32 | 33 | void progress_start(progress_cb_t callback, size_t expected_total); 34 | void progress_update(size_t bytes_done); 35 | 36 | /* progress callback implementations for various display styles */ 37 | void progress_bar(size_t total, size_t done); 38 | void progress_gauge(size_t total, size_t done); 39 | void progress_gauge_xxx(size_t total, size_t done); 40 | 41 | #endif /* _SUNXI_TOOLS_PROGRESS_H */ 42 | -------------------------------------------------------------------------------- /script.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "common.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "script.h" 26 | 27 | /* 28 | */ 29 | struct script *script_new(void) 30 | { 31 | struct script *script; 32 | if ((script = malloc(sizeof(*script)))) 33 | list_init(&script->sections); 34 | return script; 35 | } 36 | 37 | void script_delete(struct script *script) 38 | { 39 | struct list_entry *o; 40 | 41 | assert(script); 42 | 43 | while ((o = list_last(&script->sections))) { 44 | struct script_section *section = container_of(o, 45 | struct script_section, sections); 46 | 47 | script_section_delete(section); 48 | } 49 | 50 | free(script); 51 | } 52 | 53 | /* 54 | */ 55 | struct script_section *script_section_new(struct script *script, 56 | const char *name) 57 | { 58 | struct script_section *section; 59 | 60 | assert(script); 61 | assert(name && *name); 62 | 63 | if ((section = malloc(sizeof(*section)))) { 64 | size_t l = strlen(name); 65 | if (l>31) /* truncate */ 66 | l=31; 67 | memcpy(section->name, name, l); 68 | section->name[l] = '\0'; 69 | 70 | list_init(§ion->entries); 71 | list_append(&script->sections, §ion->sections); 72 | } 73 | return section; 74 | } 75 | 76 | void script_section_delete(struct script_section *section) 77 | { 78 | struct list_entry *o; 79 | 80 | assert(section); 81 | 82 | while ((o = list_last(§ion->entries))) { 83 | struct script_entry *entry = container_of(o, 84 | struct script_entry, entries); 85 | 86 | script_entry_delete(entry); 87 | } 88 | 89 | if (!list_empty(§ion->sections)) 90 | list_remove(§ion->sections); 91 | } 92 | 93 | struct script_section *script_find_section(struct script *script, 94 | const char *name) 95 | { 96 | struct list_entry *o; 97 | struct script_section *section; 98 | 99 | assert(script); 100 | assert(name); 101 | 102 | for (o = list_first(&script->sections); o; 103 | o = list_next(&script->sections, o)) { 104 | section = container_of(o, struct script_section, sections); 105 | 106 | if (strcmp(section->name, name) == 0) 107 | return section; 108 | } 109 | 110 | return NULL; 111 | } 112 | 113 | /* 114 | */ 115 | static inline void script_entry_append(struct script_section *section, 116 | struct script_entry *entry, 117 | enum script_value_type type, 118 | const char *name) 119 | { 120 | size_t l; 121 | 122 | assert(section); 123 | assert(entry); 124 | assert(name); 125 | 126 | l = strlen(name); 127 | if (l>31) /* truncate */ 128 | l=31; 129 | memcpy(entry->name, name, l); 130 | entry->name[l] = '\0'; 131 | 132 | entry->type = type; 133 | 134 | list_append(§ion->entries, &entry->entries); 135 | } 136 | 137 | void script_entry_delete(struct script_entry *entry) 138 | { 139 | void *container; 140 | 141 | assert(entry); 142 | assert(entry->type == SCRIPT_VALUE_TYPE_SINGLE_WORD || 143 | entry->type == SCRIPT_VALUE_TYPE_STRING || 144 | entry->type == SCRIPT_VALUE_TYPE_GPIO || 145 | entry->type == SCRIPT_VALUE_TYPE_NULL); 146 | 147 | if (!list_empty(&entry->entries)) 148 | list_remove(&entry->entries); 149 | 150 | switch(entry->type) { 151 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: 152 | container = container_of(entry, struct script_single_entry, entry); 153 | break; 154 | case SCRIPT_VALUE_TYPE_STRING: 155 | container = container_of(entry, struct script_string_entry, entry); 156 | break; 157 | case SCRIPT_VALUE_TYPE_GPIO: 158 | container = container_of(entry, struct script_gpio_entry, entry); 159 | break; 160 | case SCRIPT_VALUE_TYPE_NULL: 161 | container = container_of(entry, struct script_null_entry, entry); 162 | break; 163 | default: 164 | abort(); 165 | } 166 | 167 | free(container); 168 | } 169 | 170 | struct script_null_entry *script_null_entry_new(struct script_section *section, 171 | const char *name) 172 | { 173 | struct script_null_entry *entry; 174 | 175 | assert(section); 176 | assert(name && *name); 177 | 178 | if ((entry = malloc(sizeof(*entry)))) { 179 | script_entry_append(section, &entry->entry, 180 | SCRIPT_VALUE_TYPE_NULL, name); 181 | } 182 | 183 | return entry; 184 | } 185 | 186 | struct script_single_entry *script_single_entry_new(struct script_section *section, 187 | const char *name, 188 | uint32_t value) 189 | { 190 | struct script_single_entry *entry; 191 | 192 | assert(section); 193 | assert(name && *name); 194 | 195 | if ((entry = malloc(sizeof(*entry)))) { 196 | entry->value = value; 197 | 198 | script_entry_append(section, &entry->entry, 199 | SCRIPT_VALUE_TYPE_SINGLE_WORD, name); 200 | } 201 | 202 | return entry; 203 | } 204 | 205 | struct script_string_entry *script_string_entry_new(struct script_section *section, 206 | const char *name, 207 | size_t l, const char *s) 208 | { 209 | struct script_string_entry *entry; 210 | 211 | assert(section); 212 | assert(name); 213 | assert(s); 214 | 215 | if ((entry = malloc(sizeof(*entry)+l+1))) { 216 | entry->l = l; 217 | memcpy(entry->string, s, l); 218 | entry->string[l] = '\0'; 219 | 220 | script_entry_append(section, &entry->entry, 221 | SCRIPT_VALUE_TYPE_STRING, name); 222 | } 223 | 224 | return entry; 225 | } 226 | 227 | struct script_gpio_entry *script_gpio_entry_new(struct script_section *section, 228 | const char *name, 229 | unsigned port, unsigned num, 230 | int32_t data[4]) 231 | { 232 | struct script_gpio_entry *entry; 233 | 234 | assert(section); 235 | assert(name && *name); 236 | 237 | if ((entry = malloc(sizeof(*entry)))) { 238 | entry->port = port; 239 | entry->port_num = num; 240 | for (int i=0; i<4; i++) 241 | entry->data[i] = data[i]; 242 | 243 | script_entry_append(section, &entry->entry, 244 | SCRIPT_VALUE_TYPE_GPIO, name); 245 | } 246 | 247 | return entry; 248 | } 249 | 250 | struct script_entry *script_find_entry(struct script_section *section, 251 | const char *name) 252 | { 253 | struct list_entry *o; 254 | struct script_entry *ep; 255 | 256 | assert(section); 257 | assert(name); 258 | 259 | for (o = list_first(§ion->entries); o; 260 | o = list_next(§ion->entries, o)) { 261 | ep = container_of(o, struct script_entry, entries); 262 | 263 | if (strcmp(ep->name, name) == 0) 264 | return ep; 265 | } 266 | 267 | return NULL; 268 | } 269 | -------------------------------------------------------------------------------- /script.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_SCRIPT_H 18 | #define _SUNXI_TOOLS_SCRIPT_H 19 | 20 | #include "list.h" 21 | 22 | #define GPIO_BANK_MAX 14 /* N, (zero-based) index 13 */ 23 | 24 | /** head of the data tree */ 25 | struct script { 26 | struct list_entry sections; 27 | }; 28 | 29 | /** head of each section */ 30 | struct script_section { 31 | char name[32]; 32 | 33 | struct list_entry sections; 34 | struct list_entry entries; 35 | }; 36 | 37 | /** types of values */ 38 | enum script_value_type { 39 | SCRIPT_VALUE_TYPE_SINGLE_WORD = 1, 40 | SCRIPT_VALUE_TYPE_STRING, 41 | SCRIPT_VALUE_TYPE_MULTI_WORD, 42 | SCRIPT_VALUE_TYPE_GPIO, 43 | SCRIPT_VALUE_TYPE_NULL, 44 | }; 45 | 46 | /** generic entry */ 47 | struct script_entry { 48 | char name[32]; 49 | enum script_value_type type; 50 | 51 | struct list_entry entries; 52 | }; 53 | 54 | /** null entry */ 55 | struct script_null_entry { 56 | struct script_entry entry; 57 | }; 58 | 59 | /** entry with 32b value */ 60 | struct script_single_entry { 61 | struct script_entry entry; 62 | 63 | uint32_t value; 64 | }; 65 | 66 | /** entry with string value */ 67 | struct script_string_entry { 68 | struct script_entry entry; 69 | 70 | size_t l; 71 | char string[]; 72 | }; 73 | 74 | /** entry describing a GPIO */ 75 | struct script_gpio_entry { 76 | struct script_entry entry; 77 | 78 | unsigned port, port_num; 79 | int32_t data[4]; 80 | }; 81 | 82 | /** create a new script tree */ 83 | struct script *script_new(void); 84 | /** deletes a tree recursively */ 85 | void script_delete(struct script *); 86 | 87 | /** create a new section appended to a given tree */ 88 | struct script_section *script_section_new(struct script *script, 89 | const char *name); 90 | /** deletes a section recursvely and removes it from the script */ 91 | void script_section_delete(struct script_section *section); 92 | 93 | /** find existing section */ 94 | struct script_section *script_find_section(struct script *script, 95 | const char *name); 96 | 97 | /** deletes an entry and removes it from the section */ 98 | void script_entry_delete(struct script_entry *entry); 99 | 100 | /** create a new empty/null entry appended to a section */ 101 | struct script_null_entry *script_null_entry_new(struct script_section *section, 102 | const char *name); 103 | /** create a new single word entry appended to a section */ 104 | struct script_single_entry *script_single_entry_new(struct script_section *section, 105 | const char *name, 106 | uint32_t value); 107 | /** create a new string entry appended to a section */ 108 | struct script_string_entry *script_string_entry_new(struct script_section *section, 109 | const char *name, 110 | size_t l, const char *s); 111 | /** create a new GPIO entry appended to a section */ 112 | struct script_gpio_entry *script_gpio_entry_new(struct script_section *script, 113 | const char *name, 114 | unsigned port, unsigned num, 115 | int32_t data[4]); 116 | 117 | /** find existing entry in a giving section */ 118 | struct script_entry *script_find_entry(struct script_section *section, 119 | const char *name); 120 | #endif 121 | -------------------------------------------------------------------------------- /script_bin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "common.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "script.h" 28 | #include "script_bin.h" 29 | 30 | #define pr_info(...) pr_error("fexc-bin: " __VA_ARGS__) 31 | #define pr_err(...) pr_error("E: fexc-bin: " __VA_ARGS__) 32 | 33 | #ifdef DEBUG 34 | #define pr_debug(...) pr_error("D: fexc-bin: " __VA_ARGS__) 35 | #else 36 | #define pr_debug(...) 37 | #endif 38 | 39 | #define PTR(B, OFF) (void*)((char*)(B)+(OFF)) 40 | #define WORDS(S) (((S)+(sizeof(uint32_t)-1))/(sizeof(uint32_t))) 41 | 42 | /* 43 | * generator 44 | */ 45 | size_t script_bin_size(struct script *script, 46 | size_t *sections, size_t *entries) 47 | { 48 | size_t words = 0, bin_size = 0; 49 | struct list_entry *ls, *le; 50 | struct script_section *section; 51 | struct script_entry *entry; 52 | struct script_string_entry *string; 53 | 54 | *sections = *entries = 0; 55 | 56 | /* count */ 57 | for (ls = list_first(&script->sections); ls; 58 | ls = list_next(&script->sections, ls)) { 59 | section = container_of(ls, struct script_section, sections); 60 | size_t c = 0; 61 | 62 | for (le = list_first(§ion->entries); le; 63 | le = list_next(§ion->entries, le)) { 64 | size_t size = 0; 65 | entry = container_of(le, struct script_entry, entries); 66 | c++; 67 | 68 | switch(entry->type) { 69 | case SCRIPT_VALUE_TYPE_NULL: 70 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: 71 | size = sizeof(uint32_t); 72 | break; 73 | case SCRIPT_VALUE_TYPE_STRING: 74 | string = container_of(entry, struct script_string_entry, 75 | entry); 76 | size = string->l; 77 | break; 78 | case SCRIPT_VALUE_TYPE_GPIO: 79 | size = sizeof(struct script_bin_gpio_value); 80 | break; 81 | default: 82 | abort(); 83 | } 84 | words += WORDS(size); 85 | } 86 | *sections += 1; 87 | *entries += c; 88 | } 89 | 90 | bin_size = sizeof(struct script_bin_head) + 91 | (*sections)*sizeof(struct script_bin_section) + 92 | (*entries)*sizeof(struct script_bin_entry) + 93 | words*sizeof(uint32_t); 94 | pr_debug("sections:%zu entries:%zu data:%zu/%zu -> %zu\n", 95 | *sections, *entries, words, words*sizeof(uint32_t), 96 | bin_size); 97 | return bin_size; 98 | } 99 | 100 | int script_generate_bin(void *bin, size_t bin_size, 101 | struct script *script, 102 | size_t sections, size_t entries) 103 | { 104 | struct script_bin_head *head; 105 | struct script_bin_section *section; 106 | struct script_bin_entry *entry; 107 | void *data; 108 | 109 | struct list_entry *ls, *le; 110 | 111 | head = bin; 112 | section = head->section; 113 | entry = (void*)section+sections*sizeof(*section); 114 | data = (void*)entry+entries*sizeof(*entry); 115 | 116 | pr_debug("head....:%p\n", head); 117 | pr_debug("section.:%p (offset:%zu, each:%zu)\n", section, 118 | (void*)section-bin, sizeof(*section)); 119 | pr_debug("entry...:%p (offset:%zu, each:%zu)\n", entry, 120 | (void*)entry-bin, sizeof(*entry)); 121 | pr_debug("data....:%p (offset:%zu)\n", data, 122 | (void*)data-bin); 123 | 124 | head->sections = sections; 125 | head->filesize = bin_size; 126 | head->version[0] = 1; 127 | head->version[1] = 2; 128 | 129 | for (ls = list_first(&script->sections); ls; 130 | ls = list_next(&script->sections, ls)) { 131 | struct script_section *s; 132 | size_t c = 0; 133 | s = container_of(ls, struct script_section, sections); 134 | 135 | memcpy(section->name, s->name, strlen(s->name)); 136 | section->offset = ((void*)entry-bin)>>2; 137 | 138 | for (le = list_first(&s->entries); le; 139 | le = list_next(&s->entries, le)) { 140 | struct script_entry *e; 141 | e = container_of(le, struct script_entry, entries); 142 | size_t size = 0; 143 | 144 | memcpy(entry->name, e->name, strlen(e->name)); 145 | entry->offset = ((void*)data-bin)>>2; 146 | entry->pattern = (e->type<<16); 147 | 148 | switch(e->type) { 149 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: { 150 | struct script_single_entry *single; 151 | int32_t *bdata = data; 152 | single = container_of(e, struct script_single_entry, entry); 153 | 154 | *bdata = single->value; 155 | size = sizeof(*bdata); 156 | }; break; 157 | case SCRIPT_VALUE_TYPE_STRING: { 158 | struct script_string_entry *string; 159 | string = container_of(e, struct script_string_entry, entry); 160 | size = string->l; 161 | memcpy(data, string->string, size); 162 | /* align */ 163 | size += sizeof(uint32_t)-1; 164 | size /= sizeof(uint32_t); 165 | size *= sizeof(uint32_t); 166 | }; break; 167 | case SCRIPT_VALUE_TYPE_MULTI_WORD: 168 | abort(); 169 | case SCRIPT_VALUE_TYPE_GPIO: { 170 | struct script_gpio_entry *gpio; 171 | struct script_bin_gpio_value *bdata = data; 172 | gpio = container_of(e, struct script_gpio_entry, entry); 173 | bdata->port = gpio->port; 174 | bdata->port_num = gpio->port_num; 175 | bdata->mul_sel = gpio->data[0]; 176 | bdata->pull = gpio->data[1]; 177 | bdata->drv_level = gpio->data[2]; 178 | bdata->data = gpio->data[3]; 179 | size = sizeof(*bdata); 180 | }; break; 181 | case SCRIPT_VALUE_TYPE_NULL: 182 | size = sizeof(uint32_t); 183 | break; 184 | } 185 | 186 | data += size; 187 | entry->pattern |= (size>>2); 188 | pr_debug("%s.%s <%p> (type:%d, words:%d (%zu), offset:%d)\n", 189 | section->name, entry->name, entry, 190 | (entry->pattern>>16) & 0xffff, 191 | (entry->pattern>>0) & 0xffff, size, 192 | entry->offset); 193 | c++; 194 | entry++; 195 | } 196 | 197 | section->length = c; 198 | pr_debug("%s <%p> (length:%d, offset:%d)\n", 199 | section->name, section, section->length, section->offset); 200 | 201 | section++; 202 | } 203 | return 1; 204 | } 205 | 206 | /* 207 | * decompiler 208 | */ 209 | static int decompile_section(void *bin, size_t bin_size, 210 | const char *filename, 211 | struct script_bin_section *section, 212 | struct script *script) 213 | { 214 | struct script_bin_entry *entry; 215 | struct script_section *s; 216 | int size; 217 | 218 | if ((section->offset < 0) || (section->offset > (int)(bin_size / 4))) { 219 | pr_err("Malformed data: invalid section offset: %d\n", 220 | section->offset); 221 | return 0; 222 | } 223 | 224 | size = bin_size - 4 * section->offset; 225 | 226 | if ((section->length < 0) || 227 | (section->length > (size / (int)sizeof(struct script_bin_entry)))) { 228 | pr_err("Malformed data: invalid section length: %d\n", 229 | section->length); 230 | return 0; 231 | } 232 | 233 | if ((s = script_section_new(script, section->name)) == NULL) 234 | goto malloc_error; 235 | 236 | entry = PTR(bin, section->offset<<2); 237 | 238 | for (int i = section->length; i--; entry++) { 239 | void *data = PTR(bin, entry->offset<<2); 240 | unsigned type, words; 241 | type = (entry->pattern >> 16) & 0xffff; 242 | words = (entry->pattern >> 0) & 0xffff; 243 | 244 | for (char *p = entry->name; *p; p++) 245 | if (!(isalnum(*p) || *p == '_' || *p == '-')) { 246 | pr_info("Warning: Malformed entry key \"%s\"\n", 247 | entry->name); 248 | break; 249 | } 250 | 251 | switch(type) { 252 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: { 253 | uint32_t *v = data; 254 | if (words != 1) { 255 | pr_err("%s: %s.%s: invalid length %d (assuming %d)\n", 256 | filename, section->name, entry->name, words, 1); 257 | } 258 | if (!script_single_entry_new(s, entry->name, *v)) 259 | goto malloc_error; 260 | }; break; 261 | case SCRIPT_VALUE_TYPE_STRING: { 262 | size_t bytes = words << 2; 263 | const char *p, *pe, *v = data; 264 | 265 | for(p=v, pe=v+bytes; *p && p!=pe; p++) 266 | ; /* seek end-of-string */ 267 | 268 | if (!script_string_entry_new(s, entry->name, p-v, v)) 269 | goto malloc_error; 270 | }; break; 271 | case SCRIPT_VALUE_TYPE_GPIO: { 272 | struct script_bin_gpio_value *gpio = data; 273 | int32_t v[4]; 274 | if (words != 6) { 275 | pr_err("%s: %s.%s: invalid length %d (assuming %d)\n", 276 | filename, section->name, entry->name, words, 6); 277 | } else if (gpio->port == 0xffff) { 278 | ; /* port:power */ 279 | } else if (gpio->port < 1 || gpio->port > GPIO_BANK_MAX) { 280 | pr_err("%s: %s.%s: unknown GPIO port bank ", 281 | filename, section->name, entry->name); 282 | char c = 'A' + gpio->port - 1; 283 | if (c >= 'A' && c <= 'Z') 284 | pr_err("%c ", c); 285 | pr_err("(%u)\n", gpio->port); 286 | goto failure; 287 | } 288 | v[0] = gpio->mul_sel; 289 | v[1] = gpio->pull; 290 | v[2] = gpio->drv_level; 291 | v[3] = gpio->data; 292 | 293 | if (!script_gpio_entry_new(s, entry->name, 294 | gpio->port, gpio->port_num, 295 | v)) 296 | goto malloc_error; 297 | }; break; 298 | case SCRIPT_VALUE_TYPE_NULL: 299 | if (!*entry->name) { 300 | pr_err("%s: empty entry in section: %s\n", filename, section->name); 301 | } else if (!script_null_entry_new(s, entry->name)) { 302 | goto malloc_error; 303 | } 304 | break; 305 | default: 306 | pr_err("%s: %s.%s: unknown type %d\n", 307 | filename, section->name, entry->name, type); 308 | goto failure; 309 | } 310 | } 311 | return 1; 312 | 313 | malloc_error: 314 | pr_err("%s: %s\n", "malloc", strerror(errno)); 315 | failure: 316 | return 0; 317 | } 318 | 319 | #define SCRIPT_BIN_VERSION_LIMIT 0x10 320 | #define SCRIPT_BIN_SECTION_LIMIT 0x100 321 | 322 | int script_decompile_bin(void *bin, size_t bin_size, 323 | const char *filename, 324 | struct script *script) 325 | { 326 | unsigned int i; 327 | struct script_bin_head *head = bin; 328 | 329 | if ((head->version[0] > SCRIPT_BIN_VERSION_LIMIT) || 330 | (head->version[1] > SCRIPT_BIN_VERSION_LIMIT)) { 331 | pr_err("Malformed data: version %u.%u.\n", 332 | head->version[0], head->version[1]); 333 | return 0; 334 | } 335 | 336 | if (head->sections > SCRIPT_BIN_SECTION_LIMIT) { 337 | pr_err("Malformed data: too many sections (%u).\n", 338 | head->sections); 339 | return 0; 340 | } 341 | 342 | pr_info("%s: version: %u.%u\n", filename, 343 | head->version[0], head->version[1]); 344 | pr_info("%s: size: %zu (%u sections), header value: %u\n", filename, 345 | bin_size, head->sections, head->filesize); 346 | 347 | /* TODO: SANITY: compare head.sections with bin_size */ 348 | for (i=0; i < head->sections; i++) { 349 | struct script_bin_section *section = &head->section[i]; 350 | 351 | if (!decompile_section(bin, bin_size, filename, 352 | section, script)) 353 | return 0; 354 | } 355 | return 1; 356 | } 357 | -------------------------------------------------------------------------------- /script_bin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUNXI_TOOLS_SCRIPT_BIN_H 18 | #define _SUNXI_TOOLS_SCRIPT_BIN_H 19 | 20 | /** binary representation of the head of a section */ 21 | struct script_bin_section { 22 | char name[32]; 23 | int32_t length; 24 | int32_t offset; 25 | }; 26 | 27 | /** binary representation of the head of the script file */ 28 | struct script_bin_head { 29 | uint32_t sections; 30 | uint32_t filesize; 31 | uint32_t version[2]; 32 | struct script_bin_section section[]; 33 | }; 34 | 35 | /** binary representation of the head of an entry */ 36 | struct script_bin_entry { 37 | char name[32]; 38 | int32_t offset; 39 | int32_t pattern; 40 | }; 41 | 42 | /** binary representation of a GPIO */ 43 | struct script_bin_gpio_value { 44 | int32_t port; 45 | int32_t port_num; 46 | int32_t mul_sel; 47 | int32_t pull; 48 | int32_t drv_level; 49 | int32_t data; 50 | }; 51 | 52 | size_t script_bin_size(struct script *script, 53 | size_t *sections, size_t *entries); 54 | 55 | int script_generate_bin(void *bin, size_t bin_size, struct script *script, 56 | size_t sections, size_t entries); 57 | int script_decompile_bin(void *bin, size_t bin_size, 58 | const char *filename, 59 | struct script *script); 60 | #endif 61 | -------------------------------------------------------------------------------- /script_extractor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Olliver Schinagl 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define SCRIPT_START 0x43000000 27 | #define SCRIPT_SIZE 0x20000 28 | 29 | int main(void) { 30 | char *addr; 31 | int fd; 32 | int i; 33 | 34 | fd = open("/dev/mem", O_RDONLY); 35 | addr = (char *)mmap(NULL, SCRIPT_SIZE, PROT_READ, MAP_SHARED, fd, SCRIPT_START); 36 | for (i = 0; i < SCRIPT_SIZE; i++) 37 | putchar(addr[i]); 38 | munmap(addr, SCRIPT_SIZE); 39 | close(fd); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /script_fex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #include "common.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "script.h" 26 | #include "script_fex.h" 27 | 28 | #define MAX_LINE 255 29 | 30 | #define pr_info(...) pr_error("fexc-fex: " __VA_ARGS__) 31 | #define pr_err(...) pr_error("E: fexc-fex: " __VA_ARGS__) 32 | 33 | #ifdef DEBUG 34 | #define pr_debug(...) pr_error("D: fexc-fex: " __VA_ARGS__) 35 | #else 36 | #define pr_debug(...) 37 | #endif 38 | 39 | /* 40 | * generator 41 | */ 42 | static inline size_t strlen2(const char *s) 43 | { 44 | size_t l = strlen(s); 45 | const char *p = &s[l-1]; 46 | while (l && *p >= '0' && *p <= '9') { 47 | l--; 48 | p--; 49 | } 50 | return l; 51 | } 52 | 53 | static int find_full_match(const char *s, size_t l, const char **list) 54 | { 55 | while (*list) { 56 | if (memcmp(s, *list, l) == 0) 57 | return 1; 58 | list++; 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | /** 65 | */ 66 | static int decompile_single_mode(const char *name) 67 | { 68 | static const char *hexa_entries[] = { 69 | "dram_baseaddr", "dram_zq", "dram_tpr", "dram_emr", 70 | "g2d_size", 71 | "rtp_press_threshold", "rtp_sensitive_level", 72 | "ctp_twi_addr", "csi_twi_addr", "csi_twi_addr_b", "tkey_twi_addr", 73 | "lcd_gamma_tbl_", 74 | "gsensor_twi_addr", 75 | NULL }; 76 | size_t l = strlen2(name); 77 | 78 | if (find_full_match(name, l, hexa_entries)) 79 | return 0; 80 | else 81 | return -1; 82 | } 83 | 84 | int script_generate_fex(FILE *out, const char *UNUSED(filename), 85 | struct script *script) 86 | { 87 | struct list_entry *ls, *le; 88 | struct script_section *section; 89 | struct script_entry *entry; 90 | 91 | for (ls = list_first(&script->sections); ls; 92 | ls = list_next(&script->sections, ls)) { 93 | section = container_of(ls, struct script_section, sections); 94 | 95 | fprintf(out, "[%s]\n", section->name); 96 | for (le = list_first(§ion->entries); le; 97 | le = list_next(§ion->entries, le)) { 98 | entry = container_of(le, struct script_entry, entries); 99 | 100 | switch(entry->type) { 101 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: { 102 | int mode = decompile_single_mode(entry->name); 103 | struct script_single_entry *single; 104 | single = container_of(entry, struct script_single_entry, entry); 105 | 106 | fprintf(out, "%s = ", entry->name); 107 | if (mode < 0) 108 | fprintf(out, "%d", single->value); 109 | else if (mode > 0) 110 | fprintf(out, "0x%0*x", mode, single->value); 111 | else 112 | fprintf(out, "0x%x", single->value); 113 | fputc('\n', out); 114 | }; break; 115 | case SCRIPT_VALUE_TYPE_STRING: { 116 | struct script_string_entry *string; 117 | string = container_of(entry, struct script_string_entry, entry); 118 | fprintf(out, "%s = \"%.*s\"\n", entry->name, 119 | (int)string->l, string->string); 120 | }; break; 121 | case SCRIPT_VALUE_TYPE_MULTI_WORD: 122 | abort(); 123 | case SCRIPT_VALUE_TYPE_GPIO: { 124 | char port = 'A'-1; 125 | struct script_gpio_entry *gpio; 126 | gpio = container_of(entry, struct script_gpio_entry, entry); 127 | 128 | if (gpio->port == 0xffff) { 129 | fprintf(out, "%s = port:power%u", entry->name, 130 | gpio->port_num); 131 | } else { 132 | port += gpio->port; 133 | fprintf(out, "%s = port:P%c%02u", entry->name, 134 | port, gpio->port_num); 135 | } 136 | for (const int *p = gpio->data, *pe = p+4; p != pe; p++) { 137 | if (*p == -1) 138 | fputs("", out); 139 | else 140 | fprintf(out, "<%d>", *p); 141 | } 142 | fputc('\n', out); 143 | }; break; 144 | case SCRIPT_VALUE_TYPE_NULL: 145 | fprintf(out, "%s =\n", entry->name); 146 | break; 147 | } 148 | } 149 | fputc('\n', out); 150 | } 151 | return 1; 152 | } 153 | 154 | /* 155 | * parser 156 | */ 157 | 158 | /** find first not blank char */ 159 | static inline char *skip_blank(char *p) 160 | { 161 | while(isblank(*p)) 162 | p++; 163 | return p; 164 | } 165 | 166 | /** trim out blank chars at the end of a string */ 167 | static inline char *rtrim(const char *s, char *p) 168 | { 169 | if (p>s) { 170 | while (p!=s && isblank(*--p)) 171 | ; 172 | *++p='\0'; 173 | } 174 | return p; 175 | } 176 | 177 | /** 178 | */ 179 | int script_parse_fex(FILE *in, const char *filename, struct script *script) 180 | { 181 | char buffer[MAX_LINE+1]; 182 | int ok = 1; 183 | struct script_section *last_section = NULL; 184 | 185 | /* TODO: deal with longer lines correctly (specially in comments) */ 186 | for(size_t line = 1; ok && fgets(buffer, sizeof(buffer), in); line++) { 187 | char *s = skip_blank(buffer); /* beginning */ 188 | char *pe = s; /* \0... to be found */ 189 | 190 | if (*pe) while (*++pe) 191 | ; 192 | 193 | if (pe>s && pe[-1] == '\n') { 194 | if (pe>s+1 && pe[-2] == '\r') 195 | pe -= 2; 196 | else 197 | pe -= 1; 198 | *pe = '\0'; 199 | } 200 | 201 | pe = rtrim(s, pe); 202 | 203 | /* Some lines end in a trailing semicolon. */ 204 | if (pe > s && pe[-1] == ';') 205 | *--pe = '\0'; 206 | 207 | if (pe == s || *s == ';' || *s == '#') 208 | continue; /* empty */ 209 | if (*s == ':') { 210 | /* see https://github.com/linux-sunxi/sunxi-boards/issues/50 */ 211 | pr_error("Warning: %s:%zu: invalid line, suspecting typo/malformed comment.\n", 212 | filename, line); 213 | continue; /* ignore this line */ 214 | } 215 | if (*s == '[') { 216 | /* section */ 217 | char *p = ++s; 218 | while (isalnum(*p) || *p == '_' || *p == '-' || *p == '/') 219 | p++; 220 | 221 | if (*p == ']' && *(p+1) == '\0') { 222 | *p = '\0'; 223 | if ((last_section = script_section_new(script, s))) 224 | continue; 225 | 226 | perror("malloc"); 227 | } else if (*p) { 228 | pr_error("E: %s:%zu: invalid character at %zu.\n", 229 | filename, line, p-buffer+1); 230 | } else { 231 | pr_error("E: %s:%zu: incomplete section declaration.\n", 232 | filename, line); 233 | } 234 | ok = 0; 235 | } else { 236 | /* key = value */ 237 | const char *key = s; 238 | char *mark, *p = s; 239 | 240 | if (!last_section) { 241 | pr_error("E: %s:%zu: data must follow a section.\n", 242 | filename, line); 243 | goto parse_error; 244 | }; 245 | 246 | while (isalnum(*p) || *p == '_' || *p == '-') 247 | p++; 248 | mark = p; 249 | p = skip_blank(p); 250 | if (*p != '=') 251 | goto invalid_char_at_p; 252 | *mark = '\0'; /* truncate key */ 253 | p = skip_blank(p+1); 254 | 255 | if (*p == '\0') { 256 | /* NULL */ 257 | if (script_null_entry_new(last_section, key)) 258 | continue; 259 | perror("malloc"); 260 | } else if (pe > p+1 && *p == '"' && pe[-1] == '"') { 261 | /* string */ 262 | p++; *--pe = '\0'; 263 | if (script_string_entry_new(last_section, key, pe-p, p)) { 264 | pr_debug("%s.%s = \"%.*s\"\n", 265 | last_section->name, key, 266 | (int)(pe-p), p); 267 | continue; 268 | } 269 | perror("malloc"); 270 | } else if (memcmp("port:", p, 5) == 0) { 271 | /* GPIO */ 272 | p += 5; 273 | if (p[0] == 'P' && 274 | (p[1] < 'A' || p[1] > ('A' + GPIO_BANK_MAX))) 275 | ; 276 | else if (*p != 'P' && 277 | memcmp(p, "power", 5) != 0) 278 | ; 279 | else { 280 | char *end; 281 | int port; 282 | long v; 283 | 284 | if (*p == 'P') { 285 | /* port:PXN */ 286 | port = p[1] - 'A' + 1; 287 | p += 2; 288 | } else { 289 | /* port:powerN */ 290 | port = 0xffff; 291 | p += 5; 292 | } 293 | 294 | v = strtol(p, &end, 10); 295 | if (end == p) 296 | goto invalid_char_at_p; 297 | else if (v<0 || v>255) { 298 | pr_error("E: %s:%zu: port out of range at %zu (%ld).\n", 299 | filename, line, p-buffer+1, v); 300 | } else { 301 | int data[] = {-1,-1,-1,-1}; 302 | int port_num = v; 303 | p = end; 304 | for (int i=0; *p && i<4; i++) { 305 | if (memcmp(p, "", 9) == 0) { 306 | p += 9; 307 | continue; 308 | } else if (*p == '<') { 309 | v = strtol(++p, &end, 10); 310 | if (end == p) { 311 | ; 312 | } else if (v<0 || v>INT32_MAX) { 313 | pr_error("E: %s:%zu: value out of range at %zu (%ld).\n", 314 | filename, line, p-buffer+1, v); 315 | goto parse_error; 316 | } else if (*end != '>') { 317 | p = end; 318 | } else { 319 | p = end+1; 320 | data[i] = v; 321 | continue; 322 | } 323 | } 324 | break; 325 | } 326 | if (*p) 327 | goto invalid_char_at_p; 328 | if (script_gpio_entry_new(last_section, key, 329 | port, port_num, data)) { 330 | pr_debug("%s.%s = GPIO %d.%d (%d,%d,%d,%d)\n", 331 | last_section->name, key, 332 | port, port_num, 333 | data[0], data[1], data[2], data[3]); 334 | continue; 335 | } 336 | perror("malloc"); 337 | } 338 | } 339 | } else if (isdigit(*p) || (*p == '-' && isdigit(*(p+1)))) { 340 | long long v = 0; 341 | char *end; 342 | v = strtoll(p, &end, 0); 343 | p = end; 344 | if (p != pe) { 345 | goto invalid_char_at_p; 346 | } else if (v > UINT32_MAX) { 347 | pr_error("E: %s:%zu: value out of range %lld.\n", 348 | filename, line, v); 349 | } else if (script_single_entry_new(last_section, key, v)) { 350 | pr_debug("%s.%s = %lld\n", 351 | last_section->name, key, v); 352 | continue; 353 | } 354 | } else { 355 | /* goto invalid_char_at_p; */ 356 | pr_error("Warning: %s:%zu: unquoted value '%s', assuming string\n", 357 | filename, line, p); 358 | if (script_string_entry_new(last_section, key, pe-p, p)) { 359 | pr_debug("%s.%s = \"%s\"\n", 360 | last_section->name, key, p); 361 | continue; 362 | } 363 | perror("malloc"); 364 | } 365 | pr_error("E: %s:%zu: parse error at %zu.\n", 366 | filename, line, p-buffer+1); 367 | goto parse_error; 368 | invalid_char_at_p: 369 | pr_error("E: %s:%zu: invalid character at %zu.\n", 370 | filename, line, p-buffer+1); 371 | parse_error: 372 | ok = 0; 373 | } 374 | }; 375 | 376 | if (ferror(in)) 377 | ok = 0; 378 | return ok; 379 | } 380 | -------------------------------------------------------------------------------- /script_fex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUBXI_TOOLS_SCRIPT_FEX_H 18 | #define _SUBXI_TOOLS_SCRIPT_FEX_H 19 | 20 | int script_parse_fex(FILE *in, const char *filename, struct script *script); 21 | int script_generate_fex(FILE *out, const char *filename, struct script *script); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /script_uboot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #include "common.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "script.h" 24 | #include "script_uboot.h" 25 | 26 | #define pr_info(...) pr_error("fexc-uboot: " __VA_ARGS__) 27 | #define pr_err(...) pr_error("E: fexc-uboot: " __VA_ARGS__) 28 | 29 | #ifdef DEBUG 30 | #define pr_debug(...) pr_error("D: fexc-uboot: " __VA_ARGS__) 31 | #else 32 | #define pr_debug(...) 33 | #endif 34 | 35 | struct members { 36 | const char *name; 37 | const char *translation; 38 | int mode; 39 | }; 40 | #define foreach_member(I, T) for (const struct members *I = T; \ 41 | I < T+ARRAY_SIZE(T); I++) 42 | 43 | /* 44 | */ 45 | static inline void out_u32_member(FILE *out, const char *key, int hexa, 46 | struct script_single_entry *val) 47 | { 48 | const char *fmt; 49 | if (hexa) 50 | fmt = "\t.%s = %#x,\n"; 51 | else 52 | fmt = "\t.%s = %u,\n"; 53 | 54 | fprintf(out, fmt, key, val->value); 55 | } 56 | 57 | static inline void out_gpio_member(FILE *out, const char *key, 58 | struct script_gpio_entry *gpio) 59 | { 60 | fprintf(out, "\t.%s = ", key); 61 | 62 | if (gpio->port == 0xffff) 63 | fprintf(out, "GPIO_AXP_CFG(%u", gpio->port_num); 64 | else 65 | fprintf(out, "GPIO_CFG(%u, %u", gpio->port, gpio->port_num); 66 | 67 | for (const int *p = gpio->data, *pe = p+4; p != pe; p++) { 68 | if (*p == -1) 69 | fputs(", 0xff", out); 70 | else 71 | fprintf(out, ", %u", *p); 72 | } 73 | 74 | fputs("),\n", out); 75 | } 76 | 77 | static inline void out_null_member(FILE *out, const char *key) 78 | { 79 | fprintf(out, "\t/* %s is NULL */\n", key); 80 | } 81 | 82 | static inline int out_member(FILE *out, const char *key, int mode, 83 | struct script_entry *ep) 84 | { 85 | switch (ep->type) { 86 | case SCRIPT_VALUE_TYPE_SINGLE_WORD: 87 | out_u32_member(out, key, mode, 88 | container_of(ep, struct script_single_entry, entry)); 89 | break; 90 | case SCRIPT_VALUE_TYPE_NULL: 91 | out_null_member(out, key); 92 | break; 93 | case SCRIPT_VALUE_TYPE_GPIO: 94 | out_gpio_member(out, key, 95 | container_of(ep, struct script_gpio_entry, entry)); 96 | break; 97 | default: 98 | return 0; 99 | } 100 | return 1; 101 | } 102 | 103 | /* 104 | * DRAM 105 | */ 106 | static struct members dram_members[] = { 107 | { .name="dram_clock" }, 108 | { .name="dram_clk", .translation="clock" }, 109 | { .name="dram_type" }, 110 | { .name="dram_rank_num" }, 111 | { .name="dram_density" }, 112 | { .name="dram_chip_density", .translation="density" }, 113 | { .name="dram_io_width" }, 114 | { .name="dram_bus_width" }, 115 | { .name="dram_cas" }, 116 | { .name="dram_zq" }, 117 | { .name="dram_odt_en" }, 118 | { .name="dram_size" }, 119 | { .name="dram_tpr0", .mode=1 }, 120 | { .name="dram_tpr1", .mode=1 }, 121 | { .name="dram_tpr2", .mode=1 }, 122 | { .name="dram_tpr3", .mode=1 }, 123 | { .name="dram_tpr4", .mode=1 }, 124 | { .name="dram_tpr5", .mode=1 }, 125 | { .name="dram_emr1", .mode=1 }, 126 | { .name="dram_emr2", .mode=1 }, 127 | { .name="dram_emr3", .mode=1 }, 128 | }; 129 | 130 | static int generate_dram_struct(FILE *out, struct script_section *sp) 131 | { 132 | struct script_entry *ep; 133 | const char *key; 134 | int ret = 1; 135 | 136 | fprintf(out, "static struct dram_para dram_para = {\n"); 137 | foreach_member(mp, dram_members) { 138 | ep = script_find_entry(sp, mp->name); 139 | if (!ep) 140 | continue; 141 | 142 | key = (mp->translation) ? mp->translation : mp->name+5; 143 | if (!out_member(out, key, mp->mode, ep)) { 144 | pr_err("dram_para: %s: invalid field\n", ep->name); 145 | ret = 0; 146 | } 147 | 148 | } 149 | fprintf(out, "};\n"); 150 | fputs("\nunsigned long sunxi_dram_init(void)\n" 151 | "{\n\treturn dramc_init(&dram_para);\n}\n", 152 | out); 153 | 154 | return ret; 155 | } 156 | 157 | #if 0 158 | /* 159 | * PMU 160 | */ 161 | static struct members pmu_members[] = { 162 | { .name = "pmu_used2" }, 163 | { .name = "pmu_para" }, 164 | { .name = "pmu_adpdet" }, 165 | { .name = "pmu_shutdown_chgcur" }, 166 | { .name = "pmu_shutdown_chgcur2" }, 167 | { .name = "pmu_pwroff_vol" }, 168 | { .name = "pmu_pwron_vol" }, 169 | }; 170 | 171 | static int generate_pmu_struct(FILE *out, struct script_section *target, 172 | struct script_section *pmu_para) 173 | { 174 | struct list_entry *le; 175 | struct script_section *sp; 176 | struct script_entry *ep; 177 | const char *key; 178 | int ret = 1; 179 | 180 | fputs("\nstatic struct pmu_para pmu_para = {\n", out); 181 | 182 | sp = target; 183 | for (le = list_first(&sp->entries); le; 184 | le = list_next(&sp->entries, le)) { 185 | ep = container_of(le, struct script_entry, entries); 186 | 187 | if (!out_member(out, ep->name, 0, ep)) { 188 | pr_err("target: %s: invalid field\n", ep->name); 189 | ret = 0; 190 | } 191 | } 192 | 193 | foreach_member(mp, pmu_members) { 194 | ep = script_find_entry(pmu_para, mp->name); 195 | if (!ep) 196 | continue; 197 | 198 | key = (mp->translation) ? mp->translation : mp->name+4; 199 | if (!out_member(out, key, mp->mode, ep)) { 200 | pr_err("pmu_para: %s: invalid field\n", mp->name); 201 | ret = 0; 202 | } 203 | } 204 | 205 | fputs("};\n", out); 206 | fputs("\nint sunxi_pmu_init(void)\n" 207 | "{\n\treturn PMU_init(&pmu_para);\n}\n", 208 | out); 209 | return ret; 210 | 211 | (void) pmu_para; 212 | } 213 | #endif 214 | 215 | int script_generate_uboot(FILE *out, const char *UNUSED(filename), 216 | struct script *script) 217 | { 218 | struct { 219 | const char *name; 220 | struct script_section *sp; 221 | } sections[] = { 222 | { "dram_para", NULL }, 223 | #if 0 224 | { "target", NULL }, 225 | { "pmu_para", NULL }, 226 | #endif 227 | }; 228 | 229 | for (unsigned i=0; i\n" 244 | #if 0 245 | "#include \n" 246 | #endif 247 | "#include \n\n", 248 | out); 249 | 250 | generate_dram_struct(out, sections[0].sp); 251 | #if 0 252 | generate_pmu_struct(out, sections[1].sp, sections[2].sp); 253 | #endif 254 | 255 | return 1; 256 | } 257 | -------------------------------------------------------------------------------- /script_uboot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Alejandro Mery 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef _SUBXI_TOOLS_SCRIPT_UBOOT_H 18 | #define _SUBXI_TOOLS_SCRIPT_UBOOT_H 19 | 20 | int script_generate_uboot(FILE *out, const char *filename, struct script *script); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /soc_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Siarhei Siamashka 3 | * Copyright (C) 2016 Bernhard Nortmann 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef _SUNXI_TOOLS_SOC_INFO_H 19 | #define _SUNXI_TOOLS_SOC_INFO_H 20 | 21 | #include 22 | #include 23 | 24 | /* SoC version information, as retrieved by the FEL protocol */ 25 | struct aw_fel_version { 26 | char signature[8]; 27 | uint32_t soc_id; /* 0x00162300 */ 28 | uint32_t unknown_0a; /* 1 */ 29 | uint16_t protocol; /* 1 */ 30 | uint8_t unknown_12; /* 0x44 */ 31 | uint8_t unknown_13; /* 0x08 */ 32 | uint32_t scratchpad; /* 0x7e00 */ 33 | uint32_t pad[2]; /* unused */ 34 | } __attribute__((packed)); 35 | 36 | /* 37 | * Buffer for a SoC name string. We want at least 6 + 1 characters, to store 38 | * the hexadecimal ID "0xABCD" for unknown SoCs, plus the terminating NUL. 39 | */ 40 | typedef char soc_name_t[8]; 41 | 42 | /* 43 | * The 'sram_swap_buffers' structure is used to describe information about 44 | * pairwise memory regions in SRAM, the content of which needs to be exchanged 45 | * before calling the U-Boot SPL code and then exchanged again before returning 46 | * control back to the FEL code from the BROM. 47 | */ 48 | typedef struct { 49 | uint32_t buf1; /* BROM buffer */ 50 | uint32_t buf2; /* backup storage location */ 51 | uint32_t size; /* buffer size */ 52 | } sram_swap_buffers; 53 | 54 | /* 55 | * Contains information on the watchdog peripheral, to enable reset 56 | */ 57 | typedef struct { 58 | /* Register that needs to be written to */ 59 | uint32_t reg_mode; 60 | /* Value to write to trigger a reset */ 61 | uint32_t reg_mode_value; 62 | } watchdog_info; 63 | 64 | /* 65 | * sunxi sid sections 66 | */ 67 | typedef struct { 68 | const char *name; 69 | uint32_t offset; 70 | uint32_t size_bits; 71 | } sid_section; 72 | 73 | #define SID_SECTION(_name, _offset, _size_bits) { \ 74 | .name = _name, \ 75 | .offset = _offset, \ 76 | .size_bits = _size_bits, \ 77 | } 78 | 79 | /* 80 | * Each SoC variant may have its own list of memory buffers to be exchanged 81 | * and the information about the placement of the thunk code, which handles 82 | * the transition of execution from the BROM FEL code to the U-Boot SPL and 83 | * back. 84 | * 85 | * Note: the entries in the 'swap_buffers' tables need to be sorted by 'buf1' 86 | * addresses. And the 'buf1' addresses are the BROM data buffers, while 'buf2' 87 | * addresses are the intended backup locations. 88 | * 89 | * Also for performance reasons, we optionally want to have MMU enabled with 90 | * optimal section attributes configured (the code from the BROM should use 91 | * I-cache, writing data to the DRAM area should use write combining). The 92 | * reason is that the BROM FEL protocol implementation moves data using the 93 | * CPU somewhere on the performance critical path when transferring data over 94 | * USB. The older SoC variants (A10/A13/A20/A31/A23) already have MMU enabled 95 | * and we only need to adjust section attributes. The BROM in newer SoC variants 96 | * (A33/A83T/H3) doesn't enable MMU any more, so we need to find some 16K of 97 | * spare space in SRAM to place the translation table there and specify it as 98 | * the 'mmu_tt_addr' field in the 'soc_sram_info' structure. The 'mmu_tt_addr' 99 | * address must be 16K aligned. 100 | * 101 | * If an SoC has the "secure boot" fuse burned, it will enter FEL mode in 102 | * non-secure state, so with the SCR.NS bit set. Since in this mode the 103 | * secure/non-secure state restrictions are actually observed, we suffer 104 | * from several restrictions: 105 | * - No access to the SID information (both via memory mapped and "register"). 106 | * - No access to secure SRAM (SRAM A2 on H3/A64/H5). 107 | * - No access to the secure side of the GIC, so it can't be configured to 108 | * be accessible from non-secure world. 109 | * - No RMR trigger on ARMv8 cores to bring the core into AArch64. 110 | * However it has been found out that a simple "smc" call will immediately 111 | * return from monitor mode, but with the NS bit cleared, so access to all 112 | * secure peripherals is suddenly possible. 113 | * The 'needs_smc_workaround_if_zero_word_at_addr' field can be used to 114 | * have a check for this condition (reading from restricted addresses 115 | * typically returns zero) and then activate the SMC workaround if needed. 116 | */ 117 | typedef struct { 118 | uint32_t soc_id; /* ID of the SoC */ 119 | const char *name; /* human-readable SoC name string */ 120 | uint32_t spl_addr; /* SPL load address */ 121 | uint32_t scratch_addr; /* A safe place to upload & run code */ 122 | uint32_t thunk_addr; /* Address of the thunk code */ 123 | uint32_t thunk_size; /* Maximal size of the thunk code */ 124 | bool needs_l2en; /* Set the L2EN bit */ 125 | uint32_t mmu_tt_addr; /* MMU translation table address */ 126 | uint32_t sid_base; /* base address for SID registers */ 127 | uint32_t sid_offset; /* offset for SID_KEY[0-3], "root key" */ 128 | const sid_section *sid_sections; /* sid memory maps */ 129 | uint32_t rvbar_reg; /* MMIO address of RVBARADDR0_L register */ 130 | uint32_t rvbar_reg_alt;/* alternative MMIO address of RVBARADDR0_L register */ 131 | uint32_t ver_reg; /* MMIO address of "Version Register" */ 132 | const watchdog_info *watchdog; /* Used for reset */ 133 | bool sid_fix; /* Use SID workaround (read via register) */ 134 | /* Use I$ workaround (disable I$ before first write to prevent stale thunk */ 135 | bool icache_fix; 136 | /* Use SMC workaround (enter secure mode) if can't read from this address */ 137 | uint32_t needs_smc_workaround_if_zero_word_at_addr; 138 | uint32_t sram_size; /* Usable contiguous SRAM at spl_addr */ 139 | sram_swap_buffers *swap_buffers; 140 | } soc_info_t; 141 | 142 | 143 | void get_soc_name_from_id(soc_name_t buffer, uint32_t soc_id); 144 | soc_info_t *get_soc_info_from_id(uint32_t soc_id); 145 | soc_info_t *get_soc_info_from_version(struct aw_fel_version *buf); 146 | const soc_info_t *get_next_soc(const soc_info_t *prev); 147 | 148 | #endif /* _SUNXI_TOOLS_SOC_INFO_H */ 149 | -------------------------------------------------------------------------------- /sunxi-fel.1: -------------------------------------------------------------------------------- 1 | .\" Manpage for sunxi-fel 2 | .\" Copyright (C) 2018 by Andre Przywara 3 | .TH sunxi-fel 1 "14 Jan 2022" "1.5" "sunxi-fel man page" 4 | .SH NAME 5 | sunxi-fel \- controlling USB BootROM protocol for Allwinner CPUs 6 | .SH SYNOPSIS 7 | sunxi-fel [OPTIONS] COMMAND [ARGS] 8 | .SH DESCRIPTION 9 | sunxi-fel is a script interface for USB communication with the BootROM of 10 | Allwinner CPUs. 11 | 12 | On explicit request (typically by pressing a button often labeled "uboot" 13 | or "recovery"), or when all other booting methods fail, the CPU's early ROM 14 | code enters the so called FEL mode, where it will wait for USB commands sent 15 | by some host to the Allwinner CPU's USB OTG interface. sunxi-fel implements 16 | this FEL protocol and communicates with the ROM code, to download or upload 17 | data and to start code execution. 18 | 19 | Besides simply allowing to write to or to read from device memory, sunxi-fel 20 | also helps with more complex things, which involve uploading code, executing 21 | it and then returning to FEL mode, to allow further data transfer or inspection. 22 | In particular it supports loading and executing U-Boot, including the primary 23 | SPL stage. 24 | .SH "OPTIONS" 25 | Those options affect general execution and should be put first, before any 26 | actual commands. 27 | .sp 28 | .B \-h, \-\-help 29 | .RS 4 30 | Print a help message and exit. 31 | .RE 32 | .sp 33 | .B \-v, \-\-verbose 34 | .RS 4 35 | Enable verbose logging. 36 | .RE 37 | .sp 38 | .B \-p, \-\-progress 39 | .RS 4 40 | "write" transfers show a progress bar. 41 | .RE 42 | .sp 43 | .B \-l, \-\-list 44 | .RS 4 45 | Enumerate all (USB) FEL devices and exit. 46 | .RE 47 | .sp 48 | .B \-\-list-socs 49 | .RS 4 50 | Print a list of all supported SoCs and exit. 51 | .RE 52 | .sp 53 | .B \-d, \-\-dev bus:devnum 54 | .RS 4 55 | Use specific USB bus and device number 56 | .RE 57 | .sp 58 | .B \-\-sid SID 59 | .RS 4 60 | Select a device by its SID key (exact match). The SID key of a particular 61 | device can be queried using the "sid" command. 62 | .RE 63 | .SH "SUNXI-FEL COMMANDS" 64 | sunxi-fel can take several commands, each followed by their parameters, and 65 | will execute them in order. The only exception is the "uboot" command, 66 | which will delay launching U-Boot until all other commands have been executed. 67 | .sp 68 | Please note that accessing any part of the DRAM will not work until the 69 | DRAM controller has been initialized. This can be achieved by uploading and 70 | executing a suitable U-Boot SPL image, using the "spl" command. Trying to 71 | access DRAM before that will most likely hang. 72 | .sp 73 | Any numbers given as parameters to those commands can be prefixed with "0x" 74 | to denote hexadecimal notation or "0" to start an octal number. 75 | They are interpretated as decimal numbers otherwise. 76 | .PP 77 | .B spl 78 | .RS 4 79 | Load and execute U-Boot SPL. 80 | .sp 81 | Upload the given binary file to the appropriate SRAM location, carefully 82 | moving the FEL stack out of the way in the process. The binary is then 83 | executed. When it returns, the FEL stack is restored and execution is 84 | transferred back to the BootROM's FEL routine. 85 | .sp 86 | If the file additionally contains a main U-Boot binary 87 | (u-boot-sunxi-with-spl.bin), this command also transfers that 88 | to memory, using the load address stored in the image file, but won't execute 89 | it. 90 | .RE 91 | .PP 92 | .B uboot 93 | .RS 4 94 | like "spl", but actually starts U-Boot. U-Boot execution will take place 95 | when the fel utility exits. This allows combining "uboot" with further "write" 96 | commands, to transfer other files possibly needed for the boot. 97 | .RE 98 | .PP 99 | .B hex[dump]
100 | .RS 4 101 | Hexadecimal memory dump. Dumps bytes of the memory region starting at 102 |
. The context will be displayed as a hexdump, suitable for human 103 | inspection. 104 | .RE 105 | .PP 106 | .B dump
107 | .RS 4 108 | Binary memory dump. Dumps bytes of the memory region starting at 109 |
. The context will be dumped "as is" to the standard output, so it 110 | can be redirected to a file and processed as binary data. 111 | .RE 112 | .PP 113 | .B exe[cute]
114 | .RS 4 115 | Start executing code at
in memory on the device. 116 | .RE 117 | .PP 118 | .B reset64
119 | .RS 4 120 | Request a warm reset of the core, starting execution in the 64-bit AArch64 121 | execution state, at
. 122 | .RE 123 | .PP 124 | .B wdreset 125 | .RS 4 126 | Reset the device by triggering the watchdog with the shortest possible period. 127 | This will reset the whole SoC, including all on-SoC peripherals, but might not 128 | affect on-board devices like PMICs or PHYs. 129 | .RE 130 | .PP 131 | .B memmove 132 | .RS 4 133 | Copy bytes within device memory, from to . 134 | .RE 135 | .PP 136 | .B readl
137 | .RS 4 138 | Read a 32-bit value from device memory at
. The value will be output 139 | as a hexadecimal number, prefixed with "0x". The address needs to be 4-byte 140 | aligned. 141 | .RE 142 | .PP 143 | .B writel
144 | .RS 4 145 | Write the given 32-bit to device memory at
. 146 | .RE 147 | .PP 148 | .B read
149 | .RS 4 150 | Write memory contents into file. Reads bytes from memory at
151 | and writes the content into . 152 | .RE 153 | .PP 154 | .B write
155 | .RS 4 156 | Store file contents into memory. Writes the entire content of into 157 | memory at
. 158 | .RE 159 | .PP 160 | .B write-with-progress 161 | .RS 4 162 | Display a textual progress bar while writing to the device. Same as "write" 163 | with the "-p" parameter. 164 | .RE 165 | .PP 166 | .B write-with-gauge 167 | .RS 4 168 | Same as write, but write the progress in percentages to the standard output. 169 | This can be piped to any "dialog" compatible program, when using the --gauge 170 | widget. 171 | .RE 172 | .PP 173 | .B write-with-xgauge 174 | .RS 4 175 | Same as write-with-gauge, but with extended gauge output. This can be piped to 176 | any "dialog" compatible program, using the --gauge widget. Aside from updating 177 | the current progress in percents, it also updates the number of bytes written 178 | and gives an estimated time to completion. 179 | .RE 180 | .PP 181 | .B multi[write] # ... 182 | .RS 4 183 | Like "write-with-progress", but with multiple load adddresses and files, 184 | all sharing the same progress bar. 185 | .RE 186 | .PP 187 | .B multi[write]-with-gauge ... 188 | .RS 4 189 | Like "write-with-gauge", but with multiple load adddresses and files, 190 | all sharing the same progress bar. 191 | .RE 192 | .PP 193 | .B multi[write]-with-xgauge ... 194 | .RS 4 195 | Like "write-with-xgauge", but with multiple load adddresses and files, 196 | all sharing the same progress bar. 197 | .RE 198 | .PP 199 | .B echo-gauge "some text" 200 | .RS 4 201 | Update prompt/caption for gauge output. This outputs a command to be 202 | interpreted by "dialog" to change the caption text. 203 | .RE 204 | .PP 205 | .B ver[sion] 206 | .RS 4 207 | Show the BROM version. This prints some static data, among other things 208 | containing the detected SoC. Can be used to verify a FEL connection is working. 209 | .RE 210 | .PP 211 | .B sid 212 | .RS 4 213 | Retrieve and output the 128-bit SID key. This key contains some form of serial 214 | number, which should be unique to each chip (although there have been reports 215 | of same SIDs for particular batches of chips). 216 | .RE 217 | .PP 218 | .B sid-registers 219 | .RS 4 220 | As the "sid" command above, but use the alternative MMIO register access method 221 | on the device. There are SoCs that require this method due to bugs in the SID 222 | implementation, those known will automatically choose this workaround when using 223 | the "sid" command. This command here is to test new SoCs for compliance. 224 | .RE 225 | .PP 226 | .B sid-dump 227 | .RS 4 228 | Read the entire SID eFuses array and dump its content. For SoCs with a known 229 | eFuses layout, this will annotate the known regions. 230 | .RE 231 | .PP 232 | .B clear
233 | .RS 4 234 | Clear bytes of memory starting at
(filling with zeroes). 235 | .RE 236 | .PP 237 | .B fill
238 | .RS 4 239 | Fills bytes of memory starting at
with the byte . 240 | .RE 241 | .PP 242 | .B spiflash-info 243 | .RS 4 244 | Retrieves basic information about a SPI flash chip attached to the SPI0 pins. 245 | This is using the same method as the BootROM does, to accesses the same storage 246 | that the device could boot from. 247 | 248 | Prints the manufacturer of the flash chip and 249 | its capacity. Should also be used to detect the presence of a SPI flash chip. 250 | .RE 251 | .PP 252 | .B spiflash-read 253 | .RS 4 254 | Reads bytes starting from offset of a SPI flash chip, storing 255 | the result into . 256 | .RE 257 | .PP 258 | .B spiflash-write 259 | .RS 4 260 | Reads and stores its content in the SPI flash, starting at offset . 261 | .RE 262 | .SH EXAMPLES 263 | .RS 4 264 | \fB$\fR sunxi-fel -v -p ver 265 | .RE 266 | .sp 267 | .RS 4 268 | \fB$\fR sunxi-fel uboot u-boot-sunxi-with-spl.bin 269 | .RE 270 | .sp 271 | .RS 4 272 | \fB$\fR sunxi-fel -v -p spl sunxi-spl.bin write 0x44000 bl31.bin write 0x4a000000 u-boot.bin reset64 0x44000 273 | .RE 274 | .SH AUTHOR 275 | Andre Przywara 276 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # tests/Makefile 3 | # 4 | # Copyright (C) 2016 Bernhard Nortmann 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | BOARDS_URL := https://github.com/linux-sunxi/sunxi-boards/archive/master.zip 20 | BOARDS_DIR := sunxi-boards 21 | 22 | check: check_all_fex coverage 23 | 24 | # Conversion cycle (.fex -> .bin -> .fex) test for all sunxi-boards 25 | check_all_fex: $(BOARDS_DIR)/README unify-fex 26 | ./test_all_fex.sh $(BOARDS_DIR) 27 | 28 | coverage: $(BOARDS_DIR)/README 29 | # Usage help / invocation with no args 30 | ../sunxi-fexc -? 2> /dev/null ; exit 0 31 | # Improve code coverage for corner cases (e.g. erroneous parameters) 32 | ./test_fex2bin_corner_cases.sh 33 | ./test_bin2fex_corner_cases.sh 34 | 35 | # Retrieve and extract sunxi-boards archive (containing all .fex) 36 | $(BOARDS_DIR).zip: 37 | curl -fLsS -o $@ $(BOARDS_URL) 38 | $(BOARDS_DIR)/README: $(BOARDS_DIR).zip 39 | @echo Extracting $< ... 40 | unzip -q $< 41 | mv sunxi-boards-master $(BOARDS_DIR) 42 | touch -r $(BOARDS_DIR) $< 43 | cat patches/*.patch | patch -p1 44 | 45 | unify-fex: unify-fex.c 46 | $(CC) -Wall -Werror -o $@ $< 47 | 48 | clean: 49 | rm -rf $(BOARDS_DIR).zip $(BOARDS_DIR) unify-fex 50 | 51 | # 52 | # Dedicated rule for Travis CI test of sunxi-boards. This assumes that the 53 | # sunxi-tools source (archive) was extracted into a subdir below the working 54 | # directory, meaning that BOARDS_DIR should be "../.." 55 | # 56 | sunxi-boards_CI: unify-fex 57 | # compile sunxi-fexc, link bin2fex and fex2bin 58 | make -C .. bin2fex fex2bin 59 | # apply patches to BOARDS_DIR, ignore mismatches 60 | cat patches/*.patch | patch --forward -r- -p2 -d $(BOARDS_DIR) || true 61 | # and finally run the tests 62 | ./test_all_fex.sh $(BOARDS_DIR) 63 | -------------------------------------------------------------------------------- /tests/fextest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (C) 2016 Bernhard Nortmann 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | echo $0 $* 19 | FEX2BIN=../fex2bin 20 | BIN2FEX=../bin2fex 21 | FEX=$1 22 | BIN=${FEX/%.fex/.bin} 23 | REVERSE=${FEX/%.fex/.new} 24 | ${FEX2BIN} ${FEX} ${BIN} 25 | ${BIN2FEX} ${BIN} ${REVERSE} 26 | # preprocess .fex, compare it to the bin2fex output 27 | if ./unify-fex ${FEX} | diff -uwB - ${REVERSE}; then 28 | # if successful, clean up the output files 29 | rm -f ${BIN} ${REVERSE} 30 | else 31 | echo '***' 32 | echo "*** ERROR processing ${FEX}" 33 | echo '***' 34 | exit 1 35 | fi 36 | -------------------------------------------------------------------------------- /tests/test_all_fex.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (C) 2016 Bernhard Nortmann 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | FEXFILES=fexfiles.lst 19 | find $1 -name '*.fex' > ${FEXFILES} 20 | while read fex; do 21 | ./fextest.sh ${fex} || exit 22 | done <${FEXFILES} 23 | rm -f ${FEXFILES} 24 | -------------------------------------------------------------------------------- /tests/test_bin2fex_corner_cases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # === Test errors / corner cases of "bin2fex", improving on code coverage === 4 | # 5 | # Copyright (C) 2016 Bernhard Nortmann 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | BIN2FEX=../bin2fex 21 | TESTFILE=sunxi-boards/sys_config/a10/a10-olinuxino-lime 22 | # use sunxi-fexc in "fex2bin" mode, testing explicit parameters at the same time 23 | FEX2BIN="../sunxi-fexc -v -q -I fex -O bin" 24 | 25 | ${FEX2BIN} ${TESTFILE}.fex ${TESTFILE}.bin 26 | # have bin2fex explicitly read /dev/stdin, to force use of fexc.c's "read_all()" 27 | cat ${TESTFILE}.bin | ${BIN2FEX} /dev/stdin > /dev/null 28 | rm -f ${TESTFILE}.bin 29 | -------------------------------------------------------------------------------- /tests/test_fex2bin_corner_cases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # === Test errors / corner cases of "fex2bin", improving on code coverage === 4 | # 5 | # Copyright (C) 2016 Bernhard Nortmann 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program. If not, see . 19 | 20 | FEX2BIN=../fex2bin 21 | 22 | function expect () { 23 | OUT=`${FEX2BIN} 2>&1` 24 | if (! echo ${OUT} | grep -q "$1"); then 25 | echo ERROR: Expected substring \"$1\" not found in output: 26 | echo ${OUT} 27 | exit 1 28 | fi 29 | #echo ${OUT} 30 | } 31 | 32 | # missing section, CRLF line ending 33 | echo -e "foobar\r\n" | expect "data must follow a section" 34 | 35 | # malformed sections 36 | expect "incomplete section declaration" <<-EOF 37 | [foobar 38 | EOF 39 | expect "invalid character at 5" <<-EOF 40 | [foo#bar] 41 | EOF 42 | 43 | # invalid entry 44 | expect "invalid character at 4" <<-EOF 45 | [foo] 46 | bar 47 | EOF 48 | 49 | # bad port specifiers 50 | expect "parse error at 12" <<-EOF 51 | [foo] 52 | bar = port:P@0 53 | EOF 54 | expect "invalid character at 14" <<-EOF 55 | [foo] 56 | bar = port:PA* 57 | EOF 58 | expect "port out of range at 14" <<-EOF 59 | [foo] 60 | bar = port:PA666 61 | EOF 62 | expect "value out of range at 17" <<-EOF 63 | [foo] 64 | bar = port:PA00<-1> 65 | EOF 66 | expect "invalid character at 18" <<-EOF 67 | [foo] 68 | bar = port:PA00<0 > 69 | EOF 70 | 71 | # bad = pairs 72 | expect "invalid character at 8" <<-EOF 73 | [foo] 74 | bar = 0* 75 | EOF 76 | expect "value out of range" <<-EOF 77 | [foo] 78 | bar = 4294967296 79 | EOF 80 | expect "unquoted value 'bad', assuming string" <<-EOF 81 | [foo] 82 | bar = bad 83 | EOF 84 | 85 | # test truncation of very long identifiers 86 | ${FEX2BIN} > /dev/null <<-EOF 87 | [an_overly_long_section_name_to_truncate] 88 | an_overly_long_entry_name_to_truncate = 0 89 | EOF 90 | -------------------------------------------------------------------------------- /tests/unify-fex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Bernhard Nortmann 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | /* 19 | * unify-fex.c 20 | * 21 | * A utility program to do some standard transformations on .fex files, 22 | * to allow simpler (diff) comparison with the output of bin2fex. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* string macro to determine if str starts with a given literal */ 32 | #define starts(str, literal) \ 33 | (strncmp(str, "" literal, sizeof(literal) - 1) == 0) 34 | 35 | int main(int argc, char **argv) 36 | { 37 | FILE *input = stdin; 38 | char line[1024]; 39 | char *c, *p; 40 | int64_t num; 41 | 42 | if (argc >= 2) { 43 | input = fopen(argv[1], "r"); 44 | if (!input) { 45 | perror("failed to open input file"); 46 | exit(EXIT_FAILURE); 47 | } 48 | } 49 | 50 | /* loop over all input lines, output goes to stdout */ 51 | while (fgets(line, sizeof(line), input)) { 52 | 53 | /* strip all whitespace (even CR/LF) from the input line */ 54 | for (c = p = line; *p; p++) { 55 | if (!isspace(*p)) 56 | *c++ = *p; 57 | } 58 | *c = '\0'; 59 | 60 | if (*line == ';' || *line == '#') 61 | /* This is a comment line, simply ignore it */ 62 | continue; 63 | if (*line == ':') 64 | continue; /* suspect malformed comment, ignore */ 65 | 66 | if ((p = strchr(line, '='))) { 67 | /* This is a = line, reformat it */ 68 | c = strdup(p + 1); 69 | sprintf(p, " = %s", c); 70 | free(c); 71 | p += 3; /* have p point to the beginning of */ 72 | 73 | if (starts(p, "port:")) { 74 | if (p[5] == 'P') { /* port:P... */ 75 | /* get pin number (including bank) */ 76 | num = ((p[6] - 'A') << 5) + strtoll(p + 7, &c, 10); 77 | c = strdup(c); 78 | sprintf(p, "port:P%c%02" PRId64 "%s", 'A' + (int)(num >> 5), num & 0x1F, c); 79 | free(c); 80 | 81 | /* check angle brackets to determine options count */ 82 | num = 0; 83 | for (c = p + 9; *c; c++) { 84 | if (*c == '<') 85 | num++; 86 | } 87 | /* append "" for missing options */ 88 | c = strrchr(p, '\0'); 89 | while (num < 4) { 90 | c += sprintf(c, ""); 91 | num++; 92 | } 93 | } 94 | } else { 95 | /* 96 | * fix formatting of numeric values, depending on the keyword 97 | * these are a bit nasty, since they vary wildly between hex 98 | * and decimal - see decompile_single_mode() in script_fex.c 99 | */ 100 | num = strtoll(p, NULL, 0); 101 | if (num || *p == '0') { 102 | int hex = starts(line, "csi_twi_addr"); 103 | hex |= starts(line, "ctp_twi_addr"); 104 | hex |= starts(line, "dram_baseaddr"); 105 | hex |= starts(line, "dram_emr"); 106 | hex |= starts(line, "dram_tpr"); 107 | hex |= starts(line, "dram_zq"); 108 | hex |= starts(line, "g2d_size"); 109 | hex |= starts(line, "gsensor_twi_addr"); 110 | hex |= starts(line, "lcd_gamma_tbl_"); 111 | hex |= starts(line, "rtp_press_threshold "); 112 | hex |= starts(line, "rtp_sensitive_level"); 113 | hex |= starts(line, "tkey_twi_addr"); 114 | 115 | /* large decimals will be decompiled as negative */ 116 | if (!hex && num >= 2147483648LL) 117 | num -= 4294967296LL; 118 | 119 | sprintf(p, hex ? "0x%" PRIx64 : "%" PRId64, num); 120 | } else { 121 | /* 122 | * We expect all other (= non-numeric) values 123 | * to be strings, always quote them. 124 | */ 125 | if (*p && (*p != '"')) { 126 | c = strdup(p); 127 | sprintf(p, "\"%s\"", c); 128 | free(c); 129 | } 130 | /* Remove a trailing semicolon. */ 131 | c = strchr(p, 0); 132 | if (*--c == ';') 133 | *c = '\0'; 134 | } 135 | } 136 | } 137 | 138 | puts(line); 139 | } 140 | 141 | if (ferror(input)) { 142 | perror("file read error"); 143 | exit(EXIT_FAILURE); 144 | } 145 | 146 | fclose(input); 147 | return EXIT_SUCCESS; 148 | } 149 | -------------------------------------------------------------------------------- /thunks/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # build "preprocessed" .h files for inclusion of ARM scratch code 3 | # 4 | 5 | SPL_THUNK := fel-to-spl-thunk.h 6 | THUNKS := clrsetbits.h 7 | THUNKS += memcpy.h 8 | THUNKS += readl_writel.h 9 | THUNKS += rmr-thunk.h 10 | THUNKS += sid_read_root.h 11 | 12 | all: $(SPL_THUNK) $(THUNKS) 13 | # clean up object files afterwards 14 | rm -f *.o 15 | 16 | # This empty prerequisite enforces a rebuild of all the headers on every run 17 | FORCE: 18 | 19 | # If not specified explicitly: try to guess a suitable ARM toolchain prefix 20 | CROSS_COMPILE ?= $(shell ../find-arm-gcc.sh) 21 | 22 | AS := $(CROSS_COMPILE)as 23 | OBJDUMP := $(CROSS_COMPILE)objdump 24 | 25 | AWK_O_TO_H := LC_ALL=C awk -f objdump_to_h.awk 26 | 27 | # The SPL thunk requires a different output format. The "style" variable for 28 | # awk controls this, and causes the htole32() conversion to be omitted. 29 | fel-to-spl-thunk.h: fel-to-spl-thunk.S FORCE 30 | $(AS) -o $(subst .S,.o,$<) -march=armv5te $< 31 | $(OBJDUMP) -d $(subst .S,.o,$<) | $(AWK_O_TO_H) -v style=old > $@ 32 | 33 | $(THUNKS): %.h: %.S FORCE 34 | $(AS) -o $(subst .S,.o,$<) -march=armv5te $< 35 | $(OBJDUMP) -d $(subst .S,.o,$<) | $(AWK_O_TO_H) > $@ 36 | -------------------------------------------------------------------------------- /thunks/README.md: -------------------------------------------------------------------------------- 1 | 2 | # thunks/README.md 3 | 4 | This directory contains assembly sources for ARM [thunk] code, and 5 | a corresponding _Makefile_. The idea is that the resulting binary routines 6 | can be transferred to a suitable target device and then executed 'remotely', 7 | usually via `sunxi-fel`. 8 | 9 | Normally you don't need to change or (re)build anything within this folder. 10 | Currently our main build process (via the parent directory's _Makefile_) 11 | only includes `fel-to-spl-thunk.h` directly. Other _.h_ files are provided 12 | **just for reference**. The main purpose of this folder is simply keeping 13 | track of _.S_ sources, to help with possible future maintenance of the 14 | various code snippets. 15 | 16 | Please note that any files lacking explicit license information are intended 17 | to be covered by the project's [overall license](../LICENSE.md) (GPLv2). 18 | 19 | 20 | [thunk]: https://en.wikipedia.org/wiki/Thunk#Interoperability 21 | -------------------------------------------------------------------------------- /thunks/clrsetbits.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Thunk code to assist with bitwise operations (set/clear) via FEL 3 | */ 4 | 5 | fel_clrsetbits_le32: 6 | ldr r0, 1f /* address */ 7 | ldr r1, [r0] /* load value */ 8 | ldr r2, 2f /* clrbits mask */ 9 | bic r1, r2 /* clear bits, post-increment r1 */ 10 | ldr r2, 3f /* setbits mask */ 11 | orr r1, r2 /* set bits (logical "or") */ 12 | str r1, [r0] /* store result */ 13 | bx lr 14 | 15 | 1: .word 0 /* addr */ 16 | 2: .word 0 /* clrbits (= bits to clear) */ 17 | 3: .word 0 /* setbits (= bits to set) */ 18 | -------------------------------------------------------------------------------- /thunks/clrsetbits.h: -------------------------------------------------------------------------------- 1 | /* : */ 2 | htole32(0xe59f0018), /* 0: ldr r0, [pc, #24] */ 3 | htole32(0xe5901000), /* 4: ldr r1, [r0] */ 4 | htole32(0xe59f2014), /* 8: ldr r2, [pc, #20] */ 5 | htole32(0xe1c11002), /* c: bic r1, r1, r2 */ 6 | htole32(0xe59f2010), /* 10: ldr r2, [pc, #16] */ 7 | htole32(0xe1811002), /* 14: orr r1, r1, r2 */ 8 | htole32(0xe5801000), /* 18: str r1, [r0] */ 9 | htole32(0xe12fff1e), /* 1c: bx lr */ 10 | -------------------------------------------------------------------------------- /thunks/fel-to-spl-thunk.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2015 Siarhei Siamashka 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice (including the next 12 | * paragraph) shall be included in all copies or substantial portions of the 13 | * Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | * DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | .arm 25 | 26 | BUF1 .req r0 27 | BUF2 .req r1 28 | TMP1 .req r2 29 | TMP2 .req r3 30 | SWAPTBL .req r4 31 | FULLSIZE .req r5 32 | BUFSIZE .req r6 33 | CHECKSUM .req r7 34 | SPL_ADDR .req r8 35 | 36 | entry_point: 37 | b setup_stack 38 | 39 | stack_begin: 40 | .space 32, 0xff 41 | stack_end: 42 | nop 43 | 44 | /* A function, which walks the table and swaps all buffers */ 45 | swap_all_buffers: 46 | adr SWAPTBL, appended_data + 4 47 | swap_next_buffer: 48 | ldr BUF1, [SWAPTBL], #4 49 | ldr BUF2, [SWAPTBL], #4 50 | ldr BUFSIZE, [SWAPTBL], #4 51 | cmp BUFSIZE, #0 52 | bxeq lr 53 | swap_next_word: 54 | ldr TMP1, [BUF1] 55 | ldr TMP2, [BUF2] 56 | subs BUFSIZE, BUFSIZE, #4 57 | str TMP1, [BUF2], #4 58 | str TMP2, [BUF1], #4 59 | bne swap_next_word 60 | b swap_next_buffer 61 | 62 | setup_stack: /* Save the original SP, LR and CPSR to stack */ 63 | ldr SPL_ADDR, appended_data 64 | adr BUF1, stack_end 65 | str sp, [BUF1, #-4]! 66 | mov sp, BUF1 67 | mrs TMP1, cpsr 68 | push {TMP1, lr} 69 | 70 | /* Disable IRQ and FIQ */ 71 | orr TMP1, #0xc0 72 | msr cpsr_c, TMP1 73 | 74 | /* Check if the instructions or data cache is enabled */ 75 | mrc p15, 0, TMP1, c1, c0, 0 76 | tst TMP1, #(1 << 2) 77 | tsteq TMP1, #(1 << 12) 78 | bne cache_is_unsupported 79 | 80 | bl swap_all_buffers 81 | 82 | verify_checksum: 83 | ldr CHECKSUM, checksum_seed 84 | mov BUF1, SPL_ADDR 85 | ldr FULLSIZE, [BUF1, #16] 86 | check_next_word: 87 | ldr TMP1, [BUF1], #4 88 | subs FULLSIZE, FULLSIZE, #4 89 | add CHECKSUM, CHECKSUM, TMP1 90 | bne check_next_word 91 | 92 | ldr TMP1, [SPL_ADDR, #12] 93 | subs CHECKSUM, CHECKSUM, TMP1, lsl #1 94 | bne checksum_is_bad 95 | 96 | /* Change 'eGON.BT0' -> 'eGON.FEL' */ 97 | ldr TMP1, egon_fel_str 98 | str TMP1, [SPL_ADDR, #8] 99 | 100 | /* 101 | * Call the SPL code, but before that make sure the CPU sees the 102 | * recently uploaded code. This requires a DSB and ISB. 103 | * The "dsb" and "isb" *instructions* are not available in ARMv5TE, 104 | * but at least for DSB we can use the CP15 register encoding. This 105 | * works for ARMv7 and v8 as well, because we have checked our SCTLR 106 | * before (in fel.c), so we know that CP15BEN is set. 107 | * The ARM926 core does not implement ISB, instead the TRM recommends 108 | * just a branch to achieve the same "flush the pipeline" effect. 109 | * As just this is not sufficient for later cores, check the MIDR 110 | * register, and do the DSB only for ARMv6 or later. 111 | * The input register for the CP15 instruction is ignored. 112 | */ 113 | mcr p15, 0, TMP1, c7, c10, 4 /* CP15DSB */ 114 | mrc p15, 0, TMP1, c0, c0, 0 /* read MIDR */ 115 | and TMP1, TMP1, #(0xf << 16) /* architecture */ 116 | cmp TMP1, #(0x6 << 16) /* ARMv5TEJ */ 117 | mcrgt p15, 0, TMP1, c7, c5, 4 /* CP15ISB, if > ARMv5TEJ */ 118 | blx SPL_ADDR 119 | 120 | /* Return back to FEL */ 121 | b return_to_fel 122 | 123 | cache_is_unsupported: 124 | /* Bail out if cache is enabled and change 'eGON.BT0' -> 'eGON.???' */ 125 | ldr TMP1, cache_enabled_str 126 | str TMP1, [SPL_ADDR, #8] 127 | b return_to_fel_noswap 128 | 129 | checksum_is_bad: 130 | /* The checksum test failed, so change 'eGON.BT0' -> 'eGON.BAD' */ 131 | ldr TMP1, checksum_failed_str 132 | str TMP1, [SPL_ADDR, #8] 133 | 134 | return_to_fel: 135 | bl swap_all_buffers 136 | return_to_fel_noswap: 137 | pop {TMP1, lr} 138 | msr cpsr_c, TMP1 /* Restore the original CPSR */ 139 | ldr sp, [sp] 140 | bx lr 141 | 142 | checksum_seed: 143 | .word 0x5f0a6c39 144 | egon_fel_str: 145 | .ascii ".FEL" 146 | cache_enabled_str: 147 | .ascii ".???" 148 | checksum_failed_str: 149 | .ascii ".BAD" 150 | 151 | appended_data: 152 | /* 153 | * The appended data uses the following format: 154 | * 155 | * struct { 156 | * uint32_t spl_addr; 157 | * sram_swap_buffers swaptbl[]; 158 | * }; 159 | * 160 | * More details about the 'spl_addr' variable and the 'sram_swap_buffers' 161 | * struct can be found in the 'fel.c' source file. 162 | */ 163 | -------------------------------------------------------------------------------- /thunks/fel-to-spl-thunk.h: -------------------------------------------------------------------------------- 1 | /* : */ 2 | 0xea000015, /* 0: b 5c */ 3 | /* : */ 4 | 0xffffffff, /* 4: .word 0xffffffff */ 5 | 0xffffffff, /* 8: .word 0xffffffff */ 6 | 0xffffffff, /* c: .word 0xffffffff */ 7 | 0xffffffff, /* 10: .word 0xffffffff */ 8 | 0xffffffff, /* 14: .word 0xffffffff */ 9 | 0xffffffff, /* 18: .word 0xffffffff */ 10 | 0xffffffff, /* 1c: .word 0xffffffff */ 11 | 0xffffffff, /* 20: .word 0xffffffff */ 12 | /* : */ 13 | 0xe1a00000, /* 24: nop */ 14 | /* : */ 15 | 0xe28f40e8, /* 28: add r4, pc, #232 */ 16 | /* : */ 17 | 0xe4940004, /* 2c: ldr r0, [r4], #4 */ 18 | 0xe4941004, /* 30: ldr r1, [r4], #4 */ 19 | 0xe4946004, /* 34: ldr r6, [r4], #4 */ 20 | 0xe3560000, /* 38: cmp r6, #0 */ 21 | 0x012fff1e, /* 3c: bxeq lr */ 22 | /* : */ 23 | 0xe5902000, /* 40: ldr r2, [r0] */ 24 | 0xe5913000, /* 44: ldr r3, [r1] */ 25 | 0xe2566004, /* 48: subs r6, r6, #4 */ 26 | 0xe4812004, /* 4c: str r2, [r1], #4 */ 27 | 0xe4803004, /* 50: str r3, [r0], #4 */ 28 | 0x1afffff9, /* 54: bne 40 */ 29 | 0xeafffff3, /* 58: b 2c */ 30 | /* : */ 31 | 0xe59f80b0, /* 5c: ldr r8, [pc, #176] */ 32 | 0xe24f0044, /* 60: sub r0, pc, #68 */ 33 | 0xe520d004, /* 64: str sp, [r0, #-4]! */ 34 | 0xe1a0d000, /* 68: mov sp, r0 */ 35 | 0xe10f2000, /* 6c: mrs r2, CPSR */ 36 | 0xe92d4004, /* 70: push {r2, lr} */ 37 | 0xe38220c0, /* 74: orr r2, r2, #192 */ 38 | 0xe121f002, /* 78: msr CPSR_c, r2 */ 39 | 0xee112f10, /* 7c: mrc 15, 0, r2, cr1, cr0, {0} */ 40 | 0xe3120004, /* 80: tst r2, #4 */ 41 | 0x03120a01, /* 84: tsteq r2, #4096 */ 42 | 0x1a000013, /* 88: bne dc */ 43 | 0xebffffe5, /* 8c: bl 28 */ 44 | /* : */ 45 | 0xe59f706c, /* 90: ldr r7, [pc, #108] */ 46 | 0xe1a00008, /* 94: mov r0, r8 */ 47 | 0xe5905010, /* 98: ldr r5, [r0, #16] */ 48 | /* : */ 49 | 0xe4902004, /* 9c: ldr r2, [r0], #4 */ 50 | 0xe2555004, /* a0: subs r5, r5, #4 */ 51 | 0xe0877002, /* a4: add r7, r7, r2 */ 52 | 0x1afffffb, /* a8: bne 9c */ 53 | 0xe598200c, /* ac: ldr r2, [r8, #12] */ 54 | 0xe0577082, /* b0: subs r7, r7, r2, lsl #1 */ 55 | 0x1a00000b, /* b4: bne e8 */ 56 | 0xe59f2048, /* b8: ldr r2, [pc, #72] */ 57 | 0xe5882008, /* bc: str r2, [r8, #8] */ 58 | 0xee072f9a, /* c0: mcr 15, 0, r2, cr7, cr10, {4} */ 59 | 0xee102f10, /* c4: mrc 15, 0, r2, cr0, cr0, {0} */ 60 | 0xe202280f, /* c8: and r2, r2, #983040 */ 61 | 0xe3520806, /* cc: cmp r2, #393216 */ 62 | 0xce072f95, /* d0: mcrgt 15, 0, r2, cr7, cr5, {4} */ 63 | 0xe12fff38, /* d4: blx r8 */ 64 | 0xea000004, /* d8: b f0 */ 65 | /* : */ 66 | 0xe59f2028, /* dc: ldr r2, [pc, #40] */ 67 | 0xe5882008, /* e0: str r2, [r8, #8] */ 68 | 0xea000002, /* e4: b f4 */ 69 | /* : */ 70 | 0xe59f2020, /* e8: ldr r2, [pc, #32] */ 71 | 0xe5882008, /* ec: str r2, [r8, #8] */ 72 | /* : */ 73 | 0xebffffcc, /* f0: bl 28 */ 74 | /* : */ 75 | 0xe8bd4004, /* f4: pop {r2, lr} */ 76 | 0xe121f002, /* f8: msr CPSR_c, r2 */ 77 | 0xe59dd000, /* fc: ldr sp, [sp] */ 78 | 0xe12fff1e, /* 100: bx lr */ 79 | /* : */ 80 | 0x5f0a6c39, /* 104: .word 0x5f0a6c39 */ 81 | /* : */ 82 | 0x4c45462e, /* 108: .word 0x4c45462e */ 83 | /* : */ 84 | 0x3f3f3f2e, /* 10c: .word 0x3f3f3f2e */ 85 | /* : */ 86 | 0x4441422e, /* 110: .word 0x4441422e */ 87 | -------------------------------------------------------------------------------- /thunks/memcpy.S: -------------------------------------------------------------------------------- 1 | /* 2 | * copy "upwards", increasing destination and source addresses 3 | */ 4 | fel_memcpy_up: 5 | ldr r0, 1f /* dst_addr */ 6 | ldr r1, 2f /* src_addr */ 7 | ldr r2, 3f /* bytes */ 8 | sub r3, r1, r0 9 | tst r3, #3 /* test LSB for word alignment */ 10 | bne copyup_tail /* unaligned access, copy byte-wise */ 11 | copyup_head: 12 | tst r1, #3 /* word boundary? */ 13 | beq copyup_loop 14 | ldrb r3, [r1], #1 /* load and post-inc */ 15 | strb r3, [r0], #1 /* store and post-inc */ 16 | subs r2, #1 /* r2 -= 1 */ 17 | bpl copyup_head 18 | bx lr /* early return on small byte count (r2 < 0) */ 19 | copyup_loop: 20 | subs r2, #4 /* r2 -= 4 */ 21 | ldrpl r3, [r1], #4 /* load and post-inc */ 22 | strpl r3, [r0], #4 /* store and post-inc */ 23 | bpl copyup_loop /* while (r2 >= 0) */ 24 | add r2, #4 /* r2 = remaining byte count */ 25 | copyup_tail: 26 | subs r2, #1 /* r2 -= 1 */ 27 | bxmi lr /* return on (r2 < 0) */ 28 | ldrb r3, [r1], #1 /* load and post-inc */ 29 | strb r3, [r0], #1 /* store and post-inc */ 30 | b copyup_tail 31 | 32 | 1: .word 0 /* dst_addr */ 33 | 2: .word 0 /* src_addr */ 34 | 3: .word 0 /* bytes */ 35 | 36 | /* 37 | * copy "downwards", using base-relative indexing 38 | */ 39 | fel_memcpy_down: 40 | ldr r0, 1f /* dst_addr */ 41 | ldr r1, 2f /* src_addr */ 42 | ldr r2, 3f /* bytes */ 43 | sub r3, r0, r1 44 | tst r3, #3 /* test LSB for word alignment */ 45 | bne copydn_tail /* unaligned access, copy byte-wise */ 46 | copydn_head: 47 | add r3, r1, r2 /* r3 = r1 + r2, for alignment check */ 48 | tst r3, #3 /* word boundary? */ 49 | beq copydn_loop 50 | subs r2, #1 /* r2 -= 1 */ 51 | bxmi lr /* early return on small byte count (r2 < 0) */ 52 | ldrb r3, [r1, r2] /* load byte */ 53 | strb r3, [r0, r2] /* store byte */ 54 | b copydn_head 55 | copydn_loop: 56 | subs r2, #4 /* r2 -= 4 */ 57 | ldrpl r3, [r1, r2] /* load word */ 58 | strpl r3, [r0, r2] /* store word */ 59 | bpl copydn_loop /* while (r2 >= 0) */ 60 | add r2, #4 /* r2 = remaining byte count */ 61 | copydn_tail: 62 | subs r2, #1 /* r2 -= 1 */ 63 | bxmi lr /* return on (r2 < 0) */ 64 | ldrb r3, [r1, r2] /* load byte */ 65 | strb r3, [r0, r2] /* store byte */ 66 | b copydn_tail 67 | 68 | 1: .word 0 /* dst_addr */ 69 | 2: .word 0 /* src_addr */ 70 | 3: .word 0 /* bytes */ 71 | -------------------------------------------------------------------------------- /thunks/memcpy.h: -------------------------------------------------------------------------------- 1 | /* : */ 2 | htole32(0xe59f0054), /* 0: ldr r0, [pc, #84] */ 3 | htole32(0xe59f1054), /* 4: ldr r1, [pc, #84] */ 4 | htole32(0xe59f2054), /* 8: ldr r2, [pc, #84] */ 5 | htole32(0xe0413000), /* c: sub r3, r1, r0 */ 6 | htole32(0xe3130003), /* 10: tst r3, #3 */ 7 | htole32(0x1a00000b), /* 14: bne 48 */ 8 | /* : */ 9 | htole32(0xe3110003), /* 18: tst r1, #3 */ 10 | htole32(0x0a000004), /* 1c: beq 34 */ 11 | htole32(0xe4d13001), /* 20: ldrb r3, [r1], #1 */ 12 | htole32(0xe4c03001), /* 24: strb r3, [r0], #1 */ 13 | htole32(0xe2522001), /* 28: subs r2, r2, #1 */ 14 | htole32(0x5afffff9), /* 2c: bpl 18 */ 15 | htole32(0xe12fff1e), /* 30: bx lr */ 16 | /* : */ 17 | htole32(0xe2522004), /* 34: subs r2, r2, #4 */ 18 | htole32(0x54913004), /* 38: ldrpl r3, [r1], #4 */ 19 | htole32(0x54803004), /* 3c: strpl r3, [r0], #4 */ 20 | htole32(0x5afffffb), /* 40: bpl 34 */ 21 | htole32(0xe2822004), /* 44: add r2, r2, #4 */ 22 | /* : */ 23 | htole32(0xe2522001), /* 48: subs r2, r2, #1 */ 24 | htole32(0x412fff1e), /* 4c: bxmi lr */ 25 | htole32(0xe4d13001), /* 50: ldrb r3, [r1], #1 */ 26 | htole32(0xe4c03001), /* 54: strb r3, [r0], #1 */ 27 | htole32(0xeafffffa), /* 58: b 48 */ 28 | /* : */ 29 | htole32(0xe59f0058), /* 68: ldr r0, [pc, #88] */ 30 | htole32(0xe59f1058), /* 6c: ldr r1, [pc, #88] */ 31 | htole32(0xe59f2058), /* 70: ldr r2, [pc, #88] */ 32 | htole32(0xe0403001), /* 74: sub r3, r0, r1 */ 33 | htole32(0xe3130003), /* 78: tst r3, #3 */ 34 | htole32(0x1a00000c), /* 7c: bne b4 */ 35 | /* : */ 36 | htole32(0xe0813002), /* 80: add r3, r1, r2 */ 37 | htole32(0xe3130003), /* 84: tst r3, #3 */ 38 | htole32(0x0a000004), /* 88: beq a0 */ 39 | htole32(0xe2522001), /* 8c: subs r2, r2, #1 */ 40 | htole32(0x412fff1e), /* 90: bxmi lr */ 41 | htole32(0xe7d13002), /* 94: ldrb r3, [r1, r2] */ 42 | htole32(0xe7c03002), /* 98: strb r3, [r0, r2] */ 43 | htole32(0xeafffff7), /* 9c: b 80 */ 44 | /* : */ 45 | htole32(0xe2522004), /* a0: subs r2, r2, #4 */ 46 | htole32(0x57913002), /* a4: ldrpl r3, [r1, r2] */ 47 | htole32(0x57803002), /* a8: strpl r3, [r0, r2] */ 48 | htole32(0x5afffffb), /* ac: bpl a0 */ 49 | htole32(0xe2822004), /* b0: add r2, r2, #4 */ 50 | /* : */ 51 | htole32(0xe2522001), /* b4: subs r2, r2, #1 */ 52 | htole32(0x412fff1e), /* b8: bxmi lr */ 53 | htole32(0xe7d13002), /* bc: ldrb r3, [r1, r2] */ 54 | htole32(0xe7c03002), /* c0: strb r3, [r0, r2] */ 55 | htole32(0xeafffffa), /* c4: b b4 */ 56 | -------------------------------------------------------------------------------- /thunks/objdump_to_h.awk: -------------------------------------------------------------------------------- 1 | # labels 2 | /[[:xdigit:]]+ <\w+>:/ { 3 | # (Note: using $0 instead of $2 would also include the address) 4 | if (style=="old") 5 | printf "\t/* %s */\n", $2 6 | else 7 | printf "\t\t/* %s */\n", $2 8 | } 9 | 10 | # disassembly lines 11 | /[[:xdigit:]]+:/ { 12 | if (style=="old") 13 | printf "\t0x%s, /* %9s %-10s", $2, $1, $3 14 | else 15 | printf "\t\thtole32(0x%s), /* %5s %-5s", $2, $1, $3 16 | 17 | for (i = 4; i <= NF; i++) 18 | if ($i == ";") { 19 | # strip comment (anything after and including ';') 20 | NF = i - 1 21 | break 22 | } 23 | # clear $1 to $3, which re-calculates $0 (= remainder of line) 24 | $3 = "" 25 | $2 = "" 26 | $1 = "" 27 | gsub("^\\s+", "") # strip leading whitespace 28 | 29 | if (style=="old") 30 | printf " %-28s */\n", $0 31 | else 32 | printf " %-23s */\n", $0 33 | } 34 | -------------------------------------------------------------------------------- /thunks/readl_writel.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Thunk code for buffered 'long' (i.e. 32-bit) read and write operations 3 | */ 4 | 5 | .equ MAX_WORDS, 0x100 - 12 6 | 7 | fel_readl_n: 8 | ldr r0, 1f /* read_addr */ 9 | adr r1, 3f /* read_data */ 10 | ldr r2, 2f /* read_count */ 11 | /* limit word count to a maximum value */ 12 | cmp r2, #MAX_WORDS 13 | movgt r2, #MAX_WORDS 14 | read_loop: 15 | subs r2, #1 16 | bxmi lr 17 | ldr r3, [r0], #4 18 | str r3, [r1], #4 19 | b read_loop 20 | 21 | 1: .word 0 /* read_addr */ 22 | 2: .word 0 /* read_count */ 23 | 3: .word 0 /* read_data */ 24 | 25 | fel_writel_n: 26 | ldr r0, 1f /* write_addr */ 27 | adr r1, 3f /* write_data */ 28 | ldr r2, 2f /* write_count */ 29 | /* limit word count to a maximum value */ 30 | cmp r2, #MAX_WORDS 31 | movgt r2, #MAX_WORDS 32 | write_loop: 33 | subs r2, #1 34 | bxmi lr 35 | ldr r3, [r1], #4 36 | str r3, [r0], #4 37 | b write_loop 38 | 39 | 1: .word 0 /* write_addr */ 40 | 2: .word 0 /* write_count */ 41 | 3: .word 0 /* write_data */ 42 | -------------------------------------------------------------------------------- /thunks/readl_writel.h: -------------------------------------------------------------------------------- 1 | /* : */ 2 | htole32(0xe59f0020), /* 0: ldr r0, [pc, #32] */ 3 | htole32(0xe28f1024), /* 4: add r1, pc, #36 */ 4 | htole32(0xe59f201c), /* 8: ldr r2, [pc, #28] */ 5 | htole32(0xe35200f4), /* c: cmp r2, #244 */ 6 | htole32(0xc3a020f4), /* 10: movgt r2, #244 */ 7 | /* : */ 8 | htole32(0xe2522001), /* 14: subs r2, r2, #1 */ 9 | htole32(0x412fff1e), /* 18: bxmi lr */ 10 | htole32(0xe4903004), /* 1c: ldr r3, [r0], #4 */ 11 | htole32(0xe4813004), /* 20: str r3, [r1], #4 */ 12 | htole32(0xeafffffa), /* 24: b 14 */ 13 | /* : */ 14 | htole32(0xe59f0020), /* 34: ldr r0, [pc, #32] */ 15 | htole32(0xe28f1024), /* 38: add r1, pc, #36 */ 16 | htole32(0xe59f201c), /* 3c: ldr r2, [pc, #28] */ 17 | htole32(0xe35200f4), /* 40: cmp r2, #244 */ 18 | htole32(0xc3a020f4), /* 44: movgt r2, #244 */ 19 | /* : */ 20 | htole32(0xe2522001), /* 48: subs r2, r2, #1 */ 21 | htole32(0x412fff1e), /* 4c: bxmi lr */ 22 | htole32(0xe4913004), /* 50: ldr r3, [r1], #4 */ 23 | htole32(0xe4803004), /* 54: str r3, [r0], #4 */ 24 | htole32(0xeafffffa), /* 58: b 48 */ 25 | -------------------------------------------------------------------------------- /thunks/rmr-thunk.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Request AArch32/AArch64 warm reset, using RVBAR and Reset Management Register 3 | * This is used on ARMv8 cores only, so force v7 code to allow dsb and isb. 4 | */ 5 | .arch armv7-a 6 | 7 | rmr_request: 8 | ldr r0, 1f /* RVBAR register address */ 9 | ldr r1, 2f /* desired entry point (reset vector) */ 10 | str r1, [r0] 11 | dsb 12 | isb /* make sure we write the address */ 13 | 14 | ldr r1, 3f /* RMR mode: bit 1 = RR, bit 0 = AA64 */ 15 | mrc p15, 0, r0, c12, c0, 2 /* read RMR */ 16 | orr r0, r0, r1 /* request warm reset (according to rmr_mode) */ 17 | mcr p15, 0, r0, c12, c0, 2 /* write RMR, trigger reset */ 18 | 19 | isb 20 | 0: 21 | wfi 22 | b 0b /* loop */ 23 | 24 | 1: .word 0 /* rvbar_reg */ 25 | 2: .word 0 /* entry_point */ 26 | 3: .word 0 /* rmr_mode (2 = AArch32, 3 = AArch64) */ 27 | -------------------------------------------------------------------------------- /thunks/rmr-thunk.h: -------------------------------------------------------------------------------- 1 | /* : */ 2 | htole32(0xe59f0028), /* 0: ldr r0, [pc, #40] */ 3 | htole32(0xe59f1028), /* 4: ldr r1, [pc, #40] */ 4 | htole32(0xe5801000), /* 8: str r1, [r0] */ 5 | htole32(0xf57ff04f), /* c: dsb sy */ 6 | htole32(0xf57ff06f), /* 10: isb sy */ 7 | htole32(0xe59f101c), /* 14: ldr r1, [pc, #28] */ 8 | htole32(0xee1c0f50), /* 18: mrc 15, 0, r0, cr12, cr0, {2} */ 9 | htole32(0xe1800001), /* 1c: orr r0, r0, r1 */ 10 | htole32(0xee0c0f50), /* 20: mcr 15, 0, r0, cr12, cr0, {2} */ 11 | htole32(0xf57ff06f), /* 24: isb sy */ 12 | htole32(0xe320f003), /* 28: wfi */ 13 | htole32(0xeafffffd), /* 2c: b 28 */ 14 | -------------------------------------------------------------------------------- /thunks/sid_read_root.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Bernhard Nortmann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice (including the next 12 | * paragraph) shall be included in all copies or substantial portions of the 13 | * Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | * DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /* 25 | * ARM thunk code to read the SID root key using register-based access. 26 | * 27 | * This is necessary for certain SoCs (e.g. H3), as the values read via 28 | * memory mapping might not be consistent. For background information see 29 | * https://groups.google.com/forum/#!topic/linux-sunxi/ynyIP8c61Qs 30 | */ 31 | 32 | SID_BASE .req r0 33 | sid_key_index .req r1 34 | 35 | .set SID_PRCTL, 0x40 /* SID program/read control register */ 36 | .set SID_PRKEY, 0x50 /* SID program key value register */ 37 | .set SID_RDKEY, 0x60 /* SID read key value register */ 38 | 39 | .set SID_OP_LOCK, 0xAC /* Efuse operation lock value */ 40 | .set SID_READ_START, (1 << 1) /* bit 1 of SID_PRCTL, Software Read Start */ 41 | .set SID_PG_START, (1 << 0) /* bit 0 of SID_PRCTL, Software Program Start */ 42 | 43 | sid_read_root_key: 44 | ldr SID_BASE, sid_base 45 | ldr sid_key_index, offset 46 | adr r3, sid_result /* result pointer */ 47 | sid_read_loop: 48 | mov r2, sid_key_index, lsl #16 /* PG_INDEX value */ 49 | orr r2, #SID_OP_LOCK << 8 /* OP_LOCK to enable SID_READ_START */ 50 | orr r2, #SID_READ_START 51 | str r2, [SID_BASE, #SID_PRCTL] /* write SID_PRCTL */ 52 | sid_read_wait: 53 | ldr r2, [SID_BASE, #SID_PRCTL] /* read SID_PRCTL */ 54 | tst r2, #SID_READ_START /* check if read operation completed */ 55 | bne sid_read_wait /* loop while bit 1 still set */ 56 | 57 | ldr r2, [SID_BASE, #SID_RDKEY] /* read SID key value */ 58 | str r2, [r3], #4 /* store SID value */ 59 | 60 | add sid_key_index, #4 61 | ldr r2, end 62 | cmp sid_key_index, r2 63 | blo sid_read_loop /* loop while (sid_key_index < 0x10) */ 64 | 65 | mov r2, #0 66 | str r2, [SID_BASE, #SID_PRCTL] /* clear SID_PRCTL */ 67 | bx lr 68 | 69 | sid_base: .word 0 70 | offset: .word 0 71 | end: .word 0 72 | sid_result: /* receives the values read from the SID registers */ 73 | -------------------------------------------------------------------------------- /thunks/sid_read_root.h: -------------------------------------------------------------------------------- 1 | /* : */ 2 | htole32(0xe59f0044), /* 0: ldr r0, [pc, #68] */ 3 | htole32(0xe59f1044), /* 4: ldr r1, [pc, #68] */ 4 | htole32(0xe28f3048), /* 8: add r3, pc, #72 */ 5 | /* : */ 6 | htole32(0xe1a02801), /* c: lsl r2, r1, #16 */ 7 | htole32(0xe3822b2b), /* 10: orr r2, r2, #44032 */ 8 | htole32(0xe3822002), /* 14: orr r2, r2, #2 */ 9 | htole32(0xe5802040), /* 18: str r2, [r0, #64] */ 10 | /* : */ 11 | htole32(0xe5902040), /* 1c: ldr r2, [r0, #64] */ 12 | htole32(0xe3120002), /* 20: tst r2, #2 */ 13 | htole32(0x1afffffc), /* 24: bne 1c */ 14 | htole32(0xe5902060), /* 28: ldr r2, [r0, #96] */ 15 | htole32(0xe4832004), /* 2c: str r2, [r3], #4 */ 16 | htole32(0xe2811004), /* 30: add r1, r1, #4 */ 17 | htole32(0xe59f2018), /* 34: ldr r2, [pc, #24] */ 18 | htole32(0xe1510002), /* 38: cmp r1, r2 */ 19 | htole32(0x3afffff2), /* 3c: bcc c */ 20 | htole32(0xe3a02000), /* 40: mov r2, #0 */ 21 | htole32(0xe5802040), /* 44: str r2, [r0, #64] */ 22 | htole32(0xe12fff1e), /* 48: bx lr */ 23 | /* : */ 24 | htole32(0x00000000), /* 4c: .word 0x00000000 */ 25 | /* : */ 26 | htole32(0x00000000), /* 50: .word 0x00000000 */ 27 | /* : */ 28 | htole32(0x00000000), /* 54: .word 0x00000000 */ 29 | -------------------------------------------------------------------------------- /uart0-helloworld-sdboot.lds: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Siarhei Siamashka 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | SECTIONS 19 | { 20 | . = 0x0000; 21 | .start : { *(.start) } 22 | .text : { *(.text) } 23 | /DISCARD/ : { *(.dynstr*) } 24 | /DISCARD/ : { *(.dynamic*) } 25 | /DISCARD/ : { *(.plt*) } 26 | /DISCARD/ : { *(.interp*) } 27 | /DISCARD/ : { *(.gnu*) } 28 | /DISCARD/ : { *(.note*) } 29 | } 30 | --------------------------------------------------------------------------------