├── .gitignore ├── LICENSE.txt ├── Makefile ├── README.txt ├── boot.S ├── c_start.c ├── config-default.mk ├── libfdt ├── Makefile.libfdt ├── fdt.c ├── fdt.h ├── fdt_ro.c ├── fdt_rw.c ├── fdt_strerror.c ├── fdt_sw.c ├── fdt_wip.c ├── libfdt.h ├── libfdt_env.h └── libfdt_internal.h ├── model.lds.S ├── semi_loader.c ├── semi_loader.h ├── semihosting.c ├── semihosting.h ├── string.c └── string.h /.gitignore: -------------------------------------------------------------------------------- 1 | filesystem.cpio.gz 2 | linux-system.axf 3 | uImage 4 | model.lds 5 | config.mk 6 | *.o 7 | *.swp 8 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, ARM Limited 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of ARM nor the names of its contributors may be 15 | used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile - build a kernel+filesystem image for stand-alone Linux booting 2 | # 3 | # Copyright (C) 2011 ARM Limited. All rights reserved. 4 | # 5 | # Use of this source code is governed by a BSD-style license that can be 6 | # found in the LICENSE.txt file. 7 | 8 | 9 | # Include config file (prefer config.mk, fall back to config-default.mk) 10 | ifneq ($(wildcard config.mk),) 11 | include config.mk 12 | else 13 | include config-default.mk 14 | endif 15 | 16 | LIBFDTOBJS = libfdt/fdt.o libfdt/fdt_ro.o libfdt/fdt_wip.o \ 17 | libfdt/fdt_sw.o libfdt/fdt_rw.o libfdt/fdt_strerror.o 18 | BOOTLOADER = boot.S 19 | OBJS = boot.o c_start.o semihosting.o string.o semi_loader.o $(LIBFDTOBJS) 20 | KERNEL = uImage 21 | 22 | IMAGE = linux-system.axf 23 | SEMIIMG = linux-system-semi.axf 24 | LD_SCRIPT = model.lds.S 25 | 26 | 27 | CC = $(CROSS_COMPILE)gcc 28 | LD = $(CROSS_COMPILE)ld 29 | 30 | # These are needed by the underlying kernel make 31 | export CROSS_COMPILE ARCH 32 | 33 | # Build all wrappers 34 | all: $(IMAGE) $(SEMIIMG) 35 | 36 | # Build just the semihosting wrapper 37 | semi: $(SEMIIMG) 38 | 39 | clean distclean: 40 | rm -f $(IMAGE) $(SEMIIMG) \ 41 | model.lds modelsemi.lds $(OBJS) $(KERNEL) 42 | 43 | $(KERNEL): $(KERNEL_SRC)/arch/arm/boot/uImage 44 | cp $< $@ 45 | 46 | $(IMAGE): $(OBJS) model.lds $(KERNEL) $(FILESYSTEM) Makefile 47 | $(LD) -o $@ $(OBJS) --script=model.lds 48 | 49 | $(SEMIIMG): $(OBJS) modelsemi.lds 50 | $(LD) -o $@ $(OBJS) --script=modelsemi.lds 51 | 52 | boot.o: $(BOOTLOADER) 53 | $(CC) $(CPPFLAGS) -DKCMD='$(KCMD)' -c -o $@ $< 54 | 55 | %.o: %.c 56 | $(CC) $(CPPFLAGS) -O2 -ffreestanding -I. -Ilibfdt -c -o $@ $< 57 | 58 | model.lds: $(LD_SCRIPT) Makefile 59 | $(CC) $(CPPFLAGS) -E -P -C -o $@ $< 60 | 61 | modelsemi.lds: $(LD_SCRIPT) Makefile 62 | $(CC) $(CPPFLAGS) -DSEMIHOSTING=1 -E -P -C -o $@ $< 63 | 64 | $(KERNEL_SRC)/arch/arm/boot/uImage: force 65 | $(MAKE) -C $(KERNEL_SRC) -j4 uImage 66 | 67 | # Pass any target we don't know about through to the kernel makefile. 68 | # This is a convenience rule so we can say 'make menuconfig' etc here. 69 | # Note that any rules in this file must have a command or be marked as 70 | # .PHONY. 71 | %: force 72 | $(MAKE) -C $(KERNEL_SRC) $@ 73 | 74 | force: ; 75 | 76 | Makefile: ; 77 | 78 | .PHONY: all semi clean distclean config.mk config-default.mk 79 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | boot-wrapper: Start Linux kernels under ARM Fast Models 2 | 3 | The boot-wrapper is a fairly simple implementation of a boot loader 4 | intended to run under an ARM Fast Model and boot Linux. 5 | 6 | License 7 | ======= 8 | 9 | The boot-wrapper is generally under a 3 clause BSD license 10 | (see LICENSE.txt for details). Note that some source files 11 | are under similar but compatible licenses. In particular 12 | libfdt is dual-license GPL/2-clause-BSD. 13 | 14 | Compilation 15 | =========== 16 | 17 | The expected method of building is to cross-compile on an 18 | x86 box. You'll need an ARM cross-compiler. On Ubuntu you 19 | can get this by installing the packages: 20 | gcc-4.6-arm-linux-gnueabi binutils-arm-linux-gnueabi 21 | libc6-armel-cross linux-libc-dev-armel-cross gcc-arm-linux-gnueabi 22 | libc6-dev-armel-cross cpp-arm-linux-gnueabi 23 | 24 | The boot-wrapper can be compiled in two ways: 25 | (1) as a small standalone binary which uses the model's semihosting 26 | ABI to load a kernel (and optionally initrd and flattened device tree) 27 | when you run the model 28 | (2) with a specific kernel and initrd compiled into the binary; 29 | this is less flexible but may be useful in some situations 30 | 31 | For case (1) you can just run: 32 | make CROSS_COMPILE=arm-linux-gnueabi- semi 33 | which will build "linux-system-semi.axf". 34 | (As with a Linux kernel cross-compile, the CROSS_COMPILE 35 | variable is set to the prefix of the cross toolchain. 36 | "arm-linux-gnueabi-" matches the prefix used by the Ubuntu 37 | cross toolchain.) 38 | 39 | For case (2) you'll need a Linux kernel tree to hand; the 40 | boot-wrapper makefile will automatically look into it to 41 | extract the kernel. By default this tree is assumed to be in 42 | "../linux-kvm-arm". Assuming you have that tree set up and 43 | have built a kernel in it, you can run: 44 | make CROSS_COMPILE=arm-linux-gnueabi- 45 | which will build "linux-system.axf". 46 | 47 | You can configure the makefile system by copying config-default.mk 48 | to config.mk and editing it. This is only likely to be useful for 49 | case (2); see the comments in config-default.mk for more information. 50 | 51 | Running 52 | ======= 53 | 54 | To run a model with a linux-system-semi.axf: 55 | 56 | RTSM_VE_Cortex-A15x1 linux-system-semi.axf -C cluster.cpu0.semihosting-cmd_line="--kernel /path/to/zImage [--initrd /path/to/initrd] [--dtb /path/to/dtb] [-- kernel command line arguments]" 57 | 58 | The paths to the kernel, initrd and device tree blob should all be 59 | host filesystem paths. The initrd and dtb are both optional. Any text 60 | following '--' is passed to the kernel as its command line; this is 61 | also optional. 62 | 63 | You may also want to pass other options to the model (for instance 64 | to enable networking); these are not described here. See the Fast 65 | Models documentation for more information. 66 | 67 | Running a linux-system.axf is the same, except that since all 68 | the files are built in there's no need to pass a command line: 69 | 70 | RTSM_VE_Cortex-A15x1 linux-system.axf 71 | 72 | Passing a command line to linux-system.axf is allowed, and any 73 | kernel/initrd/dtb/commandline specified will override the compiled-in 74 | version. 75 | -------------------------------------------------------------------------------- /boot.S: -------------------------------------------------------------------------------- 1 | /* 2 | * boot.S - simple register setup code for stand-alone Linux booting 3 | * 4 | * Copyright (C) 2011 ARM Limited. All rights reserved. 5 | * 6 | * Use of this source code is governed by a BSD-style license that can be 7 | * found in the LICENSE.txt file. 8 | */ 9 | 10 | .syntax unified 11 | .arch_extension sec 12 | .arch_extension virt 13 | .text 14 | 15 | .macro enter_hyp 16 | @ We assume we're entered in Secure Supervisor mode. To 17 | @ get to Hyp mode we have to pass through Monitor mode 18 | @ and NS-Supervisor mode. Note that there is no way to 19 | @ return to the Secure world once we've done this. 20 | @ 21 | @ This will trash r10 and r11. 22 | ldr r10, =vectors 23 | mcr p15, 0, r10, c12, c0, 1 @ Monitor vector base address 24 | @ Switch to monitor mode, which will set up the HVBAR and 25 | @ then return to us in NS-SVC 26 | smc #0 27 | @ Now we're in NS-SVC, make a Hyp call to get into Hyp mode 28 | hvc #0 29 | @ We will end up here in NS-Hyp. 30 | .endm 31 | 32 | .align 5 33 | /* We use the same vector table for Hyp and Monitor mode, since 34 | * we will only use each once and they don't overlap. 35 | */ 36 | vectors: 37 | .word 0 /* reset */ 38 | .word 0 /* undef */ 39 | b 2f /* smc */ 40 | .word 0 /* pabt */ 41 | .word 0 /* dabt */ 42 | b 1f 43 | .word 0 /* irq */ 44 | .word 0 /* fiq */ 45 | 46 | /* Return directly back to the caller without leaving Hyp mode: */ 47 | 1: mrs lr, elr_hyp 48 | mov pc, lr 49 | 50 | /* In monitor mode, set up HVBAR and SCR then return to caller in NS-SVC. */ 51 | 2: 52 | @ Set up HVBAR 53 | mrc p15, 0, r10, c1, c1, 0 @ SCR 54 | @ Set SCR.NS=1 (needed for setting HVBAR and also returning to NS state) 55 | @ .IRQ,FIQ,EA=0 (don't take aborts/exceptions to Monitor mode) 56 | @ .FW,AW=1 (CPSR.A,F modifiable in NS state) 57 | @ .nET=0 (early termination OK) 58 | @ .SCD=1 (SMC in NS mode is UNDEF, so accidental SMCs don't 59 | @ cause us to leap back into this code confusingly) 60 | @ .HCE=1 (HVC does Hyp call) 61 | bic r10, r10, #0x07f 62 | ldr r11, =0x1b1 63 | orr r10, r10, r11 64 | mcr p15, 0, r11, c1, c1, 0 65 | isb 66 | ldr r11, =vectors 67 | mcr p15, 4, r11, c12, c0, 0 @ set HVBAR 68 | @ ...and return to calling code in NS state 69 | movs pc, lr 70 | 71 | 72 | .globl start 73 | start: 74 | #ifdef SMP 75 | #ifdef VEXPRESS 76 | @ 77 | @ Program architected timer frequency 78 | @ 79 | mrc p15, 0, r0, c0, c1, 1 @ CPUID_EXT_PFR1 80 | lsr r0, r0, #16 81 | and r0, r0, #1 @ Check generic timer support 82 | beq 1f 83 | ldr r0, =24000000 @ 24MHz timer frequency 84 | mcr p15, 0, r0, c14, c0, 0 @ CNTFRQ 85 | 1: 86 | #endif 87 | @ 88 | @ CPU initialisation 89 | @ 90 | mrc p15, 0, r4, c0, c0, 5 @ MPIDR (ARMv7 only) 91 | and r4, r4, #15 @ CPU number 92 | 93 | @ 94 | @ Hypervisor / TrustZone initialization 95 | @ 96 | 97 | @ Set all interrupts to be non-secure 98 | ldr r0, =0x2c001000 @ Dist GIC base 99 | ldr r1, [r0, #0x04] @ Type Register 100 | cmp r4, #0 101 | andeq r1, r1, #0x1f 102 | movne r1, #0 103 | add r2, r0, #0x080 @ Security Register 0 104 | mvn r3, #0 105 | 2: str r3, [r2] 106 | sub r1, r1, #1 107 | add r2, r2, #4 @ Next security register 108 | cmp r1, #-1 109 | bne 2b 110 | 111 | @ Set GIC priority mask bit [7] = 1 112 | ldr r0, =0x2c002000 @ CPU GIC base 113 | mov r1, #0x80 114 | str r1, [r0, #0x4] @ GIC ICCPMR 115 | 116 | @ Set NSACR to allow coprocessor access from non-secure 117 | mrc p15, 0, r0, c1, c1, 2 118 | ldr r1, =0x43fff 119 | orr r0, r0, r1 120 | mcr p15, 0, r0, c1, c1, 2 121 | 122 | @ Check CPU nr again 123 | mrc p15, 0, r0, c0, c0, 5 @ MPIDR (ARMv7 only) 124 | bfc r0, #24, #8 @ CPU number, taking multicluster into account 125 | cmp r0, #0 @ primary CPU? 126 | beq 2f 127 | 128 | @ 129 | @ Secondary CPUs (following the RealView SMP booting protocol) 130 | @ 131 | enter_hyp 132 | 133 | ldr r1, =fs_start - 0x100 134 | adr r2, 1f 135 | ldmia r2, {r3 - r7} @ move the code to a location 136 | stmia r1, {r3 - r7} @ less likely to be overridden 137 | #ifdef VEXPRESS 138 | ldr r0, =0x1c010030 @ VE SYS_FLAGS register 139 | #else 140 | ldr r0, =0x10000030 @ RealView SYS_FLAGS register 141 | #endif 142 | mov pc, r1 @ branch to the relocated code 143 | 1: 144 | #ifdef VEXPRESS 145 | wfe 146 | #endif 147 | ldr r1, [r0] 148 | cmp r1, #0 149 | beq 1b 150 | mov pc, r1 @ branch to the given address 151 | #endif 152 | 153 | 2: 154 | @ 155 | @ UART initialisation (38400 8N1) 156 | @ 157 | #ifdef MACH_MPS 158 | ldr r0, =0x1f005000 @ UART3 base (MPS) 159 | #elif defined (VEXPRESS) 160 | ldr r0, =0x1c090000 @ UART base (Versatile Express) 161 | #else 162 | ldr r0, =0x10009000 @ UART base (RealView/EB) 163 | #endif 164 | mov r1, #0x10 @ ibrd 165 | str r1, [r0, #0x24] 166 | mov r1, #0xc300 167 | orr r1, #0x0001 @ cr 168 | str r1, [r0, #0x30] 169 | 170 | @ Now we've got rid of the secondary CPUs, set up a stack 171 | @ for CPU 0 so we can write most of this in C. 172 | ldr sp, =stacktop 173 | 174 | @ And call the C entrypoint 175 | bl c_start 176 | @ Never reached 177 | 1: b 1b 178 | 179 | @ 180 | @ Function for C code to make semihosting calls: 181 | @ 182 | .globl __semi_call 183 | __semi_call: 184 | #if defined(MACH_MPS) 185 | @ M profile semihosting is via bpkt 186 | bkpt 0xab 187 | #elif defined(__thumb__) 188 | @ Otherwise, different SVC numbers for ARM or Thumb mode 189 | svc 0xab 190 | #else 191 | svc 0x123456 192 | #endif 193 | mov pc, lr 194 | 195 | .globl __boot_kernel 196 | __boot_kernel: 197 | mov r4, r0 198 | stmfd sp!, {r1-r3} 199 | ldmia sp, {r0-r3} 200 | 201 | enter_hyp 202 | 203 | bx r4 204 | .type __boot_kernel, %function 205 | 206 | @ 207 | @ Data 208 | @ 209 | /* The kernel boot command line for builtin kernels is defined in the Make system */ 210 | .globl kernel_cmd 211 | .globl kernel_cmd_end 212 | kernel_cmd: 213 | #ifdef KCMD 214 | .asciz KCMD 215 | #endif 216 | kernel_cmd_end: 217 | -------------------------------------------------------------------------------- /c_start.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 3. Neither the name of Linaro Limited nor the names of its 15 | * contributors may be used to endorse or promote products derived 16 | * from this software without specific prior written permission. 17 | */ 18 | 19 | /* This file just contains a small glue function which fishes the 20 | * location of kernel etc out of linker script defined symbols, and 21 | * calls semi_loader functions to do the actual work of loading 22 | * and booting the kernel. 23 | */ 24 | 25 | #include 26 | #include "semihosting.h" 27 | #include "semi_loader.h" 28 | 29 | /* Linker script defined symbols for any preloaded kernel/initrd */ 30 | extern uint8_t fs_start, fs_end, kernel_entry, kernel_start, kernel_end; 31 | /* Symbols defined by boot.S */ 32 | extern uint8_t kernel_cmd, kernel_cmd_end; 33 | 34 | static struct loader_info loader; 35 | 36 | #ifdef MACH_MPS 37 | #define PLAT_ID 10000 /* MPS (temporary) */ 38 | #elif defined (VEXPRESS) 39 | #define PLAT_ID 2272 /* Versatile Express */ 40 | #else 41 | #define PLAT_ID 827 /* RealView/EB */ 42 | #endif 43 | 44 | void c_start(void) 45 | { 46 | /* Main C entry point */ 47 | loader.kernel_size = (uint32_t)&kernel_end - (uint32_t)&kernel_start; 48 | loader.initrd_start = (uint32_t)&fs_start; 49 | loader.initrd_size = (uint32_t)&fs_end - (uint32_t)&fs_start; 50 | loader.kernel_entry = (uint32_t)&kernel_entry; 51 | if (loader.kernel_size) { 52 | loader.cmdline_start = (uint32_t)&kernel_cmd; 53 | loader.cmdline_size = &kernel_cmd_end - &kernel_cmd; 54 | } 55 | load_kernel(&loader); 56 | 57 | /* Start the kernel */ 58 | if(loader.fdt_start) { 59 | boot_kernel(&loader, 0, -1, loader.fdt_start, 0); 60 | } else { 61 | boot_kernel(&loader, 0, PLAT_ID, loader.atags_start, 0); 62 | } 63 | 64 | semi_write0("[bootwrapper] ERROR: returned from boot_kernel\n"); 65 | } 66 | -------------------------------------------------------------------------------- /config-default.mk: -------------------------------------------------------------------------------- 1 | # Configuration file included in Makefile 2 | # 3 | # Copyright (C) 2011 Columbia University. All rights reserved. 4 | # Christoffer Dall 5 | # Use of this source code is governed by a BSD-style license that can be 6 | # found in the LICENSE.txt file. 7 | # 8 | # This is a sample configuration file. To make changes, copy this file to 9 | # config.mk and modify that file. 10 | # 11 | # For all systems you can override USE_INITRD and KCMD from the command-line. 12 | # 13 | 14 | ########################################################################### 15 | # Main options 16 | # 17 | CROSS_COMPILE ?= arm-unknown-eabi- 18 | ARCH ?= arm 19 | KERNEL_SRC ?= ../linux-kvm-arm 20 | 21 | # Select system: 22 | # mps: MPS (Cortex-M3) 23 | # realview_eb: RealViewPB, EB, etc. 24 | # vexpress: Versatile Express 25 | SYSTEM ?= vexpress 26 | 27 | ########################################################################### 28 | # Turn this on to use an initrd whose contents are in filesystem.cpio.gz 29 | USE_INITRD ?= no 30 | ifeq ($(USE_INITRD),yes) 31 | CPPFLAGS += -DUSE_INITRD 32 | FILESYSTEM ?= filesystem.cpio.gz 33 | else 34 | FILESYSTEM = 35 | endif 36 | 37 | ########################################################################### 38 | # Default NFS root 39 | NFS_ROOT ?= /srv/nfsroot 40 | ifeq ($(origin NFS_SERVER), undefined) 41 | NFS_SERVER := $(shell ip addr show scope global | \ 42 | sed -ne '/inet/{s/ *inet \([^/]*\)\/.*/\1/p;q}') 43 | endif 44 | 45 | 46 | ########################################################################### 47 | # MPS (Cortex-M3) definitions 48 | # 49 | ifeq ($(SYSTEM),mps) 50 | # C-flags 51 | CPPFLAGS += -DMACH_MPS -DTHUMB2_KERNEL 52 | CPPFLAGS += -march=armv7-m 53 | CPPFLAGS += -mthumb -Wa,-mthumb -Wa,-mimplicit-it=always 54 | 55 | # Kernel command line 56 | KCMD ?= "rdinit=/bin/sh console=ttyAMA3 mem=4M earlyprintk" 57 | endif # SYSTEM = mps 58 | 59 | 60 | ########################################################################### 61 | # EB, RealviewPB, etc 62 | # 63 | ifeq ($(SYSTEM),realview_eb) 64 | 65 | #CPPFLAGS += -DSMP 66 | CPPFLAGS += -march=armv7-a -marm 67 | #CPPFLAGS += -DTHUMB2_KERNEL 68 | 69 | # Default kernel command line, using initrd: 70 | ifeq ($(USE_INITRD),yes) 71 | KCMD ?= "console=ttyAMA0 mem=256M earlyprintk" 72 | endif 73 | # 74 | # Default kernel command line, without initrd: 75 | ifneq ($(USE_INITRD),yes) 76 | KCMD ?= "root=/dev/nfs nfsroot=$(NFS_HOST):$(NFS_ROOT) ip=dhcp console=ttyAMA0 mem=256M earlyprintk" 77 | endif 78 | endif # SYSTEM = realvire_eb 79 | 80 | 81 | ########################################################################### 82 | # Versatile Express 83 | # 84 | ifeq ($(SYSTEM),vexpress) 85 | 86 | CPPFLAGS += -DSMP 87 | CPPFLAGS += -march=armv7-a -marm 88 | #CPPFLAGS += -DTHUMB2_KERNEL 89 | CPPFLAGS += -DVEXPRESS 90 | 91 | # Default kernel command line, using initrd: 92 | ifeq ($(USE_INITRD),yes) 93 | KCMD ?= "console=ttyAMA0 mem=512M mem=512M@0x880000000 earlyprintk ip=dhcp" 94 | endif 95 | # 96 | # Default kernel command line, without initrd: 97 | ifneq ($(USE_INITRD),yes) 98 | KCMD ?= "console=ttyAMA0 mem=512M mem=512M@0x880000000 earlyprintk root=/dev/nfs nfsroot=$(NFS_SERVER):$(NFS_ROOT),tcp rw ip=dhcp nfsrootdebug" 99 | endif 100 | endif # SYSTEM = vexpress 101 | -------------------------------------------------------------------------------- /libfdt/Makefile.libfdt: -------------------------------------------------------------------------------- 1 | # Makefile.libfdt 2 | # 3 | # This is not a complete Makefile of itself. Instead, it is designed to 4 | # be easily embeddable into other systems of Makefiles. 5 | # 6 | -include $(d)/*.d 7 | 8 | LIBFDT_CPPFLAGS += -I$(d) 9 | LIBFDT_OBJS := \ 10 | $(d)/fdt.o \ 11 | $(d)/fdt_ro.o \ 12 | $(d)/fdt_wip.o \ 13 | $(d)/fdt_sw.o \ 14 | $(d)/fdt_rw.o \ 15 | $(d)/fdt_strerror.o 16 | 17 | CLEAN_SUBDIRS += $(d) 18 | 19 | OBJS-libfdt.a = $(LIBFDT_OBJS) 20 | libfdt.a: $(OBJS-libfdt.a) 21 | 22 | $(d)/%.o: $(d)/%.c 23 | @echo " CC[LIB] $<" 24 | $(Q)$(CC) $(LIBFDT_CPPFLAGS) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< 25 | -------------------------------------------------------------------------------- /libfdt/fdt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libfdt - Flat Device Tree manipulation 3 | * Copyright (C) 2006 David Gibson, IBM Corporation. 4 | * 5 | * libfdt is dual licensed: you can use it either under the terms of 6 | * the GPL, or the BSD license, at your option. 7 | * 8 | * a) This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21 | * MA 02110-1301 USA 22 | * 23 | * Alternatively, 24 | * 25 | * b) Redistribution and use in source and binary forms, with or 26 | * without modification, are permitted provided that the following 27 | * conditions are met: 28 | * 29 | * 1. Redistributions of source code must retain the above 30 | * copyright notice, this list of conditions and the following 31 | * disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above 33 | * copyright notice, this list of conditions and the following 34 | * disclaimer in the documentation and/or other materials 35 | * provided with the distribution. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | #include "libfdt_env.h" 52 | 53 | #include 54 | #include 55 | 56 | #include "libfdt_internal.h" 57 | 58 | int fdt_check_header(const void *fdt) 59 | { 60 | if (fdt_magic(fdt) == FDT_MAGIC) { 61 | /* Complete tree */ 62 | if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) 63 | return -FDT_ERR_BADVERSION; 64 | if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) 65 | return -FDT_ERR_BADVERSION; 66 | } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { 67 | /* Unfinished sequential-write blob */ 68 | if (fdt_size_dt_struct(fdt) == 0) 69 | return -FDT_ERR_BADSTATE; 70 | } else { 71 | return -FDT_ERR_BADMAGIC; 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | const void *fdt_offset_ptr(const void *fdt, int offset, int len) 78 | { 79 | const char *p; 80 | 81 | if (fdt_version(fdt) >= 0x11) 82 | if (((offset + len) < offset) 83 | || ((offset + len) > fdt_size_dt_struct(fdt))) 84 | return NULL; 85 | 86 | p = _fdt_offset_ptr(fdt, offset); 87 | 88 | if (p + len < p) 89 | return NULL; 90 | return p; 91 | } 92 | 93 | uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) 94 | { 95 | const uint32_t *tagp, *lenp; 96 | uint32_t tag; 97 | const char *p; 98 | 99 | if (offset % FDT_TAGSIZE) 100 | return -1; 101 | 102 | tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); 103 | if (! tagp) 104 | return FDT_END; /* premature end */ 105 | tag = fdt32_to_cpu(*tagp); 106 | offset += FDT_TAGSIZE; 107 | 108 | switch (tag) { 109 | case FDT_BEGIN_NODE: 110 | /* skip name */ 111 | do { 112 | p = fdt_offset_ptr(fdt, offset++, 1); 113 | } while (p && (*p != '\0')); 114 | if (! p) 115 | return FDT_END; 116 | break; 117 | case FDT_PROP: 118 | lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); 119 | if (! lenp) 120 | return FDT_END; 121 | /* skip name offset, length and value */ 122 | offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); 123 | break; 124 | } 125 | 126 | if (nextoffset) 127 | *nextoffset = FDT_TAGALIGN(offset); 128 | 129 | return tag; 130 | } 131 | 132 | int _fdt_check_node_offset(const void *fdt, int offset) 133 | { 134 | if ((offset < 0) || (offset % FDT_TAGSIZE) 135 | || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) 136 | return -FDT_ERR_BADOFFSET; 137 | 138 | return offset; 139 | } 140 | 141 | int fdt_next_node(const void *fdt, int offset, int *depth) 142 | { 143 | int nextoffset = 0; 144 | uint32_t tag; 145 | 146 | if (offset >= 0) 147 | if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) 148 | return nextoffset; 149 | 150 | do { 151 | offset = nextoffset; 152 | tag = fdt_next_tag(fdt, offset, &nextoffset); 153 | 154 | switch (tag) { 155 | case FDT_PROP: 156 | case FDT_NOP: 157 | break; 158 | 159 | case FDT_BEGIN_NODE: 160 | if (depth) 161 | (*depth)++; 162 | break; 163 | 164 | case FDT_END_NODE: 165 | if (depth) 166 | (*depth)--; 167 | break; 168 | 169 | case FDT_END: 170 | return -FDT_ERR_NOTFOUND; 171 | 172 | default: 173 | return -FDT_ERR_BADSTRUCTURE; 174 | } 175 | } while (tag != FDT_BEGIN_NODE); 176 | 177 | return offset; 178 | } 179 | 180 | const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) 181 | { 182 | int len = strlen(s) + 1; 183 | const char *last = strtab + tabsize - len; 184 | const char *p; 185 | 186 | for (p = strtab; p <= last; p++) 187 | if (memcmp(p, s, len) == 0) 188 | return p; 189 | return NULL; 190 | } 191 | 192 | int fdt_move(const void *fdt, void *buf, int bufsize) 193 | { 194 | FDT_CHECK_HEADER(fdt); 195 | 196 | if (fdt_totalsize(fdt) > bufsize) 197 | return -FDT_ERR_NOSPACE; 198 | 199 | memmove(buf, fdt, fdt_totalsize(fdt)); 200 | return 0; 201 | } 202 | -------------------------------------------------------------------------------- /libfdt/fdt.h: -------------------------------------------------------------------------------- 1 | #ifndef _FDT_H 2 | #define _FDT_H 3 | 4 | #ifndef __ASSEMBLY__ 5 | 6 | struct fdt_header { 7 | uint32_t magic; /* magic word FDT_MAGIC */ 8 | uint32_t totalsize; /* total size of DT block */ 9 | uint32_t off_dt_struct; /* offset to structure */ 10 | uint32_t off_dt_strings; /* offset to strings */ 11 | uint32_t off_mem_rsvmap; /* offset to memory reserve map */ 12 | uint32_t version; /* format version */ 13 | uint32_t last_comp_version; /* last compatible version */ 14 | 15 | /* version 2 fields below */ 16 | uint32_t boot_cpuid_phys; /* Which physical CPU id we're 17 | booting on */ 18 | /* version 3 fields below */ 19 | uint32_t size_dt_strings; /* size of the strings block */ 20 | 21 | /* version 17 fields below */ 22 | uint32_t size_dt_struct; /* size of the structure block */ 23 | }; 24 | 25 | struct fdt_reserve_entry { 26 | uint64_t address; 27 | uint64_t size; 28 | }; 29 | 30 | struct fdt_node_header { 31 | uint32_t tag; 32 | char name[0]; 33 | }; 34 | 35 | struct fdt_property { 36 | uint32_t tag; 37 | uint32_t len; 38 | uint32_t nameoff; 39 | char data[0]; 40 | }; 41 | 42 | #endif /* !__ASSEMBLY */ 43 | 44 | #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ 45 | #define FDT_TAGSIZE sizeof(uint32_t) 46 | 47 | #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ 48 | #define FDT_END_NODE 0x2 /* End node */ 49 | #define FDT_PROP 0x3 /* Property: name off, 50 | size, content */ 51 | #define FDT_NOP 0x4 /* nop */ 52 | #define FDT_END 0x9 53 | 54 | #define FDT_V1_SIZE (7*sizeof(uint32_t)) 55 | #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) 56 | #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) 57 | #define FDT_V16_SIZE FDT_V3_SIZE 58 | #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) 59 | 60 | #endif /* _FDT_H */ 61 | -------------------------------------------------------------------------------- /libfdt/fdt_ro.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libfdt - Flat Device Tree manipulation 3 | * Copyright (C) 2006 David Gibson, IBM Corporation. 4 | * 5 | * libfdt is dual licensed: you can use it either under the terms of 6 | * the GPL, or the BSD license, at your option. 7 | * 8 | * a) This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21 | * MA 02110-1301 USA 22 | * 23 | * Alternatively, 24 | * 25 | * b) Redistribution and use in source and binary forms, with or 26 | * without modification, are permitted provided that the following 27 | * conditions are met: 28 | * 29 | * 1. Redistributions of source code must retain the above 30 | * copyright notice, this list of conditions and the following 31 | * disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above 33 | * copyright notice, this list of conditions and the following 34 | * disclaimer in the documentation and/or other materials 35 | * provided with the distribution. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | #include "libfdt_env.h" 52 | 53 | #include 54 | #include 55 | 56 | #include "libfdt_internal.h" 57 | 58 | static int _fdt_nodename_eq(const void *fdt, int offset, 59 | const char *s, int len) 60 | { 61 | const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); 62 | 63 | if (! p) 64 | /* short match */ 65 | return 0; 66 | 67 | if (memcmp(p, s, len) != 0) 68 | return 0; 69 | 70 | if (p[len] == '\0') 71 | return 1; 72 | else if (!memchr(s, '@', len) && (p[len] == '@')) 73 | return 1; 74 | else 75 | return 0; 76 | } 77 | 78 | const char *fdt_string(const void *fdt, int stroffset) 79 | { 80 | return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; 81 | } 82 | 83 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) 84 | { 85 | FDT_CHECK_HEADER(fdt); 86 | *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); 87 | *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); 88 | return 0; 89 | } 90 | 91 | int fdt_num_mem_rsv(const void *fdt) 92 | { 93 | int i = 0; 94 | 95 | while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) 96 | i++; 97 | return i; 98 | } 99 | 100 | int fdt_subnode_offset_namelen(const void *fdt, int offset, 101 | const char *name, int namelen) 102 | { 103 | int depth; 104 | 105 | FDT_CHECK_HEADER(fdt); 106 | 107 | for (depth = 0, offset = fdt_next_node(fdt, offset, &depth); 108 | (offset >= 0) && (depth > 0); 109 | offset = fdt_next_node(fdt, offset, &depth)) { 110 | if (depth < 0) 111 | return -FDT_ERR_NOTFOUND; 112 | else if ((depth == 1) 113 | && _fdt_nodename_eq(fdt, offset, name, namelen)) 114 | return offset; 115 | } 116 | 117 | if (offset < 0) 118 | return offset; /* error */ 119 | else 120 | return -FDT_ERR_NOTFOUND; 121 | } 122 | 123 | int fdt_subnode_offset(const void *fdt, int parentoffset, 124 | const char *name) 125 | { 126 | return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); 127 | } 128 | 129 | int fdt_path_offset(const void *fdt, const char *path) 130 | { 131 | const char *end = path + strlen(path); 132 | const char *p = path; 133 | int offset = 0; 134 | 135 | FDT_CHECK_HEADER(fdt); 136 | 137 | if (*path != '/') 138 | return -FDT_ERR_BADPATH; 139 | 140 | while (*p) { 141 | const char *q; 142 | 143 | while (*p == '/') 144 | p++; 145 | if (! *p) 146 | return offset; 147 | q = strchr(p, '/'); 148 | if (! q) 149 | q = end; 150 | 151 | offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); 152 | if (offset < 0) 153 | return offset; 154 | 155 | p = q; 156 | } 157 | 158 | return offset; 159 | } 160 | 161 | const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) 162 | { 163 | const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); 164 | int err; 165 | 166 | if (((err = fdt_check_header(fdt)) != 0) 167 | || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) 168 | goto fail; 169 | 170 | if (len) 171 | *len = strlen(nh->name); 172 | 173 | return nh->name; 174 | 175 | fail: 176 | if (len) 177 | *len = err; 178 | return NULL; 179 | } 180 | 181 | const struct fdt_property *fdt_get_property(const void *fdt, 182 | int nodeoffset, 183 | const char *name, int *lenp) 184 | { 185 | uint32_t tag; 186 | const struct fdt_property *prop; 187 | int namestroff; 188 | int offset, nextoffset; 189 | int err; 190 | 191 | if (((err = fdt_check_header(fdt)) != 0) 192 | || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) 193 | goto fail; 194 | 195 | nextoffset = err; 196 | do { 197 | offset = nextoffset; 198 | 199 | tag = fdt_next_tag(fdt, offset, &nextoffset); 200 | switch (tag) { 201 | case FDT_END: 202 | err = -FDT_ERR_TRUNCATED; 203 | goto fail; 204 | 205 | case FDT_BEGIN_NODE: 206 | case FDT_END_NODE: 207 | case FDT_NOP: 208 | break; 209 | 210 | case FDT_PROP: 211 | err = -FDT_ERR_BADSTRUCTURE; 212 | prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); 213 | if (! prop) 214 | goto fail; 215 | namestroff = fdt32_to_cpu(prop->nameoff); 216 | if (strcmp(fdt_string(fdt, namestroff), name) == 0) { 217 | /* Found it! */ 218 | int len = fdt32_to_cpu(prop->len); 219 | prop = fdt_offset_ptr(fdt, offset, 220 | sizeof(*prop)+len); 221 | if (! prop) 222 | goto fail; 223 | 224 | if (lenp) 225 | *lenp = len; 226 | 227 | return prop; 228 | } 229 | break; 230 | 231 | default: 232 | err = -FDT_ERR_BADSTRUCTURE; 233 | goto fail; 234 | } 235 | } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); 236 | 237 | err = -FDT_ERR_NOTFOUND; 238 | fail: 239 | if (lenp) 240 | *lenp = err; 241 | return NULL; 242 | } 243 | 244 | const void *fdt_getprop(const void *fdt, int nodeoffset, 245 | const char *name, int *lenp) 246 | { 247 | const struct fdt_property *prop; 248 | 249 | prop = fdt_get_property(fdt, nodeoffset, name, lenp); 250 | if (! prop) 251 | return NULL; 252 | 253 | return prop->data; 254 | } 255 | 256 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) 257 | { 258 | const uint32_t *php; 259 | int len; 260 | 261 | php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); 262 | if (!php || (len != sizeof(*php))) 263 | return 0; 264 | 265 | return fdt32_to_cpu(*php); 266 | } 267 | 268 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) 269 | { 270 | int pdepth = 0, p = 0; 271 | int offset, depth, namelen; 272 | const char *name; 273 | 274 | FDT_CHECK_HEADER(fdt); 275 | 276 | if (buflen < 2) 277 | return -FDT_ERR_NOSPACE; 278 | 279 | for (offset = 0, depth = 0; 280 | (offset >= 0) && (offset <= nodeoffset); 281 | offset = fdt_next_node(fdt, offset, &depth)) { 282 | if (pdepth < depth) 283 | continue; /* overflowed buffer */ 284 | 285 | while (pdepth > depth) { 286 | do { 287 | p--; 288 | } while (buf[p-1] != '/'); 289 | pdepth--; 290 | } 291 | 292 | name = fdt_get_name(fdt, offset, &namelen); 293 | if (!name) 294 | return namelen; 295 | if ((p + namelen + 1) <= buflen) { 296 | memcpy(buf + p, name, namelen); 297 | p += namelen; 298 | buf[p++] = '/'; 299 | pdepth++; 300 | } 301 | 302 | if (offset == nodeoffset) { 303 | if (pdepth < (depth + 1)) 304 | return -FDT_ERR_NOSPACE; 305 | 306 | if (p > 1) /* special case so that root path is "/", not "" */ 307 | p--; 308 | buf[p] = '\0'; 309 | return p; 310 | } 311 | } 312 | 313 | if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) 314 | return -FDT_ERR_BADOFFSET; 315 | else if (offset == -FDT_ERR_BADOFFSET) 316 | return -FDT_ERR_BADSTRUCTURE; 317 | 318 | return offset; /* error from fdt_next_node() */ 319 | } 320 | 321 | int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, 322 | int supernodedepth, int *nodedepth) 323 | { 324 | int offset, depth; 325 | int supernodeoffset = -FDT_ERR_INTERNAL; 326 | 327 | FDT_CHECK_HEADER(fdt); 328 | 329 | if (supernodedepth < 0) 330 | return -FDT_ERR_NOTFOUND; 331 | 332 | for (offset = 0, depth = 0; 333 | (offset >= 0) && (offset <= nodeoffset); 334 | offset = fdt_next_node(fdt, offset, &depth)) { 335 | if (depth == supernodedepth) 336 | supernodeoffset = offset; 337 | 338 | if (offset == nodeoffset) { 339 | if (nodedepth) 340 | *nodedepth = depth; 341 | 342 | if (supernodedepth > depth) 343 | return -FDT_ERR_NOTFOUND; 344 | else 345 | return supernodeoffset; 346 | } 347 | } 348 | 349 | if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) 350 | return -FDT_ERR_BADOFFSET; 351 | else if (offset == -FDT_ERR_BADOFFSET) 352 | return -FDT_ERR_BADSTRUCTURE; 353 | 354 | return offset; /* error from fdt_next_node() */ 355 | } 356 | 357 | int fdt_node_depth(const void *fdt, int nodeoffset) 358 | { 359 | int nodedepth; 360 | int err; 361 | 362 | err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); 363 | if (err) 364 | return (err < 0) ? err : -FDT_ERR_INTERNAL; 365 | return nodedepth; 366 | } 367 | 368 | int fdt_parent_offset(const void *fdt, int nodeoffset) 369 | { 370 | int nodedepth = fdt_node_depth(fdt, nodeoffset); 371 | 372 | if (nodedepth < 0) 373 | return nodedepth; 374 | return fdt_supernode_atdepth_offset(fdt, nodeoffset, 375 | nodedepth - 1, NULL); 376 | } 377 | 378 | int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, 379 | const char *propname, 380 | const void *propval, int proplen) 381 | { 382 | int offset; 383 | const void *val; 384 | int len; 385 | 386 | FDT_CHECK_HEADER(fdt); 387 | 388 | /* FIXME: The algorithm here is pretty horrible: we scan each 389 | * property of a node in fdt_getprop(), then if that didn't 390 | * find what we want, we scan over them again making our way 391 | * to the next node. Still it's the easiest to implement 392 | * approach; performance can come later. */ 393 | for (offset = fdt_next_node(fdt, startoffset, NULL); 394 | offset >= 0; 395 | offset = fdt_next_node(fdt, offset, NULL)) { 396 | val = fdt_getprop(fdt, offset, propname, &len); 397 | if (val && (len == proplen) 398 | && (memcmp(val, propval, len) == 0)) 399 | return offset; 400 | } 401 | 402 | return offset; /* error from fdt_next_node() */ 403 | } 404 | 405 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) 406 | { 407 | if ((phandle == 0) || (phandle == -1)) 408 | return -FDT_ERR_BADPHANDLE; 409 | phandle = cpu_to_fdt32(phandle); 410 | return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", 411 | &phandle, sizeof(phandle)); 412 | } 413 | 414 | static int _stringlist_contains(const char *strlist, int listlen, const char *str) 415 | { 416 | int len = strlen(str); 417 | const char *p; 418 | 419 | while (listlen >= len) { 420 | if (memcmp(str, strlist, len+1) == 0) 421 | return 1; 422 | p = memchr(strlist, '\0', listlen); 423 | if (!p) 424 | return 0; /* malformed strlist.. */ 425 | listlen -= (p-strlist) + 1; 426 | strlist = p + 1; 427 | } 428 | return 0; 429 | } 430 | 431 | int fdt_node_check_compatible(const void *fdt, int nodeoffset, 432 | const char *compatible) 433 | { 434 | const void *prop; 435 | int len; 436 | 437 | prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); 438 | if (!prop) 439 | return len; 440 | if (_stringlist_contains(prop, len, compatible)) 441 | return 0; 442 | else 443 | return 1; 444 | } 445 | 446 | int fdt_node_offset_by_compatible(const void *fdt, int startoffset, 447 | const char *compatible) 448 | { 449 | int offset, err; 450 | 451 | FDT_CHECK_HEADER(fdt); 452 | 453 | /* FIXME: The algorithm here is pretty horrible: we scan each 454 | * property of a node in fdt_node_check_compatible(), then if 455 | * that didn't find what we want, we scan over them again 456 | * making our way to the next node. Still it's the easiest to 457 | * implement approach; performance can come later. */ 458 | for (offset = fdt_next_node(fdt, startoffset, NULL); 459 | offset >= 0; 460 | offset = fdt_next_node(fdt, offset, NULL)) { 461 | err = fdt_node_check_compatible(fdt, offset, compatible); 462 | if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) 463 | return err; 464 | else if (err == 0) 465 | return offset; 466 | } 467 | 468 | return offset; /* error from fdt_next_node() */ 469 | } 470 | -------------------------------------------------------------------------------- /libfdt/fdt_rw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libfdt - Flat Device Tree manipulation 3 | * Copyright (C) 2006 David Gibson, IBM Corporation. 4 | * 5 | * libfdt is dual licensed: you can use it either under the terms of 6 | * the GPL, or the BSD license, at your option. 7 | * 8 | * a) This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21 | * MA 02110-1301 USA 22 | * 23 | * Alternatively, 24 | * 25 | * b) Redistribution and use in source and binary forms, with or 26 | * without modification, are permitted provided that the following 27 | * conditions are met: 28 | * 29 | * 1. Redistributions of source code must retain the above 30 | * copyright notice, this list of conditions and the following 31 | * disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above 33 | * copyright notice, this list of conditions and the following 34 | * disclaimer in the documentation and/or other materials 35 | * provided with the distribution. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | #include "libfdt_env.h" 52 | 53 | #include 54 | #include 55 | 56 | #include "libfdt_internal.h" 57 | 58 | static int _fdt_blocks_misordered(const void *fdt, 59 | int mem_rsv_size, int struct_size) 60 | { 61 | return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) 62 | || (fdt_off_dt_struct(fdt) < 63 | (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) 64 | || (fdt_off_dt_strings(fdt) < 65 | (fdt_off_dt_struct(fdt) + struct_size)) 66 | || (fdt_totalsize(fdt) < 67 | (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); 68 | } 69 | 70 | static int _fdt_rw_check_header(void *fdt) 71 | { 72 | FDT_CHECK_HEADER(fdt); 73 | 74 | if (fdt_version(fdt) < 17) 75 | return -FDT_ERR_BADVERSION; 76 | if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), 77 | fdt_size_dt_struct(fdt))) 78 | return -FDT_ERR_BADLAYOUT; 79 | if (fdt_version(fdt) > 17) 80 | fdt_set_version(fdt, 17); 81 | 82 | return 0; 83 | } 84 | 85 | #define FDT_RW_CHECK_HEADER(fdt) \ 86 | { \ 87 | int err; \ 88 | if ((err = _fdt_rw_check_header(fdt)) != 0) \ 89 | return err; \ 90 | } 91 | 92 | static inline int _fdt_data_size(void *fdt) 93 | { 94 | return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 95 | } 96 | 97 | static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) 98 | { 99 | char *p = splicepoint; 100 | char *end = (char *)fdt + _fdt_data_size(fdt); 101 | 102 | if (((p + oldlen) < p) || ((p + oldlen) > end)) 103 | return -FDT_ERR_BADOFFSET; 104 | if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) 105 | return -FDT_ERR_NOSPACE; 106 | memmove(p + newlen, p + oldlen, end - p - oldlen); 107 | return 0; 108 | } 109 | 110 | static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, 111 | int oldn, int newn) 112 | { 113 | int delta = (newn - oldn) * sizeof(*p); 114 | int err; 115 | err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); 116 | if (err) 117 | return err; 118 | fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); 119 | fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 120 | return 0; 121 | } 122 | 123 | static int _fdt_splice_struct(void *fdt, void *p, 124 | int oldlen, int newlen) 125 | { 126 | int delta = newlen - oldlen; 127 | int err; 128 | 129 | if ((err = _fdt_splice(fdt, p, oldlen, newlen))) 130 | return err; 131 | 132 | fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); 133 | fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); 134 | return 0; 135 | } 136 | 137 | static int _fdt_splice_string(void *fdt, int newlen) 138 | { 139 | void *p = (char *)fdt 140 | + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); 141 | int err; 142 | 143 | if ((err = _fdt_splice(fdt, p, 0, newlen))) 144 | return err; 145 | 146 | fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); 147 | return 0; 148 | } 149 | 150 | static int _fdt_find_add_string(void *fdt, const char *s) 151 | { 152 | char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); 153 | const char *p; 154 | char *new; 155 | int len = strlen(s) + 1; 156 | int err; 157 | 158 | p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); 159 | if (p) 160 | /* found it */ 161 | return (p - strtab); 162 | 163 | new = strtab + fdt_size_dt_strings(fdt); 164 | err = _fdt_splice_string(fdt, len); 165 | if (err) 166 | return err; 167 | 168 | memcpy(new, s, len); 169 | return (new - strtab); 170 | } 171 | 172 | int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) 173 | { 174 | struct fdt_reserve_entry *re; 175 | int err; 176 | 177 | FDT_RW_CHECK_HEADER(fdt); 178 | 179 | re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); 180 | err = _fdt_splice_mem_rsv(fdt, re, 0, 1); 181 | if (err) 182 | return err; 183 | 184 | re->address = cpu_to_fdt64(address); 185 | re->size = cpu_to_fdt64(size); 186 | return 0; 187 | } 188 | 189 | int fdt_del_mem_rsv(void *fdt, int n) 190 | { 191 | struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); 192 | int err; 193 | 194 | FDT_RW_CHECK_HEADER(fdt); 195 | 196 | if (n >= fdt_num_mem_rsv(fdt)) 197 | return -FDT_ERR_NOTFOUND; 198 | 199 | err = _fdt_splice_mem_rsv(fdt, re, 1, 0); 200 | if (err) 201 | return err; 202 | return 0; 203 | } 204 | 205 | static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, 206 | int len, struct fdt_property **prop) 207 | { 208 | int oldlen; 209 | int err; 210 | 211 | *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 212 | if (! (*prop)) 213 | return oldlen; 214 | 215 | if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), 216 | FDT_TAGALIGN(len)))) 217 | return err; 218 | 219 | (*prop)->len = cpu_to_fdt32(len); 220 | return 0; 221 | } 222 | 223 | static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, 224 | int len, struct fdt_property **prop) 225 | { 226 | int proplen; 227 | int nextoffset; 228 | int namestroff; 229 | int err; 230 | 231 | if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) 232 | return nextoffset; 233 | 234 | namestroff = _fdt_find_add_string(fdt, name); 235 | if (namestroff < 0) 236 | return namestroff; 237 | 238 | *prop = _fdt_offset_ptr_w(fdt, nextoffset); 239 | proplen = sizeof(**prop) + FDT_TAGALIGN(len); 240 | 241 | err = _fdt_splice_struct(fdt, *prop, 0, proplen); 242 | if (err) 243 | return err; 244 | 245 | (*prop)->tag = cpu_to_fdt32(FDT_PROP); 246 | (*prop)->nameoff = cpu_to_fdt32(namestroff); 247 | (*prop)->len = cpu_to_fdt32(len); 248 | return 0; 249 | } 250 | 251 | int fdt_set_name(void *fdt, int nodeoffset, const char *name) 252 | { 253 | char *namep; 254 | int oldlen, newlen; 255 | int err; 256 | 257 | FDT_RW_CHECK_HEADER(fdt); 258 | 259 | namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); 260 | if (!namep) 261 | return oldlen; 262 | 263 | newlen = strlen(name); 264 | 265 | err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), 266 | FDT_TAGALIGN(newlen+1)); 267 | if (err) 268 | return err; 269 | 270 | memcpy(namep, name, newlen+1); 271 | return 0; 272 | } 273 | 274 | int fdt_setprop(void *fdt, int nodeoffset, const char *name, 275 | const void *val, int len) 276 | { 277 | struct fdt_property *prop; 278 | int err; 279 | 280 | FDT_RW_CHECK_HEADER(fdt); 281 | 282 | err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); 283 | if (err == -FDT_ERR_NOTFOUND) 284 | err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); 285 | if (err) 286 | return err; 287 | 288 | memcpy(prop->data, val, len); 289 | return 0; 290 | } 291 | 292 | int fdt_delprop(void *fdt, int nodeoffset, const char *name) 293 | { 294 | struct fdt_property *prop; 295 | int len, proplen; 296 | 297 | FDT_RW_CHECK_HEADER(fdt); 298 | 299 | prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 300 | if (! prop) 301 | return len; 302 | 303 | proplen = sizeof(*prop) + FDT_TAGALIGN(len); 304 | return _fdt_splice_struct(fdt, prop, proplen, 0); 305 | } 306 | 307 | int fdt_add_subnode_namelen(void *fdt, int parentoffset, 308 | const char *name, int namelen) 309 | { 310 | struct fdt_node_header *nh; 311 | int offset, nextoffset; 312 | int nodelen; 313 | int err; 314 | uint32_t tag; 315 | uint32_t *endtag; 316 | 317 | FDT_RW_CHECK_HEADER(fdt); 318 | 319 | offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); 320 | if (offset >= 0) 321 | return -FDT_ERR_EXISTS; 322 | else if (offset != -FDT_ERR_NOTFOUND) 323 | return offset; 324 | 325 | /* Try to place the new node after the parent's properties */ 326 | fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ 327 | do { 328 | offset = nextoffset; 329 | tag = fdt_next_tag(fdt, offset, &nextoffset); 330 | } while ((tag == FDT_PROP) || (tag == FDT_NOP)); 331 | 332 | nh = _fdt_offset_ptr_w(fdt, offset); 333 | nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; 334 | 335 | err = _fdt_splice_struct(fdt, nh, 0, nodelen); 336 | if (err) 337 | return err; 338 | 339 | nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 340 | memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); 341 | memcpy(nh->name, name, namelen); 342 | endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE); 343 | *endtag = cpu_to_fdt32(FDT_END_NODE); 344 | 345 | return offset; 346 | } 347 | 348 | int fdt_add_subnode(void *fdt, int parentoffset, const char *name) 349 | { 350 | return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); 351 | } 352 | 353 | int fdt_del_node(void *fdt, int nodeoffset) 354 | { 355 | int endoffset; 356 | 357 | FDT_RW_CHECK_HEADER(fdt); 358 | 359 | endoffset = _fdt_node_end_offset(fdt, nodeoffset); 360 | if (endoffset < 0) 361 | return endoffset; 362 | 363 | return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), 364 | endoffset - nodeoffset, 0); 365 | } 366 | 367 | static void _fdt_packblocks(const char *old, char *new, 368 | int mem_rsv_size, int struct_size) 369 | { 370 | int mem_rsv_off, struct_off, strings_off; 371 | 372 | mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); 373 | struct_off = mem_rsv_off + mem_rsv_size; 374 | strings_off = struct_off + struct_size; 375 | 376 | memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); 377 | fdt_set_off_mem_rsvmap(new, mem_rsv_off); 378 | 379 | memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); 380 | fdt_set_off_dt_struct(new, struct_off); 381 | fdt_set_size_dt_struct(new, struct_size); 382 | 383 | memmove(new + strings_off, old + fdt_off_dt_strings(old), 384 | fdt_size_dt_strings(old)); 385 | fdt_set_off_dt_strings(new, strings_off); 386 | fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); 387 | } 388 | 389 | int fdt_open_into(const void *fdt, void *buf, int bufsize) 390 | { 391 | int err; 392 | int mem_rsv_size, struct_size; 393 | int newsize; 394 | const char *fdtstart = fdt; 395 | const char *fdtend = fdtstart + fdt_totalsize(fdt); 396 | char *tmp; 397 | 398 | FDT_CHECK_HEADER(fdt); 399 | 400 | mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 401 | * sizeof(struct fdt_reserve_entry); 402 | 403 | if (fdt_version(fdt) >= 17) { 404 | struct_size = fdt_size_dt_struct(fdt); 405 | } else { 406 | struct_size = 0; 407 | while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) 408 | ; 409 | } 410 | 411 | if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { 412 | /* no further work necessary */ 413 | err = fdt_move(fdt, buf, bufsize); 414 | if (err) 415 | return err; 416 | fdt_set_version(buf, 17); 417 | fdt_set_size_dt_struct(buf, struct_size); 418 | fdt_set_totalsize(buf, bufsize); 419 | return 0; 420 | } 421 | 422 | /* Need to reorder */ 423 | newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size 424 | + struct_size + fdt_size_dt_strings(fdt); 425 | 426 | if (bufsize < newsize) 427 | return -FDT_ERR_NOSPACE; 428 | 429 | /* First attempt to build converted tree at beginning of buffer */ 430 | tmp = buf; 431 | /* But if that overlaps with the old tree... */ 432 | if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { 433 | /* Try right after the old tree instead */ 434 | tmp = (char *)(uintptr_t)fdtend; 435 | if ((tmp + newsize) > ((char *)buf + bufsize)) 436 | return -FDT_ERR_NOSPACE; 437 | } 438 | 439 | _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); 440 | memmove(buf, tmp, newsize); 441 | 442 | fdt_set_magic(buf, FDT_MAGIC); 443 | fdt_set_totalsize(buf, bufsize); 444 | fdt_set_version(buf, 17); 445 | fdt_set_last_comp_version(buf, 16); 446 | fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); 447 | 448 | return 0; 449 | } 450 | 451 | int fdt_pack(void *fdt) 452 | { 453 | int mem_rsv_size; 454 | 455 | FDT_RW_CHECK_HEADER(fdt); 456 | 457 | mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 458 | * sizeof(struct fdt_reserve_entry); 459 | _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); 460 | fdt_set_totalsize(fdt, _fdt_data_size(fdt)); 461 | 462 | return 0; 463 | } 464 | -------------------------------------------------------------------------------- /libfdt/fdt_strerror.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libfdt - Flat Device Tree manipulation 3 | * Copyright (C) 2006 David Gibson, IBM Corporation. 4 | * 5 | * libfdt is dual licensed: you can use it either under the terms of 6 | * the GPL, or the BSD license, at your option. 7 | * 8 | * a) This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21 | * MA 02110-1301 USA 22 | * 23 | * Alternatively, 24 | * 25 | * b) Redistribution and use in source and binary forms, with or 26 | * without modification, are permitted provided that the following 27 | * conditions are met: 28 | * 29 | * 1. Redistributions of source code must retain the above 30 | * copyright notice, this list of conditions and the following 31 | * disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above 33 | * copyright notice, this list of conditions and the following 34 | * disclaimer in the documentation and/or other materials 35 | * provided with the distribution. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | #include "libfdt_env.h" 52 | 53 | #include 54 | #include 55 | 56 | #include "libfdt_internal.h" 57 | 58 | struct fdt_errtabent { 59 | const char *str; 60 | }; 61 | 62 | #define FDT_ERRTABENT(val) \ 63 | [(val)] = { .str = #val, } 64 | 65 | static struct fdt_errtabent fdt_errtable[] = { 66 | FDT_ERRTABENT(FDT_ERR_NOTFOUND), 67 | FDT_ERRTABENT(FDT_ERR_EXISTS), 68 | FDT_ERRTABENT(FDT_ERR_NOSPACE), 69 | 70 | FDT_ERRTABENT(FDT_ERR_BADOFFSET), 71 | FDT_ERRTABENT(FDT_ERR_BADPATH), 72 | FDT_ERRTABENT(FDT_ERR_BADSTATE), 73 | 74 | FDT_ERRTABENT(FDT_ERR_TRUNCATED), 75 | FDT_ERRTABENT(FDT_ERR_BADMAGIC), 76 | FDT_ERRTABENT(FDT_ERR_BADVERSION), 77 | FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), 78 | FDT_ERRTABENT(FDT_ERR_BADLAYOUT), 79 | }; 80 | #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) 81 | 82 | const char *fdt_strerror(int errval) 83 | { 84 | if (errval > 0) 85 | return ""; 86 | else if (errval == 0) 87 | return ""; 88 | else if (errval > -FDT_ERRTABSIZE) { 89 | const char *s = fdt_errtable[-errval].str; 90 | 91 | if (s) 92 | return s; 93 | } 94 | 95 | return ""; 96 | } 97 | -------------------------------------------------------------------------------- /libfdt/fdt_sw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libfdt - Flat Device Tree manipulation 3 | * Copyright (C) 2006 David Gibson, IBM Corporation. 4 | * 5 | * libfdt is dual licensed: you can use it either under the terms of 6 | * the GPL, or the BSD license, at your option. 7 | * 8 | * a) This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21 | * MA 02110-1301 USA 22 | * 23 | * Alternatively, 24 | * 25 | * b) Redistribution and use in source and binary forms, with or 26 | * without modification, are permitted provided that the following 27 | * conditions are met: 28 | * 29 | * 1. Redistributions of source code must retain the above 30 | * copyright notice, this list of conditions and the following 31 | * disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above 33 | * copyright notice, this list of conditions and the following 34 | * disclaimer in the documentation and/or other materials 35 | * provided with the distribution. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | #include "libfdt_env.h" 52 | 53 | #include 54 | #include 55 | 56 | #include "libfdt_internal.h" 57 | 58 | static int _fdt_sw_check_header(void *fdt) 59 | { 60 | if (fdt_magic(fdt) != FDT_SW_MAGIC) 61 | return -FDT_ERR_BADMAGIC; 62 | /* FIXME: should check more details about the header state */ 63 | return 0; 64 | } 65 | 66 | #define FDT_SW_CHECK_HEADER(fdt) \ 67 | { \ 68 | int err; \ 69 | if ((err = _fdt_sw_check_header(fdt)) != 0) \ 70 | return err; \ 71 | } 72 | 73 | static void *_fdt_grab_space(void *fdt, int len) 74 | { 75 | int offset = fdt_size_dt_struct(fdt); 76 | int spaceleft; 77 | 78 | spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) 79 | - fdt_size_dt_strings(fdt); 80 | 81 | if ((offset + len < offset) || (offset + len > spaceleft)) 82 | return NULL; 83 | 84 | fdt_set_size_dt_struct(fdt, offset + len); 85 | return fdt_offset_ptr_w(fdt, offset, len); 86 | } 87 | 88 | int fdt_create(void *buf, int bufsize) 89 | { 90 | void *fdt = buf; 91 | 92 | if (bufsize < sizeof(struct fdt_header)) 93 | return -FDT_ERR_NOSPACE; 94 | 95 | memset(buf, 0, bufsize); 96 | 97 | fdt_set_magic(fdt, FDT_SW_MAGIC); 98 | fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 99 | fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); 100 | fdt_set_totalsize(fdt, bufsize); 101 | 102 | fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), 103 | sizeof(struct fdt_reserve_entry))); 104 | fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 105 | fdt_set_off_dt_strings(fdt, bufsize); 106 | 107 | return 0; 108 | } 109 | 110 | int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) 111 | { 112 | struct fdt_reserve_entry *re; 113 | int offset; 114 | 115 | FDT_SW_CHECK_HEADER(fdt); 116 | 117 | if (fdt_size_dt_struct(fdt)) 118 | return -FDT_ERR_BADSTATE; 119 | 120 | offset = fdt_off_dt_struct(fdt); 121 | if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 122 | return -FDT_ERR_NOSPACE; 123 | 124 | re = (struct fdt_reserve_entry *)((char *)fdt + offset); 125 | re->address = cpu_to_fdt64(addr); 126 | re->size = cpu_to_fdt64(size); 127 | 128 | fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); 129 | 130 | return 0; 131 | } 132 | 133 | int fdt_finish_reservemap(void *fdt) 134 | { 135 | return fdt_add_reservemap_entry(fdt, 0, 0); 136 | } 137 | 138 | int fdt_begin_node(void *fdt, const char *name) 139 | { 140 | struct fdt_node_header *nh; 141 | int namelen = strlen(name) + 1; 142 | 143 | FDT_SW_CHECK_HEADER(fdt); 144 | 145 | nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 146 | if (! nh) 147 | return -FDT_ERR_NOSPACE; 148 | 149 | nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); 150 | memcpy(nh->name, name, namelen); 151 | return 0; 152 | } 153 | 154 | int fdt_end_node(void *fdt) 155 | { 156 | uint32_t *en; 157 | 158 | FDT_SW_CHECK_HEADER(fdt); 159 | 160 | en = _fdt_grab_space(fdt, FDT_TAGSIZE); 161 | if (! en) 162 | return -FDT_ERR_NOSPACE; 163 | 164 | *en = cpu_to_fdt32(FDT_END_NODE); 165 | return 0; 166 | } 167 | 168 | static int _fdt_find_add_string(void *fdt, const char *s) 169 | { 170 | char *strtab = (char *)fdt + fdt_totalsize(fdt); 171 | const char *p; 172 | int strtabsize = fdt_size_dt_strings(fdt); 173 | int len = strlen(s) + 1; 174 | int struct_top, offset; 175 | 176 | p = _fdt_find_string(strtab - strtabsize, strtabsize, s); 177 | if (p) 178 | return p - strtab; 179 | 180 | /* Add it */ 181 | offset = -strtabsize - len; 182 | struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 183 | if (fdt_totalsize(fdt) + offset < struct_top) 184 | return 0; /* no more room :( */ 185 | 186 | memcpy(strtab + offset, s, len); 187 | fdt_set_size_dt_strings(fdt, strtabsize + len); 188 | return offset; 189 | } 190 | 191 | int fdt_property(void *fdt, const char *name, const void *val, int len) 192 | { 193 | struct fdt_property *prop; 194 | int nameoff; 195 | 196 | FDT_SW_CHECK_HEADER(fdt); 197 | 198 | nameoff = _fdt_find_add_string(fdt, name); 199 | if (nameoff == 0) 200 | return -FDT_ERR_NOSPACE; 201 | 202 | prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 203 | if (! prop) 204 | return -FDT_ERR_NOSPACE; 205 | 206 | prop->tag = cpu_to_fdt32(FDT_PROP); 207 | prop->nameoff = cpu_to_fdt32(nameoff); 208 | prop->len = cpu_to_fdt32(len); 209 | memcpy(prop->data, val, len); 210 | return 0; 211 | } 212 | 213 | int fdt_finish(void *fdt) 214 | { 215 | char *p = (char *)fdt; 216 | uint32_t *end; 217 | int oldstroffset, newstroffset; 218 | uint32_t tag; 219 | int offset, nextoffset; 220 | 221 | FDT_SW_CHECK_HEADER(fdt); 222 | 223 | /* Add terminator */ 224 | end = _fdt_grab_space(fdt, sizeof(*end)); 225 | if (! end) 226 | return -FDT_ERR_NOSPACE; 227 | *end = cpu_to_fdt32(FDT_END); 228 | 229 | /* Relocate the string table */ 230 | oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); 231 | newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); 232 | memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); 233 | fdt_set_off_dt_strings(fdt, newstroffset); 234 | 235 | /* Walk the structure, correcting string offsets */ 236 | offset = 0; 237 | while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { 238 | if (tag == FDT_PROP) { 239 | struct fdt_property *prop = 240 | fdt_offset_ptr_w(fdt, offset, sizeof(*prop)); 241 | int nameoff; 242 | 243 | if (! prop) 244 | return -FDT_ERR_BADSTRUCTURE; 245 | 246 | nameoff = fdt32_to_cpu(prop->nameoff); 247 | nameoff += fdt_size_dt_strings(fdt); 248 | prop->nameoff = cpu_to_fdt32(nameoff); 249 | } 250 | offset = nextoffset; 251 | } 252 | 253 | /* Finally, adjust the header */ 254 | fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 255 | fdt_set_magic(fdt, FDT_MAGIC); 256 | return 0; 257 | } 258 | -------------------------------------------------------------------------------- /libfdt/fdt_wip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libfdt - Flat Device Tree manipulation 3 | * Copyright (C) 2006 David Gibson, IBM Corporation. 4 | * 5 | * libfdt is dual licensed: you can use it either under the terms of 6 | * the GPL, or the BSD license, at your option. 7 | * 8 | * a) This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License as 10 | * published by the Free Software Foundation; either version 2 of the 11 | * License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21 | * MA 02110-1301 USA 22 | * 23 | * Alternatively, 24 | * 25 | * b) Redistribution and use in source and binary forms, with or 26 | * without modification, are permitted provided that the following 27 | * conditions are met: 28 | * 29 | * 1. Redistributions of source code must retain the above 30 | * copyright notice, this list of conditions and the following 31 | * disclaimer. 32 | * 2. Redistributions in binary form must reproduce the above 33 | * copyright notice, this list of conditions and the following 34 | * disclaimer in the documentation and/or other materials 35 | * provided with the distribution. 36 | * 37 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | #include "libfdt_env.h" 52 | 53 | #include 54 | #include 55 | 56 | #include "libfdt_internal.h" 57 | 58 | int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, 59 | const void *val, int len) 60 | { 61 | void *propval; 62 | int proplen; 63 | 64 | propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); 65 | if (! propval) 66 | return proplen; 67 | 68 | if (proplen != len) 69 | return -FDT_ERR_NOSPACE; 70 | 71 | memcpy(propval, val, len); 72 | return 0; 73 | } 74 | 75 | static void _fdt_nop_region(void *start, int len) 76 | { 77 | uint32_t *p; 78 | 79 | for (p = start; (char *)p < ((char *)start + len); p++) 80 | *p = cpu_to_fdt32(FDT_NOP); 81 | } 82 | 83 | int fdt_nop_property(void *fdt, int nodeoffset, const char *name) 84 | { 85 | struct fdt_property *prop; 86 | int len; 87 | 88 | prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 89 | if (! prop) 90 | return len; 91 | 92 | _fdt_nop_region(prop, len + sizeof(*prop)); 93 | 94 | return 0; 95 | } 96 | 97 | int _fdt_node_end_offset(void *fdt, int nodeoffset) 98 | { 99 | int level = 0; 100 | uint32_t tag; 101 | int offset, nextoffset; 102 | 103 | tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); 104 | if (tag != FDT_BEGIN_NODE) 105 | return -FDT_ERR_BADOFFSET; 106 | do { 107 | offset = nextoffset; 108 | tag = fdt_next_tag(fdt, offset, &nextoffset); 109 | 110 | switch (tag) { 111 | case FDT_END: 112 | return offset; 113 | 114 | case FDT_BEGIN_NODE: 115 | level++; 116 | break; 117 | 118 | case FDT_END_NODE: 119 | level--; 120 | break; 121 | 122 | case FDT_PROP: 123 | case FDT_NOP: 124 | break; 125 | 126 | default: 127 | return -FDT_ERR_BADSTRUCTURE; 128 | } 129 | } while (level >= 0); 130 | 131 | return nextoffset; 132 | } 133 | 134 | int fdt_nop_node(void *fdt, int nodeoffset) 135 | { 136 | int endoffset; 137 | 138 | endoffset = _fdt_node_end_offset(fdt, nodeoffset); 139 | if (endoffset < 0) 140 | return endoffset; 141 | 142 | _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), 143 | endoffset - nodeoffset); 144 | return 0; 145 | } 146 | -------------------------------------------------------------------------------- /libfdt/libfdt.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBFDT_H 2 | #define _LIBFDT_H 3 | /* 4 | * libfdt - Flat Device Tree manipulation 5 | * Copyright (C) 2006 David Gibson, IBM Corporation. 6 | * 7 | * libfdt is dual licensed: you can use it either under the terms of 8 | * the GPL, or the BSD license, at your option. 9 | * 10 | * a) This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU General Public License as 12 | * published by the Free Software Foundation; either version 2 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public 21 | * License along with this library; if not, write to the Free 22 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 23 | * MA 02110-1301 USA 24 | * 25 | * Alternatively, 26 | * 27 | * b) Redistribution and use in source and binary forms, with or 28 | * without modification, are permitted provided that the following 29 | * conditions are met: 30 | * 31 | * 1. Redistributions of source code must retain the above 32 | * copyright notice, this list of conditions and the following 33 | * disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above 35 | * copyright notice, this list of conditions and the following 36 | * disclaimer in the documentation and/or other materials 37 | * provided with the distribution. 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 40 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 41 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 42 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 44 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 50 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 51 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | 54 | #include 55 | #include 56 | 57 | #define FDT_FIRST_SUPPORTED_VERSION 0x10 58 | #define FDT_LAST_SUPPORTED_VERSION 0x11 59 | 60 | /* Error codes: informative error codes */ 61 | #define FDT_ERR_NOTFOUND 1 62 | /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ 63 | #define FDT_ERR_EXISTS 2 64 | /* FDT_ERR_EXISTS: Attempted to create a node or property which 65 | * already exists */ 66 | #define FDT_ERR_NOSPACE 3 67 | /* FDT_ERR_NOSPACE: Operation needed to expand the device 68 | * tree, but its buffer did not have sufficient space to 69 | * contain the expanded tree. Use fdt_open_into() to move the 70 | * device tree to a buffer with more space. */ 71 | 72 | /* Error codes: codes for bad parameters */ 73 | #define FDT_ERR_BADOFFSET 4 74 | /* FDT_ERR_BADOFFSET: Function was passed a structure block 75 | * offset which is out-of-bounds, or which points to an 76 | * unsuitable part of the structure for the operation. */ 77 | #define FDT_ERR_BADPATH 5 78 | /* FDT_ERR_BADPATH: Function was passed a badly formatted path 79 | * (e.g. missing a leading / for a function which requires an 80 | * absolute path) */ 81 | #define FDT_ERR_BADPHANDLE 6 82 | /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle 83 | * value. phandle values of 0 and -1 are not permitted. */ 84 | #define FDT_ERR_BADSTATE 7 85 | /* FDT_ERR_BADSTATE: Function was passed an incomplete device 86 | * tree created by the sequential-write functions, which is 87 | * not sufficiently complete for the requested operation. */ 88 | 89 | /* Error codes: codes for bad device tree blobs */ 90 | #define FDT_ERR_TRUNCATED 8 91 | /* FDT_ERR_TRUNCATED: Structure block of the given device tree 92 | * ends without an FDT_END tag. */ 93 | #define FDT_ERR_BADMAGIC 9 94 | /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a 95 | * device tree at all - it is missing the flattened device 96 | * tree magic number. */ 97 | #define FDT_ERR_BADVERSION 10 98 | /* FDT_ERR_BADVERSION: Given device tree has a version which 99 | * can't be handled by the requested operation. For 100 | * read-write functions, this may mean that fdt_open_into() is 101 | * required to convert the tree to the expected version. */ 102 | #define FDT_ERR_BADSTRUCTURE 11 103 | /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt 104 | * structure block or other serious error (e.g. misnested 105 | * nodes, or subnodes preceding properties). */ 106 | #define FDT_ERR_BADLAYOUT 12 107 | /* FDT_ERR_BADLAYOUT: For read-write functions, the given 108 | * device tree has it's sub-blocks in an order that the 109 | * function can't handle (memory reserve map, then structure, 110 | * then strings). Use fdt_open_into() to reorganize the tree 111 | * into a form suitable for the read-write operations. */ 112 | 113 | /* "Can't happen" error indicating a bug in libfdt */ 114 | #define FDT_ERR_INTERNAL 13 115 | /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. 116 | * Should never be returned, if it is, it indicates a bug in 117 | * libfdt itself. */ 118 | 119 | #define FDT_ERR_MAX 13 120 | 121 | /**********************************************************************/ 122 | /* Low-level functions (you probably don't need these) */ 123 | /**********************************************************************/ 124 | 125 | const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); 126 | static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) 127 | { 128 | return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); 129 | } 130 | 131 | uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); 132 | 133 | /**********************************************************************/ 134 | /* Traversal functions */ 135 | /**********************************************************************/ 136 | 137 | int fdt_next_node(const void *fdt, int offset, int *depth); 138 | 139 | /**********************************************************************/ 140 | /* General functions */ 141 | /**********************************************************************/ 142 | 143 | #define fdt_get_header(fdt, field) \ 144 | (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) 145 | #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) 146 | #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) 147 | #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) 148 | #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) 149 | #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) 150 | #define fdt_version(fdt) (fdt_get_header(fdt, version)) 151 | #define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) 152 | #define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) 153 | #define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) 154 | #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) 155 | 156 | #define __fdt_set_hdr(name) \ 157 | static inline void fdt_set_##name(void *fdt, uint32_t val) \ 158 | { \ 159 | struct fdt_header *fdth = fdt; \ 160 | fdth->name = cpu_to_fdt32(val); \ 161 | } 162 | __fdt_set_hdr(magic); 163 | __fdt_set_hdr(totalsize); 164 | __fdt_set_hdr(off_dt_struct); 165 | __fdt_set_hdr(off_dt_strings); 166 | __fdt_set_hdr(off_mem_rsvmap); 167 | __fdt_set_hdr(version); 168 | __fdt_set_hdr(last_comp_version); 169 | __fdt_set_hdr(boot_cpuid_phys); 170 | __fdt_set_hdr(size_dt_strings); 171 | __fdt_set_hdr(size_dt_struct); 172 | #undef __fdt_set_hdr 173 | 174 | /** 175 | * fdt_check_header - sanity check a device tree or possible device tree 176 | * @fdt: pointer to data which might be a flattened device tree 177 | * 178 | * fdt_check_header() checks that the given buffer contains what 179 | * appears to be a flattened device tree with sane information in its 180 | * header. 181 | * 182 | * returns: 183 | * 0, if the buffer appears to contain a valid device tree 184 | * -FDT_ERR_BADMAGIC, 185 | * -FDT_ERR_BADVERSION, 186 | * -FDT_ERR_BADSTATE, standard meanings, as above 187 | */ 188 | int fdt_check_header(const void *fdt); 189 | 190 | /** 191 | * fdt_move - move a device tree around in memory 192 | * @fdt: pointer to the device tree to move 193 | * @buf: pointer to memory where the device is to be moved 194 | * @bufsize: size of the memory space at buf 195 | * 196 | * fdt_move() relocates, if possible, the device tree blob located at 197 | * fdt to the buffer at buf of size bufsize. The buffer may overlap 198 | * with the existing device tree blob at fdt. Therefore, 199 | * fdt_move(fdt, fdt, fdt_totalsize(fdt)) 200 | * should always succeed. 201 | * 202 | * returns: 203 | * 0, on success 204 | * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree 205 | * -FDT_ERR_BADMAGIC, 206 | * -FDT_ERR_BADVERSION, 207 | * -FDT_ERR_BADSTATE, standard meanings 208 | */ 209 | int fdt_move(const void *fdt, void *buf, int bufsize); 210 | 211 | /**********************************************************************/ 212 | /* Read-only functions */ 213 | /**********************************************************************/ 214 | 215 | /** 216 | * fdt_string - retrieve a string from the strings block of a device tree 217 | * @fdt: pointer to the device tree blob 218 | * @stroffset: offset of the string within the strings block (native endian) 219 | * 220 | * fdt_string() retrieves a pointer to a single string from the 221 | * strings block of the device tree blob at fdt. 222 | * 223 | * returns: 224 | * a pointer to the string, on success 225 | * NULL, if stroffset is out of bounds 226 | */ 227 | const char *fdt_string(const void *fdt, int stroffset); 228 | 229 | /** 230 | * fdt_num_mem_rsv - retrieve the number of memory reserve map entries 231 | * @fdt: pointer to the device tree blob 232 | * 233 | * Returns the number of entries in the device tree blob's memory 234 | * reservation map. This does not include the terminating 0,0 entry 235 | * or any other (0,0) entries reserved for expansion. 236 | * 237 | * returns: 238 | * the number of entries 239 | */ 240 | int fdt_num_mem_rsv(const void *fdt); 241 | 242 | /** 243 | * fdt_get_mem_rsv - retrieve one memory reserve map entry 244 | * @fdt: pointer to the device tree blob 245 | * @address, @size: pointers to 64-bit variables 246 | * 247 | * On success, *address and *size will contain the address and size of 248 | * the n-th reserve map entry from the device tree blob, in 249 | * native-endian format. 250 | * 251 | * returns: 252 | * 0, on success 253 | * -FDT_ERR_BADMAGIC, 254 | * -FDT_ERR_BADVERSION, 255 | * -FDT_ERR_BADSTATE, standard meanings 256 | */ 257 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); 258 | 259 | /** 260 | * fdt_subnode_offset_namelen - find a subnode based on substring 261 | * @fdt: pointer to the device tree blob 262 | * @parentoffset: structure block offset of a node 263 | * @name: name of the subnode to locate 264 | * @namelen: number of characters of name to consider 265 | * 266 | * Identical to fdt_subnode_offset(), but only examine the first 267 | * namelen characters of name for matching the subnode name. This is 268 | * useful for finding subnodes based on a portion of a larger string, 269 | * such as a full path. 270 | */ 271 | int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, 272 | const char *name, int namelen); 273 | /** 274 | * fdt_subnode_offset - find a subnode of a given node 275 | * @fdt: pointer to the device tree blob 276 | * @parentoffset: structure block offset of a node 277 | * @name: name of the subnode to locate 278 | * 279 | * fdt_subnode_offset() finds a subnode of the node at structure block 280 | * offset parentoffset with the given name. name may include a unit 281 | * address, in which case fdt_subnode_offset() will find the subnode 282 | * with that unit address, or the unit address may be omitted, in 283 | * which case fdt_subnode_offset() will find an arbitrary subnode 284 | * whose name excluding unit address matches the given name. 285 | * 286 | * returns: 287 | * structure block offset of the requested subnode (>=0), on success 288 | * -FDT_ERR_NOTFOUND, if the requested subnode does not exist 289 | * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag 290 | * -FDT_ERR_BADMAGIC, 291 | * -FDT_ERR_BADVERSION, 292 | * -FDT_ERR_BADSTATE, 293 | * -FDT_ERR_BADSTRUCTURE, 294 | * -FDT_ERR_TRUNCATED, standard meanings. 295 | */ 296 | int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); 297 | 298 | /** 299 | * fdt_path_offset - find a tree node by its full path 300 | * @fdt: pointer to the device tree blob 301 | * @path: full path of the node to locate 302 | * 303 | * fdt_path_offset() finds a node of a given path in the device tree. 304 | * Each path component may omit the unit address portion, but the 305 | * results of this are undefined if any such path component is 306 | * ambiguous (that is if there are multiple nodes at the relevant 307 | * level matching the given component, differentiated only by unit 308 | * address). 309 | * 310 | * returns: 311 | * structure block offset of the node with the requested path (>=0), on success 312 | * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid 313 | * -FDT_ERR_NOTFOUND, if the requested node does not exist 314 | * -FDT_ERR_BADMAGIC, 315 | * -FDT_ERR_BADVERSION, 316 | * -FDT_ERR_BADSTATE, 317 | * -FDT_ERR_BADSTRUCTURE, 318 | * -FDT_ERR_TRUNCATED, standard meanings. 319 | */ 320 | int fdt_path_offset(const void *fdt, const char *path); 321 | 322 | /** 323 | * fdt_get_name - retrieve the name of a given node 324 | * @fdt: pointer to the device tree blob 325 | * @nodeoffset: structure block offset of the starting node 326 | * @lenp: pointer to an integer variable (will be overwritten) or NULL 327 | * 328 | * fdt_get_name() retrieves the name (including unit address) of the 329 | * device tree node at structure block offset nodeoffset. If lenp is 330 | * non-NULL, the length of this name is also returned, in the integer 331 | * pointed to by lenp. 332 | * 333 | * returns: 334 | * pointer to the node's name, on success 335 | * If lenp is non-NULL, *lenp contains the length of that name (>=0) 336 | * NULL, on error 337 | * if lenp is non-NULL *lenp contains an error code (<0): 338 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 339 | * -FDT_ERR_BADMAGIC, 340 | * -FDT_ERR_BADVERSION, 341 | * -FDT_ERR_BADSTATE, standard meanings 342 | */ 343 | const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); 344 | 345 | /** 346 | * fdt_get_property - find a given property in a given node 347 | * @fdt: pointer to the device tree blob 348 | * @nodeoffset: offset of the node whose property to find 349 | * @name: name of the property to find 350 | * @lenp: pointer to an integer variable (will be overwritten) or NULL 351 | * 352 | * fdt_get_property() retrieves a pointer to the fdt_property 353 | * structure within the device tree blob corresponding to the property 354 | * named 'name' of the node at offset nodeoffset. If lenp is 355 | * non-NULL, the length of the property value is also returned, in the 356 | * integer pointed to by lenp. 357 | * 358 | * returns: 359 | * pointer to the structure representing the property 360 | * if lenp is non-NULL, *lenp contains the length of the property 361 | * value (>=0) 362 | * NULL, on error 363 | * if lenp is non-NULL, *lenp contains an error code (<0): 364 | * -FDT_ERR_NOTFOUND, node does not have named property 365 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 366 | * -FDT_ERR_BADMAGIC, 367 | * -FDT_ERR_BADVERSION, 368 | * -FDT_ERR_BADSTATE, 369 | * -FDT_ERR_BADSTRUCTURE, 370 | * -FDT_ERR_TRUNCATED, standard meanings 371 | */ 372 | const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, 373 | const char *name, int *lenp); 374 | static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, 375 | const char *name, 376 | int *lenp) 377 | { 378 | return (struct fdt_property *)(uintptr_t) 379 | fdt_get_property(fdt, nodeoffset, name, lenp); 380 | } 381 | 382 | /** 383 | * fdt_getprop - retrieve the value of a given property 384 | * @fdt: pointer to the device tree blob 385 | * @nodeoffset: offset of the node whose property to find 386 | * @name: name of the property to find 387 | * @lenp: pointer to an integer variable (will be overwritten) or NULL 388 | * 389 | * fdt_getprop() retrieves a pointer to the value of the property 390 | * named 'name' of the node at offset nodeoffset (this will be a 391 | * pointer to within the device blob itself, not a copy of the value). 392 | * If lenp is non-NULL, the length of the property value is also 393 | * returned, in the integer pointed to by lenp. 394 | * 395 | * returns: 396 | * pointer to the property's value 397 | * if lenp is non-NULL, *lenp contains the length of the property 398 | * value (>=0) 399 | * NULL, on error 400 | * if lenp is non-NULL, *lenp contains an error code (<0): 401 | * -FDT_ERR_NOTFOUND, node does not have named property 402 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 403 | * -FDT_ERR_BADMAGIC, 404 | * -FDT_ERR_BADVERSION, 405 | * -FDT_ERR_BADSTATE, 406 | * -FDT_ERR_BADSTRUCTURE, 407 | * -FDT_ERR_TRUNCATED, standard meanings 408 | */ 409 | const void *fdt_getprop(const void *fdt, int nodeoffset, 410 | const char *name, int *lenp); 411 | static inline void *fdt_getprop_w(void *fdt, int nodeoffset, 412 | const char *name, int *lenp) 413 | { 414 | return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); 415 | } 416 | 417 | /** 418 | * fdt_get_phandle - retrieve the phandle of a given node 419 | * @fdt: pointer to the device tree blob 420 | * @nodeoffset: structure block offset of the node 421 | * 422 | * fdt_get_phandle() retrieves the phandle of the device tree node at 423 | * structure block offset nodeoffset. 424 | * 425 | * returns: 426 | * the phandle of the node at nodeoffset, on success (!= 0, != -1) 427 | * 0, if the node has no phandle, or another error occurs 428 | */ 429 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); 430 | 431 | /** 432 | * fdt_get_path - determine the full path of a node 433 | * @fdt: pointer to the device tree blob 434 | * @nodeoffset: offset of the node whose path to find 435 | * @buf: character buffer to contain the returned path (will be overwritten) 436 | * @buflen: size of the character buffer at buf 437 | * 438 | * fdt_get_path() computes the full path of the node at offset 439 | * nodeoffset, and records that path in the buffer at buf. 440 | * 441 | * NOTE: This function is expensive, as it must scan the device tree 442 | * structure from the start to nodeoffset. 443 | * 444 | * returns: 445 | * 0, on success 446 | * buf contains the absolute path of the node at 447 | * nodeoffset, as a NUL-terminated string. 448 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag 449 | * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) 450 | * characters and will not fit in the given buffer. 451 | * -FDT_ERR_BADMAGIC, 452 | * -FDT_ERR_BADVERSION, 453 | * -FDT_ERR_BADSTATE, 454 | * -FDT_ERR_BADSTRUCTURE, standard meanings 455 | */ 456 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); 457 | 458 | /** 459 | * fdt_supernode_atdepth_offset - find a specific ancestor of a node 460 | * @fdt: pointer to the device tree blob 461 | * @nodeoffset: offset of the node whose parent to find 462 | * @supernodedepth: depth of the ancestor to find 463 | * @nodedepth: pointer to an integer variable (will be overwritten) or NULL 464 | * 465 | * fdt_supernode_atdepth_offset() finds an ancestor of the given node 466 | * at a specific depth from the root (where the root itself has depth 467 | * 0, its immediate subnodes depth 1 and so forth). So 468 | * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); 469 | * will always return 0, the offset of the root node. If the node at 470 | * nodeoffset has depth D, then: 471 | * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); 472 | * will return nodeoffset itself. 473 | * 474 | * NOTE: This function is expensive, as it must scan the device tree 475 | * structure from the start to nodeoffset. 476 | * 477 | * returns: 478 | 479 | * structure block offset of the node at node offset's ancestor 480 | * of depth supernodedepth (>=0), on success 481 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag 482 | * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset 483 | * -FDT_ERR_BADMAGIC, 484 | * -FDT_ERR_BADVERSION, 485 | * -FDT_ERR_BADSTATE, 486 | * -FDT_ERR_BADSTRUCTURE, standard meanings 487 | */ 488 | int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, 489 | int supernodedepth, int *nodedepth); 490 | 491 | /** 492 | * fdt_node_depth - find the depth of a given node 493 | * @fdt: pointer to the device tree blob 494 | * @nodeoffset: offset of the node whose parent to find 495 | * 496 | * fdt_node_depth() finds the depth of a given node. The root node 497 | * has depth 0, its immediate subnodes depth 1 and so forth. 498 | * 499 | * NOTE: This function is expensive, as it must scan the device tree 500 | * structure from the start to nodeoffset. 501 | * 502 | * returns: 503 | * depth of the node at nodeoffset (>=0), on success 504 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag 505 | * -FDT_ERR_BADMAGIC, 506 | * -FDT_ERR_BADVERSION, 507 | * -FDT_ERR_BADSTATE, 508 | * -FDT_ERR_BADSTRUCTURE, standard meanings 509 | */ 510 | int fdt_node_depth(const void *fdt, int nodeoffset); 511 | 512 | /** 513 | * fdt_parent_offset - find the parent of a given node 514 | * @fdt: pointer to the device tree blob 515 | * @nodeoffset: offset of the node whose parent to find 516 | * 517 | * fdt_parent_offset() locates the parent node of a given node (that 518 | * is, it finds the offset of the node which contains the node at 519 | * nodeoffset as a subnode). 520 | * 521 | * NOTE: This function is expensive, as it must scan the device tree 522 | * structure from the start to nodeoffset, *twice*. 523 | * 524 | * returns: 525 | * structure block offset of the parent of the node at nodeoffset 526 | * (>=0), on success 527 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag 528 | * -FDT_ERR_BADMAGIC, 529 | * -FDT_ERR_BADVERSION, 530 | * -FDT_ERR_BADSTATE, 531 | * -FDT_ERR_BADSTRUCTURE, standard meanings 532 | */ 533 | int fdt_parent_offset(const void *fdt, int nodeoffset); 534 | 535 | /** 536 | * fdt_node_offset_by_prop_value - find nodes with a given property value 537 | * @fdt: pointer to the device tree blob 538 | * @startoffset: only find nodes after this offset 539 | * @propname: property name to check 540 | * @propval: property value to search for 541 | * @proplen: length of the value in propval 542 | * 543 | * fdt_node_offset_by_prop_value() returns the offset of the first 544 | * node after startoffset, which has a property named propname whose 545 | * value is of length proplen and has value equal to propval; or if 546 | * startoffset is -1, the very first such node in the tree. 547 | * 548 | * To iterate through all nodes matching the criterion, the following 549 | * idiom can be used: 550 | * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, 551 | * propval, proplen); 552 | * while (offset != -FDT_ERR_NOTFOUND) { 553 | * // other code here 554 | * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, 555 | * propval, proplen); 556 | * } 557 | * 558 | * Note the -1 in the first call to the function, if 0 is used here 559 | * instead, the function will never locate the root node, even if it 560 | * matches the criterion. 561 | * 562 | * returns: 563 | * structure block offset of the located node (>= 0, >startoffset), 564 | * on success 565 | * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the 566 | * tree after startoffset 567 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag 568 | * -FDT_ERR_BADMAGIC, 569 | * -FDT_ERR_BADVERSION, 570 | * -FDT_ERR_BADSTATE, 571 | * -FDT_ERR_BADSTRUCTURE, standard meanings 572 | */ 573 | int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, 574 | const char *propname, 575 | const void *propval, int proplen); 576 | 577 | /** 578 | * fdt_node_offset_by_phandle - find the node with a given phandle 579 | * @fdt: pointer to the device tree blob 580 | * @phandle: phandle value 581 | * 582 | * fdt_node_offset_by_phandle() returns the offset of the node 583 | * which has the given phandle value. If there is more than one node 584 | * in the tree with the given phandle (an invalid tree), results are 585 | * undefined. 586 | * 587 | * returns: 588 | * structure block offset of the located node (>= 0), on success 589 | * -FDT_ERR_NOTFOUND, no node with that phandle exists 590 | * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) 591 | * -FDT_ERR_BADMAGIC, 592 | * -FDT_ERR_BADVERSION, 593 | * -FDT_ERR_BADSTATE, 594 | * -FDT_ERR_BADSTRUCTURE, standard meanings 595 | */ 596 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); 597 | 598 | /** 599 | * fdt_node_check_compatible: check a node's compatible property 600 | * @fdt: pointer to the device tree blob 601 | * @nodeoffset: offset of a tree node 602 | * @compatible: string to match against 603 | * 604 | * 605 | * fdt_node_check_compatible() returns 0 if the given node contains a 606 | * 'compatible' property with the given string as one of its elements, 607 | * it returns non-zero otherwise, or on error. 608 | * 609 | * returns: 610 | * 0, if the node has a 'compatible' property listing the given string 611 | * 1, if the node has a 'compatible' property, but it does not list 612 | * the given string 613 | * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property 614 | * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag 615 | * -FDT_ERR_BADMAGIC, 616 | * -FDT_ERR_BADVERSION, 617 | * -FDT_ERR_BADSTATE, 618 | * -FDT_ERR_BADSTRUCTURE, standard meanings 619 | */ 620 | int fdt_node_check_compatible(const void *fdt, int nodeoffset, 621 | const char *compatible); 622 | 623 | /** 624 | * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value 625 | * @fdt: pointer to the device tree blob 626 | * @startoffset: only find nodes after this offset 627 | * @compatible: 'compatible' string to match against 628 | * 629 | * fdt_node_offset_by_compatible() returns the offset of the first 630 | * node after startoffset, which has a 'compatible' property which 631 | * lists the given compatible string; or if startoffset is -1, the 632 | * very first such node in the tree. 633 | * 634 | * To iterate through all nodes matching the criterion, the following 635 | * idiom can be used: 636 | * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); 637 | * while (offset != -FDT_ERR_NOTFOUND) { 638 | * // other code here 639 | * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); 640 | * } 641 | * 642 | * Note the -1 in the first call to the function, if 0 is used here 643 | * instead, the function will never locate the root node, even if it 644 | * matches the criterion. 645 | * 646 | * returns: 647 | * structure block offset of the located node (>= 0, >startoffset), 648 | * on success 649 | * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the 650 | * tree after startoffset 651 | * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag 652 | * -FDT_ERR_BADMAGIC, 653 | * -FDT_ERR_BADVERSION, 654 | * -FDT_ERR_BADSTATE, 655 | * -FDT_ERR_BADSTRUCTURE, standard meanings 656 | */ 657 | int fdt_node_offset_by_compatible(const void *fdt, int startoffset, 658 | const char *compatible); 659 | 660 | /**********************************************************************/ 661 | /* Write-in-place functions */ 662 | /**********************************************************************/ 663 | 664 | /** 665 | * fdt_setprop_inplace - change a property's value, but not its size 666 | * @fdt: pointer to the device tree blob 667 | * @nodeoffset: offset of the node whose property to change 668 | * @name: name of the property to change 669 | * @val: pointer to data to replace the property value with 670 | * @len: length of the property value 671 | * 672 | * fdt_setprop_inplace() replaces the value of a given property with 673 | * the data in val, of length len. This function cannot change the 674 | * size of a property, and so will only work if len is equal to the 675 | * current length of the property. 676 | * 677 | * This function will alter only the bytes in the blob which contain 678 | * the given property value, and will not alter or move any other part 679 | * of the tree. 680 | * 681 | * returns: 682 | * 0, on success 683 | * -FDT_ERR_NOSPACE, if len is not equal to the property's current length 684 | * -FDT_ERR_NOTFOUND, node does not have the named property 685 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 686 | * -FDT_ERR_BADMAGIC, 687 | * -FDT_ERR_BADVERSION, 688 | * -FDT_ERR_BADSTATE, 689 | * -FDT_ERR_BADSTRUCTURE, 690 | * -FDT_ERR_TRUNCATED, standard meanings 691 | */ 692 | int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, 693 | const void *val, int len); 694 | 695 | /** 696 | * fdt_setprop_inplace_cell - change the value of a single-cell property 697 | * @fdt: pointer to the device tree blob 698 | * @nodeoffset: offset of the node whose property to change 699 | * @name: name of the property to change 700 | * @val: cell (32-bit integer) value to replace the property with 701 | * 702 | * fdt_setprop_inplace_cell() replaces the value of a given property 703 | * with the 32-bit integer cell value in val, converting val to 704 | * big-endian if necessary. This function cannot change the size of a 705 | * property, and so will only work if the property already exists and 706 | * has length 4. 707 | * 708 | * This function will alter only the bytes in the blob which contain 709 | * the given property value, and will not alter or move any other part 710 | * of the tree. 711 | * 712 | * returns: 713 | * 0, on success 714 | * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 715 | * -FDT_ERR_NOTFOUND, node does not have the named property 716 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 717 | * -FDT_ERR_BADMAGIC, 718 | * -FDT_ERR_BADVERSION, 719 | * -FDT_ERR_BADSTATE, 720 | * -FDT_ERR_BADSTRUCTURE, 721 | * -FDT_ERR_TRUNCATED, standard meanings 722 | */ 723 | static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, 724 | const char *name, uint32_t val) 725 | { 726 | val = cpu_to_fdt32(val); 727 | return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); 728 | } 729 | 730 | /** 731 | * fdt_nop_property - replace a property with nop tags 732 | * @fdt: pointer to the device tree blob 733 | * @nodeoffset: offset of the node whose property to nop 734 | * @name: name of the property to nop 735 | * 736 | * fdt_nop_property() will replace a given property's representation 737 | * in the blob with FDT_NOP tags, effectively removing it from the 738 | * tree. 739 | * 740 | * This function will alter only the bytes in the blob which contain 741 | * the property, and will not alter or move any other part of the 742 | * tree. 743 | * 744 | * returns: 745 | * 0, on success 746 | * -FDT_ERR_NOTFOUND, node does not have the named property 747 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 748 | * -FDT_ERR_BADMAGIC, 749 | * -FDT_ERR_BADVERSION, 750 | * -FDT_ERR_BADSTATE, 751 | * -FDT_ERR_BADSTRUCTURE, 752 | * -FDT_ERR_TRUNCATED, standard meanings 753 | */ 754 | int fdt_nop_property(void *fdt, int nodeoffset, const char *name); 755 | 756 | /** 757 | * fdt_nop_node - replace a node (subtree) with nop tags 758 | * @fdt: pointer to the device tree blob 759 | * @nodeoffset: offset of the node to nop 760 | * 761 | * fdt_nop_node() will replace a given node's representation in the 762 | * blob, including all its subnodes, if any, with FDT_NOP tags, 763 | * effectively removing it from the tree. 764 | * 765 | * This function will alter only the bytes in the blob which contain 766 | * the node and its properties and subnodes, and will not alter or 767 | * move any other part of the tree. 768 | * 769 | * returns: 770 | * 0, on success 771 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 772 | * -FDT_ERR_BADMAGIC, 773 | * -FDT_ERR_BADVERSION, 774 | * -FDT_ERR_BADSTATE, 775 | * -FDT_ERR_BADSTRUCTURE, 776 | * -FDT_ERR_TRUNCATED, standard meanings 777 | */ 778 | int fdt_nop_node(void *fdt, int nodeoffset); 779 | 780 | /**********************************************************************/ 781 | /* Sequential write functions */ 782 | /**********************************************************************/ 783 | 784 | int fdt_create(void *buf, int bufsize); 785 | int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); 786 | int fdt_finish_reservemap(void *fdt); 787 | int fdt_begin_node(void *fdt, const char *name); 788 | int fdt_property(void *fdt, const char *name, const void *val, int len); 789 | static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) 790 | { 791 | val = cpu_to_fdt32(val); 792 | return fdt_property(fdt, name, &val, sizeof(val)); 793 | } 794 | #define fdt_property_string(fdt, name, str) \ 795 | fdt_property(fdt, name, str, strlen(str)+1) 796 | int fdt_end_node(void *fdt); 797 | int fdt_finish(void *fdt); 798 | 799 | /**********************************************************************/ 800 | /* Read-write functions */ 801 | /**********************************************************************/ 802 | 803 | int fdt_open_into(const void *fdt, void *buf, int bufsize); 804 | int fdt_pack(void *fdt); 805 | 806 | /** 807 | * fdt_add_mem_rsv - add one memory reserve map entry 808 | * @fdt: pointer to the device tree blob 809 | * @address, @size: 64-bit values (native endian) 810 | * 811 | * Adds a reserve map entry to the given blob reserving a region at 812 | * address address of length size. 813 | * 814 | * This function will insert data into the reserve map and will 815 | * therefore change the indexes of some entries in the table. 816 | * 817 | * returns: 818 | * 0, on success 819 | * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to 820 | * contain the new reservation entry 821 | * -FDT_ERR_BADMAGIC, 822 | * -FDT_ERR_BADVERSION, 823 | * -FDT_ERR_BADSTATE, 824 | * -FDT_ERR_BADSTRUCTURE, 825 | * -FDT_ERR_BADLAYOUT, 826 | * -FDT_ERR_TRUNCATED, standard meanings 827 | */ 828 | int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); 829 | 830 | /** 831 | * fdt_del_mem_rsv - remove a memory reserve map entry 832 | * @fdt: pointer to the device tree blob 833 | * @n: entry to remove 834 | * 835 | * fdt_del_mem_rsv() removes the n-th memory reserve map entry from 836 | * the blob. 837 | * 838 | * This function will delete data from the reservation table and will 839 | * therefore change the indexes of some entries in the table. 840 | * 841 | * returns: 842 | * 0, on success 843 | * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there 844 | * are less than n+1 reserve map entries) 845 | * -FDT_ERR_BADMAGIC, 846 | * -FDT_ERR_BADVERSION, 847 | * -FDT_ERR_BADSTATE, 848 | * -FDT_ERR_BADSTRUCTURE, 849 | * -FDT_ERR_BADLAYOUT, 850 | * -FDT_ERR_TRUNCATED, standard meanings 851 | */ 852 | int fdt_del_mem_rsv(void *fdt, int n); 853 | 854 | /** 855 | * fdt_set_name - change the name of a given node 856 | * @fdt: pointer to the device tree blob 857 | * @nodeoffset: structure block offset of a node 858 | * @name: name to give the node 859 | * 860 | * fdt_set_name() replaces the name (including unit address, if any) 861 | * of the given node with the given string. NOTE: this function can't 862 | * efficiently check if the new name is unique amongst the given 863 | * node's siblings; results are undefined if this function is invoked 864 | * with a name equal to one of the given node's siblings. 865 | * 866 | * This function may insert or delete data from the blob, and will 867 | * therefore change the offsets of some existing nodes. 868 | * 869 | * returns: 870 | * 0, on success 871 | * -FDT_ERR_NOSPACE, there is insufficient free space in the blob 872 | * to contain the new name 873 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 874 | * -FDT_ERR_BADMAGIC, 875 | * -FDT_ERR_BADVERSION, 876 | * -FDT_ERR_BADSTATE, standard meanings 877 | */ 878 | int fdt_set_name(void *fdt, int nodeoffset, const char *name); 879 | 880 | /** 881 | * fdt_setprop - create or change a property 882 | * @fdt: pointer to the device tree blob 883 | * @nodeoffset: offset of the node whose property to change 884 | * @name: name of the property to change 885 | * @val: pointer to data to set the property value to 886 | * @len: length of the property value 887 | * 888 | * fdt_setprop() sets the value of the named property in the given 889 | * node to the given value and length, creating the property if it 890 | * does not already exist. 891 | * 892 | * This function may insert or delete data from the blob, and will 893 | * therefore change the offsets of some existing nodes. 894 | * 895 | * returns: 896 | * 0, on success 897 | * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to 898 | * contain the new property value 899 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 900 | * -FDT_ERR_BADLAYOUT, 901 | * -FDT_ERR_BADMAGIC, 902 | * -FDT_ERR_BADVERSION, 903 | * -FDT_ERR_BADSTATE, 904 | * -FDT_ERR_BADSTRUCTURE, 905 | * -FDT_ERR_BADLAYOUT, 906 | * -FDT_ERR_TRUNCATED, standard meanings 907 | */ 908 | int fdt_setprop(void *fdt, int nodeoffset, const char *name, 909 | const void *val, int len); 910 | 911 | /** 912 | * fdt_setprop_cell - set a property to a single cell value 913 | * @fdt: pointer to the device tree blob 914 | * @nodeoffset: offset of the node whose property to change 915 | * @name: name of the property to change 916 | * @val: 32-bit integer value for the property (native endian) 917 | * 918 | * fdt_setprop_cell() sets the value of the named property in the 919 | * given node to the given cell value (converting to big-endian if 920 | * necessary), or creates a new property with that value if it does 921 | * not already exist. 922 | * 923 | * This function may insert or delete data from the blob, and will 924 | * therefore change the offsets of some existing nodes. 925 | * 926 | * returns: 927 | * 0, on success 928 | * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to 929 | * contain the new property value 930 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 931 | * -FDT_ERR_BADLAYOUT, 932 | * -FDT_ERR_BADMAGIC, 933 | * -FDT_ERR_BADVERSION, 934 | * -FDT_ERR_BADSTATE, 935 | * -FDT_ERR_BADSTRUCTURE, 936 | * -FDT_ERR_BADLAYOUT, 937 | * -FDT_ERR_TRUNCATED, standard meanings 938 | */ 939 | static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, 940 | uint32_t val) 941 | { 942 | val = cpu_to_fdt32(val); 943 | return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); 944 | } 945 | 946 | /** 947 | * fdt_setprop_string - set a property to a string value 948 | * @fdt: pointer to the device tree blob 949 | * @nodeoffset: offset of the node whose property to change 950 | * @name: name of the property to change 951 | * @str: string value for the property 952 | * 953 | * fdt_setprop_string() sets the value of the named property in the 954 | * given node to the given string value (using the length of the 955 | * string to determine the new length of the property), or creates a 956 | * new property with that value if it does not already exist. 957 | * 958 | * This function may insert or delete data from the blob, and will 959 | * therefore change the offsets of some existing nodes. 960 | * 961 | * returns: 962 | * 0, on success 963 | * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to 964 | * contain the new property value 965 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 966 | * -FDT_ERR_BADLAYOUT, 967 | * -FDT_ERR_BADMAGIC, 968 | * -FDT_ERR_BADVERSION, 969 | * -FDT_ERR_BADSTATE, 970 | * -FDT_ERR_BADSTRUCTURE, 971 | * -FDT_ERR_BADLAYOUT, 972 | * -FDT_ERR_TRUNCATED, standard meanings 973 | */ 974 | #define fdt_setprop_string(fdt, nodeoffset, name, str) \ 975 | fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) 976 | 977 | /** 978 | * fdt_delprop - delete a property 979 | * @fdt: pointer to the device tree blob 980 | * @nodeoffset: offset of the node whose property to nop 981 | * @name: name of the property to nop 982 | * 983 | * fdt_del_property() will delete the given property. 984 | * 985 | * This function will delete data from the blob, and will therefore 986 | * change the offsets of some existing nodes. 987 | * 988 | * returns: 989 | * 0, on success 990 | * -FDT_ERR_NOTFOUND, node does not have the named property 991 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 992 | * -FDT_ERR_BADLAYOUT, 993 | * -FDT_ERR_BADMAGIC, 994 | * -FDT_ERR_BADVERSION, 995 | * -FDT_ERR_BADSTATE, 996 | * -FDT_ERR_BADSTRUCTURE, 997 | * -FDT_ERR_TRUNCATED, standard meanings 998 | */ 999 | int fdt_delprop(void *fdt, int nodeoffset, const char *name); 1000 | 1001 | /** 1002 | * fdt_add_subnode_namelen - creates a new node based on substring 1003 | * @fdt: pointer to the device tree blob 1004 | * @parentoffset: structure block offset of a node 1005 | * @name: name of the subnode to locate 1006 | * @namelen: number of characters of name to consider 1007 | * 1008 | * Identical to fdt_add_subnode(), but use only the first namelen 1009 | * characters of name as the name of the new node. This is useful for 1010 | * creating subnodes based on a portion of a larger string, such as a 1011 | * full path. 1012 | */ 1013 | int fdt_add_subnode_namelen(void *fdt, int parentoffset, 1014 | const char *name, int namelen); 1015 | 1016 | /** 1017 | * fdt_add_subnode - creates a new node 1018 | * @fdt: pointer to the device tree blob 1019 | * @parentoffset: structure block offset of a node 1020 | * @name: name of the subnode to locate 1021 | * 1022 | * fdt_add_subnode() creates a new node as a subnode of the node at 1023 | * structure block offset parentoffset, with the given name (which 1024 | * should include the unit address, if any). 1025 | * 1026 | * This function will insert data into the blob, and will therefore 1027 | * change the offsets of some existing nodes. 1028 | 1029 | * returns: 1030 | * structure block offset of the created nodeequested subnode (>=0), on success 1031 | * -FDT_ERR_NOTFOUND, if the requested subnode does not exist 1032 | * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag 1033 | * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of 1034 | * the given name 1035 | * -FDT_ERR_NOSPACE, if there is insufficient free space in the 1036 | * blob to contain the new node 1037 | * -FDT_ERR_NOSPACE 1038 | * -FDT_ERR_BADLAYOUT 1039 | * -FDT_ERR_BADMAGIC, 1040 | * -FDT_ERR_BADVERSION, 1041 | * -FDT_ERR_BADSTATE, 1042 | * -FDT_ERR_BADSTRUCTURE, 1043 | * -FDT_ERR_TRUNCATED, standard meanings. 1044 | */ 1045 | int fdt_add_subnode(void *fdt, int parentoffset, const char *name); 1046 | 1047 | /** 1048 | * fdt_del_node - delete a node (subtree) 1049 | * @fdt: pointer to the device tree blob 1050 | * @nodeoffset: offset of the node to nop 1051 | * 1052 | * fdt_del_node() will remove the given node, including all its 1053 | * subnodes if any, from the blob. 1054 | * 1055 | * This function will delete data from the blob, and will therefore 1056 | * change the offsets of some existing nodes. 1057 | * 1058 | * returns: 1059 | * 0, on success 1060 | * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag 1061 | * -FDT_ERR_BADLAYOUT, 1062 | * -FDT_ERR_BADMAGIC, 1063 | * -FDT_ERR_BADVERSION, 1064 | * -FDT_ERR_BADSTATE, 1065 | * -FDT_ERR_BADSTRUCTURE, 1066 | * -FDT_ERR_TRUNCATED, standard meanings 1067 | */ 1068 | int fdt_del_node(void *fdt, int nodeoffset); 1069 | 1070 | /**********************************************************************/ 1071 | /* Debugging / informational functions */ 1072 | /**********************************************************************/ 1073 | 1074 | const char *fdt_strerror(int errval); 1075 | 1076 | #endif /* _LIBFDT_H */ 1077 | -------------------------------------------------------------------------------- /libfdt/libfdt_env.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBFDT_ENV_H 2 | #define _LIBFDT_ENV_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) 9 | static inline uint32_t fdt32_to_cpu(uint32_t x) 10 | { 11 | return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3); 12 | } 13 | #define cpu_to_fdt32(x) fdt32_to_cpu(x) 14 | 15 | static inline uint64_t fdt64_to_cpu(uint64_t x) 16 | { 17 | return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) 18 | | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); 19 | } 20 | #define cpu_to_fdt64(x) fdt64_to_cpu(x) 21 | #undef _B 22 | 23 | #endif /* _LIBFDT_ENV_H */ 24 | -------------------------------------------------------------------------------- /libfdt/libfdt_internal.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBFDT_INTERNAL_H 2 | #define _LIBFDT_INTERNAL_H 3 | /* 4 | * libfdt - Flat Device Tree manipulation 5 | * Copyright (C) 2006 David Gibson, IBM Corporation. 6 | * 7 | * libfdt is dual licensed: you can use it either under the terms of 8 | * the GPL, or the BSD license, at your option. 9 | * 10 | * a) This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU General Public License as 12 | * published by the Free Software Foundation; either version 2 of the 13 | * License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public 21 | * License along with this library; if not, write to the Free 22 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 23 | * MA 02110-1301 USA 24 | * 25 | * Alternatively, 26 | * 27 | * b) Redistribution and use in source and binary forms, with or 28 | * without modification, are permitted provided that the following 29 | * conditions are met: 30 | * 31 | * 1. Redistributions of source code must retain the above 32 | * copyright notice, this list of conditions and the following 33 | * disclaimer. 34 | * 2. Redistributions in binary form must reproduce the above 35 | * copyright notice, this list of conditions and the following 36 | * disclaimer in the documentation and/or other materials 37 | * provided with the distribution. 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 40 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 41 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 42 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 44 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 49 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 50 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 51 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 | */ 53 | #include 54 | 55 | #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) 56 | #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) 57 | 58 | #define FDT_CHECK_HEADER(fdt) \ 59 | { \ 60 | int err; \ 61 | if ((err = fdt_check_header(fdt)) != 0) \ 62 | return err; \ 63 | } 64 | 65 | uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); 66 | int _fdt_check_node_offset(const void *fdt, int offset); 67 | const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); 68 | int _fdt_node_end_offset(void *fdt, int nodeoffset); 69 | 70 | static inline const void *_fdt_offset_ptr(const void *fdt, int offset) 71 | { 72 | return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; 73 | } 74 | 75 | static inline void *_fdt_offset_ptr_w(void *fdt, int offset) 76 | { 77 | return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); 78 | } 79 | 80 | static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) 81 | { 82 | const struct fdt_reserve_entry *rsv_table = 83 | (const struct fdt_reserve_entry *) 84 | ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); 85 | 86 | return rsv_table + n; 87 | } 88 | static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) 89 | { 90 | return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); 91 | } 92 | 93 | #define FDT_SW_MAGIC (~FDT_MAGIC) 94 | 95 | #endif /* _LIBFDT_INTERNAL_H */ 96 | -------------------------------------------------------------------------------- /model.lds.S: -------------------------------------------------------------------------------- 1 | /* 2 | * model.lds.S - simple linker script for stand-alone Linux booting 3 | * 4 | * Copyright (C) 2011 ARM Limited. All rights reserved. 5 | * 6 | * Use of this source code is governed by a BSD-style license that can be 7 | * found in the LICENSE.txt file. 8 | */ 9 | 10 | OUTPUT_FORMAT("elf32-littlearm") 11 | OUTPUT_ARCH(arm) 12 | TARGET(binary) 13 | 14 | #ifndef SEMIHOSTING 15 | INPUT(./uImage) 16 | #ifdef USE_INITRD 17 | INPUT(./filesystem.cpio.gz) 18 | #endif 19 | #endif 20 | 21 | 22 | 23 | PHYS_OFFSET = 0x80000000; 24 | MON_OFFSET = 0xf0000000; 25 | STACKTOP = 0xff000000; 26 | 27 | 28 | SECTIONS 29 | { 30 | . = PHYS_OFFSET; 31 | 32 | . = PHYS_OFFSET + 0x8000 - 0x40; 33 | 34 | kernel_start = .; 35 | kernel_entry = . + 0x40; 36 | #ifndef SEMIHOSTING 37 | .kernel : { ./uImage } 38 | #endif 39 | kernel_end = .; 40 | 41 | . = PHYS_OFFSET + 0x00d00000; 42 | fs_start = .; 43 | #if defined(USE_INITRD) && !defined(SEMIHOSTING) 44 | .filesystem : { ./filesystem.cpio.gz } 45 | #endif 46 | fs_end = .; 47 | 48 | 49 | . = MON_OFFSET; 50 | /* Put most of the actual boot loader code up in high memory 51 | * where it won't get overwritten by kernel, initrd or atags. 52 | */ 53 | .text : { *(.text) } 54 | .data : { *(.data) } 55 | .bss : { *(.bss) } 56 | 57 | . = STACKTOP; 58 | stacktop = .; 59 | } 60 | -------------------------------------------------------------------------------- /semi_loader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 3. Neither the name of Linaro Limited nor the names of its 15 | * contributors may be used to endorse or promote products derived 16 | * from this software without specific prior written permission. 17 | */ 18 | 19 | #include 20 | #include "libfdt.h" 21 | #include "semihosting.h" 22 | #include "semi_loader.h" 23 | 24 | static void _print_info(char const **strings) 25 | { 26 | char const *string; 27 | 28 | semi_write0("[bootwrapper] "); 29 | while((string = *strings++)) 30 | semi_write0(string); 31 | } 32 | 33 | #define info(strings...) do { \ 34 | char const *__info_strings[] = { strings, NULL }; \ 35 | \ 36 | _print_info(__info_strings); \ 37 | } while(0) 38 | 39 | #define warn(strings...) info("WARNING: ", strings) 40 | #define error(strings...) info("ERROR: ", strings) 41 | 42 | #define fatal(strings...) do { \ 43 | error(strings); \ 44 | semi_fatal("[bootwrapper] BOOT FAILED\n"); \ 45 | } while(0) 46 | 47 | #define CMDLINE_KERNEL "--kernel" 48 | #define CMDLINE_INITRD "--initrd" 49 | #define CMDLINE_NOINITRD "--no-initrd" 50 | #define CMDLINE_DTB "--dtb" 51 | #define CMDLINE_FDT "--fdt" /* deprecated */ 52 | #define CMDLINE_REST "-- " 53 | 54 | static void _usage_fatal(void) 55 | { 56 | info("Usage: [" CMDLINE_KERNEL " ] [" 57 | CMDLINE_NOINITRD "|" CMDLINE_INITRD " ] [" 58 | CMDLINE_DTB " ] [" 59 | CMDLINE_REST "]\n"); 60 | fatal("Incorrect bootwrapper command-line.\n"); 61 | } 62 | 63 | #define usage_fatal(strings...) do { \ 64 | error(strings); \ 65 | _usage_fatal(); \ 66 | } while(0) 67 | 68 | static void atag_append(void **dest, unsigned tag, void const *data, unsigned size) 69 | { 70 | char *d = *dest; 71 | unsigned padded_size = ALIGN_INT(size, 4) + 8; 72 | struct atag_header header = { 73 | padded_size >> 2, 74 | tag 75 | }; 76 | 77 | if(tag == ATAG_NONE) 78 | header.size = 0; 79 | 80 | memcpy(d, &header, sizeof header); 81 | memcpy(d + 8, data, size); 82 | 83 | if(padded_size > size + 8) 84 | memset(d + 8 + size, 0, padded_size - (size + 8)); 85 | 86 | *dest = d + padded_size; 87 | } 88 | 89 | static int _fdt_make_node(void *fdt, int parentoffset, const char *name) 90 | { 91 | int e; 92 | 93 | e = fdt_subnode_offset(fdt, parentoffset, name); 94 | if(e != -FDT_ERR_NOTFOUND) 95 | return e; 96 | 97 | return fdt_add_subnode(fdt, parentoffset, name); 98 | } 99 | 100 | static void _fdt_address_and_size_cells(void *fdt, int *addrcells, int *sizecells) 101 | { 102 | int e; 103 | uint32_t const *p; 104 | 105 | if(!(p = fdt_getprop(fdt, 0, "#address-cells", &e))) 106 | goto libfdt_error; 107 | if(e != 4) 108 | goto size_error; 109 | *addrcells = fdt32_to_cpu(*p); 110 | if(!(p = fdt_getprop(fdt, 0, "#size-cells", &e))) 111 | goto libfdt_error; 112 | if(e != 4) 113 | goto size_error; 114 | *sizecells = fdt32_to_cpu(*p); 115 | 116 | /* 117 | * Sanity-check address sizes, since addresses and sizes which do 118 | * not take up exactly 4 or 8 bytes are not supported. 119 | */ 120 | if ((*addrcells != 1 && *addrcells != 2) || 121 | (*sizecells != 1 && *sizecells != 2)) 122 | goto size_error; 123 | 124 | return; 125 | 126 | libfdt_error: 127 | fatal("libfdt: ", fdt_strerror(e), ", while looking for #address-cells/#size-cells\n"); 128 | 129 | size_error: 130 | fatal("Unexpected/invalid #address-cells/#size-cells in device tree\n"); 131 | } 132 | 133 | static void update_fdt(void **dest, struct loader_info *info) 134 | { 135 | int e; 136 | int _chosen; 137 | void *fdt; 138 | uint32_t const *p; 139 | int addrcells, sizecells; 140 | 141 | if(!info->fdt_start) 142 | return; 143 | 144 | fdt = ALIGN(*dest, 4); 145 | if((e = fdt_open_into((void *)info->fdt_start, fdt, FDT_SIZE_MAX)) < 0) 146 | goto libfdt_error; 147 | 148 | _fdt_address_and_size_cells(fdt, &addrcells, &sizecells); 149 | 150 | /* 151 | * Add a memory node, but only if there isn't one already. If 152 | * there is already a memory node with non-zero size, it was put 153 | * in the DT on purpose and should take precedence over our 154 | * guesses. Otherwise, make a memory node with the appropriate 155 | * parameters. 156 | */ 157 | { 158 | int offset, depth = 0; 159 | int _memory; 160 | uint32_t reg[4]; 161 | 162 | for(offset = fdt_next_node(fdt, 0, &depth); offset >= 0; 163 | offset = fdt_next_node(fdt, offset, &depth)) { 164 | char const *name; 165 | 166 | if(depth != 1) 167 | continue; 168 | 169 | name = fdt_get_name(fdt, offset, (void *)0); 170 | if(!strcmp(name, "memory") || 171 | !strncmp(name, "memory@", 7)) { 172 | p = fdt_getprop(fdt, offset, "reg", &e); 173 | if(e < 0) 174 | goto libfdt_error; 175 | 176 | /* Check whether the part of the , tuple is nonzero */ 177 | if(fdt32_to_cpu(p[addrcells]) != 0) 178 | goto no_add_memory; 179 | if(sizecells == 2 && fdt32_to_cpu(p[addrcells + 1]) != 0) 180 | goto no_add_memory; 181 | } 182 | } 183 | 184 | if((e = _fdt_make_node(fdt, 0, "memory")) < 0) 185 | goto libfdt_error; 186 | _memory = e; 187 | 188 | /* This assumes PHYS_OFFSET and PHYS_SIZE are 32 bits, though 189 | * the fdt cells we put them in may not be. 190 | */ 191 | reg[0] = reg[1] = reg[2] = reg[3] = 0; 192 | reg[addrcells - 1] = cpu_to_fdt32(PHYS_OFFSET); 193 | reg[addrcells + sizecells - 1] = cpu_to_fdt32(PHYS_SIZE); 194 | 195 | if((e = fdt_setprop(fdt, _memory, "reg", ®, 196 | sizeof(reg[0]) * (addrcells + sizecells))) < 0) 197 | goto libfdt_error; 198 | 199 | if((e = fdt_setprop_string(fdt, _memory, "device_type", 200 | "memory")) < 0) 201 | goto libfdt_error; 202 | } 203 | 204 | no_add_memory: 205 | /* populate the "chosen" node */ 206 | 207 | if((e = _fdt_make_node(fdt, 0, "chosen")) < 0) 208 | goto libfdt_error; 209 | _chosen = e; 210 | 211 | e = fdt_setprop_string(fdt, _chosen, "bootargs", 212 | (char const *)info->cmdline_start); 213 | if(e < 0) 214 | goto libfdt_error; 215 | 216 | if(info->initrd_start) { 217 | uint32_t initrd_end = info->initrd_start + info->initrd_size; 218 | /* It's not documented whether these cells should honour 219 | * #address-cells. Currently the kernel accepts them as being 220 | * addresses of either size, so we leave them as 32 bits for now. 221 | */ 222 | if((e = fdt_setprop_cell(fdt, _chosen, "linux,initrd-start", 223 | info->initrd_start)) < 0) 224 | goto libfdt_error; 225 | 226 | if((e = fdt_setprop_cell(fdt, _chosen, "linux,initrd-end", 227 | initrd_end)) < 0) 228 | goto libfdt_error; 229 | } 230 | 231 | /* success */ 232 | 233 | /* clean up */ 234 | fdt_pack(fdt); 235 | info->fdt_start = (unsigned)fdt; 236 | info->fdt_size = fdt_totalsize(fdt); 237 | info("FDT updated.\n"); 238 | 239 | return; 240 | 241 | libfdt_error: 242 | fatal("libfdt: ", fdt_strerror(e), ", while updating device tree\n"); 243 | } 244 | 245 | /* For accessing 32-bit device ports */ 246 | #define io32(p) (*(volatile uint32_t *)(p)) 247 | 248 | static void init_cci(unsigned cci) 249 | { 250 | info("Initialising CCI\n"); 251 | 252 | /* 253 | * Ideally, the CCI device tree binding would include suitable 254 | * information so we can correctly configure the CCI, but for 255 | * now we'll just hard-code settings for the present A15xA7 256 | * models. 257 | */ 258 | 259 | /* Turn on CCI snoops and DVM messages */ 260 | io32(cci+0x4000) = 0x3; /* A15 cluster */ 261 | io32(cci+0x5000) = 0x3; /* A7 cluster */ 262 | 263 | /* Wait while change pending bit of status register is set */ 264 | while(io32(cci+0xc) & 0x1) 265 | {} 266 | } 267 | 268 | static void configure_from_fdt(struct loader_info *info) 269 | { 270 | void *fdt = (void *)info->fdt_start; 271 | uint32_t const *p; 272 | int addrcells, sizecells; 273 | int offset, len; 274 | 275 | if(!fdt) 276 | return; 277 | 278 | _fdt_address_and_size_cells(fdt, &addrcells, &sizecells); 279 | 280 | /* See if there is a CCI device to initialise */ 281 | offset = fdt_node_offset_by_compatible(fdt, 0, "arm,cci"); 282 | if (offset >= 0) { 283 | p = fdt_getprop(fdt, offset, "reg", &len); 284 | if(len != (addrcells + sizecells) * 4) 285 | info("Failed parsing device-tree node for CCI\n"); 286 | else { 287 | /* 288 | * p[addrcells - 1] is the least significant 32-bits of 289 | * the address for the CCI. On 32-bit CPUs any additional 290 | * address bits had better be zero otherwise we can't 291 | * access it as we don't enable the MMU. 292 | */ 293 | init_cci(fdt32_to_cpu(p[addrcells - 1])); 294 | } 295 | } 296 | 297 | return; 298 | } 299 | 300 | static int is_space(char c) 301 | { 302 | return c == ' '; 303 | } 304 | 305 | static void skip_space(char **s) 306 | { 307 | char *t = *s; 308 | 309 | for(t = *s; is_space(*t); t++); 310 | *s = t; 311 | } 312 | 313 | static void find_space(char **s) 314 | { 315 | char *t = *s; 316 | 317 | for(t = *s; *t && !is_space(*t); t++); 318 | *s = t; 319 | } 320 | 321 | static int match_word(char **s, char const *string) 322 | { 323 | unsigned l; 324 | 325 | l = strlen(string); 326 | if(strncmp(*s, string, l)) 327 | return 0; 328 | 329 | *s += l; 330 | skip_space(s); 331 | return 1; 332 | } 333 | 334 | /* 335 | * Match an option with a mandatory argument. 336 | * On success, a pointer to the argument is returned, with leading and 337 | * trailing whitespace stripped. 338 | */ 339 | static char *match_option(char **s, char const *option_string) 340 | { 341 | char *arg; 342 | 343 | if(!match_word(s, option_string)) 344 | return (void *)0; 345 | 346 | if(!**s) 347 | usage_fatal("Option requires as argument: ", 348 | option_string, "\n"); 349 | 350 | /* otherwise, *s now points to the argument */ 351 | arg = *s; 352 | 353 | find_space(s); /* find the end of the argument */ 354 | if(**s) { 355 | *(*s)++ = '\0'; /* null-terminate if necessary */ 356 | skip_space(s); /* skip any remaining space */ 357 | } 358 | 359 | return arg; 360 | } 361 | 362 | static void load_file_essential(void **dest, char const *filename, 363 | unsigned *size, char const *failmsg) 364 | { 365 | if(semi_load_file(dest, size, filename)) 366 | fatal(failmsg, ": \"", filename, "\"\n"); 367 | } 368 | 369 | /* is_uboot_image_format - to check an image is in uboot image format or not 370 | * @start: start address of the image 371 | * @size: size of the image 372 | * 373 | * Returns: 374 | * 0: no 375 | * 1: yes 376 | */ 377 | static int is_uboot_image_format(const char *start, const unsigned size) 378 | { 379 | if(size <= UBOOT_IMAGE_HEADER_SIZE) 380 | return 0; 381 | 382 | return !memcmp(start, uboot_image_header_magic, 383 | sizeof uboot_image_header_magic); 384 | } 385 | 386 | /* Move the kernel if necessary, based on the image type: */ 387 | static void correct_kernel_location(struct loader_info *info) 388 | { 389 | char *const text_start = (char *)(PHYS_OFFSET + TEXT_OFFSET); 390 | char *const text_end = text_start + info->kernel_size; 391 | char *const uImage_payload = text_start + UBOOT_IMAGE_HEADER_SIZE; 392 | unsigned long *const zImage_magic_p = (unsigned long *)( 393 | uImage_payload + ZIMAGE_MAGIC_OFFSET); 394 | 395 | /* 396 | * If the image is not a uImage, then it is a raw Image or zImage, 397 | * and no action is necessary: 398 | */ 399 | if(!is_uboot_image_format(text_start, info->kernel_size)) 400 | return; 401 | 402 | warn("Ignoring uImage meta-data\n"); 403 | 404 | /* 405 | * If the uImage payload is a zImage, the position-independent 406 | * nature of the zImage header means that no relocation is 407 | * needed. Instead, just enter at the start of the loaded 408 | * zImage header: 409 | */ 410 | if(text_end >= (char *)&zImage_magic_p[1] 411 | && *zImage_magic_p == ZIMAGE_MAGIC) { 412 | info->kernel_entry += UBOOT_IMAGE_HEADER_SIZE; 413 | return; 414 | } 415 | 416 | /* 417 | * Otherwise, move the payload to replace the uImage header, and 418 | * leave the entry point unmodified. 419 | */ 420 | memmove(text_start, uImage_payload, 421 | info->kernel_size - UBOOT_IMAGE_HEADER_SIZE); 422 | } 423 | 424 | static void correct_initrd_location(struct loader_info *info) 425 | { 426 | /* 427 | * if initrd image is in u-boot image format, 428 | * move initrd_start and initrd_size to ignore the header 429 | */ 430 | if(is_uboot_image_format((char *)info->initrd_start, 431 | info->initrd_size)) { 432 | warn("Ignoring uInitrd meta-data\n"); 433 | info->initrd_start += UBOOT_IMAGE_HEADER_SIZE; 434 | info->initrd_size -= UBOOT_IMAGE_HEADER_SIZE; 435 | } 436 | 437 | return; 438 | } 439 | 440 | static char semi_cmdline[SEMI_CMDLINE_MAX]; 441 | 442 | static char *kernel_arg = (void *)0; 443 | static char *initrd_arg = (void *)0; 444 | static char *fdt_arg = (void *)0; 445 | static char *dtb_arg = (void *)0; 446 | static char *cmdline_arg = (void *)0; 447 | static char *noinitrd_arg = (void *)0; 448 | 449 | static const struct { 450 | char const *option_string; 451 | char **argp; 452 | enum { OPT_ARG, OPT_BOOL, OPT_REST } action; 453 | } options[] = { 454 | { CMDLINE_KERNEL, &kernel_arg, OPT_ARG }, 455 | { CMDLINE_INITRD, &initrd_arg, OPT_ARG }, 456 | { CMDLINE_NOINITRD, &noinitrd_arg, OPT_BOOL }, 457 | { CMDLINE_FDT, &fdt_arg, OPT_ARG }, 458 | { CMDLINE_DTB, &dtb_arg, OPT_ARG }, 459 | { CMDLINE_REST, &cmdline_arg, OPT_REST }, 460 | }; 461 | 462 | void load_kernel(struct loader_info *info) 463 | { 464 | unsigned i; 465 | char *cmdline = semi_cmdline; 466 | int cmdline_length; 467 | void *phys = (char *)(PHYS_OFFSET + TEXT_OFFSET); 468 | void *atagp = (char *)(PHYS_OFFSET + ATAGS_OFFSET); 469 | 470 | union { 471 | struct atag_core core; 472 | struct atag_mem mem; 473 | struct atag_initrd2 initrd; 474 | } atag; 475 | 476 | /* Fetch the command line: */ 477 | 478 | if(semi_get_cmdline(semi_cmdline, sizeof semi_cmdline, 479 | &cmdline_length) || 480 | cmdline_length >= sizeof semi_cmdline) { 481 | warn("Failed to get semihosting command line, using built-in defaults\n"); 482 | cmdline_length = 0; 483 | } 484 | cmdline[cmdline_length] = '\0'; 485 | 486 | /* Parse the arguments (if any): */ 487 | 488 | skip_space(&cmdline); 489 | 490 | while(*cmdline) { 491 | for(i = 0; i < sizeof options / sizeof *options; i++) { 492 | char *arg; 493 | 494 | switch(options[i].action) { 495 | case OPT_BOOL: 496 | if(!match_word(&cmdline, 497 | options[i].option_string)) 498 | continue; 499 | 500 | *options[i].argp = cmdline; /* non-NULL */ 501 | goto next_arg; 502 | 503 | case OPT_REST: 504 | if(!match_word(&cmdline, 505 | options[i].option_string)) 506 | continue; 507 | 508 | *options[i].argp = cmdline; 509 | goto args_done; 510 | 511 | case OPT_ARG: 512 | arg = match_option(&cmdline, 513 | options[i].option_string); 514 | if(!arg) 515 | continue; 516 | 517 | if(*options[i].argp) 518 | usage_fatal("Duplicate option ", 519 | options[i].option_string); 520 | 521 | /* otherwise, option was parsed successfully: */ 522 | *options[i].argp = arg; 523 | goto next_arg; 524 | } 525 | } /* for(i) */ 526 | 527 | /* Failed to match any expected option: */ 528 | usage_fatal("Invalid option(s): ", cmdline); 529 | 530 | next_arg: ; 531 | } /* while(*cmdline) */ 532 | 533 | args_done: 534 | if(initrd_arg && noinitrd_arg) 535 | usage_fatal("Option --initrd conflicts with --no-initrd.\n"); 536 | 537 | if(fdt_arg) { 538 | warn("--fdt is deprecated. Please use --dtb instead.\n"); 539 | 540 | if(dtb_arg) 541 | usage_fatal("--fdt conflicts with --dtb.\n"); 542 | else 543 | dtb_arg = fdt_arg; 544 | } 545 | 546 | /* 547 | * Now, proceed to load images and set up ATAGs. 548 | * For simplicity, ATAGs are generated even if there is a DTB 549 | */ 550 | 551 | /* built-in FDT not supported, for now */ 552 | info->fdt_start = info->fdt_size = 0; 553 | 554 | info->atags_start = (unsigned)atagp; 555 | 556 | memset(&atag.core, 0, sizeof atag.core); 557 | atag_append(&atagp, ATAG_CORE, &atag.core, sizeof atag.core); 558 | 559 | /* create the essential ATAGs */ 560 | 561 | atag.mem.start = PHYS_OFFSET; 562 | atag.mem.size = PHYS_SIZE; 563 | atag_append(&atagp, ATAG_MEM, &atag.mem, sizeof atag.mem); 564 | 565 | /* load the kernel */ 566 | 567 | info->kernel_entry = (unsigned)phys; 568 | 569 | if(kernel_arg) { 570 | load_file_essential(&phys, kernel_arg, &info->kernel_size, 571 | "Failed to load kernel image"); 572 | info("Loaded kernel: ", kernel_arg, "\n"); 573 | } else if(info->kernel_size) { 574 | info("Using built-in kernel\n"); 575 | phys += info->kernel_size; 576 | } else 577 | usage_fatal("Expected " CMDLINE_KERNEL "\n"); 578 | 579 | /* move the kernel to the correct place, if necessary */ 580 | 581 | correct_kernel_location(info); 582 | 583 | phys = (char *)(PHYS_OFFSET + INITRD_OFFSET); 584 | 585 | /* load the initrd */ 586 | 587 | atag.initrd.size = 0; 588 | 589 | if(initrd_arg) { 590 | unsigned start = (unsigned)phys; 591 | 592 | load_file_essential(&phys, initrd_arg, NULL, 593 | "Failed to load initrd image"); 594 | info("Loaded initrd: ", initrd_arg, "\n"); 595 | 596 | info->initrd_start = start; 597 | info->initrd_size = (unsigned)phys - start; 598 | 599 | correct_initrd_location(info); 600 | 601 | atag.initrd.start = info->initrd_start; 602 | atag.initrd.size = info->initrd_size; 603 | 604 | } else if(info->initrd_size) { 605 | if(noinitrd_arg) { 606 | info->initrd_size = 0; 607 | info("Built-in initrd discarded, as requested\n"); 608 | } else { 609 | info("Using built-in initrd\n"); 610 | 611 | atag.initrd.start = info->initrd_start; 612 | atag.initrd.size = info->initrd_size; 613 | } 614 | } else 615 | info->initrd_size = 0; 616 | 617 | if(atag.initrd.size) 618 | atag_append(&atagp, ATAG_INITRD2, &atag.initrd, sizeof atag.initrd); 619 | 620 | /* load the FDT, if specified */ 621 | 622 | if(dtb_arg) { 623 | phys = ALIGN(phys, 4); 624 | info->fdt_start = (unsigned)phys; 625 | 626 | load_file_essential(&phys, dtb_arg, NULL, 627 | "Failed to load device tree blob"); 628 | info("Loaded FDT: ", dtb_arg, "\n"); 629 | 630 | info->fdt_size = (unsigned)phys - info->fdt_start; 631 | } 632 | 633 | /* 634 | * The FDT will get modified to reflect bootargs, initrd and memory 635 | * configuration later. 636 | */ 637 | 638 | /* set the command line */ 639 | 640 | if(cmdline_arg) { 641 | info->cmdline_start = (unsigned)cmdline_arg; 642 | info->cmdline_size = strlen(cmdline_arg) + 1; 643 | } else if(info->cmdline_size) 644 | info("Using built-in kernel bootargs\n"); 645 | 646 | /* cmdline_size is presumed to include a NUL terminator: */ 647 | if(info->cmdline_size) { 648 | atag_append(&atagp, ATAG_CMDLINE, 649 | (char *)info->cmdline_start, info->cmdline_size); 650 | info("Kernel bootargs: ", (char *)info->cmdline_start, "\n"); 651 | } 652 | 653 | atag_append(&atagp, ATAG_NONE, 0, 0); 654 | 655 | update_fdt(&phys, info); 656 | 657 | configure_from_fdt(info); 658 | } 659 | -------------------------------------------------------------------------------- /semi_loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 3. Neither the name of Linaro Limited nor the names of its 15 | * contributors may be used to endorse or promote products derived 16 | * from this software without specific prior written permission. 17 | */ 18 | 19 | #ifndef SEMI_LOADER_H 20 | #define SEMI_LOADER_H 21 | 22 | #define ATAG_NONE 0x00000000 23 | #define ATAG_CORE 0x54410001 24 | #define ATAG_MEM 0x54410002 25 | #define ATAG_INITRD2 0x54420005 26 | #define ATAG_CMDLINE 0x54410009 27 | 28 | struct atag_header { 29 | unsigned size; 30 | unsigned tag; 31 | }; 32 | 33 | struct atag_core { 34 | unsigned flags; 35 | unsigned pagesize; 36 | unsigned rootdev; 37 | }; 38 | 39 | struct atag_mem { 40 | unsigned size; 41 | unsigned start; 42 | }; 43 | 44 | struct atag_initrd2 { 45 | unsigned start; 46 | unsigned size; 47 | }; 48 | 49 | static const char uboot_image_header_magic[] = { 50 | 0x27, 0x05, 0x19, 0x56 51 | }; 52 | #define UBOOT_IMAGE_HEADER_SIZE 0x40 53 | 54 | #define ZIMAGE_MAGIC_OFFSET 36 55 | #define ZIMAGE_MAGIC 0x016f2818UL 56 | 57 | #define PHYS_OFFSET 0x80000000 58 | #define PHYS_SIZE 0x80000000 /* can limit on kernel cmdline if necessary */ 59 | #define ATAGS_OFFSET 0x100 60 | #define TEXT_OFFSET 0x8000 61 | #define INITRD_OFFSET 0xD00000 /* qemu uses the same random offset */ 62 | 63 | #define FDT_SIZE_MAX 0x10000 /* maximum size allowed for device tree blob */ 64 | 65 | #define SEMI_CMDLINE_MAX 0x1000 /* maximum semihosting command line length */ 66 | 67 | /* 68 | * Align number or pointer

up to the next boundary of size . 69 | * must be a power of two. 70 | */ 71 | #define ALIGN_INT(n, size) (((n) + ((size) - 1)) & ~((size) - 1)) 72 | #define ALIGN(p, size) ((void *)ALIGN_INT((unsigned)(p), size)) 73 | 74 | struct loader_info { 75 | unsigned kernel_size; /* nonzero indicates preloaded kernel size */ 76 | unsigned initrd_start; /* start of preloaded initrd, if any */ 77 | unsigned initrd_size; 78 | unsigned cmdline_start; /* start of cmdline buffer */ 79 | unsigned cmdline_size; 80 | 81 | /* The remaining fields are set by the loader: */ 82 | 83 | /* There could be a built-in FDT, but currently that it not supported */ 84 | unsigned fdt_start; /* start of device tree blob, if any */ 85 | unsigned fdt_size; 86 | 87 | unsigned atags_start; 88 | unsigned kernel_entry; /* kernel entry point */ 89 | }; 90 | 91 | void load_kernel(struct loader_info *info); 92 | 93 | void __boot_kernel(unsigned entry_point, 94 | unsigned r0, unsigned r1, unsigned r2, unsigned r3); 95 | 96 | static void boot_kernel(struct loader_info *info, 97 | unsigned r0, unsigned r1, unsigned r2, unsigned r3) { 98 | __boot_kernel(info->kernel_entry, r0, r1, r2, r3); 99 | } 100 | 101 | #endif /* ! SEMI_LOADER_H */ 102 | -------------------------------------------------------------------------------- /semihosting.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 3. Neither the name of Linaro Limited nor the names of its 15 | * contributors may be used to endorse or promote products derived 16 | * from this software without specific prior written permission. 17 | */ 18 | 19 | #include 20 | #include "semihosting.h" 21 | 22 | int semi_open(char const *filename, int mode) 23 | { 24 | struct { 25 | char const *filename; 26 | int mode; 27 | int filename_length; 28 | } args; 29 | 30 | args.filename = filename; 31 | args.mode = mode; 32 | args.filename_length = strlen(filename); 33 | 34 | return __semi_call(SYS_OPEN, &args); 35 | } 36 | 37 | int semi_close(int fd) 38 | { 39 | return __semi_call(SYS_CLOSE, &fd); 40 | } 41 | 42 | int semi_write0(char const *string) 43 | { 44 | return __semi_call(SYS_WRITE0, string); 45 | } 46 | 47 | int semi_read(int fd, char *buffer, int length) 48 | { 49 | struct { 50 | int fd; 51 | char *buffer; 52 | int length; 53 | } args; 54 | 55 | args.fd = fd; 56 | args.buffer = buffer; 57 | args.length = length; 58 | 59 | return __semi_call(SYS_READ, &args); 60 | } 61 | 62 | int semi_flen(int fd) 63 | { 64 | return __semi_call(SYS_FLEN, &fd); 65 | } 66 | 67 | int semi_get_cmdline(char *buffer, int size, int *length) 68 | { 69 | int result; 70 | struct { 71 | char *buffer; 72 | int size; 73 | } args; 74 | 75 | args.buffer = buffer; 76 | args.size = size; 77 | 78 | result = __semi_call(SYS_GET_CMDLINE, &args); 79 | if(result) 80 | return result; 81 | 82 | if(length) 83 | *length = args.size; 84 | 85 | return 0; 86 | } 87 | 88 | int semi_reportexc(int reason) 89 | { 90 | return __semi_call(SYS_REPORTEXC, (void *)reason); 91 | } 92 | 93 | void semi_exit(void) 94 | { 95 | semi_reportexc(REPORTEXC_REASON_APP_EXIT); 96 | while(1); /* should not be reached */ 97 | } 98 | 99 | void semi_fatal(char const *message) 100 | { 101 | semi_write0(message); 102 | semi_exit(); 103 | } 104 | 105 | int semi_load_file(void **dest, unsigned *size, char const *filename) 106 | { 107 | int result = -1; /* fail by default */ 108 | int fd = -1; 109 | int filesize; 110 | 111 | fd = semi_open(filename, OPEN_RDONLY); 112 | if(fd == -1) { 113 | semi_write0("Cannot open file: "); 114 | goto out; 115 | } 116 | 117 | filesize = semi_flen(fd); 118 | if(filesize == -1) { 119 | semi_write0("Cannot get file size for: "); 120 | goto out; 121 | } 122 | 123 | if(semi_read(fd, *dest, filesize)) { 124 | semi_write0("Could not read: "); 125 | goto out; 126 | } 127 | 128 | result = 0; /* success */ 129 | *dest = (char *)*dest + filesize; 130 | 131 | out: 132 | if(fd != -1) 133 | semi_close(fd); 134 | 135 | if(result) { /* print context for the error message */ 136 | semi_write0(filename); 137 | semi_write0("\n"); 138 | } else 139 | if(size) 140 | *size = filesize; 141 | 142 | return result; 143 | } 144 | -------------------------------------------------------------------------------- /semihosting.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Linaro Limited 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 3. Neither the name of Linaro Limited nor the names of its 15 | * contributors may be used to endorse or promote products derived 16 | * from this software without specific prior written permission. 17 | */ 18 | 19 | #ifndef SEMIHOSTING_H 20 | #define SEMIHOSTING_H 21 | 22 | #define SYS_OPEN 1 23 | #define OPEN_RDONLY 1 24 | #define SYS_CLOSE 2 25 | #define SYS_WRITE0 4 26 | #define SYS_READ 6 27 | #define SYS_FLEN 0x0C 28 | #define SYS_GET_CMDLINE 0x15 29 | #define SYS_REPORTEXC 0x18 30 | #define REPORTEXC_REASON_APP_EXIT 0x20026 31 | #define SEMIHOSTING_SVC 0x123456 /* SVC comment field for semihosting */ 32 | 33 | #ifndef __ASSEMBLER__ 34 | 35 | int __semi_call(int id, ...); 36 | int semi_open(char const *filename, int mode); 37 | int semi_close(int fd); 38 | int semi_write0(char const *string); 39 | int semi_read(int fd, char *buffer, int length); 40 | int semi_flen(int fd); 41 | int semi_get_cmdline(char *buffer, int size, int *length); 42 | int semi_reportexc(int reason); 43 | void semi_fatal(char const *message); 44 | void semi_exit(void); 45 | /* semi_load_file: *dest is advanced to point to the end of the loaded data */ 46 | int semi_load_file(void **dest, unsigned *size, char const *filename); 47 | 48 | #endif /* ! __ASSEMBLER__ */ 49 | 50 | #endif /* ! SEMIHOSTING_H */ 51 | -------------------------------------------------------------------------------- /string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static void *__memmove_down(void *__dest, __const void *__src, size_t __n) 4 | { 5 | unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src; 6 | 7 | while (__n--) 8 | *d++ = *s++; 9 | 10 | return __dest; 11 | } 12 | 13 | static void *__memmove_up(void *__dest, __const void *__src, size_t __n) 14 | { 15 | unsigned char *d = (unsigned char *)__dest + __n - 1, *s = (unsigned char *)__src + __n - 1; 16 | 17 | while (__n--) 18 | *d-- = *s--; 19 | 20 | return __dest; 21 | } 22 | 23 | void *(memcpy)(void *__dest, __const void *__src, size_t __n) 24 | { 25 | return __memmove_down(__dest, __src, __n); 26 | } 27 | 28 | void *(memmove)(void *__dest, __const void *__src, size_t __n) 29 | { 30 | if(__dest > __src) 31 | return __memmove_up(__dest, __src, __n); 32 | else 33 | return __memmove_down(__dest, __src, __n); 34 | } 35 | 36 | void *(memchr)(void const *s, int c, size_t n) 37 | { 38 | unsigned char const *_s = (unsigned char const *)s; 39 | 40 | while(n && *_s != c) { 41 | ++_s; 42 | --n; 43 | } 44 | 45 | if(n) 46 | return (void *)_s; /* the C library casts const away */ 47 | else 48 | return (void *)0; 49 | } 50 | 51 | size_t (strlen)(const char *s) 52 | { 53 | const char *sc = s; 54 | 55 | while (*sc != '\0') 56 | sc++; 57 | return sc - s; 58 | } 59 | 60 | void *(memset)(void *s, int c, size_t count) 61 | { 62 | char *xs = s; 63 | while (count--) 64 | *xs++ = c; 65 | return s; 66 | } 67 | 68 | int (memcmp)(void const *p1, void const *p2, size_t n) 69 | { 70 | unsigned char const *_p1 = p1; 71 | unsigned char const *_p2 = p2; 72 | 73 | while(n--) { 74 | if(*_p1 < *_p2) 75 | return -1; 76 | else if(*_p1 > *_p2) 77 | return 1; 78 | 79 | ++_p1; 80 | ++_p2; 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | int (strcmp)(char const *s1, char const *s2) 87 | { 88 | while(*s1 && *s2) { 89 | if(*s1 < *s2) 90 | return -1; 91 | else if(*s1 > *s2) 92 | return 1; 93 | 94 | ++s1; 95 | ++s2; 96 | } 97 | 98 | if(!*s1 && !*s2) 99 | return 0; 100 | else if(!*s1) 101 | return -1; 102 | else 103 | return 1; 104 | } 105 | 106 | int (strncmp)(char const *s1, char const *s2, size_t n) 107 | { 108 | while(*s1 && *s2 && n--) { 109 | if(*s1 < *s2) 110 | return -1; 111 | else if(*s1 > *s2) 112 | return 1; 113 | 114 | ++s1; 115 | ++s2; 116 | } 117 | 118 | if(n == 0 || (!*s1 && !*s2)) 119 | return 0; 120 | else if(!*s1) 121 | return -1; 122 | else 123 | return 1; 124 | } 125 | 126 | char *(strchr)(char const *s, int c) 127 | { 128 | unsigned char const *_s = (unsigned char const *)s; 129 | 130 | while(*_s && *_s != c) 131 | ++_s; 132 | 133 | if(*_s) 134 | return (char *)_s; /* the C library casts const away */ 135 | else 136 | return (char *)0; 137 | } 138 | -------------------------------------------------------------------------------- /string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H 2 | #define STRING_H 3 | 4 | #include 5 | 6 | extern void *(memcpy)(void *__dest, __const void *__src, size_t __n); 7 | extern void *(memmove)(void *__dest, __const void *__src, size_t __n); 8 | extern void *(memchr)(void const *s, int c, size_t n); 9 | extern size_t (strlen)(const char *s); 10 | extern void *(memset)(void *s, int c, size_t count); 11 | extern int (memcmp)(void const *p1, void const *p2, size_t n); 12 | extern int (strcmp)(char const *s1, char const *s2); 13 | extern int (strncmp)(char const *s1, char const *s2, size_t n); 14 | extern char *(strchr)(char const *s, int c); 15 | 16 | #endif 17 | --------------------------------------------------------------------------------