ipq40xx: Add ipq-aux-loader
authorRobert Marko <robimarko@gmail.com>
Thu, 19 Sep 2019 18:35:17 +0000 (20:35 +0200)
committerAlexander Couzens <lynxis@fe80.eu>
Fri, 18 Sep 2020 23:32:30 +0000 (01:32 +0200)
This adds ipq-aux-loader from Sergey Sergeev <adron@yapic.net>
It is small loader for legacy or LZMA compressed FIT images.
This is needed to add support for Mikrotik RouterBoards as they
expect a specific ELF image.
This loader enables to use LZMA compressed FIT image which will
decompress the kernel image and boot it.

Signed-off-by: Sergey Sergeev <adron@mstnt.com>
Signed-off-by: Robert Marko <robimarko@gmail.com>
(reorganzied patches)
Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
29 files changed:
target/linux/ipq40xx/image/Makefile
target/linux/ipq40xx/image/ipq-aux-loader/Makefile [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/Makefile [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/README.md [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/openwrt/Makefile [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/Debug.sh [new file with mode: 0755]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/LzmaDecode.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/board.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/cpu.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/fdt.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/head.S [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/LzmaDecode.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/LzmaTypes.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/io.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/iomap.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/printf.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/types.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/uimage/fdt.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/uimage/legacy.h [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/kernel-data.lds [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader.lds [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader2.lds [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/lzma.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/printf.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/qcom_uart.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/start.S [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/src/watchdog.c [new file with mode: 0644]
target/linux/ipq40xx/image/ipq-aux-loader/src/ubi/loader.ubi.ini [new file with mode: 0644]

index 0f03e1f4297955390ea692d173e50714c5166e6b..ea0d733678ad7522c9c025f62fbdea02ea40ffda 100644 (file)
@@ -18,6 +18,24 @@ define Device/Default
        IMAGE/sysupgrade.bin/squashfs :=
 endef
 
+define Build/ipq-aux-loader-common
+       rm -rf $@.src
+       $(MAKE) -C ipq-aux-loader \
+               PKG_BUILD_DIR="$@.src" \
+               TARGET_DIR="$(dir $@)" LOADER_NAME="$(notdir $@)" \
+               TEXT_BASE2="0x00000000" \
+               BOARD="$(BOARDNAME)" PLATFORM="$(PLATFORM)" \
+               BLOCKSIZE="$(BLOCKSIZE)" PAGESIZE="$(PAGESIZE)" \
+               UART="$(AUX_LOADER_UART)" \
+               $(1) LOADER_TYPE=$(2) compile loader.$(2)
+       mv "$@.$(2)" "$@"
+       rm -rf $@.src
+endef
+
+define Build/ipq-aux-loader-kernel
+       $(call Build/ipq-aux-loader-common,LOADER_DATA="$@",$(1))
+endef
+
 define Device/FitImage
        KERNEL_SUFFIX := -fit-uImage.itb
        KERNEL = kernel-bin | gzip | fit gzip $$(DTS_DIR)/$$(DEVICE_DTS).dtb
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/Makefile b/target/linux/ipq40xx/image/ipq-aux-loader/Makefile
new file mode 100644 (file)
index 0000000..5659b69
--- /dev/null
@@ -0,0 +1,68 @@
+#
+# Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+#
+# Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+#
+# Some parts of this code was based on the OpenWrt specific lzma-loader
+# for the Atheros AR7XXX/AR9XXX based boards:
+#      Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+
+include $(TOPDIR)/rules.mk
+
+LOADER_NAME := $(basename $(notdir $(LOADER)))
+
+ifeq ($(TARGET_DIR),)
+TARGET_DIR := $(KDIR)
+endif
+
+LOADER_ELF := $(TARGET_DIR)/$(LOADER_NAME).elf
+LOADER_UBI := $(TARGET_DIR)/$(LOADER_NAME).ubi
+
+PKG_NAME := ipq-aux-loader
+PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)
+
+.PHONY : loader-compile loader.elf
+
+$(PKG_BUILD_DIR)/.prepared:
+       mkdir $(PKG_BUILD_DIR)
+       $(CP) ./src/* $(PKG_BUILD_DIR)
+       touch $@
+
+CPU_TYPE := UNKNOWN
+
+ifeq ($(PLATFORM),mikrotik-ipq4xxx)
+       CPU_TYPE := IPQ4XXX
+       TEXT_BASE := 0x84800000
+       TEXT_BASE2 := 0x01100000
+       FAT_SIZE_START := 5000000
+       TEXT_BASE2_FAT := 0x00000000
+endif
+
+loader-compile: $(PKG_BUILD_DIR)/.prepared
+       $(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)" \
+               TEXT_BASE=$(TEXT_BASE) TEXT_BASE2=$(TEXT_BASE2) \
+               FAT_SIZE_START=$(FAT_SIZE_START) \
+               TEXT_BASE2_FAT=$(TEXT_BASE2_FAT) \
+               CPU_TYPE=$(CPU_TYPE) KERNEL_IMAGE=$(LOADER_DATA) \
+               BLOCKSIZE=$(BLOCKSIZE) PAGESIZE=$(PAGESIZE) \
+               clean $(LOADER_TYPE)
+
+loader.elf: $(PKG_BUILD_DIR)/bin/loader.elf
+       $(CP) $< $(LOADER_ELF)
+
+loader.ubi: $(PKG_BUILD_DIR)/bin/loader.ubi
+       $(CP) $< $(LOADER_UBI)
+
+download:
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: loader-compile
+
+install:
+
+clean:
+       rm -rf $(PKG_BUILD_DIR)
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/Makefile b/target/linux/ipq40xx/image/ipq-aux-loader/src/Makefile
new file mode 100644 (file)
index 0000000..8c5b7ac
--- /dev/null
@@ -0,0 +1,162 @@
+#
+# Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+#
+#  Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+#
+#  This program is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License version 2 as published
+#  by the Free Software Foundation.
+#
+
+CPU_TYPE := IPQ4XXX
+#+72M. realloc memory address
+TEXT_BASE := 0x44800000
+#RouterBOOT auto realloc flag value address. Kernel size is limited < 6M !
+TEXT_BASE2 := 0x01100000
+#fat kernels start size 5M
+FAT_SIZE_START := 5000000
+#for fat kernels <= 12M
+TEXT_BASE2_FAT := 0x00000000
+
+#ubi image vars
+BLOCKSIZE := 256k
+PAGESIZE := 4096
+
+CC := $(CROSS_COMPILE)gcc
+LD := $(CROSS_COMPILE)ld
+OBJCOPY        := $(CROSS_COMPILE)objcopy
+OBJDUMP        := $(CROSS_COMPILE)objdump
+
+BIN_FLAGS := -O binary -R .ARM.attributes -R .comment -R .debug.* -S
+
+CFLAGS = -D__KERNEL__ -DCONFIG_SYS_TEXT_BASE=$(TEXT_BASE) \
+                       -DCONFIG_ARM -D__ARM__ -fPIC -Wall -Wstrict-prototypes \
+                       -Wno-format-security -Wno-format-nonliteral \
+                       -fno-stack-protector -fstack-usage -pipe \
+                       -marm -mno-thumb-interwork -mabi=aapcs-linux -march=armv7-a \
+                       -mno-unaligned-access -fno-builtin -ffreestanding \
+                       -g -Os -fno-common -ffixed-r8
+
+ifeq ($(CPU_TYPE),IPQ4XXX)
+       CFLAGS += -DCONFIG_IPQ4XXX
+endif
+ifeq ($(CPU_TYPE),IPQ806X)
+       CFLAGS += -DCONFIG_IPQ806X
+endif
+
+#Com port number(for printf)
+ifeq ($(UART),)
+       CFLAGS += -DUARTx_DM_BASE=UART1_DM_BASE
+else
+ifeq ($(UART),NONE)
+       CFLAGS += -DUARTx_DM_BASE=NONE
+else
+       CFLAGS += -DUARTx_DM_BASE=UART$(UART)_DM_BASE
+endif
+endif
+
+#debug messages
+ifeq ($(DEBUG),true)
+       CFLAGS += -DDEBUG
+endif
+
+CFLAGS += -I./src/include
+
+ASFLAGS        = $(CFLAGS) -D__ASSEMBLY__
+
+LDFLAGS        =
+LDFLAGS_DATA = -r -b binary --oformat $(O_FORMAT) -o
+
+O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
+
+ldr := bin/loader
+ldr-bin := bin/loader.bin
+ldr-elf := bin/loader.elf
+ldr-ubifs := bin/loader.ubifs
+ldr-ubi := bin/loader.ubi
+
+tgs-h := io.h iomap.h LzmaDecode.h LzmaTypes.h printf.h types.h \
+                       uimage/fdt.h uimage/legacy.h
+tgs-lds        := kernel-data.lds loader2.lds loader.lds
+tgs-o := start.o board.o cpu.o fdt.o loader.o lzma.o LzmaDecode.o \
+                       printf.o qcom_uart.o watchdog.o data.o
+tgs2-o := head.o data2.o watchdog.o
+tgs-h := $(tgs-h:%=src/include/%)
+tgs-lds := $(tgs-lds:%=src/%)
+tgs-o := $(tgs-o:%=objs/%)
+tgs2-o := $(tgs2-o:%=objs/%)
+
+ifeq ($(KERNEL_IMAGE),)
+       KERNEL_IMAGE_FS = 0
+endif
+ifeq ($(shell test -f $(KERNEL_IMAGE); echo $$?),0)
+       KERNEL_IMAGE_FS = $(shell stat -L -c %s $(KERNEL_IMAGE))
+else
+       KERNEL_IMAGE_FS = 0
+endif
+
+#Switching to use kernel size for fat images.
+ifeq ($(shell test ${KERNEL_IMAGE_FS} -gt ${FAT_SIZE_START}; echo $$?),0)
+       TEXT_BASE2 = $(TEXT_BASE2_FAT)
+endif
+
+#Create the necessary directories
+$(shell mkdir -p objs maps bin)
+
+elf: $(ldr-elf)
+ubi: $(ldr-ubi)
+all: $(ldr-ubi)
+
+# Don't build dependencies, this may die if $(CC) isn't gcc
+dep:
+
+install:
+
+$(tgs-lds):
+$(tgs-h):
+
+$(tgs-o): $(tgs-lds)
+$(tgs-o): $(tgs-h)
+
+# objs/qcom_uart.o objs/printf.o - add it to *.o list for debug
+$(ldr-elf): $(tgs2-o)
+       @echo "Kernel size = ${KERNEL_IMAGE_FS}"
+       $(LD) $(LDFLAGS) -e _start -Ttext $(TEXT_BASE2) -o $(ldr-elf) \
+       $(tgs2-o) -Map maps/loader2.map -T src/loader2.lds
+
+$(ldr-bin): $(ldr)
+       $(OBJCOPY) $(BIN_FLAGS) $< $@
+
+$(ldr): $(tgs-o)
+       $(LD) $(LDFLAGS) -e _start -Ttext $(TEXT_BASE) \
+       $(tgs-o) -Map maps/loader.map -T src/loader.lds -o $@
+
+objs/%.o: src/%.c
+       $(CC) $(CFLAGS) -o $@ $< -c
+
+objs/%.o: src/%.S
+       $(CC) $(ASFLAGS) -o $@ $< -c
+
+objs/data2.o: $(ldr-bin)
+       $(LD) $(LDFLAGS_DATA) $@ $<
+
+objs/data.o: $(KERNEL_IMAGE)
+       $(LD) $(LDFLAGS_DATA) $@ $< -T src/kernel-data.lds
+
+$(ldr-ubi): $(ldr-ubifs)
+       $(STAGING_DIR_HOST)/bin/ubinize -p $(BLOCKSIZE:%k=%KiB) \
+               -m $(PAGESIZE) -o $@ ubi/loader.ubi.ini
+
+$(ldr-ubifs): $(ldr-elf)
+       rm -Rf ubi/ubifs-rootdir
+       mkdir ubi/ubifs-rootdir
+       cp bin/loader.elf ubi/ubifs-rootdir/kernel
+       $(STAGING_DIR_HOST)/bin/mkfs.ubifs \
+               -m $(PAGESIZE) -e 253952 -c 60 --compr=none \
+               -r ubi/ubifs-rootdir $(ldr-ubifs)
+       rm -Rf ubi/ubifs-rootdir
+
+mrproper: clean
+
+clean:
+       rm -Rf bin/* objs/* maps/* ubi/ubifs-rootdir/
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/README.md b/target/linux/ipq40xx/image/ipq-aux-loader/src/README.md
new file mode 100644 (file)
index 0000000..7bdda95
--- /dev/null
@@ -0,0 +1,6 @@
+# qcom-ipq-aux-loader
+
+This auxiliary bootloader was created to be able to run OpenWRT on devices of the Mikrotik company with is based on IPQ-4XXX and IPQ-806X series processors.
+The thing is that a RouterBOOT is able to load only programs in ELF format and a OpenWRT kernel has a format of uImage Legacy or uImage FIT.
+
+This bootloader with a small fixes can potentially be used on any ARM system(V5 and higher). Dependence from hardware here is minimal.
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/openwrt/Makefile b/target/linux/ipq40xx/image/ipq-aux-loader/src/openwrt/Makefile
new file mode 100644 (file)
index 0000000..59e6622
--- /dev/null
@@ -0,0 +1,68 @@
+#
+# Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+#
+# Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+#
+# Some parts of this code was based on the OpenWrt specific lzma-loader
+# for the Atheros AR7XXX/AR9XXX based boards:
+#      Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+
+include $(TOPDIR)/rules.mk
+
+LOADER_NAME    := $(basename $(notdir $(LOADER)))
+
+ifeq ($(TARGET_DIR),)
+TARGET_DIR     := $(KDIR)
+endif
+
+LOADER_ELF := $(TARGET_DIR)/$(LOADER_NAME).elf
+LOADER_UBI := $(TARGET_DIR)/$(LOADER_NAME).ubi
+
+PKG_NAME := ipq-aux-loader
+PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)
+
+.PHONY : loader-compile loader.elf
+
+$(PKG_BUILD_DIR)/.prepared:
+       mkdir $(PKG_BUILD_DIR)
+       $(CP) ./src/* $(PKG_BUILD_DIR)
+       touch $@
+
+CPU_TYPE := UNKNOWN
+
+ifeq ($(PLATFORM),mikrotik-ipq4xxx)
+       CPU_TYPE := IPQ4XXX
+       TEXT_BASE := 0x84800000
+       TEXT_BASE2 := 0x01100000
+       FAT_SIZE_START := 5000000
+       TEXT_BASE2_FAT := 0x00000000
+endif
+
+loader-compile: $(PKG_BUILD_DIR)/.prepared
+       $(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)" \
+               TEXT_BASE=$(TEXT_BASE) TEXT_BASE2=$(TEXT_BASE2) \
+               FAT_SIZE_START=$(FAT_SIZE_START) \
+               TEXT_BASE2_FAT=$(TEXT_BASE2_FAT) \
+               CPU_TYPE=$(CPU_TYPE) KERNEL_IMAGE=$(LOADER_DATA) \
+               BLOCKSIZE=$(BLOCKSIZE) PAGESIZE=$(PAGESIZE) \
+               clean $(LOADER_TYPE)
+
+loader.elf: $(PKG_BUILD_DIR)/bin/loader.elf
+       $(CP) $< $(LOADER_ELF)
+
+loader.ubi: $(PKG_BUILD_DIR)/bin/loader.ubi
+       $(CP) $< $(LOADER_UBI)
+
+download:
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: loader-compile
+
+install:
+
+clean:
+       rm -rf $(PKG_BUILD_DIR)
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/Debug.sh b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/Debug.sh
new file mode 100755 (executable)
index 0000000..7d9b685
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd ../
+./Debug.sh $@
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/LzmaDecode.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/LzmaDecode.c
new file mode 100644 (file)
index 0000000..cb83453
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+  LzmaDecode.c
+  LZMA Decoder (optimized for Speed version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+  { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+  BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  #ifdef _LZMA_OUT_READ
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+  }
+  #endif
+  return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *InCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+  CProb *p = vs->Probs;
+  SizeT nowPos = 0;
+  Byte previousByte = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+
+  #ifdef _LZMA_OUT_READ
+  
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+  #ifdef _LZMA_IN_CB
+  const Byte *Buffer = vs->Buffer;
+  const Byte *BufferLim = vs->BufferLim;
+  #else
+  const Byte *Buffer = inStream;
+  const Byte *BufferLim = inStream + inSize;
+  #endif
+  int state = vs->State;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  Byte *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  Byte tempDictionary[4];
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      #ifdef _LZMA_IN_CB
+      RC_INIT;
+      #else
+      RC_INIT(inStream, inSize);
+      #endif
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  #else /* if !_LZMA_OUT_READ */
+
+  int state = 0;
+  UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+  int len = 0;
+  const Byte *Buffer;
+  const Byte *BufferLim;
+  UInt32 Range;
+  UInt32 Code;
+
+  #ifndef _LZMA_IN_CB
+  *inSizeProcessed = 0;
+  #endif
+  *outSizeProcessed = 0;
+
+  {
+    UInt32 i;
+    UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+    for (i = 0; i < numProbs; i++)
+      p[i] = kBitModelTotal >> 1;
+  }
+  
+  #ifdef _LZMA_IN_CB
+  RC_INIT;
+  #else
+  RC_INIT(inStream, inSize);
+  #endif
+
+  #endif /* _LZMA_OUT_READ */
+
+  while(nowPos < outSize)
+  {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)(
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        (((
+        (nowPos 
+        #ifdef _LZMA_OUT_READ
+        + globalPos
+        #endif
+        )
+        & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        #else
+        matchByte = outStream[nowPos - rep0];
+        #endif
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (Byte)symbol;
+
+      outStream[nowPos++] = previousByte;
+      #ifdef _LZMA_OUT_READ
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      #endif
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            #ifdef _LZMA_OUT_READ
+            UInt32 pos;
+            #endif
+            UpdateBit0(prob);
+            
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit == 0)
+            #else
+            if (nowPos == 0)
+            #endif
+              return LZMA_RESULT_DATA_ERROR;
+            
+            state = state < kNumLitStates ? 9 : 11;
+            #ifdef _LZMA_OUT_READ
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            #else
+            previousByte = outStream[nowPos - rep0];
+            #endif
+            outStream[nowPos++] = previousByte;
+            #ifdef _LZMA_OUT_READ
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            #endif
+
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      #ifdef _LZMA_OUT_READ
+      if (rep0 > distanceLimit) 
+      #else
+      if (rep0 > nowPos)
+      #endif
+        return LZMA_RESULT_DATA_ERROR;
+
+      #ifdef _LZMA_OUT_READ
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+      #endif
+
+      do
+      {
+        #ifdef _LZMA_OUT_READ
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        #else
+        previousByte = outStream[nowPos - rep0];
+        #endif
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+  }
+  RC_NORMALIZE;
+
+  #ifdef _LZMA_OUT_READ
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = globalPos + (UInt32)nowPos;
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  vs->TempDictionary[0] = tempDictionary[0];
+  #endif
+
+  #ifdef _LZMA_IN_CB
+  vs->Buffer = Buffer;
+  vs->BufferLim = BufferLim;
+  #else
+  *inSizeProcessed = (SizeT)(Buffer - inStream);
+  #endif
+  *outSizeProcessed = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/board.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/board.c
new file mode 100644 (file)
index 0000000..af922cb
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <printf.h>
+#include <iomap.h>
+#include <io.h>
+#include <types.h>
+
+unsigned long int ntohl(unsigned long int d){
+       unsigned long int res = 0;
+       int a;
+       for(a = 0; a < 3; a++){
+               res |= d & 0xFF;
+               res <<= 8; d >>= 8;
+       }
+       res |= d & 0xFF;
+       return res;
+}
+
+void dump_mem(unsigned char *p, char *str){
+       printf("  %s(0x%08X) = %02x %02x %02x %02x %02x %02x %02x %02x\n",
+               str,
+               p,
+               p[0] & 0xFF, p[1] & 0xFF,
+               p[2] & 0xFF, p[3] & 0xFF,
+               p[4] & 0xFF, p[5] & 0xFF,
+               p[6] & 0xFF, p[7] & 0xFF
+       );
+}
+
+void hang(void)
+{
+       printf("### ERROR ### Please RESET the board ###\n");
+       for (;;);
+}
+
+int raise(int signum)
+{
+       /* Needs for div/mod ops */
+       printf("raise: Signal # %d caught\n", signum);
+       return 0;
+}
+
+/* Replacement (=dummy) for GNU/Linux division-by zero handler */
+void __div0 (void)
+{
+       hang();
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/cpu.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/cpu.c
new file mode 100644 (file)
index 0000000..5baf8f3
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <types.h>
+
+/* size: 4 * 4096. Start: TEXT_BASE + 40M. Try to limit to 128M.
+        !!! This region of memory should not be inside the caching area !!!
+*/
+static u32 *page_table = (void*)(CONFIG_SYS_TEXT_BASE + 0x2800000);
+
+/* start and size of memory for D-Cache */
+static u32 bi_dram_0_start = 0;
+static u32 bi_dram_0_size = 0;
+
+#define CR_C   (1 << 2)        /* Dcache enable                        */
+#define CR_I   (1 << 12)       /* Icache enable                        */
+#define CR_M   (1 << 0)        /* MMU enable                           */
+
+#define CONFIG_NR_DRAM_BANKS           1
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+#define CACHE_SETUP    0x1a
+#else
+#define CACHE_SETUP    0x1e
+#endif
+
+#define isb() __asm__ __volatile__ ("" : : : "memory")
+#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
+
+static void cp_delay (void)
+{
+       volatile int i;
+
+       /* copro seems to need some delay between reading and writing */
+       for (i = 0; i < 100; i++)
+               nop();
+       asm volatile("" : : : "memory");
+}
+
+static inline unsigned int get_cr(void)
+{
+       unsigned int val;
+       asm("mrc p15, 0, %0, c1, c0, 0  @ get CR" : "=r" (val) : : "cc");
+       return val;
+}
+
+static inline void set_cr(unsigned int val)
+{
+       asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR"
+         : : "r" (val) : "cc");
+       isb();
+}
+
+/* Values for Ctype fields in CLIDR */
+#define ARMV7_CLIDR_CTYPE_NO_CACHE             0
+#define ARMV7_CLIDR_CTYPE_INSTRUCTION_ONLY     1
+#define ARMV7_CLIDR_CTYPE_DATA_ONLY            2
+#define ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA     3
+#define ARMV7_CLIDR_CTYPE_UNIFIED              4
+
+#define ARMV7_DCACHE_INVAL_ALL         1
+#define ARMV7_DCACHE_CLEAN_INVAL_ALL   2
+#define ARMV7_DCACHE_INVAL_RANGE       3
+#define ARMV7_DCACHE_CLEAN_INVAL_RANGE 4
+
+#define ARMV7_CSSELR_IND_DATA_UNIFIED  0
+
+/* CCSIDR */
+#define CCSIDR_LINE_SIZE_OFFSET                0
+#define CCSIDR_LINE_SIZE_MASK          0x7
+#define CCSIDR_ASSOCIATIVITY_OFFSET    3
+#define CCSIDR_ASSOCIATIVITY_MASK      (0x3FF << 3)
+#define CCSIDR_NUM_SETS_OFFSET         13
+#define CCSIDR_NUM_SETS_MASK           (0x7FFF << 13)
+
+/*
+ * CP15 Barrier instructions
+ * Please note that we have separate barrier instructions in ARMv7
+ * However, we use the CP15 based instructtions because we use
+ * -march=armv5 in U-Boot
+ */
+#define CP15ISB        asm volatile ("mcr     p15, 0, %0, c7, c5, 4" : : "r" (0))
+#define CP15DSB        asm volatile ("mcr     p15, 0, %0, c7, c10, 4" : : "r" (0))
+#define CP15DMB        asm volatile ("mcr     p15, 0, %0, c7, c10, 5" : : "r" (0))
+
+static inline s32 log_2_n_round_up(u32 n)
+{
+       s32 log2n = -1;
+       u32 temp = n;
+
+       while (temp) {
+               log2n++;
+               temp >>= 1;
+       }
+
+       if (n & (n - 1))
+               return log2n + 1; /* not power of 2 - round up */
+       else
+               return log2n; /* power of 2 */
+}
+
+/*
+ * Write the level and type you want to Cache Size Selection Register(CSSELR)
+ * to get size details from Current Cache Size ID Register(CCSIDR)
+ */
+static void set_csselr(u32 level, u32 type)
+{      u32 csselr = level << 1 | type;
+
+       /* Write to Cache Size Selection Register(CSSELR) */
+       asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr));
+}
+
+static u32 get_ccsidr(void)
+{
+       u32 ccsidr;
+
+       /* Read current CP15 Cache Size ID Register */
+       asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
+       return ccsidr;
+}
+
+
+static u32 get_clidr(void)
+{
+       u32 clidr;
+
+       /* Read current CP15 Cache Level ID Register */
+       asm volatile ("mrc p15,1,%0,c0,c0,1" : "=r" (clidr));
+       return clidr;
+}
+
+static void v7_inval_dcache_level_setway(u32 level, u32 num_sets,
+                                        u32 num_ways, u32 way_shift,
+                                        u32 log2_line_len)
+{
+       int way, set, setway;
+
+       /*
+        * For optimal assembly code:
+        *      a. count down
+        *      b. have bigger loop inside
+        */
+       for (way = num_ways - 1; way >= 0 ; way--) {
+               for (set = num_sets - 1; set >= 0; set--) {
+                       setway = (level << 1) | (set << log2_line_len) |
+                                (way << way_shift);
+                       /* Invalidate data/unified cache line by set/way */
+                       asm volatile (" mcr p15, 0, %0, c7, c6, 2"
+                                       : : "r" (setway));
+               }
+       }
+       /* DSB to make sure the operation is complete */
+       CP15DSB;
+}
+
+static void v7_clean_inval_dcache_level_setway(u32 level, u32 num_sets,
+                                              u32 num_ways, u32 way_shift,
+                                              u32 log2_line_len)
+{
+       int way, set, setway;
+
+       /*
+        * For optimal assembly code:
+        *      a. count down
+        *      b. have bigger loop inside
+        */
+       for (way = num_ways - 1; way >= 0 ; way--) {
+               for (set = num_sets - 1; set >= 0; set--) {
+                       setway = (level << 1) | (set << log2_line_len) |
+                                (way << way_shift);
+                       /*
+                        * Clean & Invalidate data/unified
+                        * cache line by set/way
+                        */
+                       asm volatile (" mcr p15, 0, %0, c7, c14, 2"
+                                       : : "r" (setway));
+               }
+       }
+       /* DSB to make sure the operation is complete */
+       CP15DSB;
+}
+
+static void v7_maint_dcache_level_setway(u32 level, u32 operation)
+{
+       u32 ccsidr;
+       u32 num_sets, num_ways, log2_line_len, log2_num_ways;
+       u32 way_shift;
+
+       set_csselr(level, ARMV7_CSSELR_IND_DATA_UNIFIED);
+
+       ccsidr = get_ccsidr();
+
+       log2_line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
+                               CCSIDR_LINE_SIZE_OFFSET) + 2;
+       /* Converting from words to bytes */
+       log2_line_len += 2;
+
+       num_ways  = ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >>
+                       CCSIDR_ASSOCIATIVITY_OFFSET) + 1;
+       num_sets  = ((ccsidr & CCSIDR_NUM_SETS_MASK) >>
+                       CCSIDR_NUM_SETS_OFFSET) + 1;
+       /*
+        * According to ARMv7 ARM number of sets and number of ways need
+        * not be a power of 2
+        */
+       log2_num_ways = log_2_n_round_up(num_ways);
+
+       way_shift = (32 - log2_num_ways);
+       if (operation == ARMV7_DCACHE_INVAL_ALL) {
+               v7_inval_dcache_level_setway(level, num_sets, num_ways,
+                                     way_shift, log2_line_len);
+       } else if (operation == ARMV7_DCACHE_CLEAN_INVAL_ALL) {
+               v7_clean_inval_dcache_level_setway(level, num_sets, num_ways,
+                                                  way_shift, log2_line_len);
+       }
+}
+
+
+static void v7_maint_dcache_all(u32 operation)
+{
+       u32 level, cache_type, level_start_bit = 0;
+
+       u32 clidr = get_clidr();
+
+       for (level = 0; level < 7; level++) {
+               cache_type = (clidr >> level_start_bit) & 0x7;
+               if ((cache_type == ARMV7_CLIDR_CTYPE_DATA_ONLY) ||
+                   (cache_type == ARMV7_CLIDR_CTYPE_INSTRUCTION_DATA) ||
+                   (cache_type == ARMV7_CLIDR_CTYPE_UNIFIED))
+                       v7_maint_dcache_level_setway(level, operation);
+               level_start_bit += 3;
+       }
+}
+
+void __v7_outer_cache_flush_all(void)
+{
+}
+void v7_outer_cache_flush_all(void)
+       __attribute__((weak, alias("__v7_outer_cache_flush_all")));
+
+void __v7_outer_cache_disable(void)
+{
+}
+void v7_outer_cache_disable(void)
+       __attribute__((weak, alias("__v7_outer_cache_disable")));
+
+void __v7_outer_cache_inval_all(void)
+{
+}
+void v7_outer_cache_inval_all(void)
+       __attribute__((weak, alias("__v7_outer_cache_inval_all")));
+
+void set_l2_indirect_reg(u32 reg_addr, u32 val)
+{
+
+       asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+                     "isb\n\t"
+                     "mcr     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
+                     "isb\n\t"
+                       :
+                       : [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
+       );
+}
+
+u32 get_l2_indirect_reg(u32 reg_addr)
+{
+       u32 val;
+
+       asm volatile ("mcr     p15, 3, %[l2cpselr], c15, c0, 6\n\t"
+                     "isb\n\t"
+                     "mrc     p15, 3, %[l2cpdr],   c15, c0, 7\n\t"
+                       : [l2cpdr]"=r" (val)
+                       : [l2cpselr]"r" (reg_addr)
+       );
+
+       return val;
+}
+
+void clear_l2cache_err(void)
+{
+#if defined CONFIG_IPQ806X
+#define L2ESR_IND_ADDR         (0x204)
+       unsigned int val;
+
+       val = get_l2_indirect_reg(L2ESR_IND_ADDR);
+       set_l2_indirect_reg(L2ESR_IND_ADDR, val);
+#endif
+}
+
+void __arm_init_before_mmu(void)
+{
+}
+void arm_init_before_mmu(void)
+       __attribute__((weak, alias("__arm_init_before_mmu")));
+
+void bi_dram_0_set_ranges(u32 start, u32 size){
+       bi_dram_0_start = start;
+       bi_dram_0_size = size;
+}
+
+static inline void dram_bank_mmu_setup(int bank)
+{
+       u32     i;
+       u32 skip = (u32)page_table >> 20;
+       for (i = bi_dram_0_start >> 20;
+            i < (bi_dram_0_start + bi_dram_0_size) >> 20;
+            i++) {
+         if(i == skip){ /* foolproof */
+               continue;
+         }
+               page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP;
+       }
+}
+
+/* to activate the MMU we need to set up virtual memory: use 1M areas */
+static inline void mmu_setup(void)
+{
+       int i;
+       u32 reg;
+
+       arm_init_before_mmu();
+       /* Set up an identity-mapping for all 4GB, rw for everyone */
+       for (i = 0; i < 4096; i++)
+               page_table[i] = i << 20 | (3 << 10) | 0x12;
+
+       for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+               dram_bank_mmu_setup(i);
+       }
+
+       /* Copy the page table address to cp15 */
+       asm volatile("mcr p15, 0, %0, c2, c0, 0"
+                    : : "r" (page_table) : "memory");
+       /* Set the access control to all-supervisor */
+       asm volatile("mcr p15, 0, %0, c3, c0, 0"
+                    : : "r" (~0));
+       /* and enable the mmu */
+       reg = get_cr(); /* get control reg. */
+       cp_delay();
+       set_cr(reg | CR_M);
+}
+
+static int mmu_enabled(void)
+{
+       return get_cr() & CR_M;
+}
+
+/* cache_bit must be either CR_I or CR_C */
+static void cache_enable(uint32_t cache_bit)
+{
+       uint32_t reg;
+
+       /* The data cache is not active unless the mmu is enabled too */
+       if ((cache_bit == CR_C) && !mmu_enabled())
+               mmu_setup();
+       reg = get_cr(); /* get control reg. */
+       cp_delay();
+       set_cr(reg | cache_bit);
+}
+
+
+void enable_caches(void)
+{
+       cache_enable(CR_I);
+       cache_enable(CR_C);
+}
+
+void invalidate_dcache_all(void)
+{
+       v7_maint_dcache_all(ARMV7_DCACHE_INVAL_ALL);
+
+       v7_outer_cache_inval_all();
+}
+
+/*
+ * Performs a clean & invalidation of the entire data cache
+ * at all levels
+ */
+void flush_dcache_all(void)
+{
+       v7_maint_dcache_all(ARMV7_DCACHE_CLEAN_INVAL_ALL);
+
+       v7_outer_cache_flush_all();
+}
+
+/* cache_bit must be either CR_I or CR_C */
+static void cache_disable(uint32_t cache_bit)
+{
+       uint32_t reg;
+
+       reg = get_cr();
+       cp_delay();
+
+       if (cache_bit == CR_C) {
+               /* if cache isn;t enabled no need to disable */
+               if ((reg & CR_C) != CR_C)
+                       return;
+               /* if disabling data cache, disable mmu too */
+               cache_bit |= CR_M;
+               flush_dcache_all();
+       }
+       set_cr(reg & ~cache_bit);
+}
+
+void icache_disable(void)
+{
+       cache_disable(CR_I);
+}
+
+void dcache_disable(void)
+{
+       cache_disable(CR_C);
+}
+
+int disable_interrupts (void)
+{
+       unsigned long old,temp;
+       __asm__ __volatile__("mrs %0, cpsr\n"
+                            "orr %1, %0, #0xc0\n"
+                            "msr cpsr_c, %1"
+                            : "=r" (old), "=r" (temp)
+                            :
+                            : "memory");
+       return (old & 0x80) == 0;
+}
+
+/* Invalidate entire I-cache and branch predictor array */
+void invalidate_icache_all(void)
+{
+       /*
+        * Invalidate all instruction caches to PoU.
+        * Also flushes branch target cache.
+        */
+       asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
+
+       /* Invalidate entire branch predictor array */
+       asm volatile ("mcr p15, 0, %0, c7, c5, 6" : : "r" (0));
+
+       /* Full system DSB - make sure that the invalidation is complete */
+       CP15DSB;
+
+       /* ISB - make sure the instruction stream sees it */
+       CP15ISB;
+}
+
+
+int cleanup_before_linux(void)
+{
+       /*
+        * this function is called just before we call linux
+        * it prepares the processor for linux
+        *
+        * we turn off caches etc ...
+        */
+       disable_interrupts();
+
+       /*
+        * Turn off I-cache and invalidate it
+        */
+       icache_disable();
+       invalidate_icache_all();
+
+       /*
+        * turn off D-cache
+        * dcache_disable() in turn flushes the d-cache and disables MMU
+        */
+       dcache_disable();
+       v7_outer_cache_disable();
+
+       /*
+        * After D-cache is flushed and before it is disabled there may
+        * be some new valid entries brought into the cache. We are sure
+        * that these lines are not dirty and will not affect our execution.
+        * (because unwinding the call-stack and setting a bit in CP15 SCTRL
+        * is all we did during this. We have not pushed anything on to the
+        * stack. Neither have we affected any static data)
+        * So just invalidate the entire d-cache again to avoid coherency
+        * problems for kernel
+        */
+       invalidate_dcache_all();
+
+       clear_l2cache_err();
+
+       /* Yes. I am a paranoid */
+       /* Full system DSB - make sure that the invalidation is complete */
+       CP15DSB;
+       /* ISB - make sure the instruction stream sees it */
+       CP15ISB;
+
+       return 0;
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/fdt.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/fdt.c
new file mode 100644 (file)
index 0000000..eca6fdd
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <types.h>
+#include <uimage/fdt.h>
+
+#define FDT_ALIGN(x, a)                (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x)                (FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_FIRST_SUPPORTED_VERSION    0x10
+#define FDT_LAST_SUPPORTED_VERSION     0x11
+
+unsigned long int ntohl(unsigned long int d);
+
+static int fdt_streq(char *s1, char *s2){
+       for(; *s1 != '\0' && *s2 != '\0'; s1++, s2++)
+               if(*s1 != *s2)
+                       return 0;
+       if(*s1 == '\0' && *s2 == '\0')
+               return 1;
+       return 0;
+}
+
+static int fdt_strlen(char *s){
+       int len = 0;
+       for(; *s != '\0'; s++, len++);
+       return len;
+}
+
+/*
+       Checks fdt header variables for adequacy of values.
+*/
+int fdt_check_header(void *data, u32 data_size){
+       struct fdt_header *image = (void*)data;
+       u32 fdt_magic = ntohl(image->magic);
+       u32 totalsize = ntohl(image->totalsize);
+       u32 fdt_version = ntohl(image->version);
+       u32 off_dt_struct = ntohl(image->off_dt_struct);
+       u32 off_dt_strings = ntohl(image->off_dt_strings);
+       u32 fdt_last_comp_version = ntohl(image->last_comp_version);
+       if(fdt_magic != FDT_MAGIC)
+               return -1;
+       if(data_size < totalsize)
+               return -2;
+       if(fdt_version < FDT_FIRST_SUPPORTED_VERSION)
+               return -3;
+       if(fdt_last_comp_version > FDT_LAST_SUPPORTED_VERSION)
+               return -4;
+       if(off_dt_struct == 0 || off_dt_struct >= totalsize)
+               return -5;
+       if(off_dt_strings == 0 || off_dt_strings >= totalsize)
+               return -6;
+       return 0;
+}
+
+/*
+       Returns: prop->data and prop->len for the prop with name prop_name
+       whose parent node name is node_name.
+*/
+char *fdt_get_prop(void *data, char *node_name, char *prop_name, u32 *lenp_ret){
+       struct fdt_header *image = (void*)data;
+       u32 off_dt_struct = ntohl(image->off_dt_struct);
+       u32 off_dt_strings = ntohl(image->off_dt_strings);
+       u32 totalsize = ntohl(image->totalsize);
+       u32 offset = 0;
+       u32 nextoffset = 0;
+       /* struct memory pointer */
+       unsigned char *p = (void*)data + off_dt_struct;
+       /* props names are stored separately, in a strings heap */
+       unsigned char *n = (void*)data + off_dt_strings;
+       /* data tail pointer */
+       void *t = (void*)data + totalsize;
+       int is_node_found = 0;
+       struct fdt_property *fdt_prop;
+       char *cur_prop_name;
+       if(lenp_ret)
+               *lenp_ret = 0;
+       while(1){
+               u32 *tagp = (void*)p + offset;
+               u32 *lenp;
+               u32 tag = ntohl(*tagp);
+               /* out of range protection */
+               if((void*)tagp + sizeof(*tagp) >= t)
+                       return NULL; /* offset is out of range ! */
+               offset += FDT_TAGSIZE; /* skip tag var */
+               if(tag == FDT_END)
+                       break; /* end of tags list is reached */
+               switch(tag){
+                       case FDT_BEGIN_NODE: /* node tag. is the parent node for props and node tags. */
+                               if(fdt_streq(node_name, (char*)(p + offset)))
+                                       is_node_found = 1;
+                               else
+                                       is_node_found = 0;
+                               /* skip name var */
+                               offset += fdt_strlen((char*)(p + offset)) + 1;
+                               break;
+                       case FDT_PROP: /* props of this node */
+                               lenp = (void*)p + offset;
+                               if(is_node_found){
+                                       /* skip-name offset, length and value */
+                                       fdt_prop = (void*)p + offset - FDT_TAGSIZE;
+                                       /* out of range protection */
+                                       if((void*)fdt_prop + sizeof(*fdt_prop) >= t)
+                                               return NULL; /* fdt_prop is out of range ! */
+                                       cur_prop_name = (char *)(n + ntohl(fdt_prop->nameoff));
+                                       /* out of range protection */
+                                       if((void*)cur_prop_name >= t)
+                                               return NULL; /* nameoff is out of range ! */
+                                       if(fdt_streq(prop_name, cur_prop_name)){
+                                               if(lenp_ret)
+                                                       *lenp_ret = ntohl(*lenp);
+                                               return fdt_prop->data;
+                                       }
+                               }
+                               offset += sizeof(struct fdt_property) - FDT_TAGSIZE + ntohl(*lenp);
+                               break;
+                       case FDT_END: /* end of tags list */
+                       case FDT_END_NODE: /* end of current node */
+                               is_node_found = 0;
+                       case FDT_NOP: /* nop ? */
+                               break;
+                       default:
+                               return NULL; /* unknown tag */
+               }
+               nextoffset = FDT_TAGALIGN(offset);
+               offset = nextoffset;
+       }
+       return NULL; /* return NULL on error */
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/head.S b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/head.S
new file mode 100644 (file)
index 0000000..96d5d24
--- /dev/null
@@ -0,0 +1,83 @@
+.globl _start
+_start:
+       mov r7, pc @save REAL _start addr
+       sub     r7, r7, #8
+
+       mov r6, r1 @save ARGS[1] to r6(ARCH value)
+
+       @mov r0, r7
+       @bl owl_debug
+
+       ldr r0, =(CONFIG_SYS_TEXT_BASE)
+       mov r1, r7 @ real _start addr !
+       mov r2, r6 @ARCH value
+       @bl owl_debug
+       bl relocate_code
+
+.globl _payload_data_begin_ofs
+_payload_data_begin_ofs:
+       .word _payload_data_begin - _start
+
+.globl _payload_data_end_ofs
+_payload_data_end_ofs:
+       .word _payload_data_end - _start
+
+/*
+ * void relocate_code (dst, REAL _start addr, ARCH)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ */
+.globl relocate_code
+.align         4
+relocate_code:
+       mov     r6, r0  /* save addr of destination */
+       mov     r5, r1  /* REAL _start addr */
+       mov     r4, r2  /* ARCH */
+
+       /* Set up the stack                                                 */
+stack_setup:
+       mov     sp, r6
+
+       bl watchdog_resetup /* resetup watchdog timer */
+
+       ldr     r0, _payload_data_begin_ofs
+       add     r0, r0, r5 /* add in memory offset */
+       mov     r1, r6                  /* r1 <- scratch for copy_loop */
+       ldr     r2, _payload_data_end_ofs
+       add     r2, r2, r5 /* add in memory offset */
+
+       @bl owl_debug
+copy_loop:
+       ldmia   r0!, {r9-r10}           /* copy from source address [r0]    */
+       stmia   r1!, {r9-r10}           /* copy to   target address [r1]    */
+       cmp     r0, r2                  /* until source end address [r2]    */
+       blo     copy_loop
+
+/* Bss reset will be made by the target called function(start.S) */
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+jump_2_ram:
+/*
+ * If I-cache is enabled invalidate it.
+ * In our case(RouterBOOT) it should be turned off
+ * anyway, but let it be.
+ */
+#ifndef CONFIG_SYS_ICACHE_OFF
+       mov r0, #0
+       mcr     p15, 0, r0, c7, c5, 0   @ invalidate icache
+       mcr     p15, 0, r0, c7, c10, 4  @ DSB
+       mcr     p15, 0, r0, c7, c5, 4   @ ISB
+#endif
+       ldr     r0, =(CONFIG_SYS_TEXT_BASE)
+       mov r1, r5 /* REAL _start addr */
+       mov r2, r4 /* ARCH */
+       /* jump to it ... */
+       mov     pc, r0
+
+.type relocate_code STT_FUNC
+.size relocate_code, .-relocate_code
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/LzmaDecode.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/LzmaDecode.h
new file mode 100644 (file)
index 0000000..2870eeb
--- /dev/null
@@ -0,0 +1,113 @@
+/* 
+  LzmaDecode.h
+  LZMA Decoder interface
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+  int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  #ifdef _LZMA_OUT_READ
+  UInt32 DictionarySize;
+  #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+
+  #ifdef _LZMA_IN_CB
+  const unsigned char *Buffer;
+  const unsigned char *BufferLim;
+  #endif
+
+  #ifdef _LZMA_OUT_READ
+  unsigned char *Dictionary;
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;
+  unsigned char TempDictionary[4];
+  #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    #ifdef _LZMA_IN_CB
+    ILzmaInCallback *inCallback,
+    #else
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    #endif
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/LzmaTypes.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/LzmaTypes.h
new file mode 100644 (file)
index 0000000..9c27290
--- /dev/null
@@ -0,0 +1,45 @@
+/* 
+LzmaTypes.h 
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif 
+
+/* #define _LZMA_NO_SYSTEM_SIZE_T */
+/* You can use it, if you don't want <stddef.h> */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+#include <stddef.h>
+typedef size_t SizeT;
+#endif
+#endif
+
+#endif
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/io.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/io.h
new file mode 100644 (file)
index 0000000..bf66fa0
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARM_MINI_IO_H
+#define __ASM_ARM_MINI_IO_H
+
+#define dmb()          __asm__ __volatile__ ("" : : : "memory")
+#define __iormb()      dmb()
+#define __iowmb()      dmb()
+#define __arch_putl(v,a)               (*(volatile unsigned int *)(a) = (v))
+#define __arch_getl(a)                 (*(volatile unsigned int *)(a))
+
+#define writel(v,c)    ({ unsigned int __v = v; __iowmb(); __arch_putl(__v,c); __v; })
+#define readl(c)       ({ unsigned int __v = __arch_getl(c); __iormb(); __v; })
+
+#endif /* __ASM_ARM_MINI_IO_H */
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/iomap.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/iomap.h
new file mode 100644 (file)
index 0000000..a9c74fa
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Â Â Â Â * Redistributions of source code must retain the above copyright
+ * Â Â Â Â Â Â notice, this list of conditions and the following disclaimer.
+ * Â Â Â Â * Redistributions in binary form must reproduce the above
+ * Â Â Â Â Â Â copyright notice, this list of conditions and the following
+ * Â Â Â Â Â Â disclaimer in the documentation and/or other materials provided
+ * Â Â Â Â Â Â with the distribution.
+ * Â Â Â Â * Neither the name of The Linux Foundation nor the names of its
+ * Â Â Â Â Â Â contributors may be used to endorse or promote products derived
+ * Â Â Â Â Â Â from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PLATFORM_IPQ40XX_IOMAP_H_
+#define _PLATFORM_IPQ40XX_IOMAP_H_
+
+#ifdef CONFIG_IPQ4XXX
+#define CLK_CTL_BASE           0x01800000
+#define GCNT_BASE              0x004a1000
+#define TIMER_BASE             0x0B021000
+#define UART2_DM_BASE          0x078b0000
+#define UART1_DM_BASE          0x078af000
+#define I2C0_BASE              0x078B7000
+#define TLMM_BASE              0x01000000
+#define GPIO_CONFIG_ADDR(x) (TLMM_BASE + (x)*0x1000)
+#define GPIO_IN_OUT_ADDR(x) (TLMM_BASE + 0x4 + (x)*0x1000)
+
+#endif /* CONFIG_IPQ4XXX */
+#ifdef CONFIG_IPQ806X
+#define UART7_DM_BASE          0x16640000
+
+#endif /* CONFIG_IPQ806X */
+
+#endif /* _PLATFORM_IPQ40XX_IOMAP_H_ */
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/printf.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/printf.h
new file mode 100644 (file)
index 0000000..3cf3670
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _printf_h_
+#define _printf_h_
+
+#ifdef DEBUG
+#define debug(format, args...) printf(format, ##args)
+#else
+#define debug(...)
+#endif /* DEBUG */
+
+#include <stdarg.h>
+int printf(const char *fmt, ...);
+
+#endif /* _printf_h_ */
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/types.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/types.h
new file mode 100644 (file)
index 0000000..c30b930
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef __TYPES_MINI_H
+#define __TYPES_MINI_H
+
+typedef unsigned long long uint64_t;
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+typedef unsigned long u32;
+typedef long s32;
+typedef unsigned char u8;
+typedef unsigned short u16;
+
+typedef unsigned long ulong;
+
+#define NULL 0
+
+#endif /* __TYPES_MINI_H */
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/uimage/fdt.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/uimage/fdt.h
new file mode 100644 (file)
index 0000000..2a24650
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+       uint32_t magic;                  /* magic word FDT_MAGIC */
+       uint32_t totalsize;              /* total size of DT block */
+       uint32_t off_dt_struct;          /* offset to structure */
+       uint32_t off_dt_strings;         /* offset to strings */
+       uint32_t off_mem_rsvmap;         /* offset to memory reserve map */
+       uint32_t version;                /* format version */
+       uint32_t last_comp_version;      /* last compatible version */
+
+       /* version 2 fields below */
+       uint32_t boot_cpuid_phys;        /* Which physical CPU id we're
+                                           booting on */
+       /* version 3 fields below */
+       uint32_t size_dt_strings;        /* size of the strings block */
+
+       /* version 17 fields below */
+       uint32_t size_dt_struct;         /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+       uint64_t address;
+       uint64_t size;
+};
+
+struct fdt_node_header {
+       uint32_t tag;
+       char name[0];
+};
+
+struct fdt_property {
+       uint32_t tag;
+       uint32_t len;
+       uint32_t nameoff;
+       char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC      0xd00dfeed      /* 4: version, 4: total size */
+#define FDT_TAGSIZE    sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE 0x1             /* Start node: full name */
+#define FDT_END_NODE   0x2             /* End node */
+#define FDT_PROP       0x3             /* Property: name off,
+                                          size, content */
+#define FDT_NOP                0x4             /* nop */
+#define FDT_END                0x9
+
+#define FDT_V1_SIZE    (7*sizeof(uint32_t))
+#define FDT_V2_SIZE    (FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE    (FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE   FDT_V3_SIZE
+#define FDT_V17_SIZE   (FDT_V16_SIZE + sizeof(uint32_t))
+
+/* adding a ramdisk needs 0x44 bytes in version 2008.10 */
+#define FDT_RAMDISK_OVERHEAD   0x80
+#endif /* _FDT_H */
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/uimage/legacy.h b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/include/uimage/legacy.h
new file mode 100644 (file)
index 0000000..b252672
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef __LEGACY_H__
+#define __LEGACY_H__
+
+#define LEGACY_IH_MAGIC        0x27051956      /* LEGACY Magic Number          */
+#define FIT_IH_MAGIC   0xd00dfeed      /* FIT Magic Number */
+#define LEGACY_IH_NMLEN                32      /* LEGACY Name Length           */
+
+/*
+ * Legacy format LEGACY header,
+ * all data in network byte order (aka natural aka bigendian).
+ */
+typedef struct legacy_image_header {
+       uint32_t        ih_magic;       /* LEGACY Header Magic Number   */
+       uint32_t        ih_hcrc;        /* LEGACY Header CRC Checksum   */
+       uint32_t        ih_time;        /* LEGACY Creation Timestamp    */
+       uint32_t        ih_size;        /* LEGACY Data Size             */
+       uint32_t        ih_load;        /* Data  Load  Address          */
+       uint32_t        ih_ep;          /* Entry Point Address          */
+       uint32_t        ih_dcrc;        /* LEGACY Data CRC Checksum     */
+       uint8_t         ih_os;          /* Operating System             */
+       uint8_t         ih_arch;        /* CPU architecture             */
+       uint8_t         ih_type;        /* LEGACY Type                  */
+       uint8_t         ih_comp;        /* Compression Type             */
+       uint8_t         ih_name[LEGACY_IH_NMLEN];       /* LEGACY Name          */
+} legacy_image_header_t;
+
+#endif /* __LEGACY_H__ */
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/kernel-data.lds b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/kernel-data.lds
new file mode 100644 (file)
index 0000000..0b2c8ce
--- /dev/null
@@ -0,0 +1,9 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+SECTIONS {
+       .data.kernel : {
+               _kernel_data_start = .;
+               *(.data)
+               _kernel_data_end = .;
+       }
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader.c
new file mode 100644 (file)
index 0000000..b44abb0
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the Atheros AR7XXX/AR9XXX based boards:
+ *     Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <printf.h>
+#include <iomap.h>
+#include <io.h>
+#include <types.h>
+#include <uimage/legacy.h>
+
+#define IPQ_ARCH 4200
+
+/* beyond the image end, size not known in advance */
+extern unsigned char workspace[];
+u32 arch = 0;
+void (*kernel_entry)(int zero, int arch, unsigned int params);
+u32 kernel_p0 = 0;
+u32 kernel_p1 = IPQ_ARCH;
+u32 kernel_p2 = NULL;
+
+/* base stack poinet - 16 mb. stack grows left!
+        boot_params(12b)<--16M of stack--TEXT_BASE,_start--END of program
+        !!! TODO: replace to like workspace static mem region !!!
+*/
+//u32 *boot_params = (void*)(CONFIG_SYS_TEXT_BASE - 0x100000C);
+
+void bi_dram_0_set_ranges(u32, u32);
+int cleanup_before_linux(void);
+void enable_caches(void);
+extern u32 owl_get_sp(void);
+void serial_putc(char c);
+void watchdog_setup(int);
+unsigned long int ntohl(unsigned long int);
+void dump_mem(unsigned char *, char *);
+void reset_cpu(ulong);
+int fdt_check_header(void *, u32);
+char *fdt_get_prop(void *, char *, char *, u32 *);
+int lzma_gogogo(void *, void *, u32, u32 *);
+
+void my_memcpy(void *dst, const void *src, u32 n){
+       const void *end = src + n;
+       for(; src + 4 <= end; src += 4, dst += 4)
+               *((u32*)dst) = *((u32*)src);
+       for(; src < end; src++, dst++)
+               *((u8*)dst) = *((u8*)src);
+}
+
+int handle_legacy_header(void *_kernel_data_start, u32 kern_image_len){
+       legacy_image_header_t *image = (void*)_kernel_data_start;
+       void *kernel_load = (void*)ntohl(image->ih_load);
+       void *kernel_ep = (void*)ntohl(image->ih_ep);
+       void *src = (void*)_kernel_data_start + sizeof(legacy_image_header_t);
+       void *dst = kernel_load;
+       /* compiler optimization barrier needed for GCC >= 3.4 */
+       __asm__ __volatile__("": : :"memory");
+
+       u32 kernel_body_len = ntohl(image->ih_size);
+
+       debug("  size = %u\n", kernel_body_len);
+       debug("  name = '%s'\n", (char*)image->ih_name);
+       debug("  load = 0x%08x\n", kernel_load);
+       debug("  ep = 0x%08x\n", kernel_ep);
+
+       //check ih_size for adequate value
+       if(kern_image_len - sizeof(legacy_image_header_t) < kernel_body_len){
+               printf("\n");
+               printf("Error ! Kernel sizes mismath detected !\n");
+               printf("  details: %d - %d < %d !\n", kern_image_len,
+                       sizeof(legacy_image_header_t), kernel_body_len);
+               return -99;
+       }
+       debug("\n");
+       printf("Copy kernel...");
+       my_memcpy(dst, src, kernel_body_len);
+       printf("Done\n");
+       kernel_entry = kernel_ep;
+       return 0;
+}
+
+/* FIT - Flattened Image Tree.
+        ! Not to be confused with an FDT - Flattened Device Tree !
+        ! MAGIC of FIT == ~MAGIC of FDT !
+*/
+#define FIT_KERNEL_NODE_NAME "kernel@1"
+#define FIT_DTB_NODE_NAME "fdt@1"
+int handle_fit_header(void *_kernel_data_start, u32 kern_image_len){
+       void *data = (void*)_kernel_data_start;
+       void *kernel_load = NULL;
+       void *kernel_ep = NULL;
+       char *kernel_name = NULL;
+       char *kernel_compr = NULL;
+       void *dtb_data = NULL; //device tree blob
+       void *dtb_dst = (void*)workspace;
+       u32 dtb_body_len = 0;
+       u32 kernel_body_len = 0;
+       u32 kernel_uncompr_size = 0;
+       void *src = NULL;
+       void *dst = NULL;
+       char *tmp_c;
+       int ret;
+       /* compiler optimization barrier needed for GCC >= 3.4 */
+       __asm__ __volatile__("": : :"memory");
+       /* Do FDT header base checks */
+       ret = fdt_check_header(data, kern_image_len);
+       if(ret){
+               printf("Error ! FDT header is corrupted! check_ret = %d\n", ret);
+               return -99;
+       }
+       if(!(kernel_name = fdt_get_prop(data, FIT_KERNEL_NODE_NAME, "description", NULL)))
+               return -98;
+       if(!(tmp_c = fdt_get_prop(data, FIT_KERNEL_NODE_NAME, "load", NULL)))
+               return -97;
+       kernel_load = (void*)ntohl(*(u32*)tmp_c);
+       dst = kernel_load;
+       if(!(tmp_c = fdt_get_prop(data, FIT_KERNEL_NODE_NAME, "entry", NULL)))
+               return -96;
+       kernel_ep = (void*)ntohl(*(u32*)tmp_c);
+       if(!(src = fdt_get_prop(data, FIT_KERNEL_NODE_NAME, "data", &kernel_body_len)))
+               return -95;
+       if(!(kernel_compr = fdt_get_prop(data, FIT_KERNEL_NODE_NAME, "compression", NULL)))
+               return -94;
+       if(!(dtb_data = fdt_get_prop(data, FIT_DTB_NODE_NAME, "data", &dtb_body_len)))
+               return -93;
+
+       debug("  size = %u\n", kernel_body_len);
+       debug("  name = '%s'\n", kernel_name);
+       debug("  load = 0x%08x\n", kernel_load);
+       debug("  ep = 0x%08x\n", kernel_ep);
+       debug("  compr = %s\n", kernel_compr);
+
+       //check kernel@1->data size for adequate value
+       if(kernel_body_len >= kern_image_len){
+               printf("\n");
+               printf("Error ! Kernel sizes mismath detected !\n");
+               printf("  details: %d >= %d !\n", kernel_body_len, kern_image_len);
+               return -99;
+       }
+       debug("\n");
+       printf("Extracting LZMA kernel...");
+       watchdog_setup(30);
+       /* without this all cpu operations is very very slow ! */
+       if(dst < src){
+               /* setup D-Cache ranges. our loader head + 32M */
+               bi_dram_0_set_ranges((u32)dst, (u32)(src - dst + (void*)0x2000000));
+               enable_caches(); /* Enable I and D caches ONLY for LZMA op */
+               lzma_gogogo(dst, src, kernel_body_len, &kernel_uncompr_size);
+       }
+       cleanup_before_linux(); /* Disable I and D caches */
+
+       /* prepare device tree blob data for copy after kernel */
+       my_memcpy(dtb_dst, dtb_data, dtb_body_len);
+       //dump_mem(workspace, "dtb_data:");
+
+       kernel_entry = kernel_ep;
+       kernel_p2 = (u32)dtb_dst;
+       return 0;
+}
+
+void loader_main(u32 head_text_base, u32 _arch)
+{
+       extern char _kernel_data_start[];
+       extern char _kernel_data_end[];
+       u32 kern_image_len = _kernel_data_end  - _kernel_data_start;
+       uint32_t *_magic = (void*)_kernel_data_start;
+       u32 magic;
+       int ret = -100;
+
+       /* compiler optimization barrier needed for GCC >= 3.4 */
+       __asm__ __volatile__("": : :"memory");
+
+       printf("\n");
+       printf("OpenWrt kernel loader for Qualcomm IPQ-4XXX/IPQ-806X\n");
+       printf("Copyright (C) 2019  Sergey Sergeev <adron@mstnt.com>\n");
+
+       debug("\n");
+       debug("  head loader TEXT_BASE = 0x%08X\n", head_text_base);
+       debug("kernel loader TEXT_BASE = 0x%08X\n", CONFIG_SYS_TEXT_BASE);
+       //printf("kernel_data_start = 0x%08X\n", _kernel_data_start);
+       //printf("kernel_data_end = 0x%08X\n", _kernel_data_end);
+       printf("\n");
+
+       //watchdog_setup(5); for(;;);
+       //reset_cpu(0);
+
+       arch = _arch;
+       kernel_p1 = arch;
+       debug("ARCH = %d\n", arch);
+       if(arch != IPQ_ARCH){
+               printf("Critical alert ! ARCH mismatch: %u vs %u\n", arch, IPQ_ARCH);
+               watchdog_setup(5); for(;;);
+       }
+       magic = ntohl(*_magic);
+       debug("Kernel image header:\n");
+       switch(magic){
+               case LEGACY_IH_MAGIC:
+                       debug("  magic = 0x%x, Legacy uImage\n", magic);
+                       ret = handle_legacy_header(_kernel_data_start, kern_image_len);
+                       break;
+               case FIT_IH_MAGIC:
+                       debug("  magic = 0x%x, FIT uImage\n", magic);
+                       ret = handle_fit_header(_kernel_data_start, kern_image_len);
+                       break;
+               default:
+                       printf("  magic = 0x%x, UNKNOWN !!!\n", magic);
+       }
+       if(ret){
+               printf("\n");
+               printf("Op ret = %d\n", ret);
+               printf("Auto reboot in 5 sec\n");
+               watchdog_setup(5); for(;;);
+       }
+
+       printf("Starting kernel at 0x%08x\n", kernel_entry);
+       printf("\n");
+       cleanup_before_linux();
+       kernel_entry(kernel_p0, kernel_p1, kernel_p2);
+       reset_cpu(0);
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader.lds b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader.lds
new file mode 100644 (file)
index 0000000..968585f
--- /dev/null
@@ -0,0 +1,20 @@
+OUTPUT_ARCH(arm)
+SECTIONS {
+       .text : {
+               _start = .;
+               *(.text)
+               *(.text.*)
+               *(.data)
+               *(.data.*)
+       }
+       . = ALIGN(32);
+       _bss_start = .;
+       .bss : {
+               *(.bss)
+               *(.bss.*)
+       }
+       . = ALIGN(32);
+       _bss_end = .;
+       . = ALIGN(32);
+       workspace = .;
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader2.lds b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/loader2.lds
new file mode 100644 (file)
index 0000000..ea5955c
--- /dev/null
@@ -0,0 +1,20 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+SECTIONS {
+       .text : {
+               _start = .;
+               *(.text)
+               *(.text.*)
+               *(.rodata)
+               *(.rodata.*)
+       }
+
+       . = ALIGN(32);
+       .data : {
+               _payload_data_begin = .;
+               *(.data)
+               _payload_data_end = .;
+               *(.data.*)
+               . = . + 524288;         /* workaround for buggy bootloaders */
+       }
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/lzma.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/lzma.c
new file mode 100644 (file)
index 0000000..7312b16
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the Atheros AR7XXX/AR9XXX based boards:
+ *     Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <printf.h>
+#include <types.h>
+#include <LzmaDecode.h>
+
+/* beyond the image end, size not known in advance */
+extern unsigned char workspace[];
+
+static CLzmaDecoderState lzma_state;
+static unsigned char *lzma_data;
+static unsigned long lzma_datasize;
+static unsigned long lzma_outsize;
+static unsigned long kernel_la;
+
+static void lzma_init_data(void *_kernel_la, void *_lzma_data, u32 _lzma_datasize)
+{
+       kernel_la = (unsigned long)_kernel_la;
+       lzma_data = _lzma_data;
+       lzma_datasize = _lzma_datasize;
+}
+
+static __inline__ unsigned char lzma_get_byte(void)
+{
+       unsigned char c;
+
+       lzma_datasize--;
+       c = *lzma_data++;
+
+       return c;
+}
+
+static int lzma_init_props(u32 *lzma_outsize_ret)
+{
+       unsigned char props[LZMA_PROPERTIES_SIZE];
+       int res;
+       int i;
+
+       /* read lzma properties */
+       for (i = 0; i < LZMA_PROPERTIES_SIZE; i++)
+               props[i] = lzma_get_byte();
+
+       /* read the lower half of uncompressed size in the header */
+       lzma_outsize = ((SizeT) lzma_get_byte()) +
+                      ((SizeT) lzma_get_byte() << 8) +
+                      ((SizeT) lzma_get_byte() << 16) +
+                      ((SizeT) lzma_get_byte() << 24);
+
+       if(lzma_outsize_ret)
+               *lzma_outsize_ret = lzma_outsize;
+       /* skip rest of the header (upper half of uncompressed size) */
+       for (i = 0; i < 4; i++)
+               lzma_get_byte();
+
+       res = LzmaDecodeProperties(&lzma_state.Properties, props,
+                                       LZMA_PROPERTIES_SIZE);
+       return res;
+}
+
+static int lzma_decompress(unsigned char *outStream)
+{
+       SizeT ip, op;
+       int ret;
+
+       lzma_state.Probs = (CProb *) workspace;
+
+       ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream,
+                        lzma_outsize, &op);
+
+       if (ret != LZMA_RESULT_OK) {
+               int i;
+
+               printf("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
+                   ret, lzma_data + ip, lzma_outsize, ip, op);
+
+               for (i = 0; i < 16; i++)
+                       printf("%02x ", lzma_data[ip + i]);
+
+               printf("\n");
+       }
+       return ret;
+}
+
+int lzma_gogogo(void *_kernel_la, void *_lzma_data, u32 _lzma_datasize, u32 *lzma_outsize_ret){
+       int res;
+       lzma_init_data(_kernel_la, _lzma_data, _lzma_datasize);
+       res = lzma_init_props(lzma_outsize_ret);
+       if (res != LZMA_RESULT_OK) {
+               printf("Incorrect LZMA stream properties!\n");
+               return -1;
+       }
+       res = lzma_decompress((unsigned char *) kernel_la);
+       if (res != LZMA_RESULT_OK) {
+               printf("failed, ");
+               switch (res) {
+               case LZMA_RESULT_DATA_ERROR:
+                       printf("data error!\n");
+                       break;
+               default:
+                       printf("unknown error %d!\n", res);
+               }
+               return -2;
+       } else {
+               printf("Done\n");
+       }
+       return 0;
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/printf.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/printf.c
new file mode 100644 (file)
index 0000000..fccedb5
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include       <printf.h>
+
+extern void serial_putc(char c);
+
+/* this is the maximum width for a variable */
+#define                LP_MAX_BUF      256
+
+/* macros */
+#define                IsDigit(x)      ( ((x) >= '0') && ((x) <= '9') )
+#define                Ctod(x)         ( (x) - '0')
+
+/* forward declaration */
+static int PrintChar(char *, char, int, int);
+static int PrintString(char *, char *, int, int);
+static int PrintNum(char *, unsigned int, int, int, int, int, char, int);
+
+/* private variable */
+static const char theFatalMsg[] = "fatal error in lp_Print!";
+
+/* -*-
+ * A low level printf() function.
+ */
+static void
+lp_Print(void (*output)(void *, char *, int),
+        void * arg,
+        char *fmt,
+        va_list ap)
+{
+
+#define        OUTPUT(arg, s, l)  \
+  { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
+       (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
+    } else { \
+      (*output)(arg, s, l); \
+    } \
+  }
+
+    char buf[LP_MAX_BUF];
+
+    char c;
+    char *s;
+    long int num;
+
+    int longFlag;
+    int negFlag;
+    int width;
+    int prec;
+    int ladjust;
+    char padc;
+
+    int length;
+
+    for(;;) {
+       {
+           /* scan for the next '%' */
+           char *fmtStart = fmt;
+           while ( (*fmt != '\0') && (*fmt != '%')) {
+               fmt ++;
+           }
+
+           /* flush the string found so far */
+           OUTPUT(arg, fmtStart, fmt-fmtStart);
+
+           /* are we hitting the end? */
+           if (*fmt == '\0') break;
+       }
+
+       /* we found a '%' */
+       fmt ++;
+
+       /* check for long */
+       if (*fmt == 'l') {
+           longFlag = 1;
+           fmt ++;
+       } else {
+           longFlag = 0;
+       }
+
+       /* check for other prefixes */
+       width = 0;
+       prec = -1;
+       ladjust = 0;
+       padc = ' ';
+
+       if (*fmt == '-') {
+           ladjust = 1;
+           fmt ++;
+       }
+
+       if (*fmt == '0') {
+           padc = '0';
+           fmt++;
+       }
+
+       if (IsDigit(*fmt)) {
+           while (IsDigit(*fmt)) {
+               width = 10 * width + Ctod(*fmt++);
+           }
+       }
+
+       if (*fmt == '.') {
+           fmt ++;
+           if (IsDigit(*fmt)) {
+               prec = 0;
+               while (IsDigit(*fmt)) {
+                   prec = prec*10 + Ctod(*fmt++);
+               }
+           }
+       }
+
+
+       /* check format flag */
+       negFlag = 0;
+       switch (*fmt) {
+        case 'b':
+           if (longFlag) {
+               num = va_arg(ap, long int);
+           } else {
+               num = va_arg(ap, int);
+           }
+           length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case 'd':
+        case 'D':
+           if (longFlag) {
+               num = va_arg(ap, long int);
+           } else {
+               num = va_arg(ap, int);
+           }
+           if (num < 0) {
+               num = - num;
+               negFlag = 1;
+           }
+           length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case 'o':
+        case 'O':
+           if (longFlag) {
+               num = va_arg(ap, long int);
+           } else {
+               num = va_arg(ap, int);
+           }
+           length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case 'u':
+        case 'U':
+           if (longFlag) {
+               num = va_arg(ap, long int);
+           } else {
+               num = va_arg(ap, int);
+           }
+           length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case 'x':
+           if (longFlag) {
+               num = va_arg(ap, long int);
+           } else {
+               num = va_arg(ap, int);
+           }
+           length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case 'X':
+           if (longFlag) {
+               num = va_arg(ap, long int);
+           } else {
+               num = va_arg(ap, int);
+           }
+           length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case 'c':
+           c = (char)va_arg(ap, int);
+           length = PrintChar(buf, c, width, ladjust);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case 's':
+           s = (char*)va_arg(ap, char *);
+           length = PrintString(buf, s, width, ladjust);
+           OUTPUT(arg, buf, length);
+           break;
+
+        case '\0':
+           fmt --;
+           break;
+
+        default:
+           /* output this char as it is */
+           OUTPUT(arg, fmt, 1);
+       }       /* switch (*fmt) */
+
+       fmt ++;
+    }          /* for(;;) */
+
+    /* special termination call */
+    OUTPUT(arg, "\0", 1);
+}
+
+
+/* --------------- local help functions --------------------- */
+static int
+PrintChar(char * buf, char c, int length, int ladjust)
+{
+    int i;
+
+    if (length < 1) length = 1;
+    if (ladjust) {
+       *buf = c;
+       for (i=1; i< length; i++) buf[i] = ' ';
+    } else {
+       for (i=0; i< length-1; i++) buf[i] = ' ';
+       buf[length - 1] = c;
+    }
+    return length;
+}
+
+static int
+PrintString(char * buf, char* s, int length, int ladjust)
+{
+    int i;
+    int len=0;
+    char* s1 = s;
+    while (*s1++) len++;
+    if (length < len) length = len;
+
+    if (ladjust) {
+       for (i=0; i< len; i++) buf[i] = s[i];
+       for (i=len; i< length; i++) buf[i] = ' ';
+    } else {
+       for (i=0; i< length-len; i++) buf[i] = ' ';
+       for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
+    }
+    return length;
+}
+
+#define wr2p(tmp){ \
+       iters_count++; \
+       if((tmp) <= 9){ \
+               *p++ = '0' + (tmp); \
+       }else if(upcase) { \
+               *p++ = 'A' + (tmp) - 10; \
+       }else{ \
+               *p++ = 'a' + (tmp) - 10; \
+       } \
+}
+
+/* 32 bit DEC unsigned int convert to string */
+/* https://stackoverflow.com/questions/33203044/number-to-digits-without-using-strings-nor-division-by-10 */
+static int my_dec2str(char *p, unsigned int A, int upcase){
+       unsigned R, N;
+       unsigned long long Q; /* 32 bit Q can be owerflow, so use 64 bit */
+       int iters_count = 0;
+       if(A < 10){
+               wr2p(A);
+               return iters_count;
+       }
+       if(A == 10){
+               wr2p(0);
+               wr2p(1);
+               return iters_count;
+       }
+       while(A > 0){
+               Q = (((unsigned long long)A >> 1LLU) + (unsigned long long)A) >> 1LLU;
+               Q = ((Q >>  4LLU) + Q);
+               Q = ((Q >>  8LLU) + Q);
+               Q = ((Q >> 16LLU) + Q) >> 3LLU;
+               /* either Q = A / 10 or Q + 1 = A / 10 for all 32-bit unsigned A */
+               R = A - 10 * Q;
+               N = Q;
+               if(R > 9){
+                       R = A - 10 * (Q + 1);
+                       N = Q + 1;
+               }
+               A = N;
+               //printf("R = %u, Q = %u\n", R, Q);
+               wr2p(R);
+       }
+       return iters_count;
+}
+
+/* 32 bit HEX unsigned int convert to string */
+static int my_hex2str(char *p, unsigned int  A, int upcase){
+       int iters_count = 0;
+       if(A < 16){
+               wr2p(A);
+               return iters_count;
+       }
+       while(A > 0){
+               wr2p(A & 0xF);
+               //printf("%d\n", A & 0xF);
+               A >>= 4;
+       }
+       return iters_count;
+}
+
+
+static int
+PrintNum(char * buf, unsigned int u, int base, int negFlag,
+        int length, int ladjust, char padc, int upcase)
+{
+    /* algorithm :
+     *  1. prints the number from left to right in reverse form.
+     *  2. fill the remaining spaces with padc if length is longer than
+     *     the actual length
+     *     TRICKY : if left adjusted, no "0" padding.
+     *             if negtive, insert  "0" padding between "0" and number.
+     *  3. if (!ladjust) we reverse the whole string including paddings
+     *  4. otherwise we only reverse the actual string representing the num.
+     */
+
+    int actualLength =0;
+    char *p = buf;
+    int i;
+
+               if(base == 10)
+                       p += my_dec2str(p, u, upcase);
+               if(base == 16)
+                       p += my_hex2str(p, u, upcase);
+
+    if (negFlag) {
+       *p++ = '-';
+    }
+
+    /* figure out actual length and adjust the maximum length */
+    actualLength = p - buf;
+    if (length < actualLength) length = actualLength;
+
+    /* add padding */
+    if (ladjust) {
+       padc = ' ';
+    }
+    if (negFlag && !ladjust && (padc == '0')) {
+       for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
+       buf[length -1] = '-';
+    } else {
+       for (i = actualLength; i< length; i++) buf[i] = padc;
+    }
+
+
+    /* prepare to reverse the string */
+    {
+       int begin = 0;
+       int end;
+       if (ladjust) {
+           end = actualLength - 1;
+       } else {
+           end = length -1;
+       }
+
+       while (end > begin) {
+           char tmp = buf[begin];
+           buf[begin] = buf[end];
+           buf[end] = tmp;
+           begin ++;
+           end --;
+       }
+    }
+
+    /* adjust the string pointer */
+    return length;
+}
+
+static void printf_output(void *arg, char *s, int l)
+{
+    int i;
+
+    // special termination call
+    if ((l==1) && (s[0] == '\0')) return;
+
+    for (i=0; i< l; i++) {
+       serial_putc(s[i]);
+       if (s[i] == '\n') serial_putc('\r');
+    }
+}
+
+int printf(const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    lp_Print(printf_output, 0, (char*)fmt, ap);
+    va_end(ap);
+    return 0;
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/qcom_uart.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/qcom_uart.c
new file mode 100644 (file)
index 0000000..89123ac
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <iomap.h>
+#include <io.h>
+
+/* Number of characters for Transmission */
+#define MSM_BOOT_UART_DM_NO_CHARS_FOR_TX(base) ((base) + 0x040)
+
+/*UART General Command */
+#define MSM_BOOT_UART_DM_CR_GENERAL_CMD(x)   ((x) << 8)
+
+#define MSM_BOOT_UART_DM_GCMD_NULL            MSM_BOOT_UART_DM_CR_GENERAL_CMD(0)
+#define MSM_BOOT_UART_DM_GCMD_CR_PROT_EN      MSM_BOOT_UART_DM_CR_GENERAL_CMD(1)
+#define MSM_BOOT_UART_DM_GCMD_CR_PROT_DIS     MSM_BOOT_UART_DM_CR_GENERAL_CMD(2)
+#define MSM_BOOT_UART_DM_GCMD_RES_TX_RDY_INT  MSM_BOOT_UART_DM_CR_GENERAL_CMD(3)
+#define MSM_BOOT_UART_DM_GCMD_SW_FORCE_STALE  MSM_BOOT_UART_DM_CR_GENERAL_CMD(4)
+#define MSM_BOOT_UART_DM_GCMD_ENA_STALE_EVT   MSM_BOOT_UART_DM_CR_GENERAL_CMD(5)
+#define MSM_BOOT_UART_DM_GCMD_DIS_STALE_EVT   MSM_BOOT_UART_DM_CR_GENERAL_CMD(6)
+
+/* UART Command Register */
+#if PERIPH_BLK_BLSP
+#define MSM_BOOT_UART_DM_CR(base)              ((base) + 0xA8)
+#else
+#define MSM_BOOT_UART_DM_CR(base)              ((base) + 0x10)
+#endif
+#define MSM_BOOT_UART_DM_CR_RX_ENABLE        (1 << 0)
+#define MSM_BOOT_UART_DM_CR_RX_DISABLE       (1 << 1)
+#define MSM_BOOT_UART_DM_CR_TX_ENABLE        (1 << 2)
+#define MSM_BOOT_UART_DM_CR_TX_DISABLE       (1 << 3)
+
+/* UART Status Register */
+#if PERIPH_BLK_BLSP
+#define MSM_BOOT_UART_DM_SR(base)              ((base) + 0x0A4)
+#else
+#define MSM_BOOT_UART_DM_SR(base)              ((base) + 0x008)
+#endif
+#define MSM_BOOT_UART_DM_SR_RXRDY            (1 << 0)
+#define MSM_BOOT_UART_DM_SR_RXFULL           (1 << 1)
+#define MSM_BOOT_UART_DM_SR_TXRDY            (1 << 2)
+#define MSM_BOOT_UART_DM_SR_TXEMT            (1 << 3)
+#define MSM_BOOT_UART_DM_SR_UART_OVERRUN     (1 << 4)
+#define MSM_BOOT_UART_DM_SR_PAR_FRAME_ERR    (1 << 5)
+#define MSM_BOOT_UART_DM_RX_BREAK            (1 << 6)
+#define MSM_BOOT_UART_DM_HUNT_CHAR           (1 << 7)
+#define MSM_BOOT_UART_DM_RX_BRK_START_LAST   (1 << 8)
+
+/* UART DM TX FIFO Registers - 4 */
+#if PERIPH_BLK_BLSP
+#define MSM_BOOT_UART_DM_TF(base, x)         ((base) + 0x100+(4*(x)))
+#else
+#define MSM_BOOT_UART_DM_TF(base, x)         ((base) + 0x70+(4*(x)))
+#endif
+
+/* UART Interrupt Status Register */
+#if PERIPH_BLK_BLSP
+#define MSM_BOOT_UART_DM_ISR(base)          ((base) + 0xB4)
+#else
+#define MSM_BOOT_UART_DM_ISR(base)          ((base) + 0x14)
+#endif
+
+#define MSM_BOOT_UART_DM_TXLEV               (1 << 0)
+#define MSM_BOOT_UART_DM_RXHUNT              (1 << 1)
+#define MSM_BOOT_UART_DM_RXBRK_CHNG          (1 << 2)
+#define MSM_BOOT_UART_DM_RXSTALE             (1 << 3)
+#define MSM_BOOT_UART_DM_RXLEV               (1 << 4)
+#define MSM_BOOT_UART_DM_DELTA_CTS           (1 << 5)
+#define MSM_BOOT_UART_DM_CURRENT_CTS         (1 << 6)
+#define MSM_BOOT_UART_DM_TX_READY            (1 << 7)
+#define MSM_BOOT_UART_DM_TX_ERROR            (1 << 8)
+#define MSM_BOOT_UART_DM_TX_DONE             (1 << 9)
+#define MSM_BOOT_UART_DM_RXBREAK_START       (1 << 10)
+#define MSM_BOOT_UART_DM_RXBREAK_END         (1 << 11)
+#define MSM_BOOT_UART_DM_PAR_FRAME_ERR_IRQ   (1 << 12)
+
+#define NONE 0x0
+
+#if UARTx_DM_BASE == NONE
+void serial_putc(char c){ } /* quiet mode */
+#else
+
+void serial_putc(char c){
+       unsigned int base = UARTx_DM_BASE;
+       unsigned int num_of_chars = 1;
+       unsigned int tx_word = 0;
+
+       /* Write to NO_CHARS_FOR_TX register number of characters
+        * to be transmitted. However, before writing TX_FIFO must
+        * be empty as indicated by TX_READY interrupt in IMR register
+        *
+        * Check if transmit FIFO is empty.
+        * If not we'll wait for TX_READY interrupt. */
+       if(!(readl(MSM_BOOT_UART_DM_SR(base)) & MSM_BOOT_UART_DM_SR_TXEMT)){
+               while(!(readl(MSM_BOOT_UART_DM_ISR(base)) & MSM_BOOT_UART_DM_TX_READY));
+       }
+
+       /* We are here. FIFO is ready to be written. */
+       /* Write number of characters to be written */
+       writel(num_of_chars, MSM_BOOT_UART_DM_NO_CHARS_FOR_TX(base));
+
+       /* Clear TX_READY interrupt */
+       writel(MSM_BOOT_UART_DM_GCMD_RES_TX_RDY_INT, MSM_BOOT_UART_DM_CR(base));
+
+       /* Wait till TX FIFO has space */
+       while(!(readl(MSM_BOOT_UART_DM_SR(base)) & MSM_BOOT_UART_DM_SR_TXRDY));
+       if(c == '\n'){
+               /* Replace linefeed char "\n" with carriage return + linefeed "\r\n". */
+               tx_word = '\r';
+               tx_word <<= 8;
+               tx_word |= '\n';
+       }else{
+               tx_word = c; /* We need only one char */
+       }
+       /* TX FIFO has space. Write the chars */
+       writel(tx_word, MSM_BOOT_UART_DM_TF(base, 0));
+}
+
+#endif /* UARTx_DM_BASE == NONE */
+
+/*
+//for HEAD loader debug
+#include "printf.h"
+#include "types.h"
+void owl_debug(u32 r0, u32 r1, u32 r2){
+       printf("Hello OWL! 0x%x, 0x%x, 0x%x\n", r0, r1, r2);
+}
+int raise (int signum)
+{
+       return 0;
+}
+*/
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/start.S b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/start.S
new file mode 100644 (file)
index 0000000..54ead22
--- /dev/null
@@ -0,0 +1,69 @@
+.globl _start
+_start:
+       mov r7, r1 @save REAL _start addr
+       mov r6, r2 @ARCH value
+
+/* set the cpu to SVC32 mode */
+       mrs     r0, cpsr
+       bic     r0, r0, #0x1f
+       orr     r0, r0, #0xd3
+       msr     cpsr,r0
+
+/* Move vector table
+        Set vector address in CP15 VBAR register */
+       ldr     r0, =vector_table_stub
+       mcr     p15, 0, r0, c12, c0, 0  @Set VBAR
+
+/* Lets clear a bss */
+clear_bss:
+       ldr     r0, =_bss_start
+       ldr     r1, =_bss_end
+       mov     r2, #0x00000000         /* clear                            */
+clbss_l:
+       cmp     r0, r1                  /* clear loop... */
+       bhs     clbss_e                 /* if reached end of bss, exit */
+       str     r2, [r0]
+       add     r0, r0, #4
+       b       clbss_l
+clbss_e:
+
+/* Set stackpointer in internal RAM to call loader_main */
+call_loader_main:
+       /* stack grows left! <--SP--TEXT_BASE,_start--END of program */
+       ldr     sp, =(CONFIG_SYS_TEXT_BASE)
+       bic     sp, sp, #7 /* 8-byte alignment for ABI compliance */
+       mov r0, r7 @REAL _start addr
+       mov r1, r6 @ARCH
+       bl      loader_main
+
+.globl owl_get_sp
+owl_get_sp:
+       mov     r0, sp
+       mov     pc, lr @ back to my caller
+
+/* stub for IRQ vector table. we do not need
+        interrupt handlers, exception handlers, etc...
+        so if one of them happens, then just
+        wait(in deadloop) for the watchdogs reboot! */
+.globl vector_table_stub
+.align         4
+vector_table_stub:
+       b vector_table_stub @dead loop
+       ldr     pc, _undefined_instruction
+       ldr     pc, _software_interrupt
+       ldr     pc, _prefetch_abort
+       ldr     pc, _data_abort
+       ldr     pc, _not_used
+       ldr     pc, _irq
+       ldr     pc, _fiq
+_undefined_instruction: .word vector_table_stub
+_software_interrupt:   .word vector_table_stub
+_prefetch_abort:       .word vector_table_stub
+_data_abort:           .word vector_table_stub
+_not_used:             .word vector_table_stub
+_irq:                  .word vector_table_stub
+_fiq:                  .word vector_table_stub
+_pad:                  .word 0x12345678 /* now 16*4=64 */
+.global _end_vector_table_stub
+_end_vector_table_stub:
+       .balignl 16,0xdeadbeef
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/src/watchdog.c b/target/linux/ipq40xx/image/ipq-aux-loader/src/src/watchdog.c
new file mode 100644 (file)
index 0000000..72b3b7e
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Auxiliary kernel loader for Qualcom IPQ-4XXX/806X based boards
+ *
+ * Copyright (C) 2019 Sergey Sergeev <adron@mstnt.com>
+ *
+ * Some structures and code has been taken from the U-Boot project.
+ *     (C) Copyright 2008 Semihalf
+ *     (C) Copyright 2000-2005
+ *     Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <io.h>
+
+#define WDT_RESETUP_PERIOD 10
+
+#ifdef CONFIG_IPQ4XXX
+#define WDT_BASE               0xB017000
+#define WDT_RST    (WDT_BASE + 0x4)
+#define WDT_EN    (WDT_BASE + 0x8)
+#define WDT_STS (WDT_BASE + 0xc)
+#define WDT_BARK_TIME    (WDT_BASE + 0x10)
+#define WDT_BITE_TIME    (WDT_BASE + 0x14)
+
+#define GCNT_PSHOLD            0x004AB000
+
+void watchdog_setup(int period){
+       writel(0, WDT_EN);
+       writel(1, WDT_RST);
+       writel(period * 65536, WDT_BARK_TIME);
+       writel(period * 65536, WDT_BITE_TIME);
+       writel(1,  WDT_EN);
+}
+
+void reset_cpu(unsigned long addr)
+{
+       /* clear ps-hold bit to reset the soc */
+       writel(0, GCNT_PSHOLD);
+       while (1);
+}
+
+#endif /* CONFIG_IPQ4XXX */
+
+#ifdef CONFIG_IPQ806X
+#define MSM_CLK_CTL_BASE    0x00900000
+
+#define MSM_TMR_BASE        0x0200A000
+#define MSM_GPT_BASE        (MSM_TMR_BASE + 0x04)
+#define MSM_DGT_BASE        (MSM_TMR_BASE + 0x24)
+
+#define GPT_REG(off)        (MSM_GPT_BASE + (off))
+#define DGT_REG(off)        (MSM_DGT_BASE + (off))
+
+#define APCS_WDT0_EN        (MSM_TMR_BASE + 0x0040)
+#define APCS_WDT0_RST       (MSM_TMR_BASE + 0x0038)
+#define APCS_WDT0_BARK_TIME (MSM_TMR_BASE + 0x004C)
+#define APCS_WDT0_BITE_TIME (MSM_TMR_BASE + 0x005C)
+
+#define APCS_WDT0_CPU0_WDOG_EXPIRED_ENABLE (MSM_CLK_CTL_BASE + 0x3820)
+
+/* Watchdog bite time set to default reset value */
+#define RESET_WDT_BITE_TIME 0x31F3
+
+/* Watchdog bark time value is ketp larger than the watchdog timeout
+ * of 0x31F3, effectively disabling the watchdog bark interrupt
+ */
+#define RESET_WDT_BARK_TIME (5 * RESET_WDT_BITE_TIME)
+
+void watchdog_setup(int period){
+       writel(0, APCS_WDT0_EN);
+       writel(1, APCS_WDT0_RST);
+       writel(period * 32768, APCS_WDT0_BARK_TIME);
+       writel(period * 32768, APCS_WDT0_BITE_TIME);
+       writel(1, APCS_WDT0_EN);
+       writel(1, APCS_WDT0_CPU0_WDOG_EXPIRED_ENABLE);
+}
+
+void reset_cpu(unsigned long addr)
+{
+       writel(0, APCS_WDT0_EN);
+       writel(1, APCS_WDT0_RST);
+       writel(RESET_WDT_BARK_TIME, APCS_WDT0_BARK_TIME);
+       writel(RESET_WDT_BITE_TIME, APCS_WDT0_BITE_TIME);
+       writel(1, APCS_WDT0_EN);
+       writel(1, APCS_WDT0_CPU0_WDOG_EXPIRED_ENABLE);
+
+       for(;;);
+}
+#endif /* CONFIG_IPQ806X */
+
+void watchdog_resetup(void){
+       watchdog_setup(WDT_RESETUP_PERIOD);
+}
diff --git a/target/linux/ipq40xx/image/ipq-aux-loader/src/ubi/loader.ubi.ini b/target/linux/ipq40xx/image/ipq-aux-loader/src/ubi/loader.ubi.ini
new file mode 100644 (file)
index 0000000..96fd301
--- /dev/null
@@ -0,0 +1,9 @@
+[Kernel]
+mode = ubi
+image = bin/loader.ubifs
+vol_name = Kernel
+vol_size = 15000000
+;vol_flags = 0
+vol_type = dynamic
+vol_alignment = 1
+vol_id = 0