Commit e125a9da authored by NiteHawk's avatar NiteHawk Committed by GitHub
Browse files

Merge pull request #88 from n1tehawk/20161109_copyl

fel: Implement memory copy operations and "memmove" command
parents 1e219c0b 95d8d239
......@@ -50,7 +50,7 @@ MISC_TOOLS = phoenix_info sunxi-nand-image-builder
# ARM binaries and images
# Note: To use this target, set/adjust CROSS_COMPILE and MKSUNXIBOOT if needed
BINFILES = fel-pio.bin jtag-loop.sunxi fel-sdboot.sunxi uart0-helloworld-sdboot.sunxi
BINFILES = jtag-loop.sunxi fel-sdboot.sunxi uart0-helloworld-sdboot.sunxi
CROSS_COMPILE ?= arm-none-eabi-
CROSS_CC ?= $(CROSS_COMPILE)gcc
......@@ -148,19 +148,11 @@ phoenix_info: phoenix_info.c
%.sunxi: %.bin
$(MKSUNXIBOOT) $< $@
fel-pio.bin: fel-pio.elf fel-pio.nm
ARM_ELF_FLAGS = -Os -marm -fpic -Wall
ARM_ELF_FLAGS += -fno-common -fno-builtin -ffreestanding -nostdinc -fno-strict-aliasing
ARM_ELF_FLAGS += -mno-thumb-interwork -fno-stack-protector -fno-toplevel-reorder
ARM_ELF_FLAGS += -Wstrict-prototypes -Wno-format-nonliteral -Wno-format-security
fel-pio.elf: fel-pio.c fel-pio.lds
$(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T fel-pio.lds
fel-pio.nm: fel-pio.elf
$(CROSS_COMPILE)nm $< | grep -v " _" >$@
jtag-loop.elf: jtag-loop.c jtag-loop.lds
$(CROSS_CC) -g $(ARM_ELF_FLAGS) $< -nostdlib -o $@ -T jtag-loop.lds -Wl,-N
......
......@@ -44,7 +44,7 @@ finds. You can print a list of all FEL devices currently connected/detected
with `./sunxi-fel --list --verbose`.
### fel-gpio
Simple wrapper (script) around `fel-pio` and `sunxi-fel`
Simple wrapper (script) around `sunxi-pio` and `sunxi-fel`
to allow GPIO manipulations via FEL
### fel-sdboot
......@@ -58,11 +58,8 @@ Allwinner devices and can be used for testing. Additionally, it may
serve as a template/example for developing simple bare metal code
(LED blinking and other similar GPIO related things).
### fel-pio
ARM native helper (binary) for `fel-gpio`
### sunxi-pio
Manipulate PIO register dumps
Manipulate PIO registers/dumps
### sunxi-nand-part
Tool for manipulating Allwinner NAND partition tables
......
00002000 T pio_to_sram
00002004 T sram_to_pio
/*
* (C) Copyright 2011 Henrik Nordstrom <henrik@henriknordstrom.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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
Build instructions:
arm-none-linux-gnueabi-gcc -g -Os -fno-common -ffixed-r8 -msoft-float -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder fel-copy.c -c
arm-none-linux-gnueabi-objcopy -O binary fel-copy.o fel-copy.bin
Parameters:
0x2100 Destination address
0x2104 Source address
0x2108 Length
Source address is updated, allowing repeated copy to same destination
*/
#define CONFIG_BASE 0x2100
void copy(void)
{
unsigned long *b = (void *)CONFIG_BASE;
unsigned long **ptr = (void *)b++;
unsigned long *a = *ptr;
unsigned long i = *b++;
while (i--) {
*b++ = *a++;
}
*ptr = a;
}
......@@ -20,26 +20,24 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
pio_to_sram=0x2000
sram_to_pio=0x2004
pio_base=0x01c20800
pio_size=0x228
sram_addr=0x3000
if [ -f fel-pio.bin ]; then
./sunxi-fel write 0x2000 fel-pio.bin
else
./sunxi-fel write 0x2000 bin/fel-pio.bin
fi
./sunxi-fel exec $pio_to_sram
./sunxi-fel read 0x3000 0x228 pio.reg
# read PIO
./sunxi-fel memmove $sram_addr $pio_base $pio_size
./sunxi-fel read $sram_addr $pio_size pio.reg
./sunxi-pio -i pio.reg print > pio.old
cat pio.old | fgrep -v '<0><0><0><0>'
while read cmd; do
./sunxi-pio -i pio.reg -o pio.reg $cmd
./sunxi-fel write 0x3000 pio.reg
./sunxi-fel exe 0x2004
./sunxi-fel exe 0x2000
./sunxi-fel read 0x3000 0x228 pio.reg
# write PIO
./sunxi-fel write $sram_addr pio.reg
./sunxi-fel memmove $pio_base $sram_addr $pio_size
# (re-)read PIO
./sunxi-fel memmove $sram_addr $pio_base $pio_size
./sunxi-fel read $sram_addr $pio_size pio.reg
./sunxi-pio -i pio.reg print > pio.new
diff -U0 pio.old pio.new || true
mv -f pio.new pio.old
......
/*
* (C) Copyright 2011 Henrik Nordstrom <henrik@henriknordstrom.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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
Build instructions:
arm-none-eabi-gcc -g -Os -fno-common -fno-builtin -ffreestanding -nostdinc -mno-thumb-interwork -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fno-toplevel-reorder fel-pio.c -nostdlib -o fel-pio.elf
arm-none-eabi-objcopy -O binary fel-pio.elf fel-pio.bin
arm-none-eabi-nm fel-pio.o
*/
void _pio_to_sram(void);
void _sram_to_pio(void);
void pio_to_sram(void)
{
_pio_to_sram();
}
void sram_to_pio(void)
{
_sram_to_pio();
}
void _pio_to_sram(void)
{
unsigned long *a = (void *)0x1c20800;
unsigned long *b = (void *)0x3000;
int i = 0x228 >> 2;
while (i--) {
*b++ = *a++;
}
}
void _sram_to_pio(void)
{
unsigned long *a = (void *)0x1c20800;
unsigned long *b = (void *)0x3000;
int i = 0x228 >> 2;
while (i--) {
*a++ = *b++;
}
}
/*
* Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
SECTIONS
{
. = 0x2000;
.text : { *(.text) }
/DISCARD/ : { *(.dynstr*) }
/DISCARD/ : { *(.dynamic*) }
/DISCARD/ : { *(.plt*) }
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
/DISCARD/ : { *(.note*) }
}
......@@ -996,6 +996,7 @@ int main(int argc, char **argv)
" dump address length Binary memory dump\n"
" exe[cute] address Call function address\n"
" reset64 address RMR request for AArch64 warm boot\n"
" memmove dest source size Copy <size> bytes within device memory\n"
" readl address Read 32-bit value from device memory\n"
" writel address value Write 32-bit value to device memory\n"
" read address length file Write memory contents into file\n"
......@@ -1090,6 +1091,11 @@ int main(int argc, char **argv)
} else if (strncmp(argv[1], "dump", 4) == 0 && argc > 3) {
aw_fel_dump(handle, strtoul(argv[2], NULL, 0), strtoul(argv[3], NULL, 0));
skip = 3;
} else if (strcmp(argv[1], "memmove") == 0 && argc > 4) {
/* three parameters: destination addr, source addr, byte count */
fel_memmove(handle, strtoul(argv[2], NULL, 0),
strtoul(argv[3], NULL, 0), strtoul(argv[4], NULL, 0));
skip = 4;
} else if (strcmp(argv[1], "readl") == 0 && argc > 2) {
printf("0x%08x\n", fel_readl(handle, strtoul(argv[2], NULL, 0)));
skip = 2;
......
......@@ -368,6 +368,122 @@ void fel_writel_n(feldev_handle *dev, uint32_t addr, uint32_t *src, size_t count
}
}
/*
* move (arbitrary byte count) data between addresses within SoC memory
*
* These functions try to copy as many bytes as possible using 32-bit word
* transfers, and handle any unaligned bytes ('head' and 'tail') separately.
*
* This is useful for the same reasons that "readl"/"writel" were introduced:
* Byte-oriented transfers ("string" copy) might not give the expected results
* when accessing hardware registers, like e.g. the (G)PIO config/state.
*
* We have two different low-level functions, where the copy operation moves
* upwards or downwards respectively. This allows a non-destructive "memmove"
* wrapper to select the suitable one in case of memory overlap.
*/
static void fel_memcpy_up(feldev_handle *dev,
uint32_t dst_addr, uint32_t src_addr, size_t size)
{
if (size == 0) return;
/*
* copy "upwards", increasing destination and source addresses
*/
uint32_t arm_code[] = {
htole32(0xe59f0054), /* ldr r0, [pc, #84] ; ldr r0, [dst_addr] */
htole32(0xe59f1054), /* ldr r1, [pc, #84] ; ldr r1, [src_addr] */
htole32(0xe59f2054), /* ldr r2, [pc, #84] ; ldr r2, [size] */
htole32(0xe0413000), /* sub r3, r1, r0 ; r3 = r1 - r0 */
htole32(0xe3130003), /* tst r3, #3 ; test lower bits */
htole32(0x1a00000b), /* bne copyup_tail ; unaligned copying */
/* copyup_head: */
htole32(0xe3110003), /* tst r1, #3 ; word-aligned? */
htole32(0x0a000004), /* beq copyup_loop */
htole32(0xe4d13001), /* ldrb r3, [r1], #1 ; load and post-inc */
htole32(0xe4c03001), /* strb r3, [r0], #1 ; store and post-inc */
htole32(0xe2522001), /* subs r2, r2, #1 ; r2 -= 1 */
htole32(0x5afffff9), /* bpl copyup_head ; while (r2 >= 0) */
htole32(0xe12fff1e), /* bx lr ; early return */
/* copyup_loop: */
htole32(0xe2522004), /* subs r2, r2, #4 ; r2 -= 4 */
htole32(0x54913004), /* ldrpl r3, [r1], #4 ; load and post-inc */
htole32(0x54803004), /* strpl r3, [r0], #4 ; store and post-inc */
htole32(0x5afffffb), /* bpl copyup_loop ; while (r2 >= 0) */
htole32(0xe2822004), /* add r2, r2, #4 ; remaining bytes */
/* copyup_tail: */
htole32(0xe2522001), /* subs r2, r2, #1 ; r2 -= 1 */
htole32(0x412fff1e), /* bxmi lr ; return if (r2 < 0) */
htole32(0xe4d13001), /* ldrb r3, [r1], #1 ; load and post-inc */
htole32(0xe4c03001), /* strb r3, [r0], #1 ; store and post-inc */
htole32(0xeafffffa), /* b copyup_tail */
htole32(dst_addr), /* destination address */
htole32(src_addr), /* source address */
htole32(size), /* size (= byte count) */
};
aw_fel_write(dev, arm_code, dev->soc_info->scratch_addr, sizeof(arm_code));
aw_fel_execute(dev, dev->soc_info->scratch_addr);
}
static void fel_memcpy_down(feldev_handle *dev,
uint32_t dst_addr, uint32_t src_addr, size_t size)
{
if (size == 0) return;
/*
* This ARM code makes use of decreasing values in r2
* for memory indexing relative to the base addresses in r0 and r1.
*/
uint32_t arm_code[] = {
htole32(0xe59f0058), /* ldr r0, [pc, #88] ; ldr r0, [dst_addr] */
htole32(0xe59f1058), /* ldr r1, [pc, #88] ; ldr r1, [src_addr] */
htole32(0xe59f2058), /* ldr r2, [pc, #88] ; ldr r2, [size] */
htole32(0xe0403001), /* sub r3, r0, r1 ; r3 = r0 - r1 */
htole32(0xe3130003), /* tst r3, #3 ; test lower bits */
htole32(0x1a00000c), /* bne copydn_tail ; unaligned copying */
/* copydn_head: */
htole32(0xe0813002), /* add r3, r1, r2 ; r3 = r1 + r2 */
htole32(0xe3130003), /* tst r3, #3 ; word-aligned? */
htole32(0x0a000004), /* beq copydn_loop */
htole32(0xe2522001), /* subs r2, r2, #1 ; r2 -= 1 */
htole32(0x412fff1e), /* bxmi lr ; early return */
htole32(0xe7d13002), /* ldrb r3, [r1, r2] ; load byte */
htole32(0xe7c03002), /* strb r3, [r0, r2] ; store byte */
htole32(0xeafffff7), /* b copydn_head */
/* copydn_loop: */
htole32(0xe2522004), /* subs r2, r2, #4 ; r2 -= 4 */
htole32(0x57913002), /* ldrpl r3, [r1, r2] ; load word */
htole32(0x57803002), /* strpl r3, [r0, r2] ; store word */
htole32(0x5afffffb), /* bpl copydn_loop ; while (r2 >= 0) */
htole32(0xe2822004), /* add r2, r2, #4 ; remaining bytes */
/* copydn_tail: */
htole32(0xe2522001), /* subs r2, r2, #1 ; r2 -= 1 */
htole32(0x412fff1e), /* bxmi lr ; return if (r2 < 0) */
htole32(0xe7d13002), /* ldrb r3, [r1, r2] ; load byte */
htole32(0xe7c03002), /* strb r3, [r0, r2] ; store byte */
htole32(0xeafffffa), /* b copydn_tail */
htole32(dst_addr), /* destination address */
htole32(src_addr), /* source address */
htole32(size), /* size (= byte count) */
};
aw_fel_write(dev, arm_code, dev->soc_info->scratch_addr, sizeof(arm_code));
aw_fel_execute(dev, dev->soc_info->scratch_addr);
}
void fel_memmove(feldev_handle *dev,
uint32_t dst_addr, uint32_t src_addr, size_t size)
{
/*
* To ensure non-destructive operation, we need to select "downwards"
* copying if the destination overlaps the source region.
*/
if (dst_addr >= src_addr && dst_addr < (src_addr + size))
fel_memcpy_down(dev, dst_addr, src_addr, size);
else
fel_memcpy_up(dev, dst_addr, src_addr, size);
}
/*
* Memory access to the SID (root) keys proved to be unreliable for certain
* SoCs. This function uses an alternative, register-based approach to retrieve
......
......@@ -67,6 +67,9 @@ void aw_fel_execute(feldev_handle *dev, uint32_t offset);
void fel_readl_n(feldev_handle *dev, uint32_t addr, uint32_t *dst, size_t count);
void fel_writel_n(feldev_handle *dev, uint32_t addr, uint32_t *src, size_t count);
void fel_memmove(feldev_handle *dev,
uint32_t dst_addr, uint32_t src_addr, size_t size);
/* retrieve SID root key */
bool fel_get_sid_root_key(feldev_handle *dev, uint32_t *result,
bool force_workaround);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment