diff options
author | Greg Bellows <greg.bellows@linaro.org> | 2014-12-17 15:54:24 -0600 |
---|---|---|
committer | Greg Bellows <greg.bellows@linaro.org> | 2014-12-17 15:58:14 -0600 |
commit | eaa27adbcb66c26a4741c0be640730ec062e9fb0 (patch) | |
tree | 84d0ca5fe878abd136a981cb779d08a5683a0b0d | |
parent | 452005de0650d686567acd1e2cfdda41bf9ffc09 (diff) | |
parent | 46745a4031d369881f0a9ec9b4483f7c37a113fa (diff) |
Merge branch 'shrink'
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Conflicts:
arm/tztest_common.c
arm/tztest_mmu.c
arm/tztest_mmu.h
arm/tztest_nonsecure_svc.c
arm/tztest_secure_svc.c
81 files changed, 1374 insertions, 6508 deletions
@@ -5,25 +5,24 @@ endif include config.mak -.PHONY: arch_clean clean distclean cscope +.PHONY: arch_clean clean distclean # libcflat paths -LIBCFLAT_objdir = lib/libcflat -LIBCFLAT_srcdir = lib/libcflat -LIBCFLAT_archdir = lib/libcflat/$(ARCH) +LIBCFLAT_objdir = libcflat +LIBCFLAT_srcdir = libcflat +LIBCFLAT_archdir = libcflat/$(ARCH) LIBCFLAT_archive = $(LIBCFLAT_objdir)/libcflat.a -LIBCFLAT_OBJS = \ - $(LIBCFLAT_objdir)/argv.o \ - $(LIBCFLAT_objdir)/printf.o \ - $(LIBCFLAT_objdir)/string.o \ - $(LIBCFLAT_objdir)/report.o - -# libfdt paths -LIBFDT_objdir = lib/libfdt -LIBFDT_srcdir = lib/libfdt -LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a -LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES)) -LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION)) +LIBCFLAT_OBJS = $(LIBCFLAT_objdir)/printf.o \ + $(LIBCFLAT_objdir)/string.o \ + $(LIBCFLAT_archdir)/io.o \ + $(LIBCFLAT_archdir)/misc.o +LIBEABI_OBJS = $(LIBCFLAT_archdir)/eabi_compat.o + +LIBEABI = $(LIBCFLAT_archdir)/libeabi.a +libgcc := $(shell $(CC) -m$(ARCH) --print-libgcc-file-name) +CFLAGS += -I$(ARCH) -DASM + +FLATLIBS = $(LIBCFLAT_archive) $(libgcc) $(LIBEABI) # cc-option # Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) @@ -31,15 +30,13 @@ LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION)) cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) -CFLAGS += -marm -CFLAGS += -mcpu=$(PROCESSOR) +CFLAGS += -m${ARCH} -mcpu=$(PROCESSOR) CFLAGS += $(autodepend-flags) CFLAGS += -std=gnu99 CFLAGS += -ffreestanding CFLAGS += -Wextra -Werror -Wall CFLAGS += -g -O0 -CFLAGS += -Ilib -I$(LIBFDT_srcdir) -I $(LIBCFLAT_srcdir) -I$(LIBCFLAT_archdir) -CFLAGS += -Ilib -I/usr/arm-linux-gnueabi/include/ +CFLAGS += -Ilib -I $(LIBCFLAT_srcdir)/include -I$(LIBCFLAT_archdir)/include CFLAGS += -Iplatform/$(PLAT) CFLAGS += $(call cc-option, -fomit-frame-pointer, "") CFLAGS += $(call cc-option, -fno-stack-protector, "") @@ -55,25 +52,22 @@ include $(ARCH)/Makefile.tztest $(LIBCFLAT_archive): $(LIBCFLAT_OBJS) $(AR) rcs $@ $^ -include $(LIBFDT_srcdir)/Makefile.libfdt -$(LIBFDT_archive): CFLAGS += -Wno-sign-compare -$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) - $(AR) rcs $@ $^ - %.o: %.S $(CC) $(CFLAGS) -c -nostdlib -o $@ $< -include */.*.d */*/.*.d -clean: arch_clean - $(RM) $(LIBCFLAT_archive) $(LIBCFLAT_OBJS) $(LIBCFLAT_objdir)/.*.d +$(LIBEABI): $(LIBEABI_OBJS) + $(AR) rcs $@ $^ -libfdt_clean: - $(RM) $(LIBFDT_archive) $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) \ - $(LIBFDT_objdir)/.*.d +libeabi_clean: + $(RM) $(LIBEABI) $(LIBEABI_OBJS) + +clean: arch_clean libeabi_clean + $(RM) $(LIBCFLAT_archive) $(LIBCFLAT_OBJS) $(LIBCFLAT_objdir)/.*.d libcflat_clean: $(RM) $(LIBCFLAT_archive) $(LIBCFLAT_OBJS) -distclean: clean libfdt_clean libcflat_clean - $(RM) config.mak ..d +distclean: clean libcflat_clean + $(RM) config.mak ..d cscope.* @@ -1,7 +1,62 @@ -ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make +CONFIGURE +---------- +Configure the test using ./configure before building. Running configure +without any options will give the default platform of vexpress-a15 with the +default CPU cortex-a15. -./arm-softmmu/qemu-system-arm -machine vexpress-a15 -cpu cortex-a15 -bios -/path/to/tztest.img -serial stdio -m 1024 -semihosting + ./configure -arm-linux-gnueabi-objdump -xdSt tztest +For more options use "-?" + ./configure -? + +Other platforms/cpus can be specified as follows: + + ./configure --plat=virt --cpu=cortex-a15 + + +BUILD +----- +Once configured, the test can be built my simply using make. This will produce +an output test image that can be used with QEMU. + + make + +The test image can also be built with debug verbosity for extended runtime +messages by building as follows. + + CFLAGS=-DDEBUG make + + +RUN +---- +Using compatible machine and cpu properties, the output test image can be run +using the following QEMU command line: + + ./arm-softmmu/qemu-system-arm -machine <plat> -cpu <cpu> -bios + /path/to/tztest.img -serial stdio -m 1024 + +For example, to run the default vexpress-a15 test image on qemu: + + arm-softmmu/qemu-system-arm -bios ~/git/qemu.tztest/arm/tztest.img \ + -serial stdio -m 1024 -machine type=vexpress-a15 -cpu cortex-a15 + +DEBUG +----- +A number of facilities are provided for assiting in debugging. Both secure and +non-secure test ELF binaries are produced and made available for debugging. + +tztest_nonsecure.elf +tztest_secure.elf + +A GDB script is provided for loading and debugging these ELF files with GDB. +To debug, do the following: + +Start QEMU with GDB enabled and waiting. + + ./arm-softmmu/qemu-system-arm ... -s -S + +Start gdb-multiarch from the root of the test directory. No options are needed +as the supplied .gdbinit should load the ELF images at the correct addresses. + + gdb-multiarch diff --git a/arm/Makefile.tztest b/arm/Makefile.tztest index f697256..052e2fa 100644 --- a/arm/Makefile.tztest +++ b/arm/Makefile.tztest @@ -7,33 +7,22 @@ TZBOOT = $(ARCH)/tzboot.o TZSECLOAD = $(ARCH)/tztest_secure.lds TZNSECLOAD = $(ARCH)/tztest_nonsecure.lds TZSECOBJS = $(ARCH)/secure_init.o \ - $(ARCH)/tztest_secure_svc.o \ + $(ARCH)/secure_svc.o \ + $(ARCH)/secure_asm.o \ + $(ARCH)/monitor.o \ + $(ARCH)/monitor_asm.o \ $(ARCH)/sm_asm.o \ $(ARCH)/sm.o TZNSECOBJS = $(ARCH)/nonsecure_init.o \ - $(ARCH)/tztest_nonsecure_svc.o \ + $(ARCH)/nonsecure_svc.o \ $(ARCH)/tztest.o -TZOBJS = $(ARCH)/tztest_mmu.o \ - $(ARCH)/tztest_common.o -LIBCFLAT_OBJS += $(LIBCFLAT_objdir)/devicetree.o \ - $(LIBCFLAT_objdir)/virtio.o \ - $(LIBCFLAT_objdir)/virtio-testdev.o \ - $(LIBCFLAT_archdir)/io.o \ - $(LIBCFLAT_archdir)/misc.o \ - $(LIBCFLAT_archdir)/setup.o \ - $(LIBCFLAT_archdir)/spinlock.o \ - $(LIBCFLAT_archdir)/processor.o +TZOBJS = $(ARCH)/common_mmu.o \ + $(ARCH)/common_svc.o all: $(TZTEST_IMAGE) ################################################################## -libeabi = $(LIBCFLAT_archdir)/libeabi.a -eabiobjs = $(LIBCFLAT_archdir)/eabi_compat.o -libgcc := $(shell $(CC) -m$(ARCH) --print-libgcc-file-name) -CFLAGS += -I$(ARCH) -DASM - -FLATLIBS = $(LIBCFLAT_archive) $(LIBFDT_archive) $(libgcc) $(libeabi) COMMON = $(FLATLIBS) $(TZOBJS) $(SECTEST): $(TZSECOBJS) $(COMMON) $(TZSECLOAD) $(TZNSECLOAD) $(TZBOOT) @@ -65,15 +54,9 @@ $(TZNSECLOAD): $(ARCH)/tztest_nonsecure.lds.S Makefile platform/$(PLAT)/ %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -$(libeabi): $(eabiobjs) - $(AR) rcs $@ $^ - -arch_clean: libeabi_clean +arch_clean: $(RM) $(TZOBJS) $(TZSECOBJS) $(TZNSECOBJS) \ $(TZSECLOAD) $(TZNSECLOAD) $(TZBOOT) \ $(SECTEST) $(SECTESTIMAGE) $(NSECTEST) $(NSECTESTIMAGE) \ $(TZTEST_IMAGE) \ $(LIBCFLAT_OBJS) $(LIBCFLAT_archdir)/.*.d $(ARCH)/.*.d - -libeabi_clean: - $(RM) $(libeabi) $(eabiobjs) diff --git a/arm/arm32.h b/arm/arm32.h index 2c5e963..1dd46a5 100644 --- a/arm/arm32.h +++ b/arm/arm32.h @@ -45,6 +45,7 @@ #define CPSR_T (1 << 5) #define CPSR_F (1 << 6) #define CPSR_I (1 << 7) +#define CPSR_A (1 << 8) #define MPIDR_CPU_MASK 0xff #define MPIDR_CLUSTER_MASK (0xff << 8) diff --git a/arm/tztest_asm.h b/arm/common_defs.h index de46a6b..de46a6b 100644 --- a/arm/tztest_asm.h +++ b/arm/common_defs.h diff --git a/arm/common_mmu.c b/arm/common_mmu.c new file mode 100644 index 0000000..cf9fc15 --- /dev/null +++ b/arm/common_mmu.c @@ -0,0 +1,128 @@ +#include "common_svc.h" +#include "common_mmu.h" +#include "common_defs.h" + +void pagetable_add_section_entries(uint32_t *ttbr, pagetable_map_entry_t *pe) +{ + uint32_t va = pe->va; + uint32_t pa = pe->pa; + uint32_t len = pe->len; + uint32_t l1idx = va >> L1_INDEX_SHIFT; + uint32_t l1attr = SECTION; + uint32_t size = SECTION_SIZE; + + l1attr |= IS_SET(pe, NONSECURE) ? SECTION_NS : 0; + l1attr |= IS_SET(pe, P0_R) + ? IS_SET(pe, P0_W) ? SECTION_P0_RW : SECTION_P0_RO + : SECTION_P0_NONE; + l1attr |= IS_SET(pe, P1_R) + ? IS_SET(pe, P1_W) ? SECTION_P1_RW : SECTION_P1_RO + : SECTION_P1_NONE; + l1attr |= IS_SET(pe, P0_X) ? 0 : SECTION_XN; + l1attr |= IS_SET(pe, P1_X) ? 0 : SECTION_PXN; + l1attr |= IS_SET(pe, NOTGLOBAL) ? (SECTION_NG) : 0; + l1attr |= IS_SET(pe, DEVICE) + ? IS_SET(pe, SHARED) + ? SECTION_DEVICE_SHAREABLE : SECTION_DEVICE_UNSHAREABLE + : IS_SET(pe, SHARED) ? (SECTION_S) : 0; + l1attr |= IS_SET(pe, WT_CACHED) + ? SECTION_WT_CACHED : IS_SET(pe, WB_CACHED) + ? SECTION_WB_CACHED + : IS_SET(pe, WBA_CACHED) + ? SECTION_WBA_CACHED : SECTION_UNCACHED; + + /* Round up to the next segment increment */ + len = (len + (SECTION_SIZE-1)) & ~(SECTION_SIZE-1); + + for (; len > 0; va += size, pa += size, len -= size) { + l1idx = L1_INDEX(va); + ttbr[l1idx] = (pa & SECTION_PA_MASK) | l1attr; + DEBUG_MSG("Mapped L1 0x%x to 0x%x (%p (0x%x) = 0x%x)\n", + va, pa, &ttbr[l1idx], l1idx, ttbr[l1idx]); + } +} + +void pagetable_add_page_entries(uint32_t *ttbr, pagetable_map_entry_t *pe) +{ + uint32_t va = pe->va; + uint32_t pa = pe->pa; + uint32_t len = pe->len; + uint32_t l2len = 0;; + uint32_t *l2base = ttbr + BYTE_TO_INT(L1_TABLE_SIZE); + uint32_t *l2addr; + uint32_t size = PAGE_SIZE(PAGE); + uint32_t l1attr = L1_TYPE_PAGE, l2attr = L2_TYPE(pe->type); + uint32_t l1idx, l2idx; + + l1attr |= IS_SET(pe, NONSECURE) ? PAGE_NS : 0; + l1attr |= IS_SET(pe, P1_X) ? 0 : PAGE_PXN; + + l2attr |= IS_SET(pe, P0_R) + ? IS_SET(pe, P0_W) ? PAGE_P0_RW : PAGE_P0_RO + : PAGE_P0_NONE; + l2attr |= IS_SET(pe, P1_R) + ? IS_SET(pe, P1_W) ? PAGE_P1_RW : PAGE_P1_RO + : PAGE_P1_NONE; + l2attr |= IS_SET(pe, P0_X) ? 0 : PAGE_XN(PAGE_SMALL); + l2attr |= IS_SET(pe, NOTGLOBAL) ? (PAGE_NG) : 0; + l2attr |= IS_SET(pe, DEVICE) + ? IS_SET(pe, SHARED) + ? PAGE_DEVICE_SHAREABLE + : PAGE_DEVICE_UNSHAREABLE(PAGE_SMALL) + : IS_SET(pe, SHARED) ? (PAGE_S) : 0; + l2attr |= IS_SET(pe, WT_CACHED) + ? PAGE_WT_CACHED + : IS_SET(pe, WB_CACHED) + ? PAGE_WB_CACHED + : IS_SET(pe, WBA_CACHED) + ? PAGE_WBA_CACHED(PAGE_SMALL) + : PAGE_UNCACHED(PAGE_SMALL); + + /* Round up to the next page increment */ + len = (len + (PAGE_SIZE(PAGE)-1)) & ~(PAGE_SIZE(PAGE)-1); + + while (len > 0) { + l1idx = L1_INDEX(va); + l2addr = l2base + BYTE_TO_INT(L2_TABLE_SIZE * l1idx); + ttbr[l1idx] = (uint32_t)l2addr | l1attr; + + DEBUG_MSG("Added L1 0x%x to 0x%x (ttbrn[%x] = %x)\n", + va, l2addr, l1idx, ttbr[l1idx]); + + /* Set the level 2 page table size to the smaller of the total + * remaining length or the remaining length in the 1MB section. + */ + l2len = L1_MAP_SIZE - (va & (L1_MAP_SIZE - 1)); + l2len = (l2len > len) ? len : l2len; + + for (; l2len > 0; va += size, pa += size, l2len -= size, len -= size) { + l2idx = L2_INDEX(va); + l2addr[l2idx] = (pa & PAGE_PA_MASK) | l2attr; + DEBUG_MSG("Mapped L2 0x%x to 0x%x (%p (0x%x) = 0x%x)\n", + va, pa, &l2addr[l2idx], l2idx, l2addr[l2idx]); + } + } +} + +void pagetable_add_entries(uint32_t *ttbr, pagetable_map_entry_t *entries, + uint32_t count) +{ + uint32_t i; + + for (i = 0; i < count; i++) { + if (entries[i].type == SECTION) { + pagetable_add_section_entries(ttbr, &entries[i]); + } else if (entries[i].type == PAGE || entries[i].type == LARGE_PAGE) { + pagetable_add_page_entries(ttbr, &entries[i]); + } + } +} + +void pagetable_init(uint32_t *ttbr) +{ + int i; + + for (i = 0; i < BYTE_TO_INT(L1_TABLE_SIZE); i++) { + ttbr[i] = 0; + } +} diff --git a/arm/common_mmu.h b/arm/common_mmu.h new file mode 100644 index 0000000..43da031 --- /dev/null +++ b/arm/common_mmu.h @@ -0,0 +1,145 @@ + +#ifndef _TZTEST_MMU_H +#define _TZTEST_MMU_H + +#include "sm.h" + +#define LARGE_PAGE (0 << 0) +#define PAGE (1 << 0) +#define SECTION (1 << 1) +#define SECURE (0 << 0) +#define NONSECURE (1 << 0) +#define P0_R (1 << 1) +#define P0_W (2 << 1) +#define P0_X (4 << 1) +#define P0_NONE (0 << 1) +#define P1_R (1 << 4) +#define P1_W (2 << 4) +#define P1_X (4 << 4) +#define SHARED (1 << 7) +#define NOTGLOBAL (1 << 8) +#define DEVICE (1 << 9) +#define UNCACHED (0 << 10) +#define WT_CACHED (1 << 10) +#define WB_CACHED (2 << 10) +#define WBA_CACHED (3 << 10) +#define DOMAIN(_d) ((_d) << 16) + +#define L1_TYPE_PAGE (1 << 0) +#define L1_TYPE_SECTION ((0 << 18) | (1 << 1)) + +#define L1_INDEX_BITS 12 +#define L1_TABLE_SIZE ((1 << L1_INDEX_BITS) << 2) +#define L1_INDEX_SHIFT 20 +#define L1_MAP_SIZE (1 << L1_INDEX_SHIFT) +#define L1_INDEX_MASK ((1 << L1_INDEX_BITS) - 1) + +#define L2_TYPE(_sz) (1 << (_sz)) + +#define L2_INDEX_BITS 8 +#define L2_TABLE_SIZE (1 << 10) +#define L2_INDEX_SHIFT 12 +#define L2_MAP_SIZE (1 << L2_INDEX_SHIFT) +#define L2_INDEX_MASK ((1 << L2_INDEX_BITS) - 1) + +#define BYTE_TO_INT(_val) ((_val) >> 2) +#define INT_TO_BYTE(_val) ((_val) << 2) +#define L1_INDEX(_va) (((_va)>>L1_INDEX_SHIFT) & L1_INDEX_MASK) +#define L2_INDEX(_va) (((_va)>>L2_INDEX_SHIFT) & L2_INDEX_MASK) + +#define SECTION_PXN (1 << 0) +#define SECTION_B (1 << 2) +#define SECTION_C (1 << 3) +#define SECTION_XN (1 << 4) +#define SECTION_DOMAIN(_d) ((_d) << 5) +#define SECTION_NS (1 << 19) +#define SECTION_TEX(v) (1 << 12) +#define SECTION_S (1 << 16) +#define SECTION_NG (1 << 17) +#define SECTION_SIZE L1_MAP_SIZE +#define SECTION_PA_SHIFT L1_INDEX_SHIFT +#define SECTION_PA_MASK ~((1 << SECTION_PA_SHIFT) - 1) + +/* Fix SCTLR.AFE bit */ + +#define SECTION_P1_RW ((0 << 15) | (1 << 10)) +#define SECTION_P1_RO ((1 << 15) | (1 << 10)) +#define SECTION_P1_NONE 0 +#define SECTION_P0_RW ((0 << 15) | (3 << 10)) +#define SECTION_P0_RO ((0 << 15) | (2 << 10)) +#define SECTION_P0_NONE ((0 << 15) | (1 << 10)) + +/* These remap description describe the memory region if SCTLR.TRE = 0 + * (no region atrribute remap). + */ +#define SECTION_DEVICE_SHAREABLE (SECTION_B) +#define SECTION_DEVICE_UNSHAREABLE (SECTION_TEX(2)) +#define SECTION_WT_CACHED (SECTION_C) +#define SECTION_WB_CACHED (SECTION_C | SECTION_B) +#define SECTION_UNCACHED (SECTION_TEX(1)) +#define SECTION_WBA_CACHED (SECTION_TEX(1) | SECTION_C | SECTION_B) + +#define SMALL_PAGE_SIZE 0x1000 +#define LARGE_PAGE_SIZE 0x10000 +#define PAGE_SIZE(_type) ((_type == PAGE) \ + ? SMALL_PAGE_SIZE : LARGE_PAGE_SIZE) + +#define PAGE_PASHIFT L2_INDEX_SHIFT +#define PAGE_PA_MASK ~((1 << PAGE_PASHIFT) - 1) +#define PAGE_LARGE (0 << 1) +#define PAGE_SMALL (1 << 1) +#define PAGE_PXN (1 << 2) +#define PAGE_NS (1 << 3) +#define PAGE_DOMAIN(_d) ((_d) << 5) +#define PAGE_B (1 << 2) +#define PAGE_C (1 << 3) +#define PAGE_LARGE_XN (1 << 15) +#define PAGE_SMALL_XN (1 << 0) +#define PAGE_XN(_sz) ((PAGE_LARGE == (_sz)) \ + ? PAGE_LARGE_XN : PAGE_SMALL_XN) +#define PAGE_S (1 << 10) +#define PAGE_NG (1 << 11) +#define PAGE_LARGE_TEX(_v) ((_v) << 12) +#define PAGE_SMALL_TEX(_v) ((_v) << 6) +#define PAGE_TEX(_sz, _v) (PAGE_LARGE == (_sz)) \ + ? PAGE_LARGE_TEX(_v) \ + : PAGE_SMALL_TEX(_v) + +#define PAGE_P1_RW ((0 << 9) | (1 << 4)) +#define PAGE_P1_RO ((1 << 9) | (1 << 4)) +#define PAGE_P1_NONE 0 +#define PAGE_P0_RW ((0 << 9) | (3 << 4)) +#define PAGE_P0_RO ((0 << 9) | (2 << 4)) +#define PAGE_P0_NONE ((0 << 9) | (1 << 4)) + +/* These remap description describe the memory region if SCTLR.TRE = 0 + * (no region atrribute remap). + */ +#define PAGE_DEVICE_SHAREABLE (PAGE_B) +#define PAGE_DEVICE_UNSHAREABLE(_sz) (PAGE_TEX((_sz), 2)) +#define PAGE_WT_CACHED (PAGE_C) +#define PAGE_WB_CACHED (PAGE_C | PAGE_B) +#define PAGE_UNCACHED(_sz) (PAGE_TEX((_sz), 1)) +#define PAGE_WBA_CACHED(_sz) (PAGE_TEX((_sz), 1) | PAGE_C | PAGE_B) + +typedef struct { + uint32_t type; + uint32_t va; + uint32_t pa; + uint32_t len; + uint32_t attr; +} pagetable_map_entry_t; + +#define ENTRIES_COUNT(_ent) (sizeof(_ent)/sizeof((_ent)[0])) + +#define PT_ADD_ENTRIES(_tbl, _ent) \ + pagetable_add_entries((_tbl), (_ent), ENTRIES_COUNT(_ent)) +#define IS_SET(_pe, _attr) ((_attr) == ((_pe)->attr & (_attr))) + + +extern void pagetable_init(uint32_t *); +extern void pagetable_init_common(uint32_t *table); +extern void pagetable_add_entries(uint32_t *, pagetable_map_entry_t *, + uint32_t); + +#endif diff --git a/arm/common_svc.c b/arm/common_svc.c new file mode 100644 index 0000000..666bcbf --- /dev/null +++ b/arm/common_svc.c @@ -0,0 +1,42 @@ +#include "common_svc.h" +#include "common_mmu.h" +#include "common_defs.h" +#include "sm.h" + +extern uint32_t _shared_memory_heap_base; + +pagetable_map_entry_t uart_pagetable_entries[] = { + {.va = UART0_BASE, .pa = UART0_BASE, .type = PAGE, .len = 0x1000, + .attr = SHARED | NOTGLOBAL | UNCACHED | P1_R | P1_W | P0_R | P0_W | + NONSECURE }, +}; + +pagetable_map_entry_t heap_pagetable_entries[] = { + {.va = (uint32_t)&_shared_memory_heap_base, + .pa = (uint32_t)&_shared_memory_heap_base, + .type = PAGE, .len = 0x1000, + .attr = SHARED | NOTGLOBAL | UNCACHED | P1_R | P1_W | P0_R | P0_W }, +}; + +void pagetable_init_common(uint32_t *table) +{ + PT_ADD_ENTRIES(table, uart_pagetable_entries); + PT_ADD_ENTRIES(table, heap_pagetable_entries); +} + +#ifdef DEBUG +void validate_state(uint32_t mode, uint32_t state) +{ + tztest_svc_desc_t desc; + + assert((_read_cpsr() & CPSR_MODE_MASK) == mode); + + CLEAR_SVC_DESC(desc); + __svc(SVC_GET_SECURE_STATE, &desc); + assert(desc.secure_state.state == state); +} +#else +void validate_state(__attribute__((unused)) uint32_t mode, + __attribute__((unused)) uint32_t state) {} +#endif + diff --git a/arm/common_svc.h b/arm/common_svc.h new file mode 100644 index 0000000..a9f19d5 --- /dev/null +++ b/arm/common_svc.h @@ -0,0 +1,71 @@ +#ifndef _COMMON_SVC_H +#define _COMMON_SVC_H + +#include "tztest_builtins.h" +#include "sm.h" +#include "libcflat.h" + +typedef struct { + uint32_t (*func)(uint32_t); + uint32_t arg; + uint32_t ret; +} tztest_dispatch_t; + +typedef struct { + union { + tztest_dispatch_t dispatch; + struct { + uint32_t reg; + uint32_t val; + } reg_read; + struct { + uint32_t state; + } secure_state; + }; +} tztest_svc_desc_t; + +#define CLEAR_SVC_DESC(_desc) memset(&(_desc), sizeof(tztest_svc_desc_t), 0) + +typedef struct { + union { + tztest_dispatch_t dispatch; + }; +} tztest_smc_desc_t; + +#ifdef DEBUG +#define DEBUG_MSG(_str, ...) \ + printf("\n[DEBUG] %s: " _str, __FUNCTION__, ##__VA_ARGS__) +#define DEBUG_ARG +#else +#define DEBUG_MSG(_str, ...) +#define DEBUG_ARG __attribute__ ((unused)) +#endif + +#define MODE_STR(_mode) \ + ((_mode == MON) ? "MON" : \ + (_mode == SVC) ? "SVC" : \ + (_mode == SYS) ? "SYS" : \ + (_mode == USR) ? "USR" : "Unknown") + + +#define FAULT_STR(_s) \ + ((0x01 == (_s)) ? "Alignment fault" : \ + (0x02 == (_s)) ? "Debug event" : \ + (0x03 == (_s)) ? "Access flag fault" : \ + (0x04 == (_s)) ? "Instruction cache maintenance" : \ + (0x05 == (_s)) ? "Translation fault" : \ + (0x06 == (_s)) ? "Access flag fault" : \ + (0x07 == (_s)) ? "Translation fault" : \ + (0x08 == (_s)) ? "Synchronous external abort" : \ + (0x09 == (_s)) ? "Domain fault" : \ + (0x0b == (_s)) ? "Domain fault" : \ + (0x0c == (_s)) ? "External abort on table walk" : \ + (0x0d == (_s)) ? "Permisison fault" : \ + (0x0e == (_s)) ? "Synchronous external abort" : \ + (0x0f == (_s)) ? "Permisison fault" : \ + (0x10 == (_s)) ? "TLB conflict abort" : \ + (0x1c == (_s)) ? "External parity err on table walk" : \ + (0x1e == (_s)) ? "External parity err on table walk" : \ + "Unknown") + +#endif diff --git a/arm/monitor.c b/arm/monitor.c new file mode 100644 index 0000000..32675a8 --- /dev/null +++ b/arm/monitor.c @@ -0,0 +1,25 @@ + +#include "common_svc.h" +#include "common_defs.h" + +void monitor_init_ns_entry(uint32_t entry_point) +{ + struct sm_nsec_ctx *nsec_ctx; + + + /* Set-up the non-secure context so that the switch to nonsecure state + * resumes at initiallizing the nonsecure svc mode. + */ + nsec_ctx = sm_get_nsec_ctx(); + nsec_ctx->mon_lr = entry_point; + nsec_ctx->mon_spsr = CPSR_MODE_SVC | CPSR_I; +} + + +void monitor_dispatch(tztest_smc_desc_t *desc) +{ + uint32_t (*func)(uint32_t) = desc->dispatch.func; + DEBUG_MSG("Entered\n"); + desc->dispatch.ret = func(desc->dispatch.arg); + DEBUG_MSG("Exiting\n"); +} diff --git a/arm/monitor_asm.S b/arm/monitor_asm.S new file mode 100644 index 0000000..9105a68 --- /dev/null +++ b/arm/monitor_asm.S @@ -0,0 +1,50 @@ + +#include "common_defs.h" + +.align 5 +.global monitor_vectors +monitor_vectors: + b . /* Reset */ + b . /* Undefined instruction */ + b monitor_smc_vect /* Secure monitor call */ + b . /* Prefetch abort */ + b . /* Data abort */ + b . /* Reserved */ + b . /* IRQ */ + b . /* FIQ */ + +monitor_smc_vect: + cmp r0, #SMC_YIELD + bge sm_smc_entry + srsdb sp!, #CPSR_MODE_MON + cmp r0, #SMC_NOOP + beq 1f + push {r0-r3} + mov r0, r1 + bl monitor_dispatch + pop {r0-r3} +1: rfefd sp! + +.global monitor_init +/* monitor_init(nonsecure_entrypt) */ +monitor_init: + push {lr} + + /* Set-up the monitor stack */ + mrs r10, cpsr + cps #CPSR_MODE_MON + ldr sp, =mon_stacktop + msr cpsr, r10 + + /* Set-up mvbar */ + ldr r10, =monitor_vectors + mcr p15, 0, r10, c12, c0, 1 + + /* Call to set the nonsecure entry point to be the save r0 value passed in + * by the boot code. This will be the initial entry point on the first + * monitor context switch. + */ + bl monitor_init_ns_entry + + pop {pc} + diff --git a/arm/nonsecure_init.S b/arm/nonsecure_init.S index d1d8c2c..656454e 100644 --- a/arm/nonsecure_init.S +++ b/arm/nonsecure_init.S @@ -1,7 +1,10 @@ -#include "tztest_asm.h" - -b nonsecure_vectors +#include "common_defs.h" +/* The nonsecure image load code must be placed at the beginning of the image + * as this is the starting point for the boot code to load. The loader code + * will pass the initial starting point back to the boot code for later + * execution. + */ nonsecure_load: ldr r0, =_flash_nsectext_start ldr r1, =_ram_nsectext_start @@ -21,6 +24,7 @@ copy_nsecdata: subs r2, r2, #1 bne copy_nsecdata + ldr r0, =nonsecure_init mov pc, lr .align 5 @@ -39,24 +43,24 @@ nonsecure_vectors: nonsecure_undef_vec: srsdb sp!, #CPSR_MODE_UND - bl nsec_undef_handler + bl nonsecure_undef_handler rfefd sp! nonsecure_pabort_vec: mrc p15, 0, r0, c5, c0, 1 /* IFSR */ mrc p15, 0, r1, c6, c0, 2 /* IFAR */ - bl nsec_pabort_handler + bl nonsecure_pabort_handler b end nonsecure_dabort_vec: mrc p15, 0, r0, c5, c0, 0 /* DFSR */ mrc p15, 0, r1, c6, c0, 0 /* DFAR */ - bl nsec_dabort_handler + bl nonsecure_dabort_handler b end nonsecure_svc_vec: srsdb sp!, #CPSR_MODE_SVC - bl nsec_svc_handler + bl nonsecure_svc_handler rfefd sp! nonsecure_init: @@ -105,12 +109,12 @@ nonsecure_mmu_init: mcr p15, 0, r10, c3, c0, 0 /* This function will return the initialized base address */ - bl tztest_nonsecure_pagetable_init + bl nonsecure_pagetable_init /* Set TTBR0 to the initialized address plus enable shareable write-back * write-allocate. */ - ldr r10, =nsec_l1_page_table + ldr r10, =_nsec_l1_page_table orr r10, r10, #0xB mcr p15, 0, r10, c2, c0, 0 diff --git a/arm/nonsecure_loader.h b/arm/nonsecure_loader.h new file mode 100644 index 0000000..f19b12f --- /dev/null +++ b/arm/nonsecure_loader.h @@ -0,0 +1,18 @@ +#ifndef _NONSECURE_LOADER_H +#define _NONSECURE_LOADER_H +#include "sm.h" + +extern uint32_t _nsec_l1_page_table; +extern uint32_t _ram_nsectext_start; +extern uint32_t _ram_nsecdata_start; +extern uint32_t _nsecstack_start; +extern uint32_t _nsectext_size; +extern uint32_t _nsecdata_size; +extern uint32_t _nsecstack_size; +extern uint32_t _shared_memory_heap_base; +extern uint32_t _common_memory_heap_base; +extern volatile int _tztest_exception; +extern volatile int _tztest_exception_status; +extern volatile int _tztest_exception_addr; + +#endif diff --git a/arm/nonsecure_svc.c b/arm/nonsecure_svc.c new file mode 100644 index 0000000..332dc51 --- /dev/null +++ b/arm/nonsecure_svc.c @@ -0,0 +1,138 @@ +#include "nonsecure_loader.h" +#include "common_svc.h" +#include "common_mmu.h" +#include "common_defs.h" + +uint32_t nonsecure_dispatch_sec_usr_function(uint32_t (*)(uint32_t), uint32_t); +uint32_t nonsecure_dispatch_sec_svc_function(uint32_t (*)(uint32_t), uint32_t); +uint32_t *nsec_l1_page_table = &_nsec_l1_page_table; +volatile int *tztest_exception = &_tztest_exception; +volatile int *tztest_exception_addr = &_tztest_exception_addr; +volatile int *tztest_exception_status = &_tztest_exception_status; +uint32_t ram_nsectext_start = (uint32_t)&_ram_nsectext_start; +uint32_t ram_nsecdata_start = (uint32_t)&_ram_nsecdata_start; +uint32_t nsecstack_start = (uint32_t)&_nsecstack_start; +uint32_t nsectext_size = (uint32_t)&_nsectext_size; +uint32_t nsecdata_size = (uint32_t)&_nsecdata_size; +uint32_t nsecstack_size = (uint32_t)&_nsecstack_size; +tztest_smc_desc_t smc_desc; + +void nonsecure_svc_handler(volatile uint32_t op, + volatile tztest_svc_desc_t *desc) +{ + int ret = 0; + switch (op) { + case SVC_DISPATCH_MONITOR: + op = SMC_DISPATCH_MONITOR; + __smc(op, desc); + break; + case SVC_DISPATCH_SECURE_USR: + DEBUG_MSG("Dispatching secure usr function\n"); + desc->dispatch.ret = + nonsecure_dispatch_sec_usr_function(desc->dispatch.func, + desc->dispatch.arg); + DEBUG_MSG("Returning from secure usr function, ret = 0x%x\n", + desc->dispatch.ret); + break; + case SVC_DISPATCH_SECURE_SVC: + DEBUG_MSG("Dispatching secure svc function\n"); + desc->dispatch.ret = + nonsecure_dispatch_sec_svc_function(desc->dispatch.func, + desc->dispatch.arg); + DEBUG_MSG("Returning from secure svc function, ret = 0x%x\n", + desc->dispatch.ret); + break; + case SVC_DISPATCH_NONSECURE_SVC: + DEBUG_MSG("Dispatching nonsecure svc function\n"); + desc->dispatch.ret = desc->dispatch.func(desc->dispatch.arg); + DEBUG_MSG("Returning from nonsecure svc function, ret = 0x%x\n", + desc->dispatch.ret); + break; + case SVC_GET_SECURE_STATE: + /* This SVC handler is only accessible from the nonsecure vector + * table, so unless something went drastically wrong with the + * tables, it should be safe to assume we are in a nonsecure state. + */ + desc->secure_state.state = TZTEST_STATE_NONSECURE; + break; + case SVC_EXIT: + op = SMC_EXIT; + __smc(op, ret); + break; + } +} + +void nonsecure_undef_handler() { + DEBUG_MSG("Undefined exception taken\n"); + *tztest_exception = CPSR_MODE_UND; + *tztest_exception_status = 0; +} + +void nonsecure_pabort_handler(int status, DEBUG_ARG int addr) { + DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", status, addr); + *tztest_exception = CPSR_MODE_ABT; + *tztest_exception_status = status & 0x1f; +} + +void nonsecure_dabort_handler(int status, DEBUG_ARG int addr) { + DEBUG_MSG("Data Abort: %s\n", FAULT_STR(status & 0x1f)); + DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", + status & 0x1f, addr); + *tztest_exception = CPSR_MODE_ABT; + *tztest_exception_status = status & 0x1f; +} + +uint32_t nonsecure_dispatch_sec_usr_function(uint32_t (*func)(uint32_t), + uint32_t arg) +{ + volatile int r0 = SMC_DISPATCH_SECURE_USR; + tztest_smc_desc_t *desc_p = &smc_desc; + + smc_desc.dispatch.func = func; + smc_desc.dispatch.arg = arg; + DEBUG_MSG("Entered\n"); + __smc(r0, desc_p); + DEBUG_MSG("Exiting, func = 0x%x\n", smc_desc.dispatch.func); + return smc_desc.dispatch.ret; +} + +uint32_t nonsecure_dispatch_sec_svc_function(uint32_t (*func)(uint32_t), + uint32_t arg) +{ + volatile int op = SMC_DISPATCH_SECURE_SVC; + tztest_smc_desc_t desc, *desc_p = &desc; + + desc.dispatch.func = func; + desc.dispatch.arg = arg; + DEBUG_MSG("Entered op = %x\n", op); + __smc(op, desc_p); + DEBUG_MSG("Exiting\n"); + return desc.dispatch.ret; +} + +void nonsecure_pagetable_init() +{ + pagetable_map_entry_t nsec_pagetable_entries[] = { + {.va = (uint32_t)ram_nsectext_start, .pa = (uint32_t)ram_nsectext_start, + .type = PAGE, .len = nsectext_size, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_X | P0_R | P0_X | + NONSECURE }, + {.va = (uint32_t)ram_nsecdata_start, .pa = (uint32_t)ram_nsecdata_start, + .type = PAGE, .len = nsecdata_size, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P0_R | P0_W | + NONSECURE }, + {.va = (uint32_t)nsecstack_start, .pa = (uint32_t)nsecstack_start, + .type = PAGE, .len = nsecstack_size, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P0_R | P0_W | + NONSECURE }, + {.va = (uint32_t)nsec_l1_page_table, .pa = (uint32_t)nsec_l1_page_table, + .type = SECTION, .len = 16*1024*1024, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W }, + }; + + pagetable_init(nsec_l1_page_table); + + PT_ADD_ENTRIES(nsec_l1_page_table, nsec_pagetable_entries); + + pagetable_init_common(nsec_l1_page_table); +} diff --git a/arm/secure_asm.S b/arm/secure_asm.S new file mode 100644 index 0000000..9761a6c --- /dev/null +++ b/arm/secure_asm.S @@ -0,0 +1,40 @@ + +#include "common_defs.h" + +.global secure_dispatch_usr +secure_dispatch_usr: + /* Push the LR onto the stack so we can return immediately from the svc + * handler on return. + */ + push {lr} + + /* Reset the user stack for the dispatch, so we have a clean stack */ + cps #CPSR_MODE_SYS + ldr sp, =sec_usr_stacktop + push {r0, r1} + cps #CPSR_MODE_SVC + + /* Return to USR mode to execute the dispatch function in r0 + */ + ldr r0, =dispatch_usr_wrapper + mov r1, #CPSR_MODE_USR + push {r0, r1} + rfefd sp! + +/* This is the user-side dispatch wrapper that accepts the function pointer and + * function arg in r0 & r1 respectively. The wrapper is simply an anstraction + * layer for translating the input parameters into the user function call. + */ +dispatch_usr_wrapper: + pop {r0, r1} + mov r2, r0 + mov r0, r1 + mov pc, r2 + +.global secure_shutdown +secure_shutdown: + ldr r0, =SYSREG_BASE + add r0, r0, #SYSREG_CFGCTRL + ldr r1, =SYS_SHUTDOWN + str r1, [r0] + b secure_shutdown diff --git a/arm/secure_init.S b/arm/secure_init.S index a911aa0..c77838f 100644 --- a/arm/secure_init.S +++ b/arm/secure_init.S @@ -1,8 +1,8 @@ -#include "tztest_asm.h" +#include "common_defs.h" .arch_extension sec -.align 5 +.section .vectors, "ax" secure_vectors: b secure_init /* reset */ b secure_undef_vec /* undef */ @@ -15,19 +15,22 @@ secure_vectors: secure_undef_vec: srsdb sp!, #CPSR_MODE_UND - bl sec_undef_handler + push {r10} + ldr r10, =secure_undef_handler + blx r10 + pop {r10} rfefd sp! secure_pabort_vec: mrc p15, 0, r0, c5, c0, 1 /* IFSR */ mrc p15, 0, r1, c6, c0, 2 /* IFAR */ - bl sec_pabort_handler + bl secure_pabort_handler b end secure_dabort_vec: mrc p15, 0, r0, c5, c0, 0 /* DFSR */ mrc p15, 0, r1, c6, c0, 0 /* DFAR */ - bl sec_dabort_handler + bl secure_dabort_handler b end secure_svc_vec: @@ -45,47 +48,32 @@ secure_svc_vec: pop {pc} 1: srsdb sp!, #CPSR_MODE_SVC - bl sec_svc_handler + push {r10} + ldr r10, =secure_svc_handler + blx r10 + pop {r10} rfefd sp! -.align 5 -monitor_vectors: - b . /* Reset */ - b . /* Undefined instruction */ - b monitor_smc_vect /* Secure monitor call */ - b . /* Prefetch abort */ - b . /* Data abort */ - b . /* Reserved */ - b . /* IRQ */ - b . /* FIQ */ - -monitor_smc_vect: - cmp r0, #SMC_YIELD - bge sm_smc_entry - srsdb sp!, #CPSR_MODE_MON - cmp r0, #SMC_NOOP - beq 1f - push {r0-r3} - mov r0, r1 - bl tztest_dispatch_monitor - pop {r0-r3} -1: rfefd sp! - - .globl secure_init +.section .text secure_init: + /* We enter with R0 pointing to the nonsecure entry point. Put it in R11 + * for now to avoid overwriting it on calls. */ + mov r11, r0 + /* Disable interrupts for now */ mrs r10, cpsr - orr r10, r10, #0xc0 @ Mask IRQ and FIQ + orr r10, r10, #0xc0 /* Mask IRQ and FIQ */ msr cpsr, r10 - /* Make sure secure vectors are based at 0 */ + /* During startup, before the MMU is enabled we'll set-up the vecs in low + * mem. + */ mrc p15, 0, r10, c1, c0, 0 - bic r10, r10, #0x2000 @ SCTLR.V = 0 + bic r10, r10, #0x2000 /* SCTLR.V = 0 */ mcr p15, 0, r10, c1, c0, 0 + ldr r10, =secure_vectors + mcr p15, 0, r10, c12, c0, 0 /* VBAR = secure_vectors */ - /* Set up secure VBAR */ - ldr r11, =secure_vectors - mcr p15, 0, r11, c12, c0, 0 isb secure_stack_init: @@ -118,12 +106,12 @@ secure_mmu_init: mcr p15, 0, r10, c3, c0, 0 /* Set-up the initial secure page tables */ - bl tztest_secure_pagetable_init + bl secure_pagetable_init /* Set TTBR0 to the initialized address plus enable shareable write-back * write-allocate. */ - ldr r10, =sec_l1_page_table + ldr r10, =_sec_l1_page_table orr r10, r10, #0xB mcr p15, 0, r10, c2, c0, 0 @@ -139,65 +127,39 @@ secure_mmu_init: isb dsb -#ifdef DEBUG +secure_remap_vecs: + /* Now that we have enabled the MMU, move the mapping of the secure vector + * table to high mem. + * No need to set up VBAR as we'll be using hivec */ + mrc p15, 0, r10, c1, c0, 0 + orr r10, r10, #0x2000 @ SCTLR.V = 1 + mcr p15, 0, r10, c1, c0, 0 + /* Check that are entry state makes sense before initializing the monitor * mode. */ - bl check_init_mode -#endif + bl secure_check_init secure_init_monitor: - /* Set-up the monitor stack */ - mrs r1, cpsr - cps #CPSR_MODE_MON - ldr sp, =mon_stacktop - msr cpsr, r1 - - /* Set-up mvbar */ - ldr r0, =monitor_vectors - mcr p15, 0, r0, c12, c0, 1 - - bl tztest_secure_svc_init_monitor + /* Call monitor mode initialization and pass to it the non-secure execution + * entry point. + */ + mov r0, r11 + bl monitor_init + /* Once monitor mode is set-up, we yield to non-secure execution. The + * non-secure entrypoint was established in monitor init. + */ mov r0, #SMC_YIELD smc #0 - bl tztest_secure_svc_loop + /* The first return to the secure world will set us off into our + * secure-side monitor loop. The only way out is to issue an EXIT SMC call + * to the secure world. + */ + bl secure_svc_loop /* If we get here we are on the way out, poweroff the device */ end: - ldr r0, =SYSREG_BASE - add r0, r0, #SYSREG_CFGCTRL - ldr r1, =SYS_SHUTDOWN - str r1, [r0] - b end - - .globl dispatch_secure_usr -dispatch_secure_usr: - /* Push the LR onto the stack so we can return immediately from the svc - * handler on return. - */ - push {lr} + b secure_shutdown - /* Reset the user stack for the dispatch, so we have a clean stack */ - cps #CPSR_MODE_SYS - ldr sp, =sec_usr_stacktop - push {r0, r1} - cps #CPSR_MODE_SVC - - /* Return to USR mode to execute the dispatch function in r0 - */ - ldr r0, =dispatch_usr_wrapper - mov r1, #CPSR_MODE_USR - push {r0, r1} - rfefd sp! - -/* This is the user-side dispatch wrapper that accepts the function pointer and - * function arg in r0 & r1 respectively. The wrapper is simply an anstraction - * layer for translating the input parameters into the user function call. - */ -dispatch_usr_wrapper: - pop {r0, r1} - mov r2, r0 - mov r0, r1 - mov pc, r2 diff --git a/arm/secure_loader.h b/arm/secure_loader.h new file mode 100644 index 0000000..577d6e5 --- /dev/null +++ b/arm/secure_loader.h @@ -0,0 +1,21 @@ +#ifndef _SECURE_LOADER_H +#define _SECURE_LOADER_H +#include "sm.h" + +extern int _ram_nsec_base; +extern uint32_t _sec_l1_page_table; +extern uint32_t _ram_secvecs_start; +extern uint32_t _ram_sectext_start; +extern uint32_t _ram_secdata_start; +extern uint32_t _secstack_start; +extern uint32_t _secvecs_size; +extern uint32_t _sectext_size; +extern uint32_t _secdata_size; +extern uint32_t _secstack_size; +extern uint32_t _shared_memory_heap_base; +extern uint32_t _common_memory_heap_base; +extern volatile uint32_t _tztest_exception; +extern volatile uint32_t _tztest_exception_addr; +extern volatile uint32_t _tztest_exception_status; + +#endif diff --git a/arm/secure_svc.c b/arm/secure_svc.c new file mode 100644 index 0000000..3ba4471 --- /dev/null +++ b/arm/secure_svc.c @@ -0,0 +1,184 @@ +#include "secure_loader.h" +#include "common_svc.h" +#include "common_mmu.h" +#include "common_defs.h" + +/* Make the below globals volatile as found that the compiler uses the + * register value ratherh than the memory value making it look like the writes + * actually happened. + */ + +int secure_dispatch_usr(int, int); +void secure_svc_loop(int initial_r0, int initial_r1); + +volatile uint32_t *exception = &_tztest_exception; +volatile uint32_t *exception_addr = &_tztest_exception_addr; +volatile uint32_t *exception_status = &_tztest_exception_status; +uint32_t *sec_l1_page_table = &_sec_l1_page_table; +uint32_t ram_secvecs_start = (uint32_t)&_ram_secvecs_start; +uint32_t ram_sectext_start = (uint32_t)&_ram_sectext_start; +uint32_t ram_secdata_start = (uint32_t)&_ram_secdata_start; +uint32_t secstack_start = (uint32_t)&_secstack_start; +uint32_t secvecs_size = (uint32_t)&_secvecs_size; +uint32_t sectext_size = (uint32_t)&_sectext_size; +uint32_t secdata_size = (uint32_t)&_secdata_size; +uint32_t secstack_size = (uint32_t)&_secstack_size; + +pagetable_map_entry_t nsec_pagetable_entries[] = { + {.va = (uint32_t)&_ram_nsec_base, .pa = (uint32_t)&_ram_nsec_base, + .type = SECTION, .len = SECTION_SIZE * 2, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P1_X | P0_R | + P0_W | P0_X | NONSECURE }, +}; + +pagetable_map_entry_t sysreg_pagetable_entries[] = { + {.va = SYSREG_BASE, .pa = SYSREG_BASE, + .type = PAGE, .len = 0x1000, + .attr = SHARED | NOTGLOBAL | UNCACHED | P1_R | P1_W | P0_R | P0_W | + NONSECURE }, +}; + +void secure_svc_handler(volatile uint32_t op, volatile tztest_svc_desc_t *desc) +{ + DEBUG_MSG("Entered\n"); + switch (op) { + case SVC_DISPATCH_MONITOR: + op = SMC_DISPATCH_MONITOR; + __smc(op, desc); + break; + case SVC_GET_SECURE_STATE: + /* This SVC handler is only accessible from the secure vector + * table, so unless something went drastically wrong with the + * tables, it should be safe to assume we are in a nonsecure state. + */ + desc->secure_state.state = TZTEST_STATE_SECURE; + break; + } + DEBUG_MSG("Exiting\n"); + return; +} + +void secure_undef_handler() { + DEBUG_MSG("Undefined exception taken\n"); + *exception = CPSR_MODE_UND; + *exception_status = 0; +} + +void secure_pabort_handler(int status, int addr) { + DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", status, addr); + *exception = CPSR_MODE_ABT; + *exception_addr = addr; + *exception_status = status & 0x1f; +} + +void secure_dabort_handler(int status, int addr) { + DEBUG_MSG("Data Abort: %s\n", FAULT_STR(status & 0x1f)); + DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", + status & 0x1f, addr); + *exception = CPSR_MODE_ABT; + *exception_addr = addr; + *exception_status = status & 0x1f; +} + +void secure_check_init() +{ + printf("\nValidating startup state:\n"); + + printf("\tChecking for security extension ..."); + int idpfr1 = 0; + /* Read the ID_PFR1 CP register and check that it is marked for support of + * the security extension. + */ + __mrc(15, 0, idpfr1, 0, 1, 1); + if (0x10 != (idpfr1 & 0xf0)) { + printf("FAILED\n"); + DEBUG_MSG("current IDPFR1 (%d) != expected IDPFR1 (%d)\n", + (idpfr1 & 0xf0), 0x10); + exit(1); + } else { + printf("PASSED\n"); + } + + printf("\tChecking initial processor mode... "); + if (CPSR_MODE_SVC != (_read_cpsr() & 0x1f)) { + printf("FAILED\n"); + DEBUG_MSG("current CPSR (%d) != expected CPSR (%d)\n", + (_read_cpsr() & 0x1f), CPSR_MODE_SVC); + assert(CPSR_MODE_SVC == (_read_cpsr() & 0x1f)); + } else { + printf("PASSED\n"); + } + + // Test: Check that on reset if sec et present, starts in sec state + // pg. B1-1204 + printf("\tChecking initial security state... "); + if (0 != (_read_scr() & SCR_NS)) { + printf("Failed\n"); + DEBUG_MSG("current SCR.NS (%d) != expected SCR.NS (%d)\n", + (_read_cpsr() & SCR_NS), 0); + assert(0 == (_read_scr() & SCR_NS)); + } else { + printf("PASSED\n"); + } +} + +void secure_svc_loop(int initial_op, int initial_data) +{ + volatile int op = initial_op; + tztest_smc_desc_t *data = (tztest_smc_desc_t *)initial_data; + uint32_t (*func)(uint32_t); + + DEBUG_MSG("Initial call\n"); + + while (SMC_EXIT != op) { + switch (op) { + case SMC_DISPATCH_SECURE_USR: + DEBUG_MSG("Dispatching secure USR function\n"); + data->dispatch.ret = + secure_dispatch_usr((int)data->dispatch.func, + data->dispatch.arg); + DEBUG_MSG("Returned from secure USR dispatch\n"); + break; + case SMC_DISPATCH_SECURE_SVC: + func = (uint32_t (*)())data->dispatch.func; + DEBUG_MSG("Dispatching secure SVC function\n"); + data->dispatch.ret = func(data->dispatch.arg); + DEBUG_MSG("Returned from secure SVC dispatch\n"); + break; + } + op = SMC_YIELD; + __smc(op, data); + DEBUG_MSG("Handling smc op 0x%x\n", op); + } + + DEBUG_MSG("Exiting\n"); +} + +void secure_pagetable_init() +{ + pagetable_map_entry_t sec_pagetable_entries[] = { + {.va = (uint32_t)0xFFFF0000, .pa = (uint32_t)ram_secvecs_start, + .type = PAGE, .len = secvecs_size, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_X | P0_R | P0_X }, + {.va = (uint32_t)ram_sectext_start, .pa = (uint32_t)ram_sectext_start, + .type = PAGE, .len = sectext_size, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_X | P0_R | P0_X }, + {.va = (uint32_t)ram_secdata_start, .pa = (uint32_t)ram_secdata_start, + .type = PAGE, .len = secdata_size, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P0_R | P0_W }, + {.va = (uint32_t)secstack_start, .pa = (uint32_t)secstack_start, + .type = PAGE, .len = secstack_size, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W | P0_R | P0_W }, + {.va = (uint32_t)sec_l1_page_table, .pa = (uint32_t)sec_l1_page_table, + .type = SECTION, .len = 16*1024*1024, + .attr = SHARED | NOTGLOBAL | WBA_CACHED | P1_R | P1_W }, + }; + + pagetable_init(sec_l1_page_table); + + PT_ADD_ENTRIES(sec_l1_page_table, sysreg_pagetable_entries); + PT_ADD_ENTRIES(sec_l1_page_table, sec_pagetable_entries); + PT_ADD_ENTRIES(sec_l1_page_table, nsec_pagetable_entries); + + pagetable_init_common(sec_l1_page_table); +} diff --git a/arm/sm_asm.S b/arm/sm_asm.S index bcfb84a..cab7b54 100644 --- a/arm/sm_asm.S +++ b/arm/sm_asm.S @@ -28,7 +28,6 @@ #include <asm.S> #include <arm32.h> #include <arm32_macros.S> -//#include <sm/teesmc.h> FUNC sm_save_modes_regs , : /* User mode registers has to be saved from system mode */ diff --git a/arm/tzboot.S b/arm/tzboot.S index 26ae976..937561d 100644 --- a/arm/tzboot.S +++ b/arm/tzboot.S @@ -42,11 +42,22 @@ init_cpu: ldr r11, =boot_vectors mcr p15, 0, r11, c12, c0, 0 isb - + /* Start by setting up the boot stack*/ ldr sp, =boot_stacktop load_images: + /* First copy the vector section text into RAM */ + ldr r0, =_flash_secvecs_start + ldr r1, =_ram_secvecs_start + ldr r2, =_secvecs_size +copy_secvecs: + ldrb r10, [r0], #1 + strb r10, [r1], #1 + subs r2, r2, #1 + bne copy_secvecs + + /* Next copy the text section into RAM */ ldr r0, =_flash_sectext_start ldr r1, =_ram_sectext_start ldr r2, =_sectext_size @@ -55,7 +66,8 @@ copy_sectext: strb r10, [r1], #1 subs r2, r2, #1 bne copy_sectext - + + /* Last copy the text section into RAM */ ldr r0, =_flash_secdata_start ldr r1, =_ram_secdata_start ldr r2, =_secdata_size @@ -64,12 +76,19 @@ copy_secdata: strb r10, [r1], #1 subs r2, r2, #1 bne copy_secdata - + + /* Branch to the nonsecure image base. It should be set-up so that this is + * the image loader which returns the starting execution point. + */ mov r0, #FLASH_NSEC_BASE - add r0, r0, #0x4 blx r0 - - bl secure_init - -end: + + /* Branch to the starting point of the secure image in RAM which should + * kick off initialization. + */ + mov r1, #RAM_SEC_BASE + bx r1 + + /* We shouldn't get here as the secure image will shutdown */ +end: b end diff --git a/arm/tztest.c b/arm/tztest.c index c79c609..5a539d8 100644 --- a/arm/tztest.c +++ b/arm/tztest.c @@ -1,10 +1,12 @@ #include "tztest.h" +volatile int *tztest_fail_count = &_tztest_fail_count; +volatile int *tztest_test_count = &_tztest_test_count; + /* Make the below globals volatile as found that the compiler uses the * register value ratherh than the memory value making it look like the writes * actually happened. */ -extern uint32_t _shared_memory_heap_base; uint32_t mon_noop() { return 0; } @@ -151,59 +153,32 @@ uint32_t P1_nonsecure_check_mask_bits() return ret; } -#define TZTEST_SECURE_USR_PATTERN 0x87654321 -#define TZTEST_SECURE_SVC_PATTERN 0x12345678 - -uint32_t tztest_secure_usr_test1(uint32_t arg) -{ - DEBUG_MSG("Entered arg = 0x%x\n", arg); - __svc(1,0); - DEBUG_MSG("Exiting\n"); - - return arg/2; -} -SECURE_USR_FUNC(tztest_secure_usr_test1); - -uint32_t tztest_secure_svc_test1(uint32_t arg) +uint32_t MON_check_state() { - DEBUG_MSG("arg = 0x%x\n", arg); - return arg*2; -} + printf("\nValidating monitor mode:\n"); -uint32_t tztest_check_secure_usr_handshake() -{ - uint32_t ret = 0; - DISPATCH_SECURE_USR(tztest_secure_usr_test1, - TZTEST_SECURE_USR_PATTERN, ret); + uint32_t cpsr = _read_cpsr(); - if (TZTEST_SECURE_USR_PATTERN/2 != ret) { - DEBUG_MSG("\n***** Failed secure usr handshake *****\n"); - assert(TZTEST_SECURE_USR_PATTERN/2 == ret); - } + printf("\tChecking monitor mode... "); + TEST_CONDITION(CPSR_MODE_MON == (cpsr & CPSR_MODE_MASK)); - return ret; -} + // Test: Check that CPSR.A/I.F are set to 1 on exception to mon mode + // pg. B1-1182 + printf("\tChecking monitor mode CPSR.F value... "); + TEST_CONDITION(CPSR_F == (CPSR_F & cpsr)); -uint32_t tztest_check_secure_svc_handshake() -{ - uint32_t ret = 0; - DISPATCH_SECURE_SVC(tztest_secure_svc_test1, - TZTEST_SECURE_SVC_PATTERN, ret); + printf("\tChecking monitor mode CPSR.I value... "); + TEST_CONDITION(CPSR_I == (CPSR_I & cpsr)); - if (TZTEST_SECURE_SVC_PATTERN*2 != ret) { - DEBUG_MSG("\n***** Failed secure svc handshake *****\n"); - assert(TZTEST_SECURE_SVC_PATTERN*2 == ret); - } + printf("\tChecking monitor mode CPSR.A value... "); + TEST_CONDITION(CPSR_A == (CPSR_A & cpsr)); - return ret; + return 0; } -uint32_t MON_check_state() +uint32_t MON_check_exceptions() { - printf("\nValidating monitor mode:\n"); - - printf("\tChecking monitor mode... "); - TEST_CONDITION(CPSR_MODE_MON == ((_read_cpsr() & CPSR_MODE_MASK))); + printf("\nValidating monitor mode exception:\n"); uint32_t scr = _read_scr(); @@ -212,8 +187,7 @@ uint32_t MON_check_state() * Test: Check that an exception from mon mode, NS cleared to 0 * pg. B1-1170 */ - - /* Set our security state to secure */ + /* Set our starting security state to secure */ _write_scr(scr & ~SCR_NS); printf("\tChecking state after secure monitor... "); TEST_FUNCTION(smc_noop(), !SCR_NS == ((_read_scr() & SCR_NS))); @@ -250,64 +224,6 @@ uint32_t P1_nonsecure_novirt_behavior() return ret; } -#define TZTEST_SVAL 0xaaaaaaaa -#define TZTEST_NSVAL ~TZTEST_SVAL -#define TZTEST_GET_REG_SECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr & ~SCR_NS); \ - (_val) = _read_##_reg(); \ - } while(0) - -#define TZTEST_GET_REG_NONSECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr | SCR_NS); \ - (_val) = _read_##_reg(); \ - } while(0) - -#define TZTEST_SET_REG_SECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr & ~SCR_NS); \ - _write_##_reg(_val); \ - } while(0) - -#define TZTEST_SET_REG_NONSECURE_BANK(_reg, _val) \ - do { \ - _write_scr(scr | SCR_NS); \ - _write_##_reg(_val); \ - } while(0) - -#define TZTEST_GET_REG_BANKS(_reg, _sval, _nsval) \ - do { \ - TZTEST_GET_REG_SECURE_BANK(_reg, _sval); \ - TZTEST_GET_REG_NONSECURE_BANK(_reg, _nsval);\ - } while(0) - -#define TZTEST_SET_REG_BANKS(_reg, _sval, _nsval) \ - do { \ - TZTEST_SET_REG_SECURE_BANK(_reg, _sval); \ - TZTEST_SET_REG_NONSECURE_BANK(_reg, _nsval);\ - } while(0) - -#define VERIFY_REGISTER_CUSTOM(_reg, _mask, _sval, _nsval) \ - do { \ - uint32_t sval = 0, nsval = 0; \ - uint32_t _reg[2] = {0,0}; \ - printf("\tChecking %s banks... ", #_reg); \ - TZTEST_GET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ - TZTEST_SET_REG_BANKS(_reg, (_sval), (_nsval)); \ - TZTEST_GET_REG_SECURE_BANK(_reg, sval); \ - TZTEST_GET_REG_NONSECURE_BANK(_reg, nsval); \ - TEST_CONDITION(((sval & (_mask)) != (nsval & (_mask))) && \ - (((_sval) & (_mask)) == (sval & (_mask))) && \ - (((_nsval) & (_mask)) == (nsval & (_mask)))); \ - TZTEST_SET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ - } while(0) - -#define VERIFY_REGISTER(_reg) \ - VERIFY_REGISTER_CUSTOM(_reg, 0xFFFFFFFF, TZTEST_SVAL, TZTEST_NSVAL) - -extern uint32_t nsec_l1_page_table; -extern uint32_t nonsecure_vectors; uint32_t MON_check_banked_regs() { uint32_t scr = _read_scr(); @@ -331,7 +247,7 @@ uint32_t MON_check_banked_regs() * be wrong. */ VERIFY_REGISTER_CUSTOM(ttbr0, 0xFFF00000, - (uint32_t)&nsec_l1_page_table, TZTEST_NSVAL); + (uint32_t)nsec_l1_page_table, TZTEST_NSVAL); VERIFY_REGISTER(ttbr1); /* Modifying TTBCR is highly disruptive, so the test is heavily restricted @@ -369,6 +285,62 @@ uint32_t MON_check_banked_regs() return 0; } +#ifdef DEBUG +uint32_t tztest_div_by_2(uint32_t arg) {return arg/2;} +SECURE_USR_FUNC(tztest_div_by_2); + +#define TZTEST_HANDSHAKE_FUNC(_name, _remote) \ + uint32_t _name(uint32_t arg) { \ + uint32_t ret = 0; \ + _remote(tztest_div_by_2, arg, ret); \ + assert(arg/2 == ret); \ + return ret; \ + } + +TZTEST_HANDSHAKE_FUNC(hs_with_ns_svc, DISPATCH_NONSECURE_SVC) +TZTEST_HANDSHAKE_FUNC(hs_with_s_svc, DISPATCH_SECURE_SVC) +TZTEST_HANDSHAKE_FUNC(hs_with_s_usr, DISPATCH_SECURE_USR) +TZTEST_HANDSHAKE_FUNC(hs_with_mon, DISPATCH_MONITOR) + +#define CHECK_HANDSHAKE(_func) \ + _func; \ + if (val/2 != ret) { \ + DEBUG_MSG("Handshake %s FAILED (0x%x != 0x%x)\n", \ + #_func, val/2, ret); \ + assert(val/2 == ret); \ + } \ + +void test_handshake() +{ + uint32_t ret = 0; + uint32_t val = TZTEST_SVAL; + + /* NS_USR -> NS_SVC */ + CHECK_HANDSHAKE(ret = hs_with_ns_svc(val)); + + /* NS_USR -> NS_SVC -> S_SVC */ + CHECK_HANDSHAKE(ret = hs_with_s_svc(val)); + + /* NS_USR -> NS_SVC -> S_SVC -> S_USR */ + CHECK_HANDSHAKE(ret = hs_with_s_usr(val)); + + /* NS_USR -> NS_SVC -> MON */ + CHECK_HANDSHAKE(ret = hs_with_mon(val)); + + /* NS_SVC -> S_SVC */ + CHECK_HANDSHAKE(DISPATCH_NONSECURE_SVC(hs_with_s_svc, val, ret)); + + /* NS_SVC -> S_USR */ + CHECK_HANDSHAKE(DISPATCH_NONSECURE_SVC(hs_with_s_usr, val, ret)); + + /* NS_SVC -> MON */ + CHECK_HANDSHAKE(DISPATCH_NONSECURE_SVC(hs_with_mon, val, ret)); + + /* S_SVC -> MON */ + CHECK_HANDSHAKE(DISPATCH_SECURE_SVC(hs_with_mon, val, ret)); +} +#endif + uint32_t tztest_nonsecure_usr_main() { uint32_t ret = 0; @@ -381,13 +353,13 @@ uint32_t tztest_nonsecure_usr_main() P0_nonsecure_check_register_access(); #ifdef DEBUG - tztest_check_secure_usr_handshake(); - tztest_check_secure_svc_handshake(); + test_handshake(); #endif DISPATCH_SECURE_USR(P0_secure_check_register_access, 0, ret); DISPATCH_MONITOR(MON_check_state, 0, ret); + DISPATCH_MONITOR(MON_check_exceptions, 0, ret); DISPATCH_MONITOR(MON_check_banked_regs, 0, ret); DISPATCH_NONSECURE_SVC(P1_nonsecure_check_mask_bits, 0, ret); @@ -429,6 +401,10 @@ uint32_t tztest_nonsecure_usr_main() // pg. B1-1158 // Test: Check that irq/fiq interrupts routed to mon mode use mvbar entry // pg. B1-1168 + // Test: Check that IRQ exceptions are routed properly + // figure: B1-8 + // Test: Check that FIQ exceptions are routed properly + // figure: B1-9 #endif #ifdef NONTZ_TEST // Test: Check that mon mode is only avail if sec ext. present @@ -462,13 +438,3 @@ uint32_t tztest_nonsecure_usr_main() // figure: B1-6 // Test: Check that data abort exceptions are routed properly // figure: B1-7 - // Test: Check that IRQ exceptions are routed properly - // figure: B1-8 - // Test: Check that FIQ exceptions are routed properly - // figure: B1-9 - // Test: Check that CPSR.A/I.F are set to 1 on exception to mon mode - // pg. B1-1182 - // Test: Check that on reset if sec et present, starts in sec state - // pg. B1-1204 - // Note: Unaligned access can cause abort in PMSA - // diff --git a/arm/tztest.h b/arm/tztest.h index bb0d0ca..34ced86 100644 --- a/arm/tztest.h +++ b/arm/tztest.h @@ -1,74 +1,11 @@ #ifndef _TZTEST_H #define _TZTEST_H -#include "tztest_asm.h" -#include "tztest_builtins.h" -#include "tztest_mmu.h" -#include "sm.h" -#include "libcflat.h" - -typedef struct { - uint32_t (*func)(uint32_t); - uint32_t arg; - uint32_t ret; -} tztest_dispatch_t; - -typedef struct { - union { - tztest_dispatch_t dispatch; - struct { - uint32_t reg; - uint32_t val; - } reg_read; - struct { - uint32_t state; - } secure_state; - }; -} tztest_svc_desc_t; - -#define CLEAR_SVC_DESC(_desc) memset(&(_desc), sizeof(tztest_svc_desc_t), 0) - -typedef struct { - union { - tztest_dispatch_t dispatch; - }; -} tztest_smc_desc_t; - -#ifdef DEBUG -#define DEBUG_MSG(_str, ...) \ - printf("\n[DEBUG] %s: " _str, __FUNCTION__, ##__VA_ARGS__) -#define DEBUG_ARG -#else -#define DEBUG_MSG(_str, ...) -#define DEBUG_ARG __attribute__ ((unused)) -#endif +#include "common_defs.h" +#include "common_svc.h" -#define MODE_STR(_mode) \ - ((_mode == MON) ? "MON" : \ - (_mode == SVC) ? "SVC" : \ - (_mode == SYS) ? "SYS" : \ - (_mode == USR) ? "USR" : "Unknown") - - -#define FAULT_STR(_s) \ - ((0x01 == (_s)) ? "Alignment fault" : \ - (0x02 == (_s)) ? "Debug event" : \ - (0x03 == (_s)) ? "Access flag fault" : \ - (0x04 == (_s)) ? "Instruction cache maintenance" : \ - (0x05 == (_s)) ? "Translation fault" : \ - (0x06 == (_s)) ? "Access flag fault" : \ - (0x07 == (_s)) ? "Translation fault" : \ - (0x08 == (_s)) ? "Synchronous external abort" : \ - (0x09 == (_s)) ? "Domain fault" : \ - (0x0b == (_s)) ? "Domain fault" : \ - (0x0c == (_s)) ? "External abort on table walk" : \ - (0x0d == (_s)) ? "Permisison fault" : \ - (0x0e == (_s)) ? "Synchronous external abort" : \ - (0x0f == (_s)) ? "Permisison fault" : \ - (0x10 == (_s)) ? "TLB conflict abort" : \ - (0x1c == (_s)) ? "External parity err on table walk" : \ - (0x1e == (_s)) ? "External parity err on table walk" : \ - "Unknown") +extern volatile int _tztest_fail_count; +extern volatile int _tztest_test_count; #define CALL(_f) __svc(0, _f) #define RETURN(_r) __svc(0,(_r)) @@ -120,10 +57,70 @@ typedef struct { *tztest_exception = 0; \ } while (0) +#define TZTEST_SVAL 0xaaaaaaaa +#define TZTEST_NSVAL ~TZTEST_SVAL +#define TZTEST_GET_REG_SECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr & ~SCR_NS); \ + (_val) = _read_##_reg(); \ + } while(0) + +#define TZTEST_GET_REG_NONSECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr | SCR_NS); \ + (_val) = _read_##_reg(); \ + } while(0) + +#define TZTEST_SET_REG_SECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr & ~SCR_NS); \ + _write_##_reg(_val); \ + } while(0) + +#define TZTEST_SET_REG_NONSECURE_BANK(_reg, _val) \ + do { \ + _write_scr(scr | SCR_NS); \ + _write_##_reg(_val); \ + } while(0) + +#define TZTEST_GET_REG_BANKS(_reg, _sval, _nsval) \ + do { \ + TZTEST_GET_REG_SECURE_BANK(_reg, _sval); \ + TZTEST_GET_REG_NONSECURE_BANK(_reg, _nsval);\ + } while(0) + +#define TZTEST_SET_REG_BANKS(_reg, _sval, _nsval) \ + do { \ + TZTEST_SET_REG_SECURE_BANK(_reg, _sval); \ + TZTEST_SET_REG_NONSECURE_BANK(_reg, _nsval);\ + } while(0) + +#define VERIFY_REGISTER_CUSTOM(_reg, _mask, _sval, _nsval) \ + do { \ + uint32_t sval = 0, nsval = 0; \ + uint32_t _reg[2] = {0,0}; \ + printf("\tChecking %s banks... ", #_reg); \ + TZTEST_GET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ + TZTEST_SET_REG_BANKS(_reg, (_sval), (_nsval)); \ + TZTEST_GET_REG_SECURE_BANK(_reg, sval); \ + TZTEST_GET_REG_NONSECURE_BANK(_reg, nsval); \ + TEST_CONDITION(((sval & (_mask)) != (nsval & (_mask))) && \ + (((_sval) & (_mask)) == (sval & (_mask))) && \ + (((_nsval) & (_mask)) == (nsval & (_mask)))); \ + TZTEST_SET_REG_BANKS(_reg, _reg[!SCR_NS], _reg[SCR_NS]); \ + } while(0) + +#define VERIFY_REGISTER(_reg) \ + VERIFY_REGISTER_CUSTOM(_reg, 0xFFFFFFFF, TZTEST_SVAL, TZTEST_NSVAL) + extern volatile int *tztest_exception; +extern volatile int *tztest_exception_addr; extern volatile int *tztest_exception_status; extern volatile int *tztest_fail_count; extern volatile int *tztest_test_count; extern void validate_state(uint32_t, uint32_t); +extern uint32_t _shared_memory_heap_base; +extern uint32_t *nsec_l1_page_table; +extern uint32_t *nsec_l2_page_table; #endif diff --git a/arm/tztest_builtins.h b/arm/tztest_builtins.h index b5f32d3..a1f61f5 100644 --- a/arm/tztest_builtins.h +++ b/arm/tztest_builtins.h @@ -12,6 +12,8 @@ "mov r0, %[r0]\n" \ "mov r1, %[r1]\n" \ "smc 0\n" \ + "mov %[r0], r0\n" \ + "mov %[r1], r1\n" \ : [r0] "+r" (_op), [r1] "+r" (_data) \ ) diff --git a/arm/tztest_common.c b/arm/tztest_common.c deleted file mode 100644 index 2633943..0000000 --- a/arm/tztest_common.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "tztest.h" - -#ifdef DEBUG -void validate_state(uint32_t mode, uint32_t state) -{ - tztest_svc_desc_t desc; - - assert((_read_cpsr() & CPSR_MODE_MASK) == mode); - - CLEAR_SVC_DESC(desc); - __svc(SVC_GET_SECURE_STATE, &desc); - assert(desc.secure_state.state == state); -} -#else -void validate_state(__attribute__((unused)) uint32_t mode, - __attribute__((unused)) uint32_t state) {} -#endif - diff --git a/arm/tztest_mmu.c b/arm/tztest_mmu.c deleted file mode 100644 index 92b0fbe..0000000 --- a/arm/tztest_mmu.c +++ /dev/null @@ -1,32 +0,0 @@ -#include "tztest.h" -#include "tztest_mmu.h" - -void pagetable_add_sections(uint32_t *ttbrn, pagetable_map_entry_t *entries, - uint32_t count) -{ - uint32_t num; /* Number of 1MB sections */ - uint32_t Vidx; /* 1MB Index into page table */ - uint32_t Pidx; /* 1MB Index into page table */ - uint32_t i; - uint32_t shift = SECTION_SHIFT, size = SECTION_SIZE; - - for (i = 0; i < count; i++) { - Vidx = entries[i].va >> shift; - Pidx = entries[i].pa >> shift; - num = ((entries[i].size + (size-1)) & ~(size-1)) >> shift; - for (; num > 0; Vidx++, Pidx++, num--) { - ttbrn[Vidx] = (Pidx << shift) | entries[i].attr; - DEBUG_MSG("Mapped 0x%x to 0x%x in entry ttbrn[%x] = %x\n", - Vidx << shift, Pidx << shift, Vidx, ttbrn[Vidx]); - } - } -} - -void pagetable_init(uint32_t *ttbrn) -{ - int i; - - for (i = 0; i < 4096; i++) { - ttbrn[0] = 0; - } -} diff --git a/arm/tztest_mmu.h b/arm/tztest_mmu.h deleted file mode 100644 index b6f6d21..0000000 --- a/arm/tztest_mmu.h +++ /dev/null @@ -1,47 +0,0 @@ - -#ifndef _TZTEST_MMU_H -#define _TZTEST_MMU_H - -#include "sm.h" - -#define SECTION_SECTION (1 << 1) -#define SECTION_B (1 << 2) -#define SECTION_C (1 << 3) -#define SECTION_NO_EXEC (1 << 4) -#define SECTION_TEX(v) (1 << 12) -#define SECTION_SHARED (1 << 16) -#define SECTION_NOTGLOBAL (1 << 17) -#define SECTION_NONSECURE (1 << 19) -#define SECTION_SIZE 0x100000 -#define SECTION_SHIFT 20 - -/* Fix SCTLR.AFE bit */ - -#define SECTION_P1_RW ((0 << 15) | (1 << 10)) -#define SECTION_P1_RO ((1 << 15) | (1 << 10)) -#define SECTION_P0_RW ((0 << 15) | (3 << 10)) -#define SECTION_P0_RO ((0 << 15) | (2 << 10)) -#define SECTION_P0_NONE ((0 << 15) | (1 << 10)) - -/* These remap description describe the memory region if SCTLR.TRE = 0 - * (no region atrribute remap). - */ -#define SECTION_DEVICE_SHAREABLE (SECTION_B) -#define SECTION_DEVICE_UNSHAREABLE (SECTION_TEX(2)) -#define SECTION_WT_CACHED (SECTION_C) -#define SECTION_WB_CACHED (SECTION_C | SECTION_B) -#define SECTION_UNCACHED (SECTION_TEX(1)) -#define SECTION_WBA_CACHED (SECTION_TEX(1) | SECTION_C | SECTION_B) - -typedef struct { - uint32_t va; - uint32_t pa; - uint32_t size; - uint32_t attr; -} pagetable_map_entry_t; - -extern void pagetable_init(uint32_t *); -extern void pagetable_add_sections(uint32_t *, pagetable_map_entry_t *, - uint32_t); - -#endif diff --git a/arm/tztest_nonsecure.lds.S b/arm/tztest_nonsecure.lds.S index 85a59d8..0296c9c 100644 --- a/arm/tztest_nonsecure.lds.S +++ b/arm/tztest_nonsecure.lds.S @@ -39,13 +39,20 @@ SECTIONS _nsecdata_size = _ram_nsecdata_end - _ram_nsecdata_start; . = ALIGN(STACK_SIZE); + _nsecstack_start = .; nsec_usr_stacktop = . + STACK_SIZE; nsec_und_stacktop = nsec_usr_stacktop + STACK_SIZE; nsec_abt_stacktop = nsec_und_stacktop + STACK_SIZE; nsec_svc_stacktop = nsec_und_stacktop + STACK_SIZE; + _nsecstack_size = nsec_svc_stacktop - _nsecstack_start; + . += 1M; - . = ALIGN(16M); - nsec_l1_page_table = .; + . = ALIGN(1M); + _nsec_l1_page_table = .; + . += 1M; + . = ALIGN(1M); + _nsec_l2_page_table = .; + . += 16M; . = TZTEST_COMMON_HEAP_BASE; _common_memory_heap_base = .; @@ -61,4 +68,6 @@ SECTIONS . += 4; _tztest_exception_status = .; . += 4; + _tztest_exception_addr = .; + . += 4; } diff --git a/arm/tztest_nonsecure_svc.c b/arm/tztest_nonsecure_svc.c deleted file mode 100644 index 7cdbcbb..0000000 --- a/arm/tztest_nonsecure_svc.c +++ /dev/null @@ -1,153 +0,0 @@ -#include "tztest.h" - -uint32_t nsec_dispatch_secure_usr_function(uint32_t (*)(uint32_t), uint32_t); -uint32_t nsec_dispatch_secure_svc_function(uint32_t (*)(uint32_t), uint32_t); -extern uint32_t nsec_l1_page_table; -extern uint32_t _ram_nsectext_start; -extern uint32_t _ram_nsecdata_start; -extern uint32_t _shared_memory_heap_base; -extern uint32_t _common_memory_heap_base; -extern volatile int _tztest_test_count; -extern volatile int _tztest_fail_count; -volatile int *tztest_test_count = &_tztest_test_count; -volatile int *tztest_fail_count = &_tztest_fail_count; -extern volatile int _tztest_exception; -extern volatile int _tztest_exception_status; -volatile int *tztest_exception = &_tztest_exception; -volatile int *tztest_exception_status = &_tztest_exception_status; - -pagetable_map_entry_t nsec_pagetable_entries[] = { - {.va = (uint32_t)&_ram_nsectext_start, .pa = (uint32_t)&_ram_nsectext_start, - .size = SECTION_SIZE, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_WBA_CACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_NONSECURE | - SECTION_SECTION }, - {.va = (uint32_t)&_ram_nsecdata_start, .pa = (uint32_t)&_ram_nsecdata_start, - .size = SECTION_SIZE * 2, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_WBA_CACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_NONSECURE | - SECTION_SECTION }, -}; - -pagetable_map_entry_t mmio_pagetable_entries[] = { - {.va = UART0_BASE, .pa = UART0_BASE, .size = SECTION_SIZE, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_UNCACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_NONSECURE | - SECTION_SECTION }, -}; - -pagetable_map_entry_t heap_pagetable_entries[] = { - {.va = (uint32_t)&_shared_memory_heap_base, - .pa = (uint32_t)&_shared_memory_heap_base, - .size = SECTION_SIZE, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_UNCACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_SECTION }, -}; - -void nsec_svc_handler(volatile uint32_t op, volatile tztest_svc_desc_t *desc) -{ - int ret = 0; - switch (op) { - case SVC_DISPATCH_MONITOR: - op = SMC_DISPATCH_MONITOR; - __smc(op, desc); - break; - case SVC_DISPATCH_SECURE_USR: - DEBUG_MSG("Dispatching secure usr function\n"); - desc->dispatch.ret = - nsec_dispatch_secure_usr_function(desc->dispatch.func, - desc->dispatch.arg); - DEBUG_MSG("Returning from secure usr function, ret = 0x%x\n", - desc->dispatch.ret); - break; - case SVC_DISPATCH_SECURE_SVC: - DEBUG_MSG("Dispatching secure svc function\n"); - desc->dispatch.ret = - nsec_dispatch_secure_svc_function(desc->dispatch.func, - desc->dispatch.arg); - DEBUG_MSG("Returning from secure svc function, ret = 0x%x\n", - desc->dispatch.ret); - break; - case SVC_DISPATCH_NONSECURE_SVC: - DEBUG_MSG("Dispatching nonsecure svc function\n"); - desc->dispatch.ret = desc->dispatch.func(desc->dispatch.arg); - DEBUG_MSG("Returning from nonsecure svc function, ret = 0x%x\n", - desc->dispatch.ret); - break; - case SVC_GET_SECURE_STATE: - /* This SVC handler is only accessible from the nonsecure vector - * table, so unless something went drastically wrong with the - * tables, it should be safe to assume we are in a nonsecure state. - */ - desc->secure_state.state = TZTEST_STATE_NONSECURE; - break; - case SVC_EXIT: - op = SMC_EXIT; - __smc(op, ret); - break; - } -} - -void nsec_undef_handler() { - DEBUG_MSG("Undefined exception taken\n"); - *tztest_exception = CPSR_MODE_UND; - *tztest_exception_status = 0; -} - -void nsec_pabort_handler(int status, DEBUG_ARG int addr) { - DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", status, addr); - *tztest_exception = CPSR_MODE_ABT; - *tztest_exception_status = status & 0x1f; -} - -void nsec_dabort_handler(int status, DEBUG_ARG int addr) { - DEBUG_MSG("Data Abort: %s\n", FAULT_STR(status & 0x1f)); - DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", - status & 0x1f, addr); - *tztest_exception = CPSR_MODE_ABT; - *tztest_exception_status = status & 0x1f; -} - -tztest_smc_desc_t smc_desc; -uint32_t nsec_dispatch_secure_usr_function(uint32_t (*func)(uint32_t), - uint32_t arg) -{ - volatile int r0 = SMC_DISPATCH_SECURE_USR; - tztest_smc_desc_t *desc_p = &smc_desc; - - smc_desc.dispatch.func = func; - smc_desc.dispatch.arg = arg; - DEBUG_MSG("Entered\n"); - __smc(r0, desc_p); - DEBUG_MSG("Exiting, func = 0x%x\n", smc_desc.dispatch.func); - return smc_desc.dispatch.ret; -} - -uint32_t nsec_dispatch_secure_svc_function(uint32_t (*func)(uint32_t), - uint32_t arg) -{ - volatile int op = SMC_DISPATCH_SECURE_SVC; - tztest_smc_desc_t desc, *desc_p = &desc; - - desc.dispatch.func = func; - desc.dispatch.arg = arg; - DEBUG_MSG("Entered op = %x\n", op); - __smc(op, desc_p); - DEBUG_MSG("Exiting\n"); - return desc.dispatch.ret; -} - -void tztest_nonsecure_pagetable_init() -{ - uint32_t *table = &nsec_l1_page_table; - uint32_t count; - - pagetable_init(table); - - pagetable_add_sections(table, mmio_pagetable_entries, 1); - count = sizeof(nsec_pagetable_entries) / sizeof(nsec_pagetable_entries[0]); - pagetable_add_sections(table, nsec_pagetable_entries, count); - pagetable_add_sections(table, heap_pagetable_entries, 1); -} - -#endif diff --git a/arm/tztest_secure.lds.S b/arm/tztest_secure.lds.S index e02f7d5..6593a5f 100644 --- a/arm/tztest_secure.lds.S +++ b/arm/tztest_secure.lds.S @@ -17,53 +17,71 @@ _ram_nsec_base = RAM_NSEC_BASE; SECTIONS { - . = FLASH_SEC_BASE; - .boot : { arm/tzboot.o } - _eboot = .; + . = FLASH_SEC_BASE; + .boot : { arm/tzboot.o } + _eboot = .; - _flash_sectext_start = .; - . = RAM_SEC_BASE; - _ram_sec_base = .; - _ram_sectext_start = .; - .text : AT ( _flash_sectext_start ) { *(.text); } - _ram_sectext_end = .; - _sectext_size = SIZEOF(.text); + _flash_secvecs_start = .; + . = RAM_SEC_BASE; + _ram_sec_base = .; - _flash_secdata_start = _flash_sectext_start + _sectext_size; - . = ALIGN(1M); - _ram_secdata_start = .; - .rodata : AT ( _flash_secdata_start ) { *(.rodata); } - .data : { *(.data); } - .bss : { *(.bss); } - _ram_secdata_end = .; - _secdata_size = _ram_secdata_end - _ram_secdata_start; + /* We separate out the secure vector table and level 1 handlers, so we + * can map it to hivecs (0xffff0000). + */ + _ram_secvecs_start = .; + .vectors : AT ( _flash_secvecs_start ) { *(.vectors); } + _ram_secvecs_end = .; + _secvecs_size = _ram_secvecs_end - _ram_secvecs_start; - . = ALIGN(STACK_SIZE); - sec_usr_stacktop = . + STACK_SIZE; - sec_und_stacktop = sec_usr_stacktop + STACK_SIZE; - sec_abt_stacktop = sec_und_stacktop + STACK_SIZE; - sec_svc_stacktop = sec_und_stacktop + STACK_SIZE; - boot_stacktop = sec_svc_stacktop; - mon_stacktop = sec_svc_stacktop + STACK_SIZE; + /* Page align the text section as we map it differently than the above + * vector text. + */ + . = ALIGN(0x1000); + _flash_sectext_start = _flash_secvecs_start + _secvecs_size; + _ram_sectext_start = .; + .text : AT ( _flash_sectext_start ) { *(.text); } + _ram_sectext_end = .; + _sectext_size = _ram_sectext_end - _ram_sectext_start; - . = ALIGN(1M); - secure_memory_heap = .; + _flash_secdata_start = _flash_sectext_start + _sectext_size; + . = ALIGN(1M); + _ram_secdata_start = .; + .rodata : AT ( _flash_secdata_start ) { *(.rodata); } + .data : { *(.data); } + .bss : { *(.bss); } + _ram_secdata_end = .; + _secdata_size = _ram_secdata_end - _ram_secdata_start; - . = ALIGN(16M); - sec_l1_page_table = .; + . = ALIGN(STACK_SIZE); + _secstack_start = .; + sec_usr_stacktop = . + STACK_SIZE; + sec_und_stacktop = sec_usr_stacktop + STACK_SIZE; + sec_abt_stacktop = sec_und_stacktop + STACK_SIZE; + sec_svc_stacktop = sec_und_stacktop + STACK_SIZE; + boot_stacktop = sec_svc_stacktop; + mon_stacktop = sec_svc_stacktop + STACK_SIZE; + _secstack_size = mon_stacktop - _secstack_start; - . = TZTEST_COMMON_HEAP_BASE; - _common_memory_heap_base = .; + . = ALIGN(1M); + secure_memory_heap = .; - . = TZTEST_SHARED_HEAP_BASE; - _shared_memory_heap_base = .; - . += 4; - _tztest_test_count = .; - . += 4; - _tztest_fail_count = .; - . += 4; - _tztest_exception = .; - . += 4; - _tztest_exception_status = .; - . += 4; + . = ALIGN(16M); + _sec_l1_page_table = .; + + . = TZTEST_COMMON_HEAP_BASE; + _common_memory_heap_base = .; + + . = TZTEST_SHARED_HEAP_BASE; + _shared_memory_heap_base = .; + . += 4; + _tztest_test_count = .; + . += 4; + _tztest_fail_count = .; + . += 4; + _tztest_exception = .; + . += 4; + _tztest_exception_status = .; + . += 4; + _tztest_exception_addr = .; + . += 4; } diff --git a/arm/tztest_secure_svc.c b/arm/tztest_secure_svc.c deleted file mode 100644 index 35db21b..0000000 --- a/arm/tztest_secure_svc.c +++ /dev/null @@ -1,206 +0,0 @@ -#include "tztest.h" - -/* Make the below globals volatile as found that the compiler uses the - * register value ratherh than the memory value making it look like the writes - * actually happened. - */ -extern int _ram_nsec_base; - -int dispatch_secure_usr(int, int); -void tztest_secure_svc_loop(int initial_r0, int initial_r1); -void *sec_allocate_secure_memory(int); -extern uint32_t sec_l1_page_table; -extern uint32_t _ram_sectext_start; -extern uint32_t _ram_secdata_start; -extern uint32_t _shared_memory_heap_base; -extern uint32_t _common_memory_heap_base; -extern volatile int _tztest_exception; -extern volatile int _tztest_exception_status; -extern volatile int _tztest_test_count; -extern volatile int _tztest_fail_count; -volatile int *tztest_test_count = &_tztest_test_count; -volatile int *tztest_fail_count = &_tztest_fail_count; -volatile int *tztest_exception = &_tztest_exception; -volatile int *tztest_exception_addr = 0; -volatile int *tztest_exception_status = &_tztest_exception_status; - -pagetable_map_entry_t sec_pagetable_entries[] = { - {.va = (uint32_t)&_ram_sectext_start, .pa = (uint32_t)&_ram_sectext_start, - .size = SECTION_SIZE, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_WBA_CACHED | - SECTION_P1_RO | SECTION_P0_RO | SECTION_SECTION }, - {.va = (uint32_t)&_ram_secdata_start, .pa = (uint32_t)&_ram_secdata_start, - .size = SECTION_SIZE * 2, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_WBA_CACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_SECTION }, -}; - -pagetable_map_entry_t nsec_pagetable_entries[] = { - {.va = (uint32_t)&_ram_nsec_base, .pa = (uint32_t)&_ram_nsec_base, - .size = SECTION_SIZE * 2, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_WBA_CACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_NONSECURE | - SECTION_SECTION }, -}; - -pagetable_map_entry_t mmio_pagetable_entries[] = { - {.va = UART0_BASE, .pa = UART0_BASE, .size = SECTION_SIZE, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_UNCACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_NONSECURE | - SECTION_SECTION }, -}; - -pagetable_map_entry_t heap_pagetable_entries[] = { - {.va = (uint32_t)&_shared_memory_heap_base, - .pa = (uint32_t)&_shared_memory_heap_base, - .size = SECTION_SIZE, - .attr = SECTION_SHARED | SECTION_NOTGLOBAL | SECTION_UNCACHED | - SECTION_P1_RW | SECTION_P0_RW | SECTION_SECTION }, -}; - -void sec_svc_handler(volatile uint32_t op, volatile tztest_svc_desc_t *desc) -{ - DEBUG_MSG("Entered\n"); - switch (op) { - case SVC_GET_SECURE_STATE: - /* This SVC handler is only accessible from the secure vector - * table, so unless something went drastically wrong with the - * tables, it should be safe to assume we are in a nonsecure state. - */ - desc->secure_state.state = TZTEST_STATE_SECURE; - break; - } - DEBUG_MSG("Exiting\n"); - return; -} - -void sec_undef_handler() { - DEBUG_MSG("Undefined exception taken\n"); - *tztest_exception = CPSR_MODE_UND; - *tztest_exception_status = 0; -} - -void sec_pabort_handler(int status, int addr) { - DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", status, addr); - *tztest_exception = CPSR_MODE_ABT; - *tztest_exception_addr = addr; - *tztest_exception_status = status & 0x1f; -} - -void sec_dabort_handler(int status, int addr) { - DEBUG_MSG("Data Abort: %s\n", FAULT_STR(status & 0x1f)); - DEBUG_MSG("status = 0x%x\taddress = 0x%x\n", - status & 0x1f, addr); - *tztest_exception = CPSR_MODE_ABT; - *tztest_exception_addr = addr; - *tztest_exception_status = status & 0x1f; -} - -int secure_test_var = 42; - -void check_init_mode() -{ - printf("\nValidating startup state:\n"); - - printf("\tChecking for security extension ..."); - int idpfr1 = 0; - /* Read the ID_PFR1 CP register and check that it is marked for support of - * the security extension. - */ - __mrc(15, 0, idpfr1, 0, 1, 1); - if (0x10 != (idpfr1 & 0xf0)) { - printf("FAILED\n"); - DEBUG_MSG("current IDPFR1 (%d) != expected IDPFR1 (%d)\n", - (idpfr1 & 0xf0), 0x10); - assert(0x10 == (idpfr1 & 0xf0)); - } else { - printf("PASSED\n"); - } - - printf("\tChecking initial processor mode... "); - if (CPSR_MODE_SVC != (_read_cpsr() & 0x1f)) { - printf("FAILED\n"); - DEBUG_MSG("current CPSR (%d) != expected CPSR (%d)\n", - (_read_cpsr() & 0x1f), CPSR_MODE_SVC); - assert(CPSR_MODE_SVC == (_read_cpsr() & 0x1f)); - } else { - printf("PASSED\n"); - } - - printf("\tChecking initial security state... "); - if (0 != (_read_scr() & SCR_NS)) { - printf("Failed\n"); - DEBUG_MSG("current SCR.NS (%d) != expected SCR.NS (%d)\n", - (_read_cpsr() & SCR_NS), 0); - assert(0 == (_read_scr() & SCR_NS)); - } else { - printf("PASSED\n"); - } -} - -void tztest_secure_svc_loop(int initial_op, int initial_data) -{ - volatile int op = initial_op; - tztest_smc_desc_t *data = (tztest_smc_desc_t *)initial_data; - uint32_t (*func)(uint32_t); - - DEBUG_MSG("Initial call\n"); - - while (SMC_EXIT != op) { - switch (op) { - case SMC_DISPATCH_SECURE_USR: - DEBUG_MSG("Dispatching secure USR function\n"); - data->dispatch.ret = - dispatch_secure_usr((int)data->dispatch.func, - data->dispatch.arg); - DEBUG_MSG("Returned from secure USR dispatch\n"); - break; - case SMC_DISPATCH_SECURE_SVC: - func = (uint32_t (*)())data->dispatch.func; - DEBUG_MSG("Dispatching secure SVC function\n"); - data->dispatch.ret = func(data->dispatch.arg); - DEBUG_MSG("Returned from secure SVC dispatch\n"); - break; - } - __smc(op, data); - DEBUG_MSG("Handling smc op 0x%x\n", op); - } - - DEBUG_MSG("Exiting\n"); -} - -void tztest_secure_pagetable_init() -{ - uint32_t *table = &sec_l1_page_table; - uint32_t count; - - pagetable_init(table); - - pagetable_add_sections(table, mmio_pagetable_entries, 1); - count = sizeof(sec_pagetable_entries) / sizeof(sec_pagetable_entries[0]); - pagetable_add_sections(table, sec_pagetable_entries, count); - count = sizeof(nsec_pagetable_entries) / sizeof(nsec_pagetable_entries[0]); - pagetable_add_sections(table, nsec_pagetable_entries, 1); - pagetable_add_sections(table, heap_pagetable_entries, 1); -} - -void tztest_secure_svc_init_monitor() -{ - struct sm_nsec_ctx *nsec_ctx; - - - /* Set-up the non-secure context so that the switch to nonsecure state - * resumes at initiallizing the nonsecure svc mode. - */ - nsec_ctx = sm_get_nsec_ctx(); - nsec_ctx->mon_lr = (uint32_t)&_ram_nsec_base; - nsec_ctx->mon_spsr = CPSR_MODE_SVC | CPSR_I; -} - -void tztest_dispatch_monitor(tztest_smc_desc_t *desc) -{ - uint32_t (*func)(uint32_t) = desc->dispatch.func; - DEBUG_MSG("Entered\n"); - func(desc->dispatch.arg); - DEBUG_MSG("Exiting\n"); -} @@ -5,8 +5,9 @@ ld=ld objcopy=objcopy ar=ar arch=arm -plat=vexpress -cross_prefix= +plat=vexpress-a15 +cpu=cortex-a15 +cross_prefix=arm-linux-gnueabi- usage() { cat <<-EOF @@ -15,7 +16,7 @@ usage() { Options include: --arch=ARCH architecture to compile for ($arch) --plat=PLATFORM platform to compile for ($plat) - --processor=PROCESSOR processor to compile for ($arch) + --cpu=PROCESSOR cpu to compile for ($arch) --cross-prefix=PREFIX cross compiler prefix --cc=CC c compiler to use ($cc) --ld=LD ld linker to use ($ld) @@ -37,8 +38,8 @@ while [[ "$1" = -* ]]; do --plat) plat="$arg" ;; - --processor) - processor="$arg" + --cpu) + cpu="$arg" ;; --cross-prefix) cross_prefix="$arg" @@ -57,10 +58,10 @@ while [[ "$1" = -* ]]; do ;; esac done -[ -z "$processor" ] && processor="$arch" +[ -z "$cpu" ] && cpu="$arch" -if [ "$processor" = "arm" ]; then - processor="cortex-a15" +if [ "$cpu" = "arm" ]; then + cpu="cortex-a15" fi # check for dependent 32 bit libraries @@ -85,7 +86,7 @@ fi cat <<EOF > config.mak ARCH=$arch PLAT=$plat -PROCESSOR=$processor +PROCESSOR=$cpu CC=$cross_prefix$cc LD=$cross_prefix$ld OBJCOPY=$cross_prefix$objcopy diff --git a/lib/libcflat/argv.c b/lib/libcflat/argv.c deleted file mode 100644 index 078a05f..0000000 --- a/lib/libcflat/argv.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "libcflat.h" - -int __argc; -char *__argv[100]; -char *__args; -char __args_copy[1000]; - -static bool isblank(char p) -{ - return p == ' ' || p == '\t'; -} - -static char *skip_blanks(char *p) -{ - while (isblank(*p)) - ++p; - return p; -} - -void __setup_args(void) -{ - char *args = __args; - char **argv = __argv; - char *p = __args_copy; - - while (*(args = skip_blanks(args)) != '\0') { - *argv++ = p; - while (*args != '\0' && !isblank(*args)) - *p++ = *args++; - *p++ = '\0'; - } - __argc = argv - __argv; -} - -void setup_args(char *args) -{ - __args = args; - __setup_args(); -} diff --git a/lib/libcflat/arm/asm-offsets.c b/lib/libcflat/arm/asm-offsets.c deleted file mode 100644 index a9c349d..0000000 --- a/lib/libcflat/arm/asm-offsets.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Adapted from arch/arm/kernel/asm-offsets.c - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "asm/ptrace.h" - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) -#define OFFSET(sym, str, mem) DEFINE(sym, offsetof(struct str, mem)) -#define COMMENT(x) asm volatile("\n->#" x) -#define BLANK() asm volatile("\n->" : : ) - -int main(void) -{ - OFFSET(S_R0, pt_regs, ARM_r0); - OFFSET(S_R1, pt_regs, ARM_r1); - OFFSET(S_R2, pt_regs, ARM_r2); - OFFSET(S_R3, pt_regs, ARM_r3); - OFFSET(S_R4, pt_regs, ARM_r4); - OFFSET(S_R5, pt_regs, ARM_r5); - OFFSET(S_R6, pt_regs, ARM_r6); - OFFSET(S_R7, pt_regs, ARM_r7); - OFFSET(S_R8, pt_regs, ARM_r8); - OFFSET(S_R9, pt_regs, ARM_r9); - OFFSET(S_R10, pt_regs, ARM_r10); - OFFSET(S_FP, pt_regs, ARM_fp); - OFFSET(S_IP, pt_regs, ARM_ip); - OFFSET(S_SP, pt_regs, ARM_sp); - OFFSET(S_LR, pt_regs, ARM_lr); - OFFSET(S_PC, pt_regs, ARM_pc); - OFFSET(S_PSR, pt_regs, ARM_cpsr); - OFFSET(S_OLD_R0, pt_regs, ARM_ORIG_r0); - DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); - return 0; -} diff --git a/lib/libcflat/arm/asm/asm-offsets.h b/lib/libcflat/arm/asm/asm-offsets.h deleted file mode 100644 index c2ff2ba..0000000 --- a/lib/libcflat/arm/asm/asm-offsets.h +++ /dev/null @@ -1 +0,0 @@ -#include "generated/asm-offsets.h" diff --git a/lib/libcflat/arm/asm/barrier.h b/lib/libcflat/arm/asm/barrier.h deleted file mode 100644 index acaeab5..0000000 --- a/lib/libcflat/arm/asm/barrier.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ASMARM_BARRIER_H_ -#define _ASMARM_BARRIER_H_ -/* - * Adapted form arch/arm/include/asm/barrier.h - */ - -#define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory") -#define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory") -#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory") - -#define mb() dsb() -#define rmb() dsb() -#define wmb() dsb(st) -#define smp_mb() dmb(ish) -#define smp_rmb() smp_mb() -#define smp_wmb() dmb(ishst) - -#endif /* _ASMARM_BARRIER_H_ */ diff --git a/lib/libcflat/arm/asm/cp15.h b/lib/libcflat/arm/asm/cp15.h deleted file mode 100644 index 7690a48..0000000 --- a/lib/libcflat/arm/asm/cp15.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _ASMARM_CP15_H_ -#define _ASMARM_CP15_H_ -/* - * From the Linux kernel arch/arm/include/asm/cp15.h - * - * CR1 bits (CP#15 CR1) - */ -#define CR_M (1 << 0) /* MMU enable */ -#define CR_A (1 << 1) /* Alignment abort enable */ -#define CR_C (1 << 2) /* Dcache enable */ -#define CR_W (1 << 3) /* Write buffer enable */ -#define CR_P (1 << 4) /* 32-bit exception handler */ -#define CR_D (1 << 5) /* 32-bit data address range */ -#define CR_L (1 << 6) /* Implementation defined */ -#define CR_B (1 << 7) /* Big endian */ -#define CR_S (1 << 8) /* System MMU protection */ -#define CR_R (1 << 9) /* ROM MMU protection */ -#define CR_F (1 << 10) /* Implementation defined */ -#define CR_Z (1 << 11) /* Implementation defined */ -#define CR_I (1 << 12) /* Icache enable */ -#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */ -#define CR_RR (1 << 14) /* Round Robin cache replacement */ -#define CR_L4 (1 << 15) /* LDR pc can set T bit */ -#define CR_DT (1 << 16) -#define CR_HA (1 << 17) /* Hardware management of Access Flag */ -#define CR_IT (1 << 18) -#define CR_ST (1 << 19) -#define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */ -#define CR_U (1 << 22) /* Unaligned access operation */ -#define CR_XP (1 << 23) /* Extended page tables */ -#define CR_VE (1 << 24) /* Vectored interrupts */ -#define CR_EE (1 << 25) /* Exception (Big) Endian */ -#define CR_TRE (1 << 28) /* TEX remap enable */ -#define CR_AFE (1 << 29) /* Access flag enable */ -#define CR_TE (1 << 30) /* Thumb exception enable */ - -#endif /* _ASMARM_CP15_H_ */ diff --git a/lib/libcflat/arm/asm/processor.h b/lib/libcflat/arm/asm/processor.h deleted file mode 100644 index b7d3be0..0000000 --- a/lib/libcflat/arm/asm/processor.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _ASMARM_PROCESSOR_H_ -#define _ASMARM_PROCESSOR_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "ptrace.h" - -enum vector { - EXCPTN_RST, - EXCPTN_UND, - EXCPTN_SVC, - EXCPTN_PABT, - EXCPTN_DABT, - EXCPTN_ADDREXCPTN, - EXCPTN_IRQ, - EXCPTN_FIQ, - EXCPTN_MAX, -}; - -typedef void (*exception_fn)(struct pt_regs *); -extern void install_exception_handler(enum vector v, exception_fn fn); - -extern void show_regs(struct pt_regs *regs); -extern void *get_sp(void); - -static inline unsigned long current_cpsr(void) -{ - unsigned long cpsr; - asm volatile("mrs %0, cpsr" : "=r" (cpsr)); - return cpsr; -} - -#define current_mode() (current_cpsr() & MODE_MASK) - -extern void -phys_start_usr(size_t stacksize, void (*func)(void *arg), void *arg); - -#endif /* _ASMARM_PROCESSOR_H_ */ diff --git a/lib/libcflat/arm/asm/ptrace.h b/lib/libcflat/arm/asm/ptrace.h deleted file mode 100644 index 3a4c753..0000000 --- a/lib/libcflat/arm/asm/ptrace.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef _ASMARM_PTRACE_H_ -#define _ASMARM_PTRACE_H_ -/* - * Adapted from Linux kernel headers - * arch/arm/include/asm/ptrace.h - * arch/arm/include/uapi/asm/ptrace.h - */ - -/* - * PSR bits - */ -#define USR_MODE 0x00000010 -#define SVC_MODE 0x00000013 -#define FIQ_MODE 0x00000011 -#define IRQ_MODE 0x00000012 -#define ABT_MODE 0x00000017 -#define HYP_MODE 0x0000001a -#define UND_MODE 0x0000001b -#define SYSTEM_MODE 0x0000001f -#define MODE32_BIT 0x00000010 -#define MODE_MASK 0x0000001f - -#define PSR_T_BIT 0x00000020 /* >= V4T, but not V7M */ -#define PSR_F_BIT 0x00000040 /* >= V4, but not V7M */ -#define PSR_I_BIT 0x00000080 /* >= V4, but not V7M */ -#define PSR_A_BIT 0x00000100 /* >= V6, but not V7M */ -#define PSR_E_BIT 0x00000200 /* >= V6, but not V7M */ -#define PSR_J_BIT 0x01000000 /* >= V5J, but not V7M */ -#define PSR_Q_BIT 0x08000000 /* >= V5E, including V7M */ -#define PSR_V_BIT 0x10000000 -#define PSR_C_BIT 0x20000000 -#define PSR_Z_BIT 0x40000000 -#define PSR_N_BIT 0x80000000 - -/* - * Groups of PSR bits - */ -#define PSR_f 0xff000000 /* Flags */ -#define PSR_s 0x00ff0000 /* Status */ -#define PSR_x 0x0000ff00 /* Extension */ -#define PSR_c 0x000000ff /* Control */ - -/* - * ARMv7 groups of PSR bits - */ -#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ -#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ -#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ -#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ - -#ifndef __ASSEMBLY__ -#include "libcflat.h" - -struct pt_regs { - unsigned long uregs[18]; -}; - -#define ARM_cpsr uregs[16] -#define ARM_pc uregs[15] -#define ARM_lr uregs[14] -#define ARM_sp uregs[13] -#define ARM_ip uregs[12] -#define ARM_fp uregs[11] -#define ARM_r10 uregs[10] -#define ARM_r9 uregs[9] -#define ARM_r8 uregs[8] -#define ARM_r7 uregs[7] -#define ARM_r6 uregs[6] -#define ARM_r5 uregs[5] -#define ARM_r4 uregs[4] -#define ARM_r3 uregs[3] -#define ARM_r2 uregs[2] -#define ARM_r1 uregs[1] -#define ARM_r0 uregs[0] -#define ARM_ORIG_r0 uregs[17] - -#define user_mode(regs) \ - (((regs)->ARM_cpsr & 0xf) == 0) - -#define processor_mode(regs) \ - ((regs)->ARM_cpsr & MODE_MASK) - -#define interrupts_enabled(regs) \ - (!((regs)->ARM_cpsr & PSR_I_BIT)) - -#define fast_interrupts_enabled(regs) \ - (!((regs)->ARM_cpsr & PSR_F_BIT)) - -#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0)) - -static inline unsigned long regs_get_register(struct pt_regs *regs, - unsigned int offset) -{ - if (offset > MAX_REG_OFFSET) - return 0; - return *(unsigned long *)((unsigned long)regs + offset); -} - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_PTRACE_H_ */ diff --git a/lib/libcflat/arm/asm/semihosting.h b/lib/libcflat/arm/asm/semihosting.h deleted file mode 100644 index ba13036..0000000 --- a/lib/libcflat/arm/asm/semihosting.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2012 Linaro Limited - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of Linaro Limited nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - */ - -#ifndef SEMIHOSTING_H -#define SEMIHOSTING_H - -#define SYS_OPEN 1 -#define OPEN_RDONLY 1 -#define SYS_CLOSE 2 -#define SYS_WRITE0 4 -#define SYS_WRITE 5 -#define SYS_READ 6 -#define SYS_FLEN 0x0C -#define SYS_GET_CMDLINE 0x15 -#define SYS_REPORTEXC 0x18 -#define REPORTEXC_REASON_APP_EXIT 0x20026 -#define SEMIHOSTING_SVC 0x123456 /* SVC comment field for semihosting */ - -#ifndef __ASSEMBLER__ - -int __semi_call(int id, ...); -int semi_open(char const *filename, int mode); -int semi_close(int fd); -int semi_write0(char const *string); -int semi_read(int fd, char *buffer, int length); -int semi_flen(int fd); -int semi_get_cmdline(char *buffer, int size, int *length); -int semi_reportexc(int reason); -void semi_fatal(char const *message); -void semi_exit(void); -/* semi_load_file: *dest is advanced to point to the end of the loaded data */ -int semi_load_file(void **dest, unsigned *size, char const *filename); - -#endif /* ! __ASSEMBLER__ */ - -#endif /* ! SEMIHOSTING_H */ diff --git a/lib/libcflat/arm/asm/setup.h b/lib/libcflat/arm/asm/setup.h deleted file mode 100644 index 8aedf6e..0000000 --- a/lib/libcflat/arm/asm/setup.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _ASMARM_SETUP_H_ -#define _ASMARM_SETUP_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -#define NR_CPUS 8 -extern u32 cpus[NR_CPUS]; -extern int nr_cpus; - -typedef u64 phys_addr_t; - -/* - * memregions implement a very simple allocator which allows physical - * memory to be partitioned into regions until all memory is allocated. - * Also, as long as not all memory has been allocated, one region (the - * highest indexable region) is used to represent the start and size of - * the remaining free memory. This means that there will always be a - * minimum of two regions: one for the unit test code, initially loaded - * at the base of physical memory (PHYS_OFFSET), and another for the - * remaining free memory. - * - * Note: This is such a simple allocator that there is no way to free - * a memregion. For more complicated memory management a single region - * can be allocated, but then have its memory managed by a more - * sophisticated allocator, e.g. a page allocator. - */ -#define NR_MEMREGIONS 16 -struct memregion { - phys_addr_t addr; - phys_addr_t size; - bool free; -}; - -extern struct memregion memregions[NR_MEMREGIONS]; -extern int nr_memregions; - -/* - * memregion_new returns a new memregion of size @size, or NULL if - * there isn't enough free memory to satisfy the request. - */ -extern struct memregion *memregion_new(phys_addr_t size); - -/* - * memregions_show outputs all memregions with the following format - * <start_addr>-<end_addr> [<USED|FREE>] - */ -extern void memregions_show(void); - -#define PHYS_OFFSET ({ memregions[0].addr; }) -#define PHYS_SHIFT 40 -#define PHYS_SIZE (1ULL << PHYS_SHIFT) -#define PHYS_MASK (PHYS_SIZE - 1ULL) - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE - 1UL)) -#define PAGE_ALIGN(addr) (((addr) + (PAGE_SIZE-1UL)) & PAGE_MASK) - -#endif /* _ASMARM_SETUP_H_ */ diff --git a/lib/libcflat/arm/asm/spinlock.h b/lib/libcflat/arm/asm/spinlock.h deleted file mode 100644 index 2118a4b..0000000 --- a/lib/libcflat/arm/asm/spinlock.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASMARM_SPINLOCK_H_ -#define _ASMARM_SPINLOCK_H_ - -struct spinlock { - int v; -}; - -extern void spin_lock(struct spinlock *lock); -extern void spin_unlock(struct spinlock *lock); - -#endif /* _ASMARM_SPINLOCK_H_ */ diff --git a/lib/libcflat/arm/io.c b/lib/libcflat/arm/io.c deleted file mode 100644 index f02c4a8..0000000 --- a/lib/libcflat/arm/io.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Each architecture must implement puts() and exit() with the I/O - * devices exposed from QEMU, e.g. pl011 and virtio-testdev. That's - * what's done here, along with initialization functions for those - * devices. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "devicetree.h" -#include "virtio-testdev.h" -#include "asm/spinlock.h" -#include "asm/io.h" - -extern void halt(int code); - -/* - * Use this guess for the pl011 base in order to make an attempt at - * having earlier printf support. We'll overwrite it with the real - * base address that we read from the device tree later. - */ -//#define QEMU_MACH_VIRT_PL011_BASE 0x09000000UL -#define QEMU_MACH_VIRT_PL011_BASE 0x1c090000UL - -static struct spinlock uart_lock; -static volatile u8 *uart0_base = (u8 *)QEMU_MACH_VIRT_PL011_BASE; - -static void uart0_init(void) -{ - const char *compatible = "arm,pl011"; - struct dt_pbus_reg base; - int ret; - - ret = dt_pbus_get_base_compatible(compatible, &base); - assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); - - if (ret) { - printf("%s: %s not found in the device tree, aborting...\n", - __func__, compatible); - abort(); - } - - uart0_base = ioremap(base.addr, base.size); -} - -void io_init(void) -{ - uart0_init(); - virtio_testdev_init(); -} - -void puts(const char *s) -{ - spin_lock(&uart_lock); - while (*s) - writeb(*s++, uart0_base); - spin_unlock(&uart_lock); -} - -void exit(int code) -{ - virtio_testdev_exit(code); - halt(code); -} diff --git a/lib/libcflat/arm/processor.c b/lib/libcflat/arm/processor.c deleted file mode 100644 index 47e290b..0000000 --- a/lib/libcflat/arm/processor.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * processor control and status functions - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "asm/setup.h" -#include "asm/ptrace.h" -#include "asm/processor.h" - -static const char *processor_modes[] = { - "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , - "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , - "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", - "UK12_26", "UK13_26", "UK14_26", "UK15_26", - "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , - "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , - "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , - "UK12_32", "UK13_32", "UK14_32", "SYS_32" -}; - -static char *vector_names[] = { - "rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq" -}; - -void show_regs(struct pt_regs *regs) -{ - unsigned long flags; - char buf[64]; - - printf("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" - "sp : %08lx ip : %08lx fp : %08lx\n", - regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, - regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); - printf("r10: %08lx r9 : %08lx r8 : %08lx\n", - regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); - printf("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", - regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4); - printf("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", - regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); - - flags = regs->ARM_cpsr; - buf[0] = flags & PSR_N_BIT ? 'N' : 'n'; - buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z'; - buf[2] = flags & PSR_C_BIT ? 'C' : 'c'; - buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; - buf[4] = '\0'; - - printf("Flags: %s IRQs o%s FIQs o%s Mode %s\n", - buf, interrupts_enabled(regs) ? "n" : "ff", - fast_interrupts_enabled(regs) ? "n" : "ff", - processor_modes[processor_mode(regs)]); - - if (!user_mode(regs)) { - unsigned int ctrl, transbase, dac; - asm volatile( - "mrc p15, 0, %0, c1, c0\n" - "mrc p15, 0, %1, c2, c0\n" - "mrc p15, 0, %2, c3, c0\n" - : "=r" (ctrl), "=r" (transbase), "=r" (dac)); - printf("Control: %08x Table: %08x DAC: %08x\n", - ctrl, transbase, dac); - } -} - -void *get_sp(void) -{ - register unsigned long sp asm("sp"); - return (void *)sp; -} - -static exception_fn exception_handlers[EXCPTN_MAX]; - -void install_exception_handler(enum vector v, exception_fn fn) -{ - if (v < EXCPTN_MAX) - exception_handlers[v] = fn; -} - -void do_handle_exception(enum vector v, struct pt_regs *regs) -{ - if (v < EXCPTN_MAX && exception_handlers[v]) { - exception_handlers[v](regs); - return; - } - - if (v < EXCPTN_MAX) - printf("Unhandled exception %d (%s)\n", v, vector_names[v]); - else - printf("%s called with vector=%d\n", __func__, v); - - printf("Exception frame registers:\n"); - show_regs(regs); - abort(); -} - -void phys_start_usr(size_t stacksize, void (*func)(void *arg), void *arg) -{ - struct memregion *m = memregion_new(stacksize); - unsigned long sp_usr = (unsigned long)(m->addr + m->size); - - sp_usr &= (~7UL); /* stack ptr needs 8-byte alignment */ - - asm volatile( - "mrs r0, cpsr\n" - "bic r0, #" xstr(MODE_MASK) "\n" - "orr r0, #" xstr(USR_MODE) "\n" - "msr cpsr_c, r0\n" - "mov r0, %0\n" - "mov sp, %1\n" - "mov pc, %2\n" - :: "r" (arg), "r" (sp_usr), "r" (func) : "r0"); -} diff --git a/lib/libcflat/arm/semihosting.c b/lib/libcflat/arm/semihosting.c deleted file mode 100644 index 7b4af2b..0000000 --- a/lib/libcflat/arm/semihosting.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2012 Linaro Limited - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of Linaro Limited nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - */ - -#include "semihosting.h" -#include "libcflat.h" - -int semi_open(char const *filename, int mode) -{ - struct { - char const *filename; - int mode; - int filename_length; - } args; - - args.filename = filename; - args.mode = mode; - args.filename_length = strlen(filename); - - return __semi_call(SYS_OPEN, &args); -} - -int semi_close(int fd) -{ - return __semi_call(SYS_CLOSE, &fd); -} - -int semi_write0(char const *string) -{ - return __semi_call(SYS_WRITE0, string); -} - -typedef struct { - int fd; - char *buffer; - int length; -} args_t; - -int semi_write(int fd, char *buffer, int length) -{ - args_t args; - - args.fd = fd; - args.buffer = buffer; - args.length = length; - - return __semi_call(SYS_WRITE, &args); -} - -int semi_read(int fd, char *buffer, int length) -{ - struct { - int fd; - char *buffer; - int length; - } args; - - args.fd = fd; - args.buffer = buffer; - args.length = length; - - return __semi_call(SYS_READ, &args); -} - -int semi_flen(int fd) -{ - return __semi_call(SYS_FLEN, &fd); -} - -int semi_get_cmdline(char *buffer, int size, int *length) -{ - int result; - struct { - char *buffer; - int size; - } args; - - args.buffer = buffer; - args.size = size; - - result = __semi_call(SYS_GET_CMDLINE, &args); - if(result) - return result; - - if(length) - *length = args.size; - - return 0; -} - -int semi_reportexc(int reason) -{ - return __semi_call(SYS_REPORTEXC, (void *)reason); -} - -void semi_exit(void) -{ - semi_reportexc(REPORTEXC_REASON_APP_EXIT); - while(1); /* should not be reached */ -} - -void semi_fatal(char const *message) -{ - semi_write0(message); - semi_exit(); -} - -int semi_load_file(void **dest, unsigned *size, char const *filename) -{ - int result = -1; /* fail by default */ - int fd = -1; - int filesize; - - fd = semi_open(filename, OPEN_RDONLY); - if(fd == -1) { - semi_write0("Cannot open file: "); - goto out; - } - - filesize = semi_flen(fd); - if(filesize == -1) { - semi_write0("Cannot get file size for: "); - goto out; - } - - if(semi_read(fd, *dest, filesize)) { - semi_write0("Could not read: "); - goto out; - } - - result = 0; /* success */ - *dest = (char *)*dest + filesize; - -out: - if(fd != -1) - semi_close(fd); - - if(result) { /* print context for the error message */ - semi_write0(filename); - semi_write0("\n"); - } else - if(size) - *size = filesize; - - return result; -} diff --git a/lib/libcflat/arm/setup.c b/lib/libcflat/arm/setup.c deleted file mode 100644 index 68a244a..0000000 --- a/lib/libcflat/arm/setup.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Initialize machine setup information and I/O. - * - * After running setup() unit tests may query how many cpus they have - * (nr_cpus), how much free memory it has, and at what physical - * address that free memory starts (memregions[1].{addr,size}), - * printf() and exit() will both work, and (argc, argv) are ready - * to be passed to main(). - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "libfdt/libfdt.h" -#include "devicetree.h" -#include "asm/spinlock.h" -#include "asm/setup.h" - -extern unsigned long stacktop; -extern void io_init(void); -extern void setup_args(const char *args); - -u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0UL) }; -int nr_cpus; - -static struct spinlock memregion_lock; -struct memregion memregions[NR_MEMREGIONS]; -int nr_memregions; - -static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused) -{ - assert(nr_cpus < NR_CPUS); - cpus[nr_cpus++] = regval; -} - -static void cpu_init(void) -{ - nr_cpus = 0; - assert(dt_for_each_cpu_node(cpu_set, NULL) == 0); -} - -static void memregions_init(phys_addr_t freemem_start) -{ - /* we only expect one membank to be defined in the DT */ - struct dt_pbus_reg regs[1]; - phys_addr_t addr, size, mem_end; - - nr_memregions = dt_get_memory_params(regs, 1); - - assert(nr_memregions > 0); - - addr = regs[0].addr; - size = regs[0].size; - mem_end = addr + size; - - assert(!(addr & ~PHYS_MASK) && !((mem_end-1) & ~PHYS_MASK)); - - memregions[0].addr = PAGE_ALIGN(addr); /* PHYS_OFFSET */ - - freemem_start = PAGE_ALIGN(freemem_start); - assert(freemem_start >= PHYS_OFFSET && freemem_start < mem_end); - - memregions[0].size = freemem_start - PHYS_OFFSET; - memregions[1].addr = freemem_start; - memregions[1].size = mem_end - freemem_start; - memregions[1].free = true; - nr_memregions = 2; - -#ifdef __arm__ - /* - * make sure 32-bit unit tests don't have any surprises when - * running without virtual memory, by ensuring the initial - * memory region uses 32-bit addresses. Other memory regions - * may have > 32-bit addresses though, and the unit tests are - * free to do as they wish with that. - */ - assert(!(memregions[0].addr >> 32)); - assert(!((memregions[0].addr + memregions[0].size - 1) >> 32)); -#endif -} - -struct memregion *memregion_new(phys_addr_t size) -{ - phys_addr_t freemem_start, mem_end; - struct memregion *mr; - - spin_lock(&memregion_lock); - - mr = &memregions[nr_memregions-1]; - - if (!mr->free || mr->size < size) { - printf("%s: requested=0x%llx, free=0x%llx.\n", size, - mr->free ? mr->size : 0ULL); - return NULL; - } - - mem_end = mr->addr + mr->size; - - mr->size = size; - mr->free = false; - - freemem_start = PAGE_ALIGN(mr->addr + size); - - if (freemem_start < mem_end && nr_memregions < NR_MEMREGIONS) { - mr->size = freemem_start - mr->addr; - memregions[nr_memregions].addr = freemem_start; - memregions[nr_memregions].size = mem_end - freemem_start; - memregions[nr_memregions].free = true; - ++nr_memregions; - } - - spin_unlock(&memregion_lock); - - return mr; -} - -void memregions_show(void) -{ - int i; - for (i = 0; i < nr_memregions; ++i) - printf("%016llx-%016llx [%s]\n", - memregions[i].addr, - memregions[i].addr + memregions[i].size - 1, - memregions[i].free ? "FREE" : "USED"); -} - -void setup(unsigned long arg __unused, unsigned long id __unused, - const void *fdt) -{ - const char *bootargs; - u32 fdt_size; - - /* - * Move the fdt to just above the stack. The free memory - * then starts just after the fdt. - */ - fdt_size = fdt_totalsize(fdt); - assert(fdt_move(fdt, &stacktop, fdt_size) == 0); - assert(dt_init(&stacktop) == 0); - - memregions_init((unsigned long)&stacktop + fdt_size); - - io_init(); - cpu_init(); - - assert(dt_get_bootargs(&bootargs) == 0); - setup_args(bootargs); -} diff --git a/lib/libcflat/arm/spinlock.c b/lib/libcflat/arm/spinlock.c deleted file mode 100644 index d8a6d4c..0000000 --- a/lib/libcflat/arm/spinlock.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "libcflat.h" -#include "asm/spinlock.h" -#include "asm/barrier.h" - -void spin_lock(struct spinlock *lock) -{ - u32 val, fail; - - dmb(); - do { - asm volatile( - "1: ldrex %0, [%2]\n" - " teq %0, #0\n" - " bne 1b\n" - " mov %0, #1\n" - " strex %1, %0, [%2]\n" - : "=&r" (val), "=&r" (fail) - : "r" (&lock->v) - : "cc" ); - } while (fail); - dmb(); -} - -void spin_unlock(struct spinlock *lock) -{ - lock->v = 0; - dmb(); -} diff --git a/lib/libcflat/asm-generic/spinlock.h b/lib/libcflat/asm-generic/spinlock.h deleted file mode 100644 index 3141744..0000000 --- a/lib/libcflat/asm-generic/spinlock.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _ASM_GENERIC_SPINLOCK_H_ -#define _ASM_GENERIC_SPINLOCK_H_ -#error need architecture specific asm/spinlock.h -#endif diff --git a/lib/libcflat/devicetree.c b/lib/libcflat/devicetree.c deleted file mode 100644 index 57e7408..0000000 --- a/lib/libcflat/devicetree.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "libfdt/libfdt.h" -#include "devicetree.h" - -static const void *fdt; -static u32 root_nr_address_cells, root_nr_size_cells; - -const void *dt_fdt(void) -{ - return fdt; -} - -bool dt_available(void) -{ - return fdt_check_header(fdt) == 0; -} - -int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells, u32 *nr_size_cells) -{ - const struct fdt_property *prop; - u32 *nr_cells; - int len; - - prop = fdt_get_property(fdt, fdtnode, "#address-cells", &len); - if (prop == NULL) - return len; - - nr_cells = (u32 *)prop->data; - *nr_address_cells = fdt32_to_cpu(*nr_cells); - - prop = fdt_get_property(fdt, fdtnode, "#size-cells", &len); - if (prop == NULL) - return len; - - nr_cells = (u32 *)prop->data; - *nr_size_cells = fdt32_to_cpu(*nr_cells); - - return 0; -} - -void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells, u32 nr_size_cells) -{ - memset(reg, 0, sizeof(struct dt_reg)); - reg->nr_address_cells = nr_address_cells; - reg->nr_size_cells = nr_size_cells; -} - -int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg) -{ - const struct fdt_property *prop; - u32 *cells, i; - unsigned nr_tuple_cells; - int len; - - prop = fdt_get_property(fdt, fdtnode, "reg", &len); - if (prop == NULL) - return len; - - cells = (u32 *)prop->data; - nr_tuple_cells = reg->nr_address_cells + reg->nr_size_cells; - regidx *= nr_tuple_cells; - - if (regidx + nr_tuple_cells > len/sizeof(u32)) - return -FDT_ERR_NOTFOUND; - - for (i = 0; i < reg->nr_address_cells; ++i) - reg->address_cells[i] = fdt32_to_cpu(cells[regidx + i]); - - regidx += reg->nr_address_cells; - for (i = 0; i < reg->nr_size_cells; ++i) - reg->size_cells[i] = fdt32_to_cpu(cells[regidx + i]); - - return 0; -} - -int dt_pbus_translate_node(int fdtnode, int regidx, - struct dt_pbus_reg *pbus_reg) -{ - struct dt_reg raw_reg; - int ret; - - dt_reg_init(&raw_reg, root_nr_address_cells, root_nr_size_cells); - - ret = dt_get_reg(fdtnode, regidx, &raw_reg); - if (ret < 0) - return ret; - - pbus_reg->addr = dt_pbus_read_cells(raw_reg.nr_address_cells, - raw_reg.address_cells); - pbus_reg->size = dt_pbus_read_cells(raw_reg.nr_size_cells, - raw_reg.size_cells); - - return 0; -} - -int dt_pbus_translate(const struct dt_device *dev, int regidx, - void *reg) -{ - return dt_pbus_translate_node(dev->fdtnode, regidx, reg); -} - -int dt_bus_match_any(const struct dt_device *dev __unused, int fdtnode) -{ - /* matches any device with a valid node */ - return fdtnode < 0 ? fdtnode : 1; -} - -static const struct dt_bus dt_default_bus = { - .match = dt_bus_match_any, - .translate = dt_pbus_translate, -}; - -void dt_bus_init_defaults(struct dt_bus *bus) -{ - memcpy(bus, &dt_default_bus, sizeof(struct dt_bus)); -} - -void dt_device_init(struct dt_device *dev, const struct dt_bus *bus, - const void *info) -{ - memset(dev, 0, sizeof(struct dt_device)); - dev->bus = bus; - dev->info = (void *)info; -} - -int dt_device_find_compatible(const struct dt_device *dev, - const char *compatible) -{ - int node, ret; - - node = fdt_node_offset_by_compatible(fdt, -1, compatible); - while (node >= 0) { - ret = dev->bus->match(dev, node); - if (ret < 0) - return ret; - else if (ret) - break; - node = fdt_node_offset_by_compatible(fdt, node, compatible); - } - return node; -} - -int dt_pbus_get_base_compatible(const char *compatible, - struct dt_pbus_reg *base) -{ - struct dt_device dev; - int node; - - dt_device_init(&dev, &dt_default_bus, NULL); - - node = dt_device_find_compatible(&dev, compatible); - if (node < 0) - return node; - - dt_device_bind_node(&dev, node); - - return dt_pbus_get_base(&dev, base); -} - -int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs) -{ - const char *pn = "device_type", *pv = "memory"; - int node, ret, pl = strlen(pv) + 1, nr = 0; - struct dt_pbus_reg reg; - - node = fdt_node_offset_by_prop_value(fdt, -1, pn, pv, pl); - - while (node >= 0) { - - while (nr < nr_regs) { - ret = dt_pbus_translate_node(node, nr, ®); - if (ret == -FDT_ERR_NOTFOUND) - break; - if (ret < 0) - return ret; - regs[nr].addr = reg.addr; - regs[nr].size = reg.size; - ++nr; - } - - node = fdt_node_offset_by_prop_value(fdt, node, pn, pv, pl); - } - - return node != -FDT_ERR_NOTFOUND ? node : nr; -} - -int dt_for_each_cpu_node(void (*func)(int fdtnode, u32 regval, void *info), - void *info) -{ - const struct fdt_property *prop; - int cpus, cpu, ret, len; - struct dt_reg raw_reg; - u32 nac, nsc; - - cpus = fdt_path_offset(fdt, "/cpus"); - if (cpus < 0) - return cpus; - - ret = dt_get_nr_cells(cpus, &nac, &nsc); - if (ret < 0) - return ret; - - dt_reg_init(&raw_reg, nac, nsc); - - dt_for_each_subnode(cpus, cpu) { - - prop = fdt_get_property(fdt, cpu, "device_type", &len); - if (prop == NULL) - return len; - - if (len != 4 || strcmp((char *)prop->data, "cpu")) - continue; - - ret = dt_get_reg(cpu, 0, &raw_reg); - if (ret < 0) - return ret; - - func(cpu, raw_reg.address_cells[0], info); - } - - return 0; -} - -int dt_get_bootargs(const char **bootargs) -{ - const struct fdt_property *prop; - int node, len; - - *bootargs = NULL; - - node = fdt_path_offset(fdt, "/chosen"); - if (node < 0) - return node; - - prop = fdt_get_property(fdt, node, "bootargs", &len); - if (prop) - *bootargs = (char *)prop->data; - else if (len < 0 && len != -FDT_ERR_NOTFOUND) - return len; - - return 0; -} - -int dt_init(const void *fdt_ptr) -{ - struct dt_bus *defbus = (struct dt_bus *)&dt_default_bus; - int root, ret; - - ret = fdt_check_header(fdt_ptr); - if (ret < 0) - return ret; - fdt = fdt_ptr; - - root = fdt_path_offset(fdt, "/"); - if (root < 0) - return root; - - ret = dt_get_nr_cells(root, &root_nr_address_cells, - &root_nr_size_cells); - if (ret < 0) - return ret; - - defbus->nr_address_cells = root_nr_address_cells; - defbus->nr_size_cells = root_nr_size_cells; - - return 0; -} diff --git a/lib/libcflat/devicetree.h b/lib/libcflat/devicetree.h deleted file mode 100644 index 7a1dc3e..0000000 --- a/lib/libcflat/devicetree.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef _DEVICETREE_H_ -#define _DEVICETREE_H_ -/* - * devicetree builds on libfdt to implement abstractions and accessors - * for Linux required device tree content. The accessors provided are - * common across architectures. See section III of the kernel doc - * Documentation/devicetree/booting-without-of.txt - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "libfdt/libfdt.h" - -/********************************************************************** - * devicetree init and libfdt helpers - **********************************************************************/ - -/* dt_init initializes devicetree with a pointer to an fdt, @fdt_ptr */ -extern int dt_init(const void *fdt_ptr); - -/* get the fdt pointer that devicetree is using */ -extern const void *dt_fdt(void); - -/* check for an initialized, valid devicetree */ -extern bool dt_available(void); - -/* traverse child nodes */ -#define dt_for_each_subnode(n, s) \ - for (s = fdt_first_subnode(dt_fdt(), n); \ - s != -FDT_ERR_NOTFOUND; \ - s = fdt_next_subnode(dt_fdt(), s)) - -/********************************************************************** - * Abstractions for required node types and properties - **********************************************************************/ - -struct dt_device { - int fdtnode; - const struct dt_bus *bus; - - /* - * info is a pointer to device specific data, which may be - * used by the bus match() and translate() functions - */ - void *info; -}; - -struct dt_bus { - /* - * match a device @dev to an fdt node @fdtnode - * returns - * - a positive value on match - * - zero on no match - * - a negative FDT_ERR_* value on failure - */ - int (*match)(const struct dt_device *dev, int fdtnode); - - /* - * translate the @regidx'th "address size" tuple of - * @dev's fdt node's "reg" property, and store the result - * in @reg, a bus specific structure - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ - int (*translate)(const struct dt_device *dev, int regidx, void *reg); - - /* the bus #address-cells and #size-cells properties */ - u32 nr_address_cells, nr_size_cells; -}; - -/* dt_bus_match_any matches any fdt node, i.e. it always returns true */ -extern int dt_bus_match_any(const struct dt_device *dev, int fdtnode); - -/* the processor bus (pbus) address type and register tuple */ -typedef u64 dt_pbus_addr_t; -struct dt_pbus_reg { - dt_pbus_addr_t addr; - dt_pbus_addr_t size; -}; - -static inline dt_pbus_addr_t dt_pbus_read_cells(u32 nr_cells, u32 *cells) -{ - switch (nr_cells) { - case 1: return cells[0]; - case 2: return ((u64)cells[0] << 32) | cells[1]; - } - return (~0ULL); -} - -/* - * dt_pbus_translate translates device node regs for the - * processor bus using the root node's #address-cells and - * #size-cells and dt_pbus_read_cells() - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_pbus_translate(const struct dt_device *dev, int regidx, - void *reg); - -/* - * dt_pbus_translate_node is the same as dt_pbus_translate but - * operates on an fdt node instead of a dt_device - */ -extern int dt_pbus_translate_node(int fdtnode, int regidx, - struct dt_pbus_reg *reg); - -/* - * dt_pbus_get_base is an alias for - * dt_pbus_translate(dev, 0, base) - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -static inline int dt_pbus_get_base(const struct dt_device *dev, - struct dt_pbus_reg *base) -{ - return dt_pbus_translate(dev, 0, base); -} - -/* - * dt_bus_init_defaults initializes @bus with - * match <- dt_bus_match_any - * translate <- dt_pbus_translate - * nr_address_cells <- #address-cells of the root node - * nr_size_cells <- #size-cells of the root node - */ -extern void dt_bus_init_defaults(struct dt_bus *bus); - -/* - * dt_device_init initializes a dt_device with the given parameters - */ -extern void dt_device_init(struct dt_device *dev, const struct dt_bus *bus, - const void *info); - -static inline void dt_device_bind_node(struct dt_device *dev, int fdtnode) -{ - dev->fdtnode = fdtnode; -} - -/* - * dt_device_find_compatible finds a @compatible node - * returns - * - node (>= 0) on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_device_find_compatible(const struct dt_device *dev, - const char *compatible); - -/* - * dt_pbus_get_base_compatible simply bundles many functions into one. - * It finds the first @compatible fdt node, then translates the 0th reg - * tuple (the base) using the processor bus translation, and finally it - * stores that result in @base. - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_pbus_get_base_compatible(const char *compatible, - struct dt_pbus_reg *base); - -/********************************************************************** - * Low-level accessors for required node types and properties - **********************************************************************/ - -/* - * dt_get_nr_cells sets @nr_address_cells and @nr_size_cells to the - * #address-cells and #size-cells properties of @fdtnode - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells, - u32 *nr_size_cells); - -/* dt_reg is a structure for "raw" reg tuples */ -#define MAX_ADDRESS_CELLS 4 -#define MAX_SIZE_CELLS 4 -struct dt_reg { - u32 nr_address_cells, nr_size_cells; - u32 address_cells[MAX_ADDRESS_CELLS]; - u32 size_cells[MAX_SIZE_CELLS]; -}; - -/* - * dt_reg_init initialize a dt_reg struct to zero and sets - * nr_address_cells and nr_size_cells to @nr_address_cells and - * @nr_size_cells respectively. - */ -extern void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells, - u32 nr_size_cells); - -/* - * dt_get_reg gets the @regidx'th reg tuple of @fdtnode's reg property - * and stores it in @reg. @reg must be initialized. - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg); - -/********************************************************************** - * High-level accessors for required node types and properties - **********************************************************************/ - -/* - * dt_get_bootargs gets a pointer to /chosen/bootargs - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_bootargs(const char **bootargs); - -/* - * dt_get_memory_params gets the memory parameters from the /memory node(s) - * storing each memory region ("address size" tuple) in consecutive entries - * of @regs, up to @nr_regs - * returns - * - number of memory regions found on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs); - -/* - * dt_for_each_cpu_node runs @func on each cpu node in the /cpus node - * passing it its fdt node, its reg property value, and @info - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_for_each_cpu_node(void (*func)(int fdtnode, u32 regval, - void *info), void *info); - -#endif /* _DEVICETREE_H_ */ diff --git a/lib/libcflat/report.c b/lib/libcflat/report.c deleted file mode 100644 index ff562a1..0000000 --- a/lib/libcflat/report.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Test result reporting - * - * Copyright (c) Siemens AG, 2014 - * - * Authors: - * Jan Kiszka <jan.kiszka@siemens.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#include "libcflat.h" - -static unsigned int tests, failures; - -void report(const char *msg_fmt, bool pass, ...) -{ - char buf[2000]; - va_list va; - - tests++; - printf("%s: ", pass ? "PASS" : "FAIL"); - va_start(va, pass); - vsnprintf(buf, sizeof(buf), msg_fmt, va); - va_end(va); - puts(buf); - puts("\n"); - if (!pass) - failures++; -} - -int report_summary(void) -{ - printf("\nSUMMARY: %d tests, %d failures\n", tests, failures); - return failures > 0 ? 1 : 0; -} diff --git a/lib/libcflat/virtio-testdev.c b/lib/libcflat/virtio-testdev.c deleted file mode 100644 index 422e0bf..0000000 --- a/lib/libcflat/virtio-testdev.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "asm/spinlock.h" -#include "virtio.h" - -#define TESTDEV_NAME "virtio-testdev" -#define VIRTIO_ID_TESTDEV 0xffff -#define TESTDEV_MAJOR_VER 1 -#define TESTDEV_MINOR_VER 1 - -#define VIRTIO_CONFIG_SIZE 64 - -enum { - VERSION = 1, - CLEAR, - EXIT, -}; - -#define TOKEN_OFFSET 0x0 -#define NARGS_OFFSET 0x4 -#define NRETS_OFFSET 0x8 -#define ARG_OFFSET(n) (0xc + (n) * 4) -#define __RET_OFFSET(nargs, n) (ARG_OFFSET(nargs) + (n) * 4) - -static struct spinlock lock; -static struct virtio_device *vdev; - -static u32 testdev_readl(unsigned offset) -{ - assert(offset <= (VIRTIO_CONFIG_SIZE - 4)); - return virtio_config_readl(vdev, offset); -} - -static void testdev_writel(unsigned offset, u32 val) -{ - assert(offset <= (VIRTIO_CONFIG_SIZE - 4)); - virtio_config_writel(vdev, offset, val); -} - -/* - * We have to write all args; nargs, nrets, ... first to avoid executing - * the token's operation until all args are in place. Then issue the op, - * and then read the return values. Reading the return values (or just - * sanity checking by reading token) will read a zero into qemu's copy - * of the token, which allows us to prepare additional ops without - * re-executing the last one. - */ -void virtio_testdev(u32 token, u32 nargs, u32 nrets, ...) -{ - va_list va; - unsigned off; - u32 n; - - if (!vdev) - return; - - spin_lock(&lock); - - testdev_writel(NARGS_OFFSET, nargs); - testdev_writel(NRETS_OFFSET, nrets); - - va_start(va, nrets); - - off = ARG_OFFSET(0); - n = nargs; - while (n--) { - testdev_writel(off, va_arg(va, unsigned)); - off += 4; - } - - /* this runs the op, but then resets token to zero */ - testdev_writel(TOKEN_OFFSET, token); - assert(testdev_readl(TOKEN_OFFSET) == 0); - - off = __RET_OFFSET(nargs, 0); - n = nrets; - while (n--) { - u32 *r = va_arg(va, unsigned *); - *r = testdev_readl(off); - off += 4; - } - - spin_unlock(&lock); - va_end(va); -} - -void virtio_testdev_version(u32 *version) -{ - virtio_testdev(VERSION, 0, 1, version); -} - -void virtio_testdev_clear(void) -{ - virtio_testdev(CLEAR, 0, 0); -} - -void virtio_testdev_exit(int code) -{ - virtio_testdev(EXIT, 1, 0, code); -} - -void virtio_testdev_init(void) -{ - u16 major, minor; - u32 version; - - vdev = virtio_bind(VIRTIO_ID_TESTDEV); - if (vdev == NULL) { - printf("%s: can't find " TESTDEV_NAME ". " - "Is '-device " TESTDEV_NAME "' " - "on the qemu command line?\n", __func__); - abort(); - } - - virtio_testdev_version(&version); - major = version >> 16; - minor = version & 0xffff; - - if (major != TESTDEV_MAJOR_VER || minor < TESTDEV_MINOR_VER) { - char *u = "qemu"; - if (major > TESTDEV_MAJOR_VER) - u = "kvm-unit-tests"; - printf("%s: incompatible version of " TESTDEV_NAME ": " - "major = %d, minor = %d. Update %s\n", - __func__, major, minor, u); - abort(); - } - - if (minor > TESTDEV_MINOR_VER) - printf("%s: " TESTDEV_NAME " has new features. " - "An update of kvm-unit-tests may be possible.\n", - __func__); -} diff --git a/lib/libcflat/virtio-testdev.h b/lib/libcflat/virtio-testdev.h deleted file mode 100644 index bed9eaf..0000000 --- a/lib/libcflat/virtio-testdev.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _VIRTIO_TESTDEV_H_ -#define _VIRTIO_TESTDEV_H_ -/* - * virtio-testdev is a driver for the virtio-testdev qemu device. - * The virtio-testdev device exposes a simple control interface to - * qemu for kvm-unit-tests through virtio. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -extern void virtio_testdev_init(void); -extern void virtio_testdev_version(u32 *version); -extern void virtio_testdev_clear(void); -extern void virtio_testdev_exit(int code); -#endif diff --git a/lib/libcflat/virtio.c b/lib/libcflat/virtio.c deleted file mode 100644 index 4c597e2..0000000 --- a/lib/libcflat/virtio.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "devicetree.h" -#include "asm/spinlock.h" -#include "asm/io.h" -#include "virtio.h" - -enum virtio_hwdesc_type { - VIRTIO_HWDESC_TYPE_DT = 0, /* device tree */ - NR_VIRTIO_HWDESC_TYPES, -}; - -enum virtio_bus_type { - VIRTIO_BUS_TYPE_MMIO = 0, /* virtio-mmio */ - NR_VIRTIO_BUS_TYPES, -}; - -struct virtio_bind_bus { - bool (*hwdesc_probe)(void); - struct virtio_device *(*device_bind)(u32 devid); -}; - -static struct virtio_device *vm_dt_device_bind(u32 devid); - -static struct virtio_bind_bus -virtio_bind_busses[NR_VIRTIO_HWDESC_TYPES][NR_VIRTIO_BUS_TYPES] = { - -[VIRTIO_HWDESC_TYPE_DT] = { - - [VIRTIO_BUS_TYPE_MMIO] = { - .hwdesc_probe = dt_available, - .device_bind = vm_dt_device_bind, - }, -}, -}; - -struct virtio_device *virtio_bind(u32 devid) -{ - struct virtio_bind_bus *bus; - struct virtio_device *dev; - int i, j; - - for (i = 0; i < NR_VIRTIO_HWDESC_TYPES; ++i) { - for (j = 0; j < NR_VIRTIO_BUS_TYPES; ++j) { - - bus = &virtio_bind_busses[i][j]; - - if (!bus->hwdesc_probe()) - continue; - - dev = bus->device_bind(devid); - if (dev) - return dev; - } - } - - return NULL; -} - -/****************************************************** - * virtio-mmio support (config space only) - ******************************************************/ - -static void vm_get(struct virtio_device *vdev, unsigned offset, - void *buf, unsigned len) -{ - struct virtio_mmio_device *vmdev = to_virtio_mmio_device(vdev); - u8 *p = buf; - unsigned i; - - for (i = 0; i < len; ++i) - p[i] = readb(vmdev->base + VIRTIO_MMIO_CONFIG + offset + i); -} - -static void vm_set(struct virtio_device *vdev, unsigned offset, - const void *buf, unsigned len) -{ - struct virtio_mmio_device *vmdev = to_virtio_mmio_device(vdev); - const u8 *p = buf; - unsigned i; - - for (i = 0; i < len; ++i) - writeb(p[i], vmdev->base + VIRTIO_MMIO_CONFIG + offset + i); -} - -static const struct virtio_config_ops vm_config_ops = { - .get = vm_get, - .set = vm_set, -}; - -#define NR_VM_DEVICES 32 -static struct spinlock vm_lock; -static struct virtio_mmio_device vm_devs[NR_VM_DEVICES]; -static int nr_vm_devs; - -static struct virtio_mmio_device *vm_new_device(u32 devid) -{ - struct virtio_mmio_device *vmdev; - - if (nr_vm_devs >= NR_VM_DEVICES) - return NULL; - - spin_lock(&vm_lock); - vmdev = &vm_devs[nr_vm_devs++]; - spin_unlock(&vm_lock); - - vmdev->vdev.id.device = devid; - vmdev->vdev.id.vendor = -1; - vmdev->vdev.config = &vm_config_ops; - - return vmdev; -} - -/****************************************************** - * virtio-mmio device tree support - ******************************************************/ - -struct vm_dt_info { - u32 devid; - void *base; -}; - -static int vm_dt_match(const struct dt_device *dev, int fdtnode) -{ - struct vm_dt_info *info = (struct vm_dt_info *)dev->info; - struct dt_pbus_reg base; - - dt_device_bind_node((struct dt_device *)dev, fdtnode); - - assert(dt_pbus_get_base(dev, &base) == 0); - info->base = ioremap(base.addr, base.size); - - return readl(info->base + VIRTIO_MMIO_DEVICE_ID) == info->devid; -} - -static struct virtio_device *vm_dt_device_bind(u32 devid) -{ - struct virtio_mmio_device *vmdev; - struct dt_device dt_dev; - struct dt_bus dt_bus; - struct vm_dt_info info; - int node; - - dt_bus_init_defaults(&dt_bus); - dt_bus.match = vm_dt_match; - - info.devid = devid; - - dt_device_init(&dt_dev, &dt_bus, &info); - - node = dt_device_find_compatible(&dt_dev, "virtio,mmio"); - assert(node >= 0 || node == -FDT_ERR_NOTFOUND); - - if (node == -FDT_ERR_NOTFOUND) - return NULL; - - vmdev = vm_new_device(devid); - vmdev->base = info.base; - - return &vmdev->vdev; -} diff --git a/lib/libcflat/virtio.h b/lib/libcflat/virtio.h deleted file mode 100644 index 16ebe7e..0000000 --- a/lib/libcflat/virtio.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef _VIRTIO_H_ -#define _VIRTIO_H_ -/* - * A minimal implementation of virtio for virtio-mmio config space - * access. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -struct virtio_device_id { - u32 device; - u32 vendor; -}; - -struct virtio_device { - struct virtio_device_id id; - const struct virtio_config_ops *config; -}; - -struct virtio_config_ops { - void (*get)(struct virtio_device *vdev, unsigned offset, - void *buf, unsigned len); - void (*set)(struct virtio_device *vdev, unsigned offset, - const void *buf, unsigned len); -}; - -extern struct virtio_device *virtio_bind(u32 devid); - -static inline u8 -virtio_config_readb(struct virtio_device *vdev, unsigned offset) -{ - u8 val; - vdev->config->get(vdev, offset, &val, 1); - return val; -} - -static inline u16 -virtio_config_readw(struct virtio_device *vdev, unsigned offset) -{ - u16 val; - vdev->config->get(vdev, offset, &val, 2); - return val; -} - -static inline u32 -virtio_config_readl(struct virtio_device *vdev, unsigned offset) -{ - u32 val; - vdev->config->get(vdev, offset, &val, 4); - return val; -} - -static inline void -virtio_config_writeb(struct virtio_device *vdev, unsigned offset, u8 val) -{ - vdev->config->set(vdev, offset, &val, 1); -} - -static inline void -virtio_config_writew(struct virtio_device *vdev, unsigned offset, u16 val) -{ - vdev->config->set(vdev, offset, &val, 2); -} - -static inline void -virtio_config_writel(struct virtio_device *vdev, unsigned offset, u32 val) -{ - vdev->config->set(vdev, offset, &val, 4); -} - -/****************************************************** - * virtio-mmio - ******************************************************/ - -#define VIRTIO_MMIO_DEVICE_ID 0x008 -#define VIRTIO_MMIO_CONFIG 0x100 - -#define to_virtio_mmio_device(vdev_ptr) \ - container_of(vdev_ptr, struct virtio_mmio_device, vdev) - -struct virtio_mmio_device { - struct virtio_device vdev; - void *base; -}; - -#endif /* _VIRTIO_H_ */ diff --git a/lib/libfdt/Makefile.libfdt b/lib/libfdt/Makefile.libfdt deleted file mode 100644 index 91126c0..0000000 --- a/lib/libfdt/Makefile.libfdt +++ /dev/null @@ -1,10 +0,0 @@ -# Makefile.libfdt -# -# This is not a complete Makefile of itself. Instead, it is designed to -# be easily embeddable into other systems of Makefiles. -# -LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 -LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h -LIBFDT_VERSION = version.lds -LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c -LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/lib/libfdt/README b/lib/libfdt/README deleted file mode 100644 index 24ad4fe..0000000 --- a/lib/libfdt/README +++ /dev/null @@ -1,4 +0,0 @@ - -The code in this directory is originally imported from the libfdt -directory of git://git.jdl.com/software/dtc.git - version 1.4.0. - diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c deleted file mode 100644 index 2ce6a44..0000000 --- a/lib/libfdt/fdt.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include <fdt.h> -#include <libfdt.h> - -#include "libfdt_internal.h" - -int fdt_check_header(const void *fdt) -{ - if (fdt_magic(fdt) == FDT_MAGIC) { - /* Complete tree */ - if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - /* Unfinished sequential-write blob */ - if (fdt_size_dt_struct(fdt) == 0) - return -FDT_ERR_BADSTATE; - } else { - return -FDT_ERR_BADMAGIC; - } - - return 0; -} - -const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) -{ - const char *p; - - if (fdt_version(fdt) >= 0x11) - if (((offset + len) < offset) - || ((offset + len) > fdt_size_dt_struct(fdt))) - return NULL; - - p = _fdt_offset_ptr(fdt, offset); - - if (p + len < p) - return NULL; - return p; -} - -uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) -{ - const fdt32_t *tagp, *lenp; - uint32_t tag; - int offset = startoffset; - const char *p; - - *nextoffset = -FDT_ERR_TRUNCATED; - tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); - if (!tagp) - return FDT_END; /* premature end */ - tag = fdt32_to_cpu(*tagp); - offset += FDT_TAGSIZE; - - *nextoffset = -FDT_ERR_BADSTRUCTURE; - switch (tag) { - case FDT_BEGIN_NODE: - /* skip name */ - do { - p = fdt_offset_ptr(fdt, offset++, 1); - } while (p && (*p != '\0')); - if (!p) - return FDT_END; /* premature end */ - break; - - case FDT_PROP: - lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); - if (!lenp) - return FDT_END; /* premature end */ - /* skip-name offset, length and value */ - offset += sizeof(struct fdt_property) - FDT_TAGSIZE - + fdt32_to_cpu(*lenp); - break; - - case FDT_END: - case FDT_END_NODE: - case FDT_NOP: - break; - - default: - return FDT_END; - } - - if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) - return FDT_END; /* premature end */ - - *nextoffset = FDT_TAGALIGN(offset); - return tag; -} - -int _fdt_check_node_offset(const void *fdt, int offset) -{ - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) - return -FDT_ERR_BADOFFSET; - - return offset; -} - -int _fdt_check_prop_offset(const void *fdt, int offset) -{ - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) - return -FDT_ERR_BADOFFSET; - - return offset; -} - -int fdt_next_node(const void *fdt, int offset, int *depth) -{ - int nextoffset = 0; - uint32_t tag; - - if (offset >= 0) - if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) - return nextoffset; - - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_PROP: - case FDT_NOP: - break; - - case FDT_BEGIN_NODE: - if (depth) - (*depth)++; - break; - - case FDT_END_NODE: - if (depth && ((--(*depth)) < 0)) - return nextoffset; - break; - - case FDT_END: - if ((nextoffset >= 0) - || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) - return -FDT_ERR_NOTFOUND; - else - return nextoffset; - } - } while (tag != FDT_BEGIN_NODE); - - return offset; -} - -int fdt_first_subnode(const void *fdt, int offset) -{ - int depth = 0; - - offset = fdt_next_node(fdt, offset, &depth); - if (offset < 0 || depth != 1) - return -FDT_ERR_NOTFOUND; - - return offset; -} - -int fdt_next_subnode(const void *fdt, int offset) -{ - int depth = 1; - - /* - * With respect to the parent, the depth of the next subnode will be - * the same as the last. - */ - do { - offset = fdt_next_node(fdt, offset, &depth); - if (offset < 0 || depth < 1) - return -FDT_ERR_NOTFOUND; - } while (depth > 1); - - return offset; -} - -const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) -{ - int len = strlen(s) + 1; - const char *last = strtab + tabsize - len; - const char *p; - - for (p = strtab; p <= last; p++) - if (memcmp(p, s, len) == 0) - return p; - return NULL; -} - -int fdt_move(const void *fdt, void *buf, int bufsize) -{ - FDT_CHECK_HEADER(fdt); - - if (fdt_totalsize(fdt) > bufsize) - return -FDT_ERR_NOSPACE; - - memmove(buf, fdt, fdt_totalsize(fdt)); - return 0; -} diff --git a/lib/libfdt/fdt.h b/lib/libfdt/fdt.h deleted file mode 100644 index 526aedb..0000000 --- a/lib/libfdt/fdt.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _FDT_H -#define _FDT_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * Copyright 2012 Kim Phillips, Freescale Semiconductor. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ASSEMBLY__ - -struct fdt_header { - fdt32_t magic; /* magic word FDT_MAGIC */ - fdt32_t totalsize; /* total size of DT block */ - fdt32_t off_dt_struct; /* offset to structure */ - fdt32_t off_dt_strings; /* offset to strings */ - fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ - fdt32_t version; /* format version */ - fdt32_t last_comp_version; /* last compatible version */ - - /* version 2 fields below */ - fdt32_t boot_cpuid_phys; /* Which physical CPU id we're - booting on */ - /* version 3 fields below */ - fdt32_t size_dt_strings; /* size of the strings block */ - - /* version 17 fields below */ - fdt32_t size_dt_struct; /* size of the structure block */ -}; - -struct fdt_reserve_entry { - fdt64_t address; - fdt64_t size; -}; - -struct fdt_node_header { - fdt32_t tag; - char name[0]; -}; - -struct fdt_property { - fdt32_t tag; - fdt32_t len; - fdt32_t nameoff; - char data[0]; -}; - -#endif /* !__ASSEMBLY */ - -#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ -#define FDT_TAGSIZE sizeof(fdt32_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(fdt32_t)) -#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) -#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) -#define FDT_V16_SIZE FDT_V3_SIZE -#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) - -#endif /* _FDT_H */ diff --git a/lib/libfdt/fdt_empty_tree.c b/lib/libfdt/fdt_empty_tree.c deleted file mode 100644 index f72d13b..0000000 --- a/lib/libfdt/fdt_empty_tree.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2012 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include <fdt.h> -#include <libfdt.h> - -#include "libfdt_internal.h" - -int fdt_create_empty_tree(void *buf, int bufsize) -{ - int err; - - err = fdt_create(buf, bufsize); - if (err) - return err; - - err = fdt_finish_reservemap(buf); - if (err) - return err; - - err = fdt_begin_node(buf, ""); - if (err) - return err; - - err = fdt_end_node(buf); - if (err) - return err; - - err = fdt_finish(buf); - if (err) - return err; - - return fdt_open_into(buf, buf, bufsize); -} - diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c deleted file mode 100644 index 50007f6..0000000 --- a/lib/libfdt/fdt_ro.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include <fdt.h> -#include <libfdt.h> - -#include "libfdt_internal.h" - -static int _fdt_nodename_eq(const void *fdt, int offset, - const char *s, int len) -{ - const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); - - if (! p) - /* short match */ - return 0; - - if (memcmp(p, s, len) != 0) - return 0; - - if (p[len] == '\0') - return 1; - else if (!memchr(s, '@', len) && (p[len] == '@')) - return 1; - else - return 0; -} - -const char *fdt_string(const void *fdt, int stroffset) -{ - return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; -} - -static int _fdt_string_eq(const void *fdt, int stroffset, - const char *s, int len) -{ - const char *p = fdt_string(fdt, stroffset); - - return (strlen(p) == len) && (memcmp(p, s, len) == 0); -} - -int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) -{ - FDT_CHECK_HEADER(fdt); - *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); - *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); - return 0; -} - -int fdt_num_mem_rsv(const void *fdt) -{ - int i = 0; - - while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) - i++; - return i; -} - -static int _nextprop(const void *fdt, int offset) -{ - uint32_t tag; - int nextoffset; - - do { - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_END: - if (nextoffset >= 0) - return -FDT_ERR_BADSTRUCTURE; - else - return nextoffset; - - case FDT_PROP: - return offset; - } - offset = nextoffset; - } while (tag == FDT_NOP); - - return -FDT_ERR_NOTFOUND; -} - -int fdt_subnode_offset_namelen(const void *fdt, int offset, - const char *name, int namelen) -{ - int depth; - - FDT_CHECK_HEADER(fdt); - - for (depth = 0; - (offset >= 0) && (depth >= 0); - offset = fdt_next_node(fdt, offset, &depth)) - if ((depth == 1) - && _fdt_nodename_eq(fdt, offset, name, namelen)) - return offset; - - if (depth < 0) - return -FDT_ERR_NOTFOUND; - return offset; /* error */ -} - -int fdt_subnode_offset(const void *fdt, int parentoffset, - const char *name) -{ - return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); -} - -int fdt_path_offset(const void *fdt, const char *path) -{ - const char *end = path + strlen(path); - const char *p = path; - int offset = 0; - - FDT_CHECK_HEADER(fdt); - - /* see if we have an alias */ - if (*path != '/') { - const char *q = strchr(path, '/'); - - if (!q) - q = end; - - p = fdt_get_alias_namelen(fdt, p, q - p); - if (!p) - return -FDT_ERR_BADPATH; - offset = fdt_path_offset(fdt, p); - - p = q; - } - - while (*p) { - const char *q; - - while (*p == '/') - p++; - if (! *p) - return offset; - q = strchr(p, '/'); - if (! q) - q = end; - - offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); - if (offset < 0) - return offset; - - p = q; - } - - return offset; -} - -const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) -{ - const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); - int err; - - if (((err = fdt_check_header(fdt)) != 0) - || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) - goto fail; - - if (len) - *len = strlen(nh->name); - - return nh->name; - - fail: - if (len) - *len = err; - return NULL; -} - -int fdt_first_property_offset(const void *fdt, int nodeoffset) -{ - int offset; - - if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) - return offset; - - return _nextprop(fdt, offset); -} - -int fdt_next_property_offset(const void *fdt, int offset) -{ - if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) - return offset; - - return _nextprop(fdt, offset); -} - -const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp) -{ - int err; - const struct fdt_property *prop; - - if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { - if (lenp) - *lenp = err; - return NULL; - } - - prop = _fdt_offset_ptr(fdt, offset); - - if (lenp) - *lenp = fdt32_to_cpu(prop->len); - - return prop; -} - -const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int offset, - const char *name, - int namelen, int *lenp) -{ - for (offset = fdt_first_property_offset(fdt, offset); - (offset >= 0); - (offset = fdt_next_property_offset(fdt, offset))) { - const struct fdt_property *prop; - - if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { - offset = -FDT_ERR_INTERNAL; - break; - } - if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), - name, namelen)) - return prop; - } - - if (lenp) - *lenp = offset; - return NULL; -} - -const struct fdt_property *fdt_get_property(const void *fdt, - int nodeoffset, - const char *name, int *lenp) -{ - return fdt_get_property_namelen(fdt, nodeoffset, name, - strlen(name), lenp); -} - -const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); - if (! prop) - return NULL; - - return prop->data; -} - -const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset(fdt, offset, lenp); - if (!prop) - return NULL; - if (namep) - *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - return prop->data; -} - -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp) -{ - return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); -} - -uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) -{ - const fdt32_t *php; - int len; - - /* FIXME: This is a bit sub-optimal, since we potentially scan - * over all the properties twice. */ - php = fdt_getprop(fdt, nodeoffset, "phandle", &len); - if (!php || (len != sizeof(*php))) { - php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof(*php))) - return 0; - } - - return fdt32_to_cpu(*php); -} - -const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen) -{ - int aliasoffset; - - aliasoffset = fdt_path_offset(fdt, "/aliases"); - if (aliasoffset < 0) - return NULL; - - return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); -} - -const char *fdt_get_alias(const void *fdt, const char *name) -{ - return fdt_get_alias_namelen(fdt, name, strlen(name)); -} - -int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) -{ - int pdepth = 0, p = 0; - int offset, depth, namelen; - const char *name; - - FDT_CHECK_HEADER(fdt); - - if (buflen < 2) - return -FDT_ERR_NOSPACE; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - while (pdepth > depth) { - do { - p--; - } while (buf[p-1] != '/'); - pdepth--; - } - - if (pdepth >= depth) { - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) { - memcpy(buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; - } - } - - if (offset == nodeoffset) { - if (pdepth < (depth + 1)) - return -FDT_ERR_NOSPACE; - - if (p > 1) /* special case so that root path is "/", not "" */ - p--; - buf[p] = '\0'; - return 0; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth) -{ - int offset, depth; - int supernodeoffset = -FDT_ERR_INTERNAL; - - FDT_CHECK_HEADER(fdt); - - if (supernodedepth < 0) - return -FDT_ERR_NOTFOUND; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - if (depth == supernodedepth) - supernodeoffset = offset; - - if (offset == nodeoffset) { - if (nodedepth) - *nodedepth = depth; - - if (supernodedepth > depth) - return -FDT_ERR_NOTFOUND; - else - return supernodeoffset; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_depth(const void *fdt, int nodeoffset) -{ - int nodedepth; - int err; - - err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); - if (err) - return (err < 0) ? err : -FDT_ERR_INTERNAL; - return nodedepth; -} - -int fdt_parent_offset(const void *fdt, int nodeoffset) -{ - int nodedepth = fdt_node_depth(fdt, nodeoffset); - - if (nodedepth < 0) - return nodedepth; - return fdt_supernode_atdepth_offset(fdt, nodeoffset, - nodedepth - 1, NULL); -} - -int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen) -{ - int offset; - const void *val; - int len; - - FDT_CHECK_HEADER(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_getprop(), then if that didn't - * find what we want, we scan over them again making our way - * to the next node. Still it's the easiest to implement - * approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - val = fdt_getprop(fdt, offset, propname, &len); - if (val && (len == proplen) - && (memcmp(val, propval, len) == 0)) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) -{ - int offset; - - if ((phandle == 0) || (phandle == -1)) - return -FDT_ERR_BADPHANDLE; - - FDT_CHECK_HEADER(fdt); - - /* FIXME: The algorithm here is pretty horrible: we - * potentially scan each property of a node in - * fdt_get_phandle(), then if that didn't find what - * we want, we scan over them again making our way to the next - * node. Still it's the easiest to implement approach; - * performance can come later. */ - for (offset = fdt_next_node(fdt, -1, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - if (fdt_get_phandle(fdt, offset) == phandle) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) -{ - int len = strlen(str); - const char *p; - - while (listlen >= len) { - if (memcmp(str, strlist, len+1) == 0) - return 1; - p = memchr(strlist, '\0', listlen); - if (!p) - return 0; /* malformed strlist.. */ - listlen -= (p-strlist) + 1; - strlist = p + 1; - } - return 0; -} - -int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible) -{ - const void *prop; - int len; - - prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); - if (!prop) - return len; - if (fdt_stringlist_contains(prop, len, compatible)) - return 0; - else - return 1; -} - -int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible) -{ - int offset, err; - - FDT_CHECK_HEADER(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_node_check_compatible(), then if - * that didn't find what we want, we scan over them again - * making our way to the next node. Still it's the easiest to - * implement approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - err = fdt_node_check_compatible(fdt, offset, compatible); - if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) - return err; - else if (err == 0) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c deleted file mode 100644 index fdba618..0000000 --- a/lib/libfdt/fdt_rw.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include <fdt.h> -#include <libfdt.h> - -#include "libfdt_internal.h" - -static int _fdt_blocks_misordered(const void *fdt, - int mem_rsv_size, int struct_size) -{ - return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) - || (fdt_off_dt_struct(fdt) < - (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) - || (fdt_off_dt_strings(fdt) < - (fdt_off_dt_struct(fdt) + struct_size)) - || (fdt_totalsize(fdt) < - (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); -} - -static int _fdt_rw_check_header(void *fdt) -{ - FDT_CHECK_HEADER(fdt); - - if (fdt_version(fdt) < 17) - return -FDT_ERR_BADVERSION; - if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), - fdt_size_dt_struct(fdt))) - return -FDT_ERR_BADLAYOUT; - if (fdt_version(fdt) > 17) - fdt_set_version(fdt, 17); - - return 0; -} - -#define FDT_RW_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = _fdt_rw_check_header(fdt)) != 0) \ - return err; \ - } - -static inline int _fdt_data_size(void *fdt) -{ - return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); -} - -static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) -{ - char *p = splicepoint; - char *end = (char *)fdt + _fdt_data_size(fdt); - - if (((p + oldlen) < p) || ((p + oldlen) > end)) - return -FDT_ERR_BADOFFSET; - if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) - return -FDT_ERR_NOSPACE; - memmove(p + newlen, p + oldlen, end - p - oldlen); - return 0; -} - -static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, - int oldn, int newn) -{ - int delta = (newn - oldn) * sizeof(*p); - int err; - err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); - if (err) - return err; - fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); - fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); - return 0; -} - -static int _fdt_splice_struct(void *fdt, void *p, - int oldlen, int newlen) -{ - int delta = newlen - oldlen; - int err; - - if ((err = _fdt_splice(fdt, p, oldlen, newlen))) - return err; - - fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); - fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); - return 0; -} - -static int _fdt_splice_string(void *fdt, int newlen) -{ - void *p = (char *)fdt - + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); - int err; - - if ((err = _fdt_splice(fdt, p, 0, newlen))) - return err; - - fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); - return 0; -} - -static int _fdt_find_add_string(void *fdt, const char *s) -{ - char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); - const char *p; - char *new; - int len = strlen(s) + 1; - int err; - - p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); - if (p) - /* found it */ - return (p - strtab); - - new = strtab + fdt_size_dt_strings(fdt); - err = _fdt_splice_string(fdt, len); - if (err) - return err; - - memcpy(new, s, len); - return (new - strtab); -} - -int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) -{ - struct fdt_reserve_entry *re; - int err; - - FDT_RW_CHECK_HEADER(fdt); - - re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); - err = _fdt_splice_mem_rsv(fdt, re, 0, 1); - if (err) - return err; - - re->address = cpu_to_fdt64(address); - re->size = cpu_to_fdt64(size); - return 0; -} - -int fdt_del_mem_rsv(void *fdt, int n) -{ - struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); - int err; - - FDT_RW_CHECK_HEADER(fdt); - - if (n >= fdt_num_mem_rsv(fdt)) - return -FDT_ERR_NOTFOUND; - - err = _fdt_splice_mem_rsv(fdt, re, 1, 0); - if (err) - return err; - return 0; -} - -static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) -{ - int oldlen; - int err; - - *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); - if (! (*prop)) - return oldlen; - - if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), - FDT_TAGALIGN(len)))) - return err; - - (*prop)->len = cpu_to_fdt32(len); - return 0; -} - -static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) -{ - int proplen; - int nextoffset; - int namestroff; - int err; - - if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) - return nextoffset; - - namestroff = _fdt_find_add_string(fdt, name); - if (namestroff < 0) - return namestroff; - - *prop = _fdt_offset_ptr_w(fdt, nextoffset); - proplen = sizeof(**prop) + FDT_TAGALIGN(len); - - err = _fdt_splice_struct(fdt, *prop, 0, proplen); - if (err) - return err; - - (*prop)->tag = cpu_to_fdt32(FDT_PROP); - (*prop)->nameoff = cpu_to_fdt32(namestroff); - (*prop)->len = cpu_to_fdt32(len); - return 0; -} - -int fdt_set_name(void *fdt, int nodeoffset, const char *name) -{ - char *namep; - int oldlen, newlen; - int err; - - FDT_RW_CHECK_HEADER(fdt); - - namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); - if (!namep) - return oldlen; - - newlen = strlen(name); - - err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), - FDT_TAGALIGN(newlen+1)); - if (err) - return err; - - memcpy(namep, name, newlen+1); - return 0; -} - -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - struct fdt_property *prop; - int err; - - FDT_RW_CHECK_HEADER(fdt); - - err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); - if (err == -FDT_ERR_NOTFOUND) - err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); - if (err) - return err; - - memcpy(prop->data, val, len); - return 0; -} - -int fdt_appendprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - struct fdt_property *prop; - int err, oldlen, newlen; - - FDT_RW_CHECK_HEADER(fdt); - - prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); - if (prop) { - newlen = len + oldlen; - err = _fdt_splice_struct(fdt, prop->data, - FDT_TAGALIGN(oldlen), - FDT_TAGALIGN(newlen)); - if (err) - return err; - prop->len = cpu_to_fdt32(newlen); - memcpy(prop->data + oldlen, val, len); - } else { - err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); - if (err) - return err; - memcpy(prop->data, val, len); - } - return 0; -} - -int fdt_delprop(void *fdt, int nodeoffset, const char *name) -{ - struct fdt_property *prop; - int len, proplen; - - FDT_RW_CHECK_HEADER(fdt); - - prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (! prop) - return len; - - proplen = sizeof(*prop) + FDT_TAGALIGN(len); - return _fdt_splice_struct(fdt, prop, proplen, 0); -} - -int fdt_add_subnode_namelen(void *fdt, int parentoffset, - const char *name, int namelen) -{ - struct fdt_node_header *nh; - int offset, nextoffset; - int nodelen; - int err; - uint32_t tag; - fdt32_t *endtag; - - FDT_RW_CHECK_HEADER(fdt); - - offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); - if (offset >= 0) - return -FDT_ERR_EXISTS; - else if (offset != -FDT_ERR_NOTFOUND) - return offset; - - /* Try to place the new node after the parent's properties */ - fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - } while ((tag == FDT_PROP) || (tag == FDT_NOP)); - - nh = _fdt_offset_ptr_w(fdt, offset); - nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; - - err = _fdt_splice_struct(fdt, nh, 0, nodelen); - if (err) - return err; - - nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); - memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); - memcpy(nh->name, name, namelen); - endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); - *endtag = cpu_to_fdt32(FDT_END_NODE); - - return offset; -} - -int fdt_add_subnode(void *fdt, int parentoffset, const char *name) -{ - return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); -} - -int fdt_del_node(void *fdt, int nodeoffset) -{ - int endoffset; - - FDT_RW_CHECK_HEADER(fdt); - - endoffset = _fdt_node_end_offset(fdt, nodeoffset); - if (endoffset < 0) - return endoffset; - - return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), - endoffset - nodeoffset, 0); -} - -static void _fdt_packblocks(const char *old, char *new, - int mem_rsv_size, int struct_size) -{ - int mem_rsv_off, struct_off, strings_off; - - mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); - struct_off = mem_rsv_off + mem_rsv_size; - strings_off = struct_off + struct_size; - - memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); - fdt_set_off_mem_rsvmap(new, mem_rsv_off); - - memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); - fdt_set_off_dt_struct(new, struct_off); - fdt_set_size_dt_struct(new, struct_size); - - memmove(new + strings_off, old + fdt_off_dt_strings(old), - fdt_size_dt_strings(old)); - fdt_set_off_dt_strings(new, strings_off); - fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); -} - -int fdt_open_into(const void *fdt, void *buf, int bufsize) -{ - int err; - int mem_rsv_size, struct_size; - int newsize; - const char *fdtstart = fdt; - const char *fdtend = fdtstart + fdt_totalsize(fdt); - char *tmp; - - FDT_CHECK_HEADER(fdt); - - mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) - * sizeof(struct fdt_reserve_entry); - - if (fdt_version(fdt) >= 17) { - struct_size = fdt_size_dt_struct(fdt); - } else { - struct_size = 0; - while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) - ; - if (struct_size < 0) - return struct_size; - } - - if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { - /* no further work necessary */ - err = fdt_move(fdt, buf, bufsize); - if (err) - return err; - fdt_set_version(buf, 17); - fdt_set_size_dt_struct(buf, struct_size); - fdt_set_totalsize(buf, bufsize); - return 0; - } - - /* Need to reorder */ - newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size - + struct_size + fdt_size_dt_strings(fdt); - - if (bufsize < newsize) - return -FDT_ERR_NOSPACE; - - /* First attempt to build converted tree at beginning of buffer */ - tmp = buf; - /* But if that overlaps with the old tree... */ - if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { - /* Try right after the old tree instead */ - tmp = (char *)(uintptr_t)fdtend; - if ((tmp + newsize) > ((char *)buf + bufsize)) - return -FDT_ERR_NOSPACE; - } - - _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); - memmove(buf, tmp, newsize); - - fdt_set_magic(buf, FDT_MAGIC); - fdt_set_totalsize(buf, bufsize); - fdt_set_version(buf, 17); - fdt_set_last_comp_version(buf, 16); - fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); - - return 0; -} - -int fdt_pack(void *fdt) -{ - int mem_rsv_size; - - FDT_RW_CHECK_HEADER(fdt); - - mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) - * sizeof(struct fdt_reserve_entry); - _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); - fdt_set_totalsize(fdt, _fdt_data_size(fdt)); - - return 0; -} diff --git a/lib/libfdt/fdt_strerror.c b/lib/libfdt/fdt_strerror.c deleted file mode 100644 index e6c3cee..0000000 --- a/lib/libfdt/fdt_strerror.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include <fdt.h> -#include <libfdt.h> - -#include "libfdt_internal.h" - -struct fdt_errtabent { - const char *str; -}; - -#define FDT_ERRTABENT(val) \ - [(val)] = { .str = #val, } - -static struct fdt_errtabent fdt_errtable[] = { - FDT_ERRTABENT(FDT_ERR_NOTFOUND), - FDT_ERRTABENT(FDT_ERR_EXISTS), - FDT_ERRTABENT(FDT_ERR_NOSPACE), - - FDT_ERRTABENT(FDT_ERR_BADOFFSET), - FDT_ERRTABENT(FDT_ERR_BADPATH), - FDT_ERRTABENT(FDT_ERR_BADSTATE), - - FDT_ERRTABENT(FDT_ERR_TRUNCATED), - FDT_ERRTABENT(FDT_ERR_BADMAGIC), - FDT_ERRTABENT(FDT_ERR_BADVERSION), - FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), - FDT_ERRTABENT(FDT_ERR_BADLAYOUT), -}; -#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) - -const char *fdt_strerror(int errval) -{ - if (errval > 0) - return "<valid offset/length>"; - else if (errval == 0) - return "<no error>"; - else if (errval > -FDT_ERRTABSIZE) { - const char *s = fdt_errtable[-errval].str; - - if (s) - return s; - } - - return "<unknown error>"; -} diff --git a/lib/libfdt/fdt_sw.c b/lib/libfdt/fdt_sw.c deleted file mode 100644 index f422754..0000000 --- a/lib/libfdt/fdt_sw.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include <fdt.h> -#include <libfdt.h> - -#include "libfdt_internal.h" - -static int _fdt_sw_check_header(void *fdt) -{ - if (fdt_magic(fdt) != FDT_SW_MAGIC) - return -FDT_ERR_BADMAGIC; - /* FIXME: should check more details about the header state */ - return 0; -} - -#define FDT_SW_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = _fdt_sw_check_header(fdt)) != 0) \ - return err; \ - } - -static void *_fdt_grab_space(void *fdt, size_t len) -{ - int offset = fdt_size_dt_struct(fdt); - int spaceleft; - - spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - - fdt_size_dt_strings(fdt); - - if ((offset + len < offset) || (offset + len > spaceleft)) - return NULL; - - fdt_set_size_dt_struct(fdt, offset + len); - return _fdt_offset_ptr_w(fdt, offset); -} - -int fdt_create(void *buf, int bufsize) -{ - void *fdt = buf; - - if (bufsize < sizeof(struct fdt_header)) - return -FDT_ERR_NOSPACE; - - memset(buf, 0, bufsize); - - fdt_set_magic(fdt, FDT_SW_MAGIC); - fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); - fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); - fdt_set_totalsize(fdt, bufsize); - - fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry))); - fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); - fdt_set_off_dt_strings(fdt, bufsize); - - return 0; -} - -int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) -{ - struct fdt_reserve_entry *re; - int offset; - - FDT_SW_CHECK_HEADER(fdt); - - if (fdt_size_dt_struct(fdt)) - return -FDT_ERR_BADSTATE; - - offset = fdt_off_dt_struct(fdt); - if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) - return -FDT_ERR_NOSPACE; - - re = (struct fdt_reserve_entry *)((char *)fdt + offset); - re->address = cpu_to_fdt64(addr); - re->size = cpu_to_fdt64(size); - - fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); - - return 0; -} - -int fdt_finish_reservemap(void *fdt) -{ - return fdt_add_reservemap_entry(fdt, 0, 0); -} - -int fdt_begin_node(void *fdt, const char *name) -{ - struct fdt_node_header *nh; - int namelen = strlen(name) + 1; - - FDT_SW_CHECK_HEADER(fdt); - - nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); - if (! nh) - return -FDT_ERR_NOSPACE; - - nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); - memcpy(nh->name, name, namelen); - return 0; -} - -int fdt_end_node(void *fdt) -{ - fdt32_t *en; - - FDT_SW_CHECK_HEADER(fdt); - - en = _fdt_grab_space(fdt, FDT_TAGSIZE); - if (! en) - return -FDT_ERR_NOSPACE; - - *en = cpu_to_fdt32(FDT_END_NODE); - return 0; -} - -static int _fdt_find_add_string(void *fdt, const char *s) -{ - char *strtab = (char *)fdt + fdt_totalsize(fdt); - const char *p; - int strtabsize = fdt_size_dt_strings(fdt); - int len = strlen(s) + 1; - int struct_top, offset; - - p = _fdt_find_string(strtab - strtabsize, strtabsize, s); - if (p) - return p - strtab; - - /* Add it */ - offset = -strtabsize - len; - struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - if (fdt_totalsize(fdt) + offset < struct_top) - return 0; /* no more room :( */ - - memcpy(strtab + offset, s, len); - fdt_set_size_dt_strings(fdt, strtabsize + len); - return offset; -} - -int fdt_property(void *fdt, const char *name, const void *val, int len) -{ - struct fdt_property *prop; - int nameoff; - - FDT_SW_CHECK_HEADER(fdt); - - nameoff = _fdt_find_add_string(fdt, name); - if (nameoff == 0) - return -FDT_ERR_NOSPACE; - - prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); - if (! prop) - return -FDT_ERR_NOSPACE; - - prop->tag = cpu_to_fdt32(FDT_PROP); - prop->nameoff = cpu_to_fdt32(nameoff); - prop->len = cpu_to_fdt32(len); - memcpy(prop->data, val, len); - return 0; -} - -int fdt_finish(void *fdt) -{ - char *p = (char *)fdt; - fdt32_t *end; - int oldstroffset, newstroffset; - uint32_t tag; - int offset, nextoffset; - - FDT_SW_CHECK_HEADER(fdt); - - /* Add terminator */ - end = _fdt_grab_space(fdt, sizeof(*end)); - if (! end) - return -FDT_ERR_NOSPACE; - *end = cpu_to_fdt32(FDT_END); - - /* Relocate the string table */ - oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); - newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); - fdt_set_off_dt_strings(fdt, newstroffset); - - /* Walk the structure, correcting string offsets */ - offset = 0; - while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { - if (tag == FDT_PROP) { - struct fdt_property *prop = - _fdt_offset_ptr_w(fdt, offset); - int nameoff; - - nameoff = fdt32_to_cpu(prop->nameoff); - nameoff += fdt_size_dt_strings(fdt); - prop->nameoff = cpu_to_fdt32(nameoff); - } - offset = nextoffset; - } - if (nextoffset < 0) - return nextoffset; - - /* Finally, adjust the header */ - fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); - fdt_set_magic(fdt, FDT_MAGIC); - return 0; -} diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c deleted file mode 100644 index c5bbb68..0000000 --- a/lib/libfdt/fdt_wip.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include <fdt.h> -#include <libfdt.h> - -#include "libfdt_internal.h" - -int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - void *propval; - int proplen; - - propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); - if (! propval) - return proplen; - - if (proplen != len) - return -FDT_ERR_NOSPACE; - - memcpy(propval, val, len); - return 0; -} - -static void _fdt_nop_region(void *start, int len) -{ - fdt32_t *p; - - for (p = start; (char *)p < ((char *)start + len); p++) - *p = cpu_to_fdt32(FDT_NOP); -} - -int fdt_nop_property(void *fdt, int nodeoffset, const char *name) -{ - struct fdt_property *prop; - int len; - - prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (! prop) - return len; - - _fdt_nop_region(prop, len + sizeof(*prop)); - - return 0; -} - -int _fdt_node_end_offset(void *fdt, int offset) -{ - int depth = 0; - - while ((offset >= 0) && (depth >= 0)) - offset = fdt_next_node(fdt, offset, &depth); - - return offset; -} - -int fdt_nop_node(void *fdt, int nodeoffset) -{ - int endoffset; - - endoffset = _fdt_node_end_offset(fdt, nodeoffset); - if (endoffset < 0) - return endoffset; - - _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), - endoffset - nodeoffset); - return 0; -} diff --git a/lib/libfdt/libfdt.h b/lib/libfdt/libfdt.h deleted file mode 100644 index 02baa84..0000000 --- a/lib/libfdt/libfdt.h +++ /dev/null @@ -1,1514 +0,0 @@ -#ifndef _LIBFDT_H -#define _LIBFDT_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <libfdt_env.h> -#include <fdt.h> - -#define FDT_FIRST_SUPPORTED_VERSION 0x10 -#define FDT_LAST_SUPPORTED_VERSION 0x11 - -/* Error codes: informative error codes */ -#define FDT_ERR_NOTFOUND 1 - /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ -#define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attemped to create a node or property which - * already exists */ -#define FDT_ERR_NOSPACE 3 - /* FDT_ERR_NOSPACE: Operation needed to expand the device - * tree, but its buffer did not have sufficient space to - * contain the expanded tree. Use fdt_open_into() to move the - * device tree to a buffer with more space. */ - -/* Error codes: codes for bad parameters */ -#define FDT_ERR_BADOFFSET 4 - /* FDT_ERR_BADOFFSET: Function was passed a structure block - * offset which is out-of-bounds, or which points to an - * unsuitable part of the structure for the operation. */ -#define FDT_ERR_BADPATH 5 - /* FDT_ERR_BADPATH: Function was passed a badly formatted path - * (e.g. missing a leading / for a function which requires an - * absolute path) */ -#define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ -#define FDT_ERR_BADSTATE 7 - /* FDT_ERR_BADSTATE: Function was passed an incomplete device - * tree created by the sequential-write functions, which is - * not sufficiently complete for the requested operation. */ - -/* Error codes: codes for bad device tree blobs */ -#define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: Structure block of the given device tree - * ends without an FDT_END tag. */ -#define FDT_ERR_BADMAGIC 9 - /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a - * device tree at all - it is missing the flattened device - * tree magic number. */ -#define FDT_ERR_BADVERSION 10 - /* FDT_ERR_BADVERSION: Given device tree has a version which - * can't be handled by the requested operation. For - * read-write functions, this may mean that fdt_open_into() is - * required to convert the tree to the expected version. */ -#define FDT_ERR_BADSTRUCTURE 11 - /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt - * structure block or other serious error (e.g. misnested - * nodes, or subnodes preceding properties). */ -#define FDT_ERR_BADLAYOUT 12 - /* FDT_ERR_BADLAYOUT: For read-write functions, the given - * device tree has it's sub-blocks in an order that the - * function can't handle (memory reserve map, then structure, - * then strings). Use fdt_open_into() to reorganize the tree - * into a form suitable for the read-write operations. */ - -/* "Can't happen" error indicating a bug in libfdt */ -#define FDT_ERR_INTERNAL 13 - /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. - * Should never be returned, if it is, it indicates a bug in - * libfdt itself. */ - -#define FDT_ERR_MAX 13 - -/**********************************************************************/ -/* Low-level functions (you probably don't need these) */ -/**********************************************************************/ - -const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); -static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) -{ - return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); -} - -uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); - -/**********************************************************************/ -/* Traversal functions */ -/**********************************************************************/ - -int fdt_next_node(const void *fdt, int offset, int *depth); - -/** - * fdt_first_subnode() - get offset of first direct subnode - * - * @fdt: FDT blob - * @offset: Offset of node to check - * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none - */ -int fdt_first_subnode(const void *fdt, int offset); - -/** - * fdt_next_subnode() - get offset of next direct subnode - * - * After first calling fdt_first_subnode(), call this function repeatedly to - * get direct subnodes of a parent node. - * - * @fdt: FDT blob - * @offset: Offset of previous subnode - * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more - * subnodes - */ -int fdt_next_subnode(const void *fdt, int offset); - -/**********************************************************************/ -/* General functions */ -/**********************************************************************/ - -#define fdt_get_header(fdt, field) \ - (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) -#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) -#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) -#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) -#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) -#define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) -#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) - -#define __fdt_set_hdr(name) \ - static inline void fdt_set_##name(void *fdt, uint32_t val) \ - { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ - fdth->name = cpu_to_fdt32(val); \ - } -__fdt_set_hdr(magic); -__fdt_set_hdr(totalsize); -__fdt_set_hdr(off_dt_struct); -__fdt_set_hdr(off_dt_strings); -__fdt_set_hdr(off_mem_rsvmap); -__fdt_set_hdr(version); -__fdt_set_hdr(last_comp_version); -__fdt_set_hdr(boot_cpuid_phys); -__fdt_set_hdr(size_dt_strings); -__fdt_set_hdr(size_dt_struct); -#undef __fdt_set_hdr - -/** - * fdt_check_header - sanity check a device tree or possible device tree - * @fdt: pointer to data which might be a flattened device tree - * - * fdt_check_header() checks that the given buffer contains what - * appears to be a flattened device tree with sane information in its - * header. - * - * returns: - * 0, if the buffer appears to contain a valid device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings, as above - */ -int fdt_check_header(const void *fdt); - -/** - * fdt_move - move a device tree around in memory - * @fdt: pointer to the device tree to move - * @buf: pointer to memory where the device is to be moved - * @bufsize: size of the memory space at buf - * - * fdt_move() relocates, if possible, the device tree blob located at - * fdt to the buffer at buf of size bufsize. The buffer may overlap - * with the existing device tree blob at fdt. Therefore, - * fdt_move(fdt, fdt, fdt_totalsize(fdt)) - * should always succeed. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_move(const void *fdt, void *buf, int bufsize); - -/**********************************************************************/ -/* Read-only functions */ -/**********************************************************************/ - -/** - * fdt_string - retrieve a string from the strings block of a device tree - * @fdt: pointer to the device tree blob - * @stroffset: offset of the string within the strings block (native endian) - * - * fdt_string() retrieves a pointer to a single string from the - * strings block of the device tree blob at fdt. - * - * returns: - * a pointer to the string, on success - * NULL, if stroffset is out of bounds - */ -const char *fdt_string(const void *fdt, int stroffset); - -/** - * fdt_num_mem_rsv - retrieve the number of memory reserve map entries - * @fdt: pointer to the device tree blob - * - * Returns the number of entries in the device tree blob's memory - * reservation map. This does not include the terminating 0,0 entry - * or any other (0,0) entries reserved for expansion. - * - * returns: - * the number of entries - */ -int fdt_num_mem_rsv(const void *fdt); - -/** - * fdt_get_mem_rsv - retrieve one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: pointers to 64-bit variables - * - * On success, *address and *size will contain the address and size of - * the n-th reserve map entry from the device tree blob, in - * native-endian format. - * - * returns: - * 0, on success - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); - -/** - * fdt_subnode_offset_namelen - find a subnode based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_subnode_offset(), but only examine the first - * namelen characters of name for matching the subnode name. This is - * useful for finding subnodes based on a portion of a larger string, - * such as a full path. - */ -int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, - const char *name, int namelen); -/** - * fdt_subnode_offset - find a subnode of a given node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_subnode_offset() finds a subnode of the node at structure block - * offset parentoffset with the given name. name may include a unit - * address, in which case fdt_subnode_offset() will find the subnode - * with that unit address, or the unit address may be omitted, in - * which case fdt_subnode_offset() will find an arbitrary subnode - * whose name excluding unit address matches the given name. - * - * returns: - * structure block offset of the requested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); - -/** - * fdt_path_offset - find a tree node by its full path - * @fdt: pointer to the device tree blob - * @path: full path of the node to locate - * - * fdt_path_offset() finds a node of a given path in the device tree. - * Each path component may omit the unit address portion, but the - * results of this are undefined if any such path component is - * ambiguous (that is if there are multiple nodes at the relevant - * level matching the given component, differentiated only by unit - * address). - * - * returns: - * structure block offset of the node with the requested path (>=0), on success - * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid - * -FDT_ERR_NOTFOUND, if the requested node does not exist - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_path_offset(const void *fdt, const char *path); - -/** - * fdt_get_name - retrieve the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the starting node - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_name() retrieves the name (including unit address) of the - * device tree node at structure block offset nodeoffset. If lenp is - * non-NULL, the length of this name is also returned, in the integer - * pointed to by lenp. - * - * returns: - * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) - * NULL, on error - * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); - -/** - * fdt_first_property_offset - find the offset of a node's first property - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * - * fdt_first_property_offset() finds the first property of the node at - * the given structure block offset. - * - * returns: - * structure block offset of the property (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested node has no properties - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_first_property_offset(const void *fdt, int nodeoffset); - -/** - * fdt_next_property_offset - step through a node's properties - * @fdt: pointer to the device tree blob - * @offset: structure block offset of a property - * - * fdt_next_property_offset() finds the property immediately after the - * one at the given structure block offset. This will be a property - * of the same node as the given property. - * - * returns: - * structure block offset of the next property (>=0), on success - * -FDT_ERR_NOTFOUND, if the given property is the last in its node - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_next_property_offset(const void *fdt, int offset); - -/** - * fdt_get_property_by_offset - retrieve the property at a given offset - * @fdt: pointer to the device tree blob - * @offset: offset of the property to retrieve - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property_by_offset() retrieves a pointer to the - * fdt_property structure within the device tree blob at the given - * offset. If lenp is non-NULL, the length of the property value is - * also returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp); - -/** - * fdt_get_property_namelen - find a property based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_get_property_namelen(), but only examine the first - * namelen characters of name for matching the property name. - */ -const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int nodeoffset, - const char *name, - int namelen, int *lenp); - -/** - * fdt_get_property - find a given property in a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property() retrieves a pointer to the fdt_property - * structure within the device tree blob corresponding to the property - * named 'name' of the node at offset nodeoffset. If lenp is - * non-NULL, the length of the property value is also returned, in the - * integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, - const char *name, - int *lenp) -{ - return (struct fdt_property *)(uintptr_t) - fdt_get_property(fdt, nodeoffset, name, lenp); -} - -/** - * fdt_getprop_by_offset - retrieve the value of a property at a given offset - * @fdt: pointer to the device tree blob - * @ffset: offset of the property to read - * @namep: pointer to a string variable (will be overwritten) or NULL - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop_by_offset() retrieves a pointer to the value of the - * property at structure block offset 'offset' (this will be a pointer - * to within the device blob itself, not a copy of the value). If - * lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. If namep is non-NULL, - * the property's namne will also be returned in the char * pointed to - * by namep (this will be a pointer to within the device tree's string - * block, not a new copy of the name). - * - * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * if namep is non-NULL *namep contiains a pointer to the property - * name. - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp); - -/** - * fdt_getprop_namelen - get property value based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_getprop(), but only examine the first namelen - * characters of name for matching the property name. - */ -const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp); - -/** - * fdt_getprop - retrieve the value of a given property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop() retrieves a pointer to the value of the property - * named 'name' of the node at offset nodeoffset (this will be a - * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline void *fdt_getprop_w(void *fdt, int nodeoffset, - const char *name, int *lenp) -{ - return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); -} - -/** - * fdt_get_phandle - retrieve the phandle of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the node - * - * fdt_get_phandle() retrieves the phandle of the device tree node at - * structure block offset nodeoffset. - * - * returns: - * the phandle of the node at nodeoffset, on success (!= 0, != -1) - * 0, if the node has no phandle, or another error occurs - */ -uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); - -/** - * fdt_get_alias_namelen - get alias based on substring - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * @namelen: number of characters of name to consider - * - * Identical to fdt_get_alias(), but only examine the first namelen - * characters of name for matching the alias name. - */ -const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen); - -/** - * fdt_get_alias - retreive the path referenced by a given alias - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * - * fdt_get_alias() retrieves the value of a given alias. That is, the - * value of the property named 'name' in the node /aliases. - * - * returns: - * a pointer to the expansion of the alias named 'name', if it exists - * NULL, if the given alias or the /aliases node does not exist - */ -const char *fdt_get_alias(const void *fdt, const char *name); - -/** - * fdt_get_path - determine the full path of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose path to find - * @buf: character buffer to contain the returned path (will be overwritten) - * @buflen: size of the character buffer at buf - * - * fdt_get_path() computes the full path of the node at offset - * nodeoffset, and records that path in the buffer at buf. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * 0, on success - * buf contains the absolute path of the node at - * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) - * characters and will not fit in the given buffer. - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); - -/** - * fdt_supernode_atdepth_offset - find a specific ancestor of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * @supernodedepth: depth of the ancestor to find - * @nodedepth: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_supernode_atdepth_offset() finds an ancestor of the given node - * at a specific depth from the root (where the root itself has depth - * 0, its immediate subnodes depth 1 and so forth). So - * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); - * will always return 0, the offset of the root node. If the node at - * nodeoffset has depth D, then: - * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); - * will return nodeoffset itself. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - - * structure block offset of the node at node offset's ancestor - * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth); - -/** - * fdt_node_depth - find the depth of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_node_depth() finds the depth of a given node. The root node - * has depth 0, its immediate subnodes depth 1 and so forth. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_depth(const void *fdt, int nodeoffset); - -/** - * fdt_parent_offset - find the parent of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_parent_offset() locates the parent node of a given node (that - * is, it finds the offset of the node which contains the node at - * nodeoffset as a subnode). - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset, *twice*. - * - * returns: - * structure block offset of the parent of the node at nodeoffset - * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_parent_offset(const void *fdt, int nodeoffset); - -/** - * fdt_node_offset_by_prop_value - find nodes with a given property value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @propname: property name to check - * @propval: property value to search for - * @proplen: length of the value in propval - * - * fdt_node_offset_by_prop_value() returns the offset of the first - * node after startoffset, which has a property named propname whose - * value is of length proplen and has value equal to propval; or if - * startoffset is -1, the very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, - * propval, proplen); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, - * propval, proplen); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen); - -/** - * fdt_node_offset_by_phandle - find the node with a given phandle - * @fdt: pointer to the device tree blob - * @phandle: phandle value - * - * fdt_node_offset_by_phandle() returns the offset of the node - * which has the given phandle value. If there is more than one node - * in the tree with the given phandle (an invalid tree), results are - * undefined. - * - * returns: - * structure block offset of the located node (>= 0), on success - * -FDT_ERR_NOTFOUND, no node with that phandle exists - * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); - -/** - * fdt_node_check_compatible: check a node's compatible property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of a tree node - * @compatible: string to match against - * - * - * fdt_node_check_compatible() returns 0 if the given node contains a - * 'compatible' property with the given string as one of its elements, - * it returns non-zero otherwise, or on error. - * - * returns: - * 0, if the node has a 'compatible' property listing the given string - * 1, if the node has a 'compatible' property, but it does not list - * the given string - * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible); - -/** - * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @compatible: 'compatible' string to match against - * - * fdt_node_offset_by_compatible() returns the offset of the first - * node after startoffset, which has a 'compatible' property which - * lists the given compatible string; or if startoffset is -1, the - * very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible); - -/** - * fdt_stringlist_contains - check a string list property for a string - * @strlist: Property containing a list of strings to check - * @listlen: Length of property - * @str: String to search for - * - * This is a utility function provided for convenience. The list contains - * one or more strings, each terminated by \0, as is found in a device tree - * "compatible" property. - * - * @return: 1 if the string is found in the list, 0 not found, or invalid list - */ -int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); - -/**********************************************************************/ -/* Write-in-place functions */ -/**********************************************************************/ - -/** - * fdt_setprop_inplace - change a property's value, but not its size - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to replace the property value with - * @len: length of the property value - * - * fdt_setprop_inplace() replaces the value of a given property with - * the data in val, of length len. This function cannot change the - * size of a property, and so will only work if len is equal to the - * current length of the property. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if len is not equal to the property's current length - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value to replace the property with - * - * fdt_setprop_inplace_u32() replaces the value of a given property - * with the 32-bit integer value in val, converting val to big-endian - * if necessary. This function cannot change the size of a property, - * and so will only work if the property already exists and has length - * 4. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 64-bit integer value to replace the property with - * - * fdt_setprop_inplace_u64() replaces the value of a given property - * with the 64-bit integer value in val, converting val to big-endian - * if necessary. This function cannot change the size of a property, - * and so will only work if the property already exists and has length - * 8. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, - const char *name, uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_inplace_cell - change the value of a single-cell property - * - * This is an alternative name for fdt_setprop_inplace_u32() - */ -static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); -} - -/** - * fdt_nop_property - replace a property with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_nop_property() will replace a given property's representation - * in the blob with FDT_NOP tags, effectively removing it from the - * tree. - * - * This function will alter only the bytes in the blob which contain - * the property, and will not alter or move any other part of the - * tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_property(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_nop_node - replace a node (subtree) with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_nop_node() will replace a given node's representation in the - * blob, including all its subnodes, if any, with FDT_NOP tags, - * effectively removing it from the tree. - * - * This function will alter only the bytes in the blob which contain - * the node and its properties and subnodes, and will not alter or - * move any other part of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_node(void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Sequential write functions */ -/**********************************************************************/ - -int fdt_create(void *buf, int bufsize); -int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); -int fdt_finish_reservemap(void *fdt); -int fdt_begin_node(void *fdt, const char *name); -int fdt_property(void *fdt, const char *name, const void *val, int len); -static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_property(fdt, name, &tmp, sizeof(tmp)); -} -static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_property(fdt, name, &tmp, sizeof(tmp)); -} -static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) -{ - return fdt_property_u32(fdt, name, val); -} -#define fdt_property_string(fdt, name, str) \ - fdt_property(fdt, name, str, strlen(str)+1) -int fdt_end_node(void *fdt); -int fdt_finish(void *fdt); - -/**********************************************************************/ -/* Read-write functions */ -/**********************************************************************/ - -int fdt_create_empty_tree(void *buf, int bufsize); -int fdt_open_into(const void *fdt, void *buf, int bufsize); -int fdt_pack(void *fdt); - -/** - * fdt_add_mem_rsv - add one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: 64-bit values (native endian) - * - * Adds a reserve map entry to the given blob reserving a region at - * address address of length size. - * - * This function will insert data into the reserve map and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new reservation entry - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); - -/** - * fdt_del_mem_rsv - remove a memory reserve map entry - * @fdt: pointer to the device tree blob - * @n: entry to remove - * - * fdt_del_mem_rsv() removes the n-th memory reserve map entry from - * the blob. - * - * This function will delete data from the reservation table and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there - * are less than n+1 reserve map entries) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_mem_rsv(void *fdt, int n); - -/** - * fdt_set_name - change the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * @name: name to give the node - * - * fdt_set_name() replaces the name (including unit address, if any) - * of the given node with the given string. NOTE: this function can't - * efficiently check if the new name is unique amongst the given - * node's siblings; results are undefined if this function is invoked - * with a name equal to one of the given node's siblings. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob - * to contain the new name - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_set_name(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_setprop - create or change a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to set the property value to - * @len: length of the property value - * - * fdt_setprop() sets the value of the named property in the given - * node to the given value and length, creating the property if it - * does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_u32 - set a property to a 32-bit integer - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value for the property (native endian) - * - * fdt_setprop_u32() sets the value of the named property in the given - * node to the given 32-bit integer value (converting to big-endian if - * necessary), or creates a new property with that value if it does - * not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, - uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_u64 - set a property to a 64-bit integer - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 64-bit integer value for the property (native endian) - * - * fdt_setprop_u64() sets the value of the named property in the given - * node to the given 64-bit integer value (converting to big-endian if - * necessary), or creates a new property with that value if it does - * not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, - uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_cell - set a property to a single cell value - * - * This is an alternative name for fdt_setprop_u32() - */ -static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, - uint32_t val) -{ - return fdt_setprop_u32(fdt, nodeoffset, name, val); -} - -/** - * fdt_setprop_string - set a property to a string value - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @str: string value for the property - * - * fdt_setprop_string() sets the value of the named property in the - * given node to the given string value (using the length of the - * string to determine the new length of the property), or creates a - * new property with that value if it does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -#define fdt_setprop_string(fdt, nodeoffset, name, str) \ - fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) - -/** - * fdt_appendprop - append to or create a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to append to - * @val: pointer to data to append to the property value - * @len: length of the data to append to the property value - * - * fdt_appendprop() appends the value to the named property in the - * given node, creating the property if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_appendprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_appendprop_u32 - append a 32-bit integer value to a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value to append to the property (native endian) - * - * fdt_appendprop_u32() appends the given 32-bit integer value - * (converting to big-endian if necessary) to the value of the named - * property in the given node, or creates a new property with that - * value if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_appendprop_u64 - append a 64-bit integer value to a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 64-bit integer value to append to the property (native endian) - * - * fdt_appendprop_u64() appends the given 64-bit integer value - * (converting to big-endian if necessary) to the value of the named - * property in the given node, or creates a new property with that - * value if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, - const char *name, uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_appendprop_cell - append a single cell value to a property - * - * This is an alternative name for fdt_appendprop_u32() - */ -static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - return fdt_appendprop_u32(fdt, nodeoffset, name, val); -} - -/** - * fdt_appendprop_string - append a string to a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @str: string value to append to the property - * - * fdt_appendprop_string() appends the given string to the value of - * the named property in the given node, or creates a new property - * with that value if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -#define fdt_appendprop_string(fdt, nodeoffset, name, str) \ - fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) - -/** - * fdt_delprop - delete a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_del_property() will delete the given property. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_delprop(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_add_subnode_namelen - creates a new node based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_add_subnode(), but use only the first namelen - * characters of name as the name of the new node. This is useful for - * creating subnodes based on a portion of a larger string, such as a - * full path. - */ -int fdt_add_subnode_namelen(void *fdt, int parentoffset, - const char *name, int namelen); - -/** - * fdt_add_subnode - creates a new node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_add_subnode() creates a new node as a subnode of the node at - * structure block offset parentoffset, with the given name (which - * should include the unit address, if any). - * - * This function will insert data into the blob, and will therefore - * change the offsets of some existing nodes. - - * returns: - * structure block offset of the created nodeequested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of - * the given name - * -FDT_ERR_NOSPACE, if there is insufficient free space in the - * blob to contain the new node - * -FDT_ERR_NOSPACE - * -FDT_ERR_BADLAYOUT - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_add_subnode(void *fdt, int parentoffset, const char *name); - -/** - * fdt_del_node - delete a node (subtree) - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_del_node() will remove the given node, including all its - * subnodes if any, from the blob. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_node(void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Debugging / informational functions */ -/**********************************************************************/ - -const char *fdt_strerror(int errval); - -#endif /* _LIBFDT_H */ diff --git a/lib/libfdt/libfdt_env.h b/lib/libfdt/libfdt_env.h deleted file mode 100644 index 9dea97d..0000000 --- a/lib/libfdt/libfdt_env.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _LIBFDT_ENV_H -#define _LIBFDT_ENV_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * Copyright 2012 Kim Phillips, Freescale Semiconductor. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stddef.h> -#include <stdint.h> -#include <string.h> - -#ifdef __CHECKER__ -#define __force __attribute__((force)) -#define __bitwise __attribute__((bitwise)) -#else -#define __force -#define __bitwise -#endif - -typedef uint16_t __bitwise fdt16_t; -typedef uint32_t __bitwise fdt32_t; -typedef uint64_t __bitwise fdt64_t; - -#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) -#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) -#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ - (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) -#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ - (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ - (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ - (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) - -static inline uint16_t fdt16_to_cpu(fdt16_t x) -{ - return (__force uint16_t)CPU_TO_FDT16(x); -} -static inline fdt16_t cpu_to_fdt16(uint16_t x) -{ - return (__force fdt16_t)CPU_TO_FDT16(x); -} - -static inline uint32_t fdt32_to_cpu(fdt32_t x) -{ - return (__force uint32_t)CPU_TO_FDT32(x); -} -static inline fdt32_t cpu_to_fdt32(uint32_t x) -{ - return (__force fdt32_t)CPU_TO_FDT32(x); -} - -static inline uint64_t fdt64_to_cpu(fdt64_t x) -{ - return (__force uint64_t)CPU_TO_FDT64(x); -} -static inline fdt64_t cpu_to_fdt64(uint64_t x) -{ - return (__force fdt64_t)CPU_TO_FDT64(x); -} -#undef CPU_TO_FDT64 -#undef CPU_TO_FDT32 -#undef CPU_TO_FDT16 -#undef EXTRACT_BYTE - -#endif /* _LIBFDT_ENV_H */ diff --git a/lib/libfdt/libfdt_internal.h b/lib/libfdt/libfdt_internal.h deleted file mode 100644 index 381133b..0000000 --- a/lib/libfdt/libfdt_internal.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _LIBFDT_INTERNAL_H -#define _LIBFDT_INTERNAL_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include <fdt.h> - -#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) - -#define FDT_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = fdt_check_header(fdt)) != 0) \ - return err; \ - } - -int _fdt_check_node_offset(const void *fdt, int offset); -int _fdt_check_prop_offset(const void *fdt, int offset); -const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); -int _fdt_node_end_offset(void *fdt, int nodeoffset); - -static inline const void *_fdt_offset_ptr(const void *fdt, int offset) -{ - return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; -} - -static inline void *_fdt_offset_ptr_w(void *fdt, int offset) -{ - return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); -} - -static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) -{ - const struct fdt_reserve_entry *rsv_table = - (const struct fdt_reserve_entry *) - ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); - - return rsv_table + n; -} -static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) -{ - return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); -} - -#define FDT_SW_MAGIC (~FDT_MAGIC) - -#endif /* _LIBFDT_INTERNAL_H */ diff --git a/lib/libfdt/version.lds b/lib/libfdt/version.lds deleted file mode 100644 index 80b322b..0000000 --- a/lib/libfdt/version.lds +++ /dev/null @@ -1,60 +0,0 @@ -LIBFDT_1.2 { - global: - fdt_next_node; - fdt_check_header; - fdt_move; - fdt_string; - fdt_num_mem_rsv; - fdt_get_mem_rsv; - fdt_subnode_offset_namelen; - fdt_subnode_offset; - fdt_path_offset; - fdt_get_name; - fdt_get_property_namelen; - fdt_get_property; - fdt_getprop_namelen; - fdt_getprop; - fdt_get_phandle; - fdt_get_alias_namelen; - fdt_get_alias; - fdt_get_path; - fdt_supernode_atdepth_offset; - fdt_node_depth; - fdt_parent_offset; - fdt_node_offset_by_prop_value; - fdt_node_offset_by_phandle; - fdt_node_check_compatible; - fdt_node_offset_by_compatible; - fdt_setprop_inplace; - fdt_nop_property; - fdt_nop_node; - fdt_create; - fdt_add_reservemap_entry; - fdt_finish_reservemap; - fdt_begin_node; - fdt_property; - fdt_end_node; - fdt_finish; - fdt_open_into; - fdt_pack; - fdt_add_mem_rsv; - fdt_del_mem_rsv; - fdt_set_name; - fdt_setprop; - fdt_delprop; - fdt_add_subnode_namelen; - fdt_add_subnode; - fdt_del_node; - fdt_strerror; - fdt_offset_ptr; - fdt_next_tag; - fdt_appendprop; - fdt_create_empty_tree; - fdt_first_property_offset; - fdt_get_property_by_offset; - fdt_getprop_by_offset; - fdt_next_property_offset; - - local: - *; -}; diff --git a/lib/libcflat/COPYRIGHT b/libcflat/COPYRIGHT index d35649c..d35649c 100644 --- a/lib/libcflat/COPYRIGHT +++ b/libcflat/COPYRIGHT diff --git a/lib/libcflat/arm/eabi_compat.c b/libcflat/arm/eabi_compat.c index 59d624d..59d624d 100644 --- a/lib/libcflat/arm/eabi_compat.c +++ b/libcflat/arm/eabi_compat.c diff --git a/lib/libcflat/arm/asm/io.h b/libcflat/arm/include/io.h index 1d0abb7..55f0548 100644 --- a/lib/libcflat/arm/asm/io.h +++ b/libcflat/arm/include/io.h @@ -1,7 +1,6 @@ #ifndef _ASMARM_IO_H_ #define _ASMARM_IO_H_ #include "libcflat.h" -#include "asm/barrier.h" #define __iomem #define __force diff --git a/libcflat/arm/io.c b/libcflat/arm/io.c new file mode 100644 index 0000000..b7fba6b --- /dev/null +++ b/libcflat/arm/io.c @@ -0,0 +1,33 @@ +/* + * Each architecture must implement puts() and exit() with the I/O + * devices exposed from QEMU, e.g. pl011 and virtio-testdev. That's + * what's done here, along with initialization functions for those + * devices. + * + * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "libcflat.h" +#include "io.h" +#include "platform.h" + +extern void halt(int code); + +/* + * Use this guess for the pl011 base in order to make an attempt at + * having earlier printf support. We'll overwrite it with the real + * base address that we read from the device tree later. + */ +static volatile u8 *uart0_base = (u8 *)UART0_BASE; + +void puts(const char *s) +{ + while (*s) + writeb(*s++, uart0_base); +} + +void exit(int code) +{ + halt(code); +} diff --git a/lib/libcflat/arm/misc.S b/libcflat/arm/misc.S index 500d14a..500d14a 100644 --- a/lib/libcflat/arm/misc.S +++ b/libcflat/arm/misc.S diff --git a/lib/libcflat/asm-generic/io.h b/libcflat/include/asm-generic/io.h index f00f4d3..f00f4d3 100644 --- a/lib/libcflat/asm-generic/io.h +++ b/libcflat/include/asm-generic/io.h diff --git a/lib/libcflat/libcflat.h b/libcflat/include/libcflat.h index 404560c..404560c 100644 --- a/lib/libcflat/libcflat.h +++ b/libcflat/include/libcflat.h diff --git a/lib/libcflat/string.h b/libcflat/include/string.h index dbab368..dbab368 100644 --- a/lib/libcflat/string.h +++ b/libcflat/include/string.h diff --git a/lib/libcflat/printf.c b/libcflat/printf.c index 89308fb..89308fb 100644 --- a/lib/libcflat/printf.c +++ b/libcflat/printf.c diff --git a/lib/libcflat/string.c b/libcflat/string.c index 026f502..026f502 100644 --- a/lib/libcflat/string.c +++ b/libcflat/string.c diff --git a/platform/vexpress/platform.h b/platform/vexpress-a15/platform.h index 9ea9282..9ea9282 100644 --- a/platform/vexpress/platform.h +++ b/platform/vexpress-a15/platform.h diff --git a/platform/vexpress-a9/platform.h b/platform/vexpress-a9/platform.h new file mode 100644 index 0000000..334da32 --- /dev/null +++ b/platform/vexpress-a9/platform.h @@ -0,0 +1,33 @@ +#ifndef _PLATFORM_H +#define _PLATFORM_H + +/* NORFLASH0 on Vexpress aseries (a15) is mapped from 0x08000000 to 0x0A000000 + * which is 32MB. It is also aliased to 0x0 (to 0x2000000). + * It is acceptable to have the text here as it is RO. + */ +#define FLASH_SEC_BASE 0x00000000 +#define FLASH_NSEC_BASE 0x00010000 + +#define RAM_SEC_BASE 0x60000000 +#define RAM_NSEC_BASE 0x68000000 + +#define UART0_BASE 0x10009000 + +/* Taken from Linux vexpress support */ +#define SYSREG_BASE 0x10000000 +#define SYSREG_CFGCTRL 0xa4 +#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20) +#define SYS_CFGFUNC_RESET 5 +#define SYS_CFGFUNC_SHUTDOWN 8 +#define SYS_CFGCTRL_START (1 << 31) +#define SYS_CFGCTRL_WRITE (1 << 30) +#define SYS_SHUTDOWN (SYS_CFGCTRL_FUNC(SYS_CFGFUNC_SHUTDOWN) | \ + SYS_CFGCTRL_START | SYS_CFGCTRL_WRITE) +#define SYS_RESET (SYS_CFGCTRL_FUNC(SYS_CFGFUNC_SHUTDOWN) | \ + SYS_CFGCTRL_START | SYS_CFGCTRL_WRITE) + +#define STACK_SIZE 0x4000 + +#define TZTEST_COMMON_HEAP_BASE 0x69000000 +#define TZTEST_SHARED_HEAP_BASE 0x6a000000 +#endif diff --git a/platform/virt/platform.h b/platform/virt/platform.h new file mode 100644 index 0000000..956d819 --- /dev/null +++ b/platform/virt/platform.h @@ -0,0 +1,33 @@ +#ifndef _PLATFORM_H +#define _PLATFORM_H + +/* NORFLASH0 on Vexpress aseries (a15) is mapped from 0x08000000 to 0x0A000000 + * which is 32MB. It is also aliased to 0x0 (to 0x2000000). + * It is acceptable to have the text here as it is RO. + */ +#define FLASH_SEC_BASE 0x00000000 +#define FLASH_NSEC_BASE 0x00010000 + +#define RAM_SEC_BASE 0x40000000 +#define RAM_NSEC_BASE 0x48000000 + +#define UART0_BASE 0x09000000 + +/* Taken from Linux vexpress support */ +#define SYSREG_BASE 0x1c010000 +#define SYSREG_CFGCTRL 0xa4 +#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20) +#define SYS_CFGFUNC_RESET 5 +#define SYS_CFGFUNC_SHUTDOWN 8 +#define SYS_CFGCTRL_START (1 << 31) +#define SYS_CFGCTRL_WRITE (1 << 30) +#define SYS_SHUTDOWN (SYS_CFGCTRL_FUNC(SYS_CFGFUNC_SHUTDOWN) | \ + SYS_CFGCTRL_START | SYS_CFGCTRL_WRITE) +#define SYS_RESET (SYS_CFGCTRL_FUNC(SYS_CFGFUNC_SHUTDOWN) | \ + SYS_CFGCTRL_START | SYS_CFGCTRL_WRITE) + +#define STACK_SIZE 0x4000 + +#define TZTEST_COMMON_HEAP_BASE 0x49000000 +#define TZTEST_SHARED_HEAP_BASE 0x4A000000 +#endif |