提交 5f2434a6 编写于 作者: L Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (158 commits)
  powerpc: Fix CHRP PCI config access for indirect_pci
  powerpc/chrp: Fix detection of Python PCI host bridge on IBM CHRPs
  powerpc: Fix 32-bit SMP boot on CHRP
  powerpc: Fix link errors on 32-bit machines using legacy DMA
  powerpc/pci: Improve detection of unassigned bridge resources
  hvc_console: Fix free_irq in spinlocked section
  powerpc: Get USE_STRICT_MM_TYPECHECKS working again
  powerpc: Reflect the used arguments in machine_init() prototype
  powerpc: Fix DMA offset for non-coherent DMA
  powerpc: fix fsl_upm nand driver modular build
  powerpc/83xx: add NAND support for the MPC8360E-RDK boards
  powerpc: FPGA support for GE Fanuc SBC610
  i2c: MPC8349E-mITX Power Management and GPIO expander driver
  powerpc: reserve two DMA channels for audio in MPC8610 HPCD device tree
  powerpc: document the "fsl,ssi-dma-channel" compatible property
  powerpc: disable CHRP and PMAC support in various defconfigs
  OF: add fsl,mcu-mpc8349emitx to the exception list
  powerpc/83xx: add DS1374 RTC support for the MPC837xE-MDS boards
  powerpc: remove support for bootmem-allocated memory for the DIU driver
  powerpc: remove non-dependent load fsl_booke PTE_64BIT
  ...
...@@ -18,10 +18,6 @@ mpc52xx.txt ...@@ -18,10 +18,6 @@ mpc52xx.txt
- Linux 2.6.x on MPC52xx family - Linux 2.6.x on MPC52xx family
mpc52xx-device-tree-bindings.txt mpc52xx-device-tree-bindings.txt
- MPC5200 Device Tree Bindings - MPC5200 Device Tree Bindings
ppc_htab.txt
- info about the Linux/PPC /proc/ppc_htab entry
smp.txt
- use and state info about Linux/PPC on MP machines
sound.txt sound.txt
- info on sound support under Linux/PPC - info on sound support under Linux/PPC
zImage_layout.txt zImage_layout.txt
......
* Freescale 83xx and 512x PCI bridges
Freescale 83xx and 512x SOCs include the same pci bridge core.
83xx/512x specific notes:
- reg: should contain two address length tuples
The first is for the internal pci bridge registers
The second is for the pci config space access registers
Example (MPC8313ERDB)
pci0: pci@e0008500 {
cell-index = <1>;
interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
interrupt-map = <
/* IDSEL 0x0E -mini PCI */
0x7000 0x0 0x0 0x1 &ipic 18 0x8
0x7000 0x0 0x0 0x2 &ipic 18 0x8
0x7000 0x0 0x0 0x3 &ipic 18 0x8
0x7000 0x0 0x0 0x4 &ipic 18 0x8
/* IDSEL 0x0F - PCI slot */
0x7800 0x0 0x0 0x1 &ipic 17 0x8
0x7800 0x0 0x0 0x2 &ipic 18 0x8
0x7800 0x0 0x0 0x3 &ipic 17 0x8
0x7800 0x0 0x0 0x4 &ipic 18 0x8>;
interrupt-parent = <&ipic>;
interrupts = <66 0x8>;
bus-range = <0x0 0x0>;
ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
clock-frequency = <66666666>;
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0xe0008500 0x100 /* internal registers */
0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
GPIO controllers on MPC8xxx SoCs
This is for the non-QE/CPM/GUTs GPIO controllers as found on
8349, 8572, 8610 and compatible.
Every GPIO controller node must have #gpio-cells property defined,
this information will be used to translate gpio-specifiers.
Required properties:
- compatible : "fsl,<CHIP>-gpio" followed by "fsl,mpc8349-gpio" for
83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx.
- #gpio-cells : Should be two. The first cell is the pin number and the
second cell is used to specify optional parameters (currently unused).
- interrupts : Interrupt mapping for GPIO IRQ (currently unused).
- interrupt-parent : Phandle for the interrupt controller that
services interrupts for this device.
- gpio-controller : Marks the port as GPIO controller.
Example of gpio-controller nodes for a MPC8347 SoC:
gpio1: gpio-controller@c00 {
#gpio-cells = <2>;
compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
reg = <0xc00 0x100>;
interrupts = <74 0x8>;
interrupt-parent = <&ipic>;
gpio-controller;
};
gpio2: gpio-controller@d00 {
#gpio-cells = <2>;
compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
reg = <0xd00 0x100>;
interrupts = <75 0x8>;
interrupt-parent = <&ipic>;
gpio-controller;
};
See booting-without-of.txt for details of how to specify GPIO
information for devices.
...@@ -20,7 +20,7 @@ Required properties: ...@@ -20,7 +20,7 @@ Required properties:
- compatible : compatible list, contains 2 entries, first is - compatible : compatible list, contains 2 entries, first is
"fsl,CHIP-dma-channel", where CHIP is the processor "fsl,CHIP-dma-channel", where CHIP is the processor
(mpc8349, mpc8350, etc.) and the second is (mpc8349, mpc8350, etc.) and the second is
"fsl,elo-dma-channel" "fsl,elo-dma-channel". However, see note below.
- reg : <registers mapping for channel> - reg : <registers mapping for channel>
- cell-index : dma channel index starts at 0. - cell-index : dma channel index starts at 0.
...@@ -82,7 +82,7 @@ Required properties: ...@@ -82,7 +82,7 @@ Required properties:
- compatible : compatible list, contains 2 entries, first is - compatible : compatible list, contains 2 entries, first is
"fsl,CHIP-dma-channel", where CHIP is the processor "fsl,CHIP-dma-channel", where CHIP is the processor
(mpc8540, mpc8560, etc.) and the second is (mpc8540, mpc8560, etc.) and the second is
"fsl,eloplus-dma-channel" "fsl,eloplus-dma-channel". However, see note below.
- cell-index : dma channel index starts at 0. - cell-index : dma channel index starts at 0.
- reg : <registers mapping for channel> - reg : <registers mapping for channel>
- interrupts : <interrupt mapping for DMA channel IRQ> - interrupts : <interrupt mapping for DMA channel IRQ>
...@@ -125,3 +125,12 @@ Example: ...@@ -125,3 +125,12 @@ Example:
interrupts = <17 2>; interrupts = <17 2>;
}; };
}; };
Note on DMA channel compatible properties: The compatible property must say
"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
driver (fsldma). Any DMA channel used by fsldma cannot be used by another
DMA driver, such as the SSI sound drivers for the MPC8610. Therefore, any DMA
channel that should be used for another driver should not use
"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel". For the SSI drivers, for
example, the compatible property should be "fsl,ssi-dma-channel". See ssi.txt
for more information.
...@@ -24,6 +24,12 @@ Required properties: ...@@ -24,6 +24,12 @@ Required properties:
"rj-master" - r.j., SSI is clock master "rj-master" - r.j., SSI is clock master
"ac97-slave" - AC97 mode, SSI is clock slave "ac97-slave" - AC97 mode, SSI is clock slave
"ac97-master" - AC97 mode, SSI is clock master "ac97-master" - AC97 mode, SSI is clock master
- fsl,playback-dma: phandle to a node for the DMA channel to use for
playback of audio. This is typically dictated by SOC
design. See the notes below.
- fsl,capture-dma: phandle to a node for the DMA channel to use for
capture (recording) of audio. This is typically dictated
by SOC design. See the notes below.
Optional properties: Optional properties:
- codec-handle : phandle to a 'codec' node that defines an audio - codec-handle : phandle to a 'codec' node that defines an audio
...@@ -36,3 +42,20 @@ Child 'codec' node required properties: ...@@ -36,3 +42,20 @@ Child 'codec' node required properties:
Child 'codec' node optional properties: Child 'codec' node optional properties:
- clock-frequency : The frequency of the input clock, which typically - clock-frequency : The frequency of the input clock, which typically
comes from an on-board dedicated oscillator. comes from an on-board dedicated oscillator.
Notes on fsl,playback-dma and fsl,capture-dma:
On SOCs that have an SSI, specific DMA channels are hard-wired for playback
and capture. On the MPC8610, for example, SSI1 must use DMA channel 0 for
playback and DMA channel 1 for capture. SSI2 must use DMA channel 2 for
playback and DMA channel 3 for capture. The developer can choose which
DMA controller to use, but the channels themselves are hard-wired. The
purpose of these two properties is to represent this hardware design.
The device tree nodes for the DMA channels that are referenced by
"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with
"fsl,ssi-dma-channel". The SOC-specific compatible string (e.g.
"fsl,mpc8610-dma-channel") can remain. If these nodes are left as
"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA
drivers (fsldma) will attempt to use them, and it will conflict with the
sound drivers.
Information about /proc/ppc_htab
=====================================================================
This document and the related code was written by me (Cort Dougan), please
email me (cort@fsmlabs.com) if you have questions, comments or corrections.
Last Change: 2.16.98
This entry in the proc directory is readable by all users but only
writable by root.
The ppc_htab interface is a user level way of accessing the
performance monitoring registers as well as providing information
about the PTE hash table.
1. Reading
Reading this file will give you information about the memory management
hash table that serves as an extended tlb for page translation on the
powerpc. It will also give you information about performance measurement
specific to the cpu that you are using.
Explanation of the 604 Performance Monitoring Fields:
MMCR0 - the current value of the MMCR0 register
PMC1
PMC2 - the value of the performance counters and a
description of what events they are counting
which are based on MMCR0 bit settings.
Explanation of the PTE Hash Table fields:
Size - hash table size in Kb.
Buckets - number of buckets in the table.
Address - the virtual kernel address of the hash table base.
Entries - the number of ptes that can be stored in the hash table.
User/Kernel - how many pte's are in use by the kernel or user at that time.
Overflows - How many of the entries are in their secondary hash location.
Percent full - ratio of free pte entries to in use entries.
Reloads - Count of how many hash table misses have occurred
that were fixed with a reload from the linux tables.
Should always be 0 on 603 based machines.
Non-error Misses - Count of how many hash table misses have occurred
that were completed with the creation of a pte in the linux
tables with a call to do_page_fault().
Error Misses - Number of misses due to errors such as bad address
and permission violations. This includes kernel access of
bad user addresses that are fixed up by the trap handler.
Note that calculation of the data displayed from /proc/ppc_htab takes
a long time and spends a great deal of time in the kernel. It would
be quite hard on performance to read this file constantly. In time
there may be a counter in the kernel that allows successive reads from
this file only after a given amount of time has passed to reduce the
possibility of a user slowing the system by reading this file.
2. Writing
Writing to the ppc_htab allows you to change the characteristics of
the powerpc PTE hash table and setup performance monitoring.
Resizing the PTE hash table is not enabled right now due to many
complications with moving the hash table, rehashing the entries
and many many SMP issues that would have to be dealt with.
Write options to ppc_htab:
- To set the size of the hash table to 64Kb:
echo 'size 64' > /proc/ppc_htab
The size must be a multiple of 64 and must be greater than or equal to
64.
- To turn off performance monitoring:
echo 'off' > /proc/ppc_htab
- To reset the counters without changing what they're counting:
echo 'reset' > /proc/ppc_htab
Note that counting will continue after the reset if it is enabled.
- To count only events in user mode or only in kernel mode:
echo 'user' > /proc/ppc_htab
...or...
echo 'kernel' > /proc/ppc_htab
Note that these two options are exclusive of one another and the
lack of either of these options counts user and kernel.
Using 'reset' and 'off' reset these flags.
- The 604 has 2 performance counters which can each count events from
a specific set of events. These sets are disjoint so it is not
possible to count _any_ combination of 2 events. One event can
be counted by PMC1 and one by PMC2.
To start counting a particular event use:
echo 'event' > /proc/ppc_htab
and choose from these events:
PMC1
----
'ic miss' - instruction cache misses
'dtlb' - data tlb misses (not hash table misses)
PMC2
----
'dc miss' - data cache misses
'itlb' - instruction tlb misses (not hash table misses)
'load miss time' - cycles to complete a load miss
3. Bugs
The PMC1 and PMC2 counters can overflow and give no indication of that
in /proc/ppc_htab.
Information about Linux/PPC SMP mode
=====================================================================
This document and the related code was written by me
(Cort Dougan, cort@fsmlabs.com) please email me if you have questions,
comments or corrections.
Last Change: 3.31.99
If you want to help by writing code or testing different hardware please
email me!
1. State of Supported Hardware
PowerSurge Architecture - tested on UMAX s900, Apple 9600
The second processor on this machine boots up just fine and
enters its idle loop. Hopefully a completely working SMP kernel
on this machine will be done shortly.
The code makes the assumption of only two processors. The changes
necessary to work with any number would not be overly difficult but
I don't have any machines with >2 processors so it's not high on my
list of priorities. If anyone else would like do to the work email
me and I can point out the places that need changed. If you have >2
processors and don't want to add support yourself let me know and I
can take a look into it.
BeBox
BeBox support hasn't been added to the 2.1.X kernels from 2.0.X
but work is being done and SMP support for BeBox is in the works.
CHRP
CHRP SMP works and is fairly solid. It's been tested on the IBM F50
with 4 processors for quite some time now.
...@@ -415,8 +415,11 @@ config PPC_64K_PAGES ...@@ -415,8 +415,11 @@ config PPC_64K_PAGES
config FORCE_MAX_ZONEORDER config FORCE_MAX_ZONEORDER
int "Maximum zone order" int "Maximum zone order"
range 9 64 if PPC_64K_PAGES
default "9" if PPC_64K_PAGES default "9" if PPC_64K_PAGES
range 13 64 if PPC64 && !PPC_64K_PAGES
default "13" if PPC64 && !PPC_64K_PAGES default "13" if PPC64 && !PPC_64K_PAGES
range 11 64
default "11" default "11"
help help
The kernel memory allocator divides physically contiguous memory The kernel memory allocator divides physically contiguous memory
...@@ -806,6 +809,19 @@ config PIN_TLB ...@@ -806,6 +809,19 @@ config PIN_TLB
endmenu endmenu
if PPC64 if PPC64
config RELOCATABLE
bool "Build a relocatable kernel"
help
This builds a kernel image that is capable of running anywhere
in the RMA (real memory area) at any 16k-aligned base address.
The kernel is linked as a position-independent executable (PIE)
and contains dynamic relocations which are processed early
in the bootup process.
One use is for the kexec on panic case where the recovery kernel
must live at a different physical address than the primary
kernel.
config PAGE_OFFSET config PAGE_OFFSET
hex hex
default "0xc000000000000000" default "0xc000000000000000"
......
...@@ -51,6 +51,11 @@ config FTR_FIXUP_SELFTEST ...@@ -51,6 +51,11 @@ config FTR_FIXUP_SELFTEST
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
default n default n
config MSI_BITMAP_SELFTEST
bool "Run self-tests of the MSI bitmap code."
depends on DEBUG_KERNEL
default n
config XMON config XMON
bool "Include xmon kernel debugger" bool "Include xmon kernel debugger"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
......
...@@ -63,7 +63,9 @@ override CC += -m$(CONFIG_WORD_SIZE) ...@@ -63,7 +63,9 @@ override CC += -m$(CONFIG_WORD_SIZE)
override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR) override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR)
endif endif
LDFLAGS_vmlinux := -Bstatic LDFLAGS_vmlinux-yy := -Bstatic
LDFLAGS_vmlinux-$(CONFIG_PPC64)$(CONFIG_RELOCATABLE) := -pie
LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-yy)
CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none -mcall-aixdesc CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none -mcall-aixdesc
CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
...@@ -102,7 +104,10 @@ endif ...@@ -102,7 +104,10 @@ endif
KBUILD_CFLAGS += $(call cc-option,-mno-altivec) KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
# No SPE instruction when building kernel # No SPE instruction when building kernel
# (We use all available options to help semi-broken compilers)
KBUILD_CFLAGS += $(call cc-option,-mno-spe) KBUILD_CFLAGS += $(call cc-option,-mno-spe)
KBUILD_CFLAGS += $(call cc-option,-mspe=no)
KBUILD_CFLAGS += $(call cc-option,-mabi=no-spe)
# Enable unit-at-a-time mode when possible. It shrinks the # Enable unit-at-a-time mode when possible. It shrinks the
# kernel considerably. # kernel considerably.
......
...@@ -310,8 +310,11 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb ...@@ -310,8 +310,11 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb
$(obj)/vmlinux.strip: vmlinux $(obj)/vmlinux.strip: vmlinux
$(STRIP) -s -R .comment $< -o $@ $(STRIP) -s -R .comment $< -o $@
# The iseries hypervisor won't take an ET_DYN executable, so this
# changes the type (byte 17) in the file to ET_EXEC (2).
$(obj)/zImage.iseries: vmlinux $(obj)/zImage.iseries: vmlinux
$(STRIP) -s -R .comment $< -o $@ $(STRIP) -s -R .comment $< -o $@
printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17
$(obj)/uImage: vmlinux $(wrapperbits) $(obj)/uImage: vmlinux $(wrapperbits)
$(call if_changed,wrap,uboot) $(call if_changed,wrap,uboot)
......
...@@ -11,7 +11,12 @@ ...@@ -11,7 +11,12 @@
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
* *
* Usage: addnote zImage * Usage: addnote zImage [note.elf]
*
* If note.elf is supplied, it is the name of an ELF file that contains
* an RPA note to use instead of the built-in one. Alternatively, the
* note.elf file may be empty, in which case the built-in RPA note is
* used (this is to simplify how this is invoked from the wrapper script).
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -43,27 +48,29 @@ char rpaname[] = "IBM,RPA-Client-Config"; ...@@ -43,27 +48,29 @@ char rpaname[] = "IBM,RPA-Client-Config";
*/ */
#define N_RPA_DESCR 8 #define N_RPA_DESCR 8
unsigned int rpanote[N_RPA_DESCR] = { unsigned int rpanote[N_RPA_DESCR] = {
0, /* lparaffinity */ 1, /* lparaffinity */
64, /* min_rmo_size */ 128, /* min_rmo_size */
0, /* min_rmo_percent */ 0, /* min_rmo_percent */
40, /* max_pft_size */ 46, /* max_pft_size */
1, /* splpar */ 1, /* splpar */
-1, /* min_load */ -1, /* min_load */
0, /* new_mem_def */ 1, /* new_mem_def */
1, /* ignore_my_client_config */ 0, /* ignore_my_client_config */
}; };
#define ROUNDUP(len) (((len) + 3) & ~3) #define ROUNDUP(len) (((len) + 3) & ~3)
unsigned char buf[512]; unsigned char buf[512];
unsigned char notebuf[512];
#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) #define GET_16BE(b, off) (((b)[off] << 8) + ((b)[(off)+1]))
#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) #define GET_32BE(b, off) ((GET_16BE((b), (off)) << 16) + \
GET_16BE((b), (off)+2))
#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ #define PUT_16BE(b, off, v) ((b)[off] = ((v) >> 8) & 0xff, \
buf[(off) + 1] = (v) & 0xff) (b)[(off) + 1] = (v) & 0xff)
#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ #define PUT_32BE(b, off, v) (PUT_16BE((b), (off), (v) >> 16), \
PUT_16BE((off) + 2, (v))) PUT_16BE((b), (off) + 2, (v)))
/* Structure of an ELF file */ /* Structure of an ELF file */
#define E_IDENT 0 /* ELF header */ #define E_IDENT 0 /* ELF header */
...@@ -88,15 +95,71 @@ unsigned char buf[512]; ...@@ -88,15 +95,71 @@ unsigned char buf[512];
unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
unsigned char *read_rpanote(const char *fname, int *nnp)
{
int notefd, nr, i;
int ph, ps, np;
int note, notesize;
notefd = open(fname, O_RDONLY);
if (notefd < 0) {
perror(fname);
exit(1);
}
nr = read(notefd, notebuf, sizeof(notebuf));
if (nr < 0) {
perror("read note");
exit(1);
}
if (nr == 0) /* empty file */
return NULL;
if (nr < E_HSIZE ||
memcmp(&notebuf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0 ||
notebuf[E_IDENT+EI_CLASS] != ELFCLASS32 ||
notebuf[E_IDENT+EI_DATA] != ELFDATA2MSB)
goto notelf;
close(notefd);
/* now look for the RPA-note */
ph = GET_32BE(notebuf, E_PHOFF);
ps = GET_16BE(notebuf, E_PHENTSIZE);
np = GET_16BE(notebuf, E_PHNUM);
if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
goto notelf;
for (i = 0; i < np; ++i, ph += ps) {
if (GET_32BE(notebuf, ph + PH_TYPE) != PT_NOTE)
continue;
note = GET_32BE(notebuf, ph + PH_OFFSET);
notesize = GET_32BE(notebuf, ph + PH_FILESZ);
if (notesize < 34 || note + notesize > nr)
continue;
if (GET_32BE(notebuf, note) != strlen(rpaname) + 1 ||
GET_32BE(notebuf, note + 8) != 0x12759999 ||
strcmp((char *)&notebuf[note + 12], rpaname) != 0)
continue;
/* looks like an RPA note, return it */
*nnp = notesize;
return &notebuf[note];
}
/* no RPA note found */
return NULL;
notelf:
fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", fname);
exit(1);
}
int int
main(int ac, char **av) main(int ac, char **av)
{ {
int fd, n, i; int fd, n, i;
int ph, ps, np; int ph, ps, np;
int nnote, nnote2, ns; int nnote, nnote2, ns;
unsigned char *rpap;
if (ac != 2) { if (ac != 2 && ac != 3) {
fprintf(stderr, "Usage: %s elf-file\n", av[0]); fprintf(stderr, "Usage: %s elf-file [rpanote.elf]\n", av[0]);
exit(1); exit(1);
} }
fd = open(av[1], O_RDWR); fd = open(av[1], O_RDWR);
...@@ -107,6 +170,7 @@ main(int ac, char **av) ...@@ -107,6 +170,7 @@ main(int ac, char **av)
nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr); nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote); nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
rpap = NULL;
n = read(fd, buf, sizeof(buf)); n = read(fd, buf, sizeof(buf));
if (n < 0) { if (n < 0) {
...@@ -124,16 +188,19 @@ main(int ac, char **av) ...@@ -124,16 +188,19 @@ main(int ac, char **av)
exit(1); exit(1);
} }
ph = GET_32BE(E_PHOFF); if (ac == 3)
ps = GET_16BE(E_PHENTSIZE); rpap = read_rpanote(av[2], &nnote2);
np = GET_16BE(E_PHNUM);
ph = GET_32BE(buf, E_PHOFF);
ps = GET_16BE(buf, E_PHENTSIZE);
np = GET_16BE(buf, E_PHNUM);
if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
goto notelf; goto notelf;
if (ph + (np + 2) * ps + nnote + nnote2 > n) if (ph + (np + 2) * ps + nnote + nnote2 > n)
goto nospace; goto nospace;
for (i = 0; i < np; ++i) { for (i = 0; i < np; ++i) {
if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { if (GET_32BE(buf, ph + PH_TYPE) == PT_NOTE) {
fprintf(stderr, "%s already has a note entry\n", fprintf(stderr, "%s already has a note entry\n",
av[1]); av[1]);
exit(0); exit(0);
...@@ -148,37 +215,42 @@ main(int ac, char **av) ...@@ -148,37 +215,42 @@ main(int ac, char **av)
/* fill in the program header entry */ /* fill in the program header entry */
ns = ph + 2 * ps; ns = ph + 2 * ps;
PUT_32BE(ph + PH_TYPE, PT_NOTE); PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
PUT_32BE(ph + PH_OFFSET, ns); PUT_32BE(buf, ph + PH_OFFSET, ns);
PUT_32BE(ph + PH_FILESZ, nnote); PUT_32BE(buf, ph + PH_FILESZ, nnote);
/* fill in the note area we point to */ /* fill in the note area we point to */
/* XXX we should probably make this a proper section */ /* XXX we should probably make this a proper section */
PUT_32BE(ns, strlen(arch) + 1); PUT_32BE(buf, ns, strlen(arch) + 1);
PUT_32BE(ns + 4, N_DESCR * 4); PUT_32BE(buf, ns + 4, N_DESCR * 4);
PUT_32BE(ns + 8, 0x1275); PUT_32BE(buf, ns + 8, 0x1275);
strcpy((char *) &buf[ns + 12], arch); strcpy((char *) &buf[ns + 12], arch);
ns += 12 + strlen(arch) + 1; ns += 12 + strlen(arch) + 1;
for (i = 0; i < N_DESCR; ++i, ns += 4) for (i = 0; i < N_DESCR; ++i, ns += 4)
PUT_32BE(ns, descr[i]); PUT_32BE(buf, ns, descr[i]);
/* fill in the second program header entry and the RPA note area */ /* fill in the second program header entry and the RPA note area */
ph += ps; ph += ps;
PUT_32BE(ph + PH_TYPE, PT_NOTE); PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
PUT_32BE(ph + PH_OFFSET, ns); PUT_32BE(buf, ph + PH_OFFSET, ns);
PUT_32BE(ph + PH_FILESZ, nnote2); PUT_32BE(buf, ph + PH_FILESZ, nnote2);
/* fill in the note area we point to */ /* fill in the note area we point to */
PUT_32BE(ns, strlen(rpaname) + 1); if (rpap) {
PUT_32BE(ns + 4, sizeof(rpanote)); /* RPA note supplied in file, just copy the whole thing over */
PUT_32BE(ns + 8, 0x12759999); memcpy(buf + ns, rpap, nnote2);
strcpy((char *) &buf[ns + 12], rpaname); } else {
ns += 12 + ROUNDUP(strlen(rpaname) + 1); PUT_32BE(buf, ns, strlen(rpaname) + 1);
for (i = 0; i < N_RPA_DESCR; ++i, ns += 4) PUT_32BE(buf, ns + 4, sizeof(rpanote));
PUT_32BE(ns, rpanote[i]); PUT_32BE(buf, ns + 8, 0x12759999);
strcpy((char *) &buf[ns + 12], rpaname);
ns += 12 + ROUNDUP(strlen(rpaname) + 1);
for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
PUT_32BE(buf, ns, rpanote[i]);
}
/* Update the number of program headers */ /* Update the number of program headers */
PUT_16BE(E_PHNUM, np + 2); PUT_16BE(buf, E_PHNUM, np + 2);
/* write back */ /* write back */
lseek(fd, (long) 0, SEEK_SET); lseek(fd, (long) 0, SEEK_SET);
......
...@@ -5,21 +5,5 @@ ...@@ -5,21 +5,5 @@
# #
DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \ DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \
checks.c checks.c
DTC_EXTRA = dtc.h srcpos.h DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
DTC_LEXFILES = dtc-lexer.l
DTC_BISONFILES = dtc-parser.y
DTC_LEX_SRCS = $(DTC_LEXFILES:%.l=%.lex.c)
DTC_BISON_SRCS = $(DTC_BISONFILES:%.y=%.tab.c)
DTC_BISON_INCLUDES = $(DTC_BISONFILES:%.y=%.tab.h)
DTC_GEN_SRCS = $(DTC_LEX_SRCS) $(DTC_BISON_SRCS)
DTC_GEN_ALL = $(DTC_GEN_SRCS) $(DTC_BISON_INCLUDES)
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
DTC_CLEANFILES = $(DTC_GEN_ALL)
# We assume the containing Makefile system can do auto-dependencies for most
# things, but we supply the dependencies on generated header files explicitly
$(addprefix $(DTC_objdir)/,$(DTC_GEN_SRCS:%.c=%.o)): $(addprefix $(DTC_objdir)/,$(DTC_BISON_INCLUDES))
...@@ -242,6 +242,42 @@ static void check_duplicate_property_names(struct check *c, struct node *dt, ...@@ -242,6 +242,42 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
} }
NODE_CHECK(duplicate_property_names, NULL, ERROR); NODE_CHECK(duplicate_property_names, NULL, ERROR);
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DIGITS "0123456789"
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
static void check_node_name_chars(struct check *c, struct node *dt,
struct node *node)
{
int n = strspn(node->name, c->data);
if (n < strlen(node->name))
FAIL(c, "Bad character '%c' in node %s",
node->name[n], node->fullpath);
}
NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
static void check_node_name_format(struct check *c, struct node *dt,
struct node *node)
{
if (strchr(get_unitname(node), '@'))
FAIL(c, "Node %s has multiple '@' characters in name",
node->fullpath);
}
NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
static void check_property_name_chars(struct check *c, struct node *dt,
struct node *node, struct property *prop)
{
int n = strspn(prop->name, c->data);
if (n < strlen(prop->name))
FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
prop->name[n], prop->name, node->fullpath);
}
PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
static void check_explicit_phandles(struct check *c, struct node *root, static void check_explicit_phandles(struct check *c, struct node *root,
struct node *node) struct node *node)
{ {
...@@ -280,16 +316,29 @@ NODE_CHECK(explicit_phandles, NULL, ERROR); ...@@ -280,16 +316,29 @@ NODE_CHECK(explicit_phandles, NULL, ERROR);
static void check_name_properties(struct check *c, struct node *root, static void check_name_properties(struct check *c, struct node *root,
struct node *node) struct node *node)
{ {
struct property *prop; struct property **pp, *prop = NULL;
for (pp = &node->proplist; *pp; pp = &((*pp)->next))
if (streq((*pp)->name, "name")) {
prop = *pp;
break;
}
prop = get_property(node, "name");
if (!prop) if (!prop)
return; /* No name property, that's fine */ return; /* No name property, that's fine */
if ((prop->val.len != node->basenamelen+1) if ((prop->val.len != node->basenamelen+1)
|| (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead" FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
" of base node name)", node->fullpath, prop->val.val); " of base node name)", node->fullpath, prop->val.val);
} else {
/* The name property is correct, and therefore redundant.
* Delete it */
*pp = prop->next;
free(prop->name);
data_free(prop->val);
free(prop);
}
} }
CHECK_IS_STRING(name_is_string, "name", ERROR); CHECK_IS_STRING(name_is_string, "name", ERROR);
NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
...@@ -301,23 +350,23 @@ NODE_CHECK(name_properties, NULL, ERROR, &name_is_string); ...@@ -301,23 +350,23 @@ NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
static void fixup_phandle_references(struct check *c, struct node *dt, static void fixup_phandle_references(struct check *c, struct node *dt,
struct node *node, struct property *prop) struct node *node, struct property *prop)
{ {
struct marker *m = prop->val.markers; struct marker *m = prop->val.markers;
struct node *refnode; struct node *refnode;
cell_t phandle; cell_t phandle;
for_each_marker_of_type(m, REF_PHANDLE) { for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset + sizeof(cell_t) <= prop->val.len); assert(m->offset + sizeof(cell_t) <= prop->val.len);
refnode = get_node_by_ref(dt, m->ref); refnode = get_node_by_ref(dt, m->ref);
if (! refnode) { if (! refnode) {
FAIL(c, "Reference to non-existent node or label \"%s\"\n", FAIL(c, "Reference to non-existent node or label \"%s\"\n",
m->ref); m->ref);
continue; continue;
} }
phandle = get_node_phandle(dt, refnode); phandle = get_node_phandle(dt, refnode);
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_be32(phandle); *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
} }
} }
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR, CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
&duplicate_node_names, &explicit_phandles); &duplicate_node_names, &explicit_phandles);
...@@ -498,6 +547,7 @@ TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN); ...@@ -498,6 +547,7 @@ TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
static struct check *check_table[] = { static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names, &duplicate_node_names, &duplicate_property_names,
&node_name_chars, &node_name_format, &property_name_chars,
&name_is_string, &name_properties, &name_is_string, &name_properties,
&explicit_phandles, &explicit_phandles,
&phandle_references, &path_references, &phandle_references, &path_references,
...@@ -511,10 +561,7 @@ static struct check *check_table[] = { ...@@ -511,10 +561,7 @@ static struct check *check_table[] = {
&obsolete_chosen_interrupt_controller, &obsolete_chosen_interrupt_controller,
}; };
int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys); void process_checks(int force, struct boot_info *bi)
void process_checks(int force, struct boot_info *bi,
int checkflag, int outversion, int boot_cpuid_phys)
{ {
struct node *dt = bi->dt; struct node *dt = bi->dt;
int i; int i;
...@@ -537,214 +584,4 @@ void process_checks(int force, struct boot_info *bi, ...@@ -537,214 +584,4 @@ void process_checks(int force, struct boot_info *bi,
"output forced\n"); "output forced\n");
} }
} }
if (checkflag) {
if (error) {
fprintf(stderr, "Warning: Skipping semantic checks due to structural errors\n");
} else {
if (!check_semantics(bi->dt, outversion,
boot_cpuid_phys))
fprintf(stderr, "Warning: Input tree has semantic errors\n");
}
}
}
/*
* Semantic check functions
*/
#define ERRMSG(...) if (quiet < 2) fprintf(stderr, "ERROR: " __VA_ARGS__)
#define WARNMSG(...) if (quiet < 1) fprintf(stderr, "Warning: " __VA_ARGS__)
#define DO_ERR(...) do {ERRMSG(__VA_ARGS__); ok = 0; } while (0)
#define CHECK_HAVE(node, propname) \
do { \
if (! (prop = get_property((node), (propname)))) \
DO_ERR("Missing \"%s\" property in %s\n", (propname), \
(node)->fullpath); \
} while (0);
#define CHECK_HAVE_WARN(node, propname) \
do { \
if (! (prop = get_property((node), (propname)))) \
WARNMSG("%s has no \"%s\" property\n", \
(node)->fullpath, (propname)); \
} while (0)
#define CHECK_HAVE_STRING(node, propname) \
do { \
CHECK_HAVE((node), (propname)); \
if (prop && !data_is_one_string(prop->val)) \
DO_ERR("\"%s\" property in %s is not a string\n", \
(propname), (node)->fullpath); \
} while (0)
#define CHECK_HAVE_STREQ(node, propname, value) \
do { \
CHECK_HAVE_STRING((node), (propname)); \
if (prop && !streq(prop->val.val, (value))) \
DO_ERR("%s has wrong %s, %s (should be %s\n", \
(node)->fullpath, (propname), \
prop->val.val, (value)); \
} while (0)
#define CHECK_HAVE_ONECELL(node, propname) \
do { \
CHECK_HAVE((node), (propname)); \
if (prop && (prop->val.len != sizeof(cell_t))) \
DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
} while (0)
#define CHECK_HAVE_WARN_ONECELL(node, propname) \
do { \
CHECK_HAVE_WARN((node), (propname)); \
if (prop && (prop->val.len != sizeof(cell_t))) \
DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
} while (0)
#define CHECK_HAVE_WARN_PHANDLE(xnode, propname, root) \
do { \
struct node *ref; \
CHECK_HAVE_WARN_ONECELL((xnode), (propname)); \
if (prop) {\
cell_t phandle = propval_cell(prop); \
if ((phandle == 0) || (phandle == -1)) { \
DO_ERR("\"%s\" property in %s contains an invalid phandle %x\n", (propname), (xnode)->fullpath, phandle); \
} else { \
ref = get_node_by_phandle((root), propval_cell(prop)); \
if (! ref) \
DO_ERR("\"%s\" property in %s refers to non-existant phandle %x\n", (propname), (xnode)->fullpath, propval_cell(prop)); \
} \
} \
} while (0)
#define CHECK_HAVE_WARN_STRING(node, propname) \
do { \
CHECK_HAVE_WARN((node), (propname)); \
if (prop && !data_is_one_string(prop->val)) \
DO_ERR("\"%s\" property in %s is not a string\n", \
(propname), (node)->fullpath); \
} while (0)
static int check_root(struct node *root)
{
struct property *prop;
int ok = 1;
CHECK_HAVE_STRING(root, "model");
CHECK_HAVE_WARN(root, "compatible");
return ok;
}
static int check_cpus(struct node *root, int outversion, int boot_cpuid_phys)
{
struct node *cpus, *cpu;
struct property *prop;
struct node *bootcpu = NULL;
int ok = 1;
cpus = get_subnode(root, "cpus");
if (! cpus) {
ERRMSG("Missing /cpus node\n");
return 0;
}
if (cpus->addr_cells != 1)
DO_ERR("%s has bad #address-cells value %d (should be 1)\n",
cpus->fullpath, cpus->addr_cells);
if (cpus->size_cells != 0)
DO_ERR("%s has bad #size-cells value %d (should be 0)\n",
cpus->fullpath, cpus->size_cells);
for_each_child(cpus, cpu) {
CHECK_HAVE_STREQ(cpu, "device_type", "cpu");
CHECK_HAVE_ONECELL(cpu, "reg");
if (prop) {
cell_t unitnum;
char *eptr;
unitnum = strtol(get_unitname(cpu), &eptr, 16);
if (*eptr) {
WARNMSG("%s has bad format unit name %s (should be CPU number\n",
cpu->fullpath, get_unitname(cpu));
} else if (unitnum != propval_cell(prop)) {
WARNMSG("%s unit name \"%s\" does not match \"reg\" property <%x>\n",
cpu->fullpath, get_unitname(cpu),
propval_cell(prop));
}
}
/* CHECK_HAVE_ONECELL(cpu, "d-cache-line-size"); */
/* CHECK_HAVE_ONECELL(cpu, "i-cache-line-size"); */
CHECK_HAVE_ONECELL(cpu, "d-cache-size");
CHECK_HAVE_ONECELL(cpu, "i-cache-size");
CHECK_HAVE_WARN_ONECELL(cpu, "clock-frequency");
CHECK_HAVE_WARN_ONECELL(cpu, "timebase-frequency");
prop = get_property(cpu, "linux,boot-cpu");
if (prop) {
if (prop->val.len)
WARNMSG("\"linux,boot-cpu\" property in %s is non-empty\n",
cpu->fullpath);
if (bootcpu)
DO_ERR("Multiple boot cpus (%s and %s)\n",
bootcpu->fullpath, cpu->fullpath);
else
bootcpu = cpu;
}
}
if (outversion < 2) {
if (! bootcpu)
WARNMSG("No cpu has \"linux,boot-cpu\" property\n");
} else {
if (bootcpu)
WARNMSG("\"linux,boot-cpu\" property is deprecated in blob version 2 or higher\n");
if (boot_cpuid_phys == 0xfeedbeef)
WARNMSG("physical boot CPU not set. Use -b option to set\n");
}
return ok;
}
static int check_memory(struct node *root)
{
struct node *mem;
struct property *prop;
int nnodes = 0;
int ok = 1;
for_each_child(root, mem) {
if (! strneq(mem->name, "memory", mem->basenamelen))
continue;
nnodes++;
CHECK_HAVE_STREQ(mem, "device_type", "memory");
CHECK_HAVE(mem, "reg");
}
if (nnodes == 0) {
ERRMSG("No memory nodes\n");
return 0;
}
return ok;
}
int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys)
{
int ok = 1;
ok = ok && check_root(dt);
ok = ok && check_cpus(dt, outversion, boot_cpuid_phys);
ok = ok && check_memory(dt);
if (! ok)
return 0;
return 1;
} }
...@@ -32,8 +32,6 @@ void data_free(struct data d) ...@@ -32,8 +32,6 @@ void data_free(struct data d)
m = nm; m = nm;
} }
assert(!d.val || d.asize);
if (d.val) if (d.val)
free(d.val); free(d.val);
} }
...@@ -43,9 +41,6 @@ struct data data_grow_for(struct data d, int xlen) ...@@ -43,9 +41,6 @@ struct data data_grow_for(struct data d, int xlen)
struct data nd; struct data nd;
int newsize; int newsize;
/* we must start with an allocated datum */
assert(!d.val || d.asize);
if (xlen == 0) if (xlen == 0)
return d; return d;
...@@ -56,11 +51,8 @@ struct data data_grow_for(struct data d, int xlen) ...@@ -56,11 +51,8 @@ struct data data_grow_for(struct data d, int xlen)
while ((d.len + xlen) > newsize) while ((d.len + xlen) > newsize)
newsize *= 2; newsize *= 2;
nd.asize = newsize;
nd.val = xrealloc(d.val, newsize); nd.val = xrealloc(d.val, newsize);
assert(nd.asize >= (d.len + xlen));
return nd; return nd;
} }
...@@ -83,16 +75,11 @@ static char get_oct_char(const char *s, int *i) ...@@ -83,16 +75,11 @@ static char get_oct_char(const char *s, int *i)
long val; long val;
x[3] = '\0'; x[3] = '\0';
x[0] = s[(*i)]; strncpy(x, s + *i, 3);
if (x[0]) {
x[1] = s[(*i)+1];
if (x[1])
x[2] = s[(*i)+2];
}
val = strtol(x, &endx, 8); val = strtol(x, &endx, 8);
if ((endx - x) == 0)
fprintf(stderr, "Empty \\nnn escape\n"); assert(endx > x);
(*i) += endx - x; (*i) += endx - x;
return val; return val;
...@@ -105,13 +92,11 @@ static char get_hex_char(const char *s, int *i) ...@@ -105,13 +92,11 @@ static char get_hex_char(const char *s, int *i)
long val; long val;
x[2] = '\0'; x[2] = '\0';
x[0] = s[(*i)]; strncpy(x, s + *i, 2);
if (x[0])
x[1] = s[(*i)+1];
val = strtol(x, &endx, 16); val = strtol(x, &endx, 16);
if ((endx - x) == 0) if (!(endx > x))
fprintf(stderr, "Empty \\x escape\n"); die("\\x used with no following hex digits\n");
(*i) += endx - x; (*i) += endx - x;
return val; return val;
...@@ -182,14 +167,29 @@ struct data data_copy_escape_string(const char *s, int len) ...@@ -182,14 +167,29 @@ struct data data_copy_escape_string(const char *s, int len)
return d; return d;
} }
struct data data_copy_file(FILE *f, size_t len) struct data data_copy_file(FILE *f, size_t maxlen)
{ {
struct data d; struct data d = empty_data;
d = data_grow_for(empty_data, len); while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;
d.len = len; if (maxlen == -1)
fread(d.val, len, 1, f); chunksize = 4096;
else
chunksize = maxlen - d.len;
d = data_grow_for(d, chunksize);
ret = fread(d.val + d.len, 1, chunksize, f);
if (ferror(f))
die("Error reading file into data: %s", strerror(errno));
if (d.len + ret < d.len)
die("Overflow reading file into data\n");
d.len += ret;
}
return d; return d;
} }
...@@ -247,7 +247,7 @@ struct data data_merge(struct data d1, struct data d2) ...@@ -247,7 +247,7 @@ struct data data_merge(struct data d1, struct data d2)
struct data data_append_cell(struct data d, cell_t word) struct data data_append_cell(struct data d, cell_t word)
{ {
cell_t beword = cpu_to_be32(word); cell_t beword = cpu_to_fdt32(word);
return data_append_data(d, &beword, sizeof(beword)); return data_append_data(d, &beword, sizeof(beword));
} }
...@@ -256,15 +256,15 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re) ...@@ -256,15 +256,15 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
{ {
struct fdt_reserve_entry bere; struct fdt_reserve_entry bere;
bere.address = cpu_to_be64(re->address); bere.address = cpu_to_fdt64(re->address);
bere.size = cpu_to_be64(re->size); bere.size = cpu_to_fdt64(re->size);
return data_append_data(d, &bere, sizeof(bere)); return data_append_data(d, &bere, sizeof(bere));
} }
struct data data_append_addr(struct data d, u64 addr) struct data data_append_addr(struct data d, uint64_t addr)
{ {
u64 beaddr = cpu_to_be64(addr); uint64_t beaddr = cpu_to_fdt64(addr);
return data_append_data(d, &beaddr, sizeof(beaddr)); return data_append_data(d, &beaddr, sizeof(beaddr));
} }
......
...@@ -28,6 +28,10 @@ ...@@ -28,6 +28,10 @@
PROPNODECHAR [a-zA-Z0-9,._+*#?@-] PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
PATHCHAR ({PROPNODECHAR}|[/]) PATHCHAR ({PROPNODECHAR}|[/])
LABEL [a-zA-Z_][a-zA-Z0-9_]* LABEL [a-zA-Z_][a-zA-Z0-9_]*
STRING \"([^\\"]|\\.)*\"
WS [[:space:]]
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
LINECOMMENT "//".*\n
%{ %{
#include "dtc.h" #include "dtc.h"
...@@ -52,29 +56,26 @@ static int dts_version; /* = 0 */ ...@@ -52,29 +56,26 @@ static int dts_version; /* = 0 */
DPRINT("<V1>\n"); \ DPRINT("<V1>\n"); \
BEGIN(V1); \ BEGIN(V1); \
} }
static void push_input_file(const char *filename);
static int pop_input_file(void);
%} %}
%% %%
<*>"/include/" BEGIN(INCLUDE); <*>"/include/"{WS}*{STRING} {
char *name = strchr(yytext, '\"') + 1;
<INCLUDE>\"[^"\n]*\" { yytext[yyleng-1] = '\0';
yytext[strlen(yytext) - 1] = 0; push_input_file(name);
if (!push_input_file(yytext + 1)) {
/* Some unrecoverable error.*/
exit(1);
}
BEGIN_DEFAULT();
} }
<*><<EOF>> { <*><<EOF>> {
if (!pop_input_file()) { if (!pop_input_file()) {
yyterminate(); yyterminate();
} }
} }
<*>\"([^\\"]|\\.)*\" { <*>{STRING} {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("String: %s\n", yytext); DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1, yylval.data = data_copy_escape_string(yytext+1,
...@@ -84,7 +85,7 @@ static int dts_version; /* = 0 */ ...@@ -84,7 +85,7 @@ static int dts_version; /* = 0 */
} }
<*>"/dts-v1/" { <*>"/dts-v1/" {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("Keyword: /dts-v1/\n"); DPRINT("Keyword: /dts-v1/\n");
dts_version = 1; dts_version = 1;
...@@ -93,7 +94,7 @@ static int dts_version; /* = 0 */ ...@@ -93,7 +94,7 @@ static int dts_version; /* = 0 */
} }
<*>"/memreserve/" { <*>"/memreserve/" {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("Keyword: /memreserve/\n"); DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT(); BEGIN_DEFAULT();
...@@ -101,7 +102,7 @@ static int dts_version; /* = 0 */ ...@@ -101,7 +102,7 @@ static int dts_version; /* = 0 */
} }
<*>{LABEL}: { <*>{LABEL}: {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("Label: %s\n", yytext); DPRINT("Label: %s\n", yytext);
yylval.labelref = strdup(yytext); yylval.labelref = strdup(yytext);
...@@ -110,7 +111,7 @@ static int dts_version; /* = 0 */ ...@@ -110,7 +111,7 @@ static int dts_version; /* = 0 */
} }
<INITIAL>[bodh]# { <INITIAL>[bodh]# {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
if (*yytext == 'b') if (*yytext == 'b')
yylval.cbase = 2; yylval.cbase = 2;
...@@ -125,7 +126,7 @@ static int dts_version; /* = 0 */ ...@@ -125,7 +126,7 @@ static int dts_version; /* = 0 */
} }
<INITIAL>[0-9a-fA-F]+ { <INITIAL>[0-9a-fA-F]+ {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
yylval.literal = strdup(yytext); yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal); DPRINT("Literal: '%s'\n", yylval.literal);
...@@ -133,7 +134,7 @@ static int dts_version; /* = 0 */ ...@@ -133,7 +134,7 @@ static int dts_version; /* = 0 */
} }
<V1>[0-9]+|0[xX][0-9a-fA-F]+ { <V1>[0-9]+|0[xX][0-9a-fA-F]+ {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
yylval.literal = strdup(yytext); yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal); DPRINT("Literal: '%s'\n", yylval.literal);
...@@ -141,7 +142,7 @@ static int dts_version; /* = 0 */ ...@@ -141,7 +142,7 @@ static int dts_version; /* = 0 */
} }
\&{LABEL} { /* label reference */ \&{LABEL} { /* label reference */
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1); DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1); yylval.labelref = strdup(yytext+1);
...@@ -149,7 +150,7 @@ static int dts_version; /* = 0 */ ...@@ -149,7 +150,7 @@ static int dts_version; /* = 0 */
} }
"&{/"{PATHCHAR}+\} { /* new-style path reference */ "&{/"{PATHCHAR}+\} { /* new-style path reference */
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
yytext[yyleng-1] = '\0'; yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2); DPRINT("Ref: %s\n", yytext+2);
...@@ -158,7 +159,7 @@ static int dts_version; /* = 0 */ ...@@ -158,7 +159,7 @@ static int dts_version; /* = 0 */
} }
<INITIAL>"&/"{PATHCHAR}+ { /* old-style path reference */ <INITIAL>"&/"{PATHCHAR}+ { /* old-style path reference */
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1); DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1); yylval.labelref = strdup(yytext+1);
...@@ -166,7 +167,7 @@ static int dts_version; /* = 0 */ ...@@ -166,7 +167,7 @@ static int dts_version; /* = 0 */
} }
<BYTESTRING>[0-9a-fA-F]{2} { <BYTESTRING>[0-9a-fA-F]{2} {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
yylval.byte = strtol(yytext, NULL, 16); yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte); DPRINT("Byte: %02x\n", (int)yylval.byte);
...@@ -174,7 +175,7 @@ static int dts_version; /* = 0 */ ...@@ -174,7 +175,7 @@ static int dts_version; /* = 0 */
} }
<BYTESTRING>"]" { <BYTESTRING>"]" {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("/BYTESTRING\n"); DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT(); BEGIN_DEFAULT();
...@@ -182,7 +183,7 @@ static int dts_version; /* = 0 */ ...@@ -182,7 +183,7 @@ static int dts_version; /* = 0 */
} }
<PROPNODENAME>{PROPNODECHAR}+ { <PROPNODENAME>{PROPNODECHAR}+ {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("PropNodeName: %s\n", yytext); DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = strdup(yytext); yylval.propnodename = strdup(yytext);
...@@ -190,20 +191,19 @@ static int dts_version; /* = 0 */ ...@@ -190,20 +191,19 @@ static int dts_version; /* = 0 */
return DT_PROPNODENAME; return DT_PROPNODENAME;
} }
"/incbin/" {
<*>[[:space:]]+ /* eat whitespace */ yylloc.file = srcpos_file;
<*>"/*"([^*]|\*+[^*/])*\*+"/" {
yylloc.filenum = srcpos_filenum;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("Comment: %s\n", yytext); DPRINT("Binary Include\n");
/* eat comments */ return DT_INCBIN;
} }
<*>"//".*\n /* eat line comments */ <*>{WS}+ /* eat whitespace */
<*>{COMMENT}+ /* eat C-style comments */
<*>{LINECOMMENT}+ /* eat C++-style comments */
<*>. { <*>. {
yylloc.filenum = srcpos_filenum; yylloc.file = srcpos_file;
yylloc.first_line = yylineno; yylloc.first_line = yylineno;
DPRINT("Char: %c (\\x%02x)\n", yytext[0], DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]); (unsigned)yytext[0]);
...@@ -227,14 +227,13 @@ static int dts_version; /* = 0 */ ...@@ -227,14 +227,13 @@ static int dts_version; /* = 0 */
*/ */
struct incl_file { struct incl_file {
int filenum; struct dtc_file *file;
FILE *file;
YY_BUFFER_STATE yy_prev_buf; YY_BUFFER_STATE yy_prev_buf;
int yy_prev_lineno; int yy_prev_lineno;
struct incl_file *prev; struct incl_file *prev;
}; };
struct incl_file *incl_file_stack; static struct incl_file *incl_file_stack;
/* /*
...@@ -245,36 +244,34 @@ struct incl_file *incl_file_stack; ...@@ -245,36 +244,34 @@ struct incl_file *incl_file_stack;
static int incl_depth = 0; static int incl_depth = 0;
int push_input_file(const char *filename) static void push_input_file(const char *filename)
{ {
FILE *f;
struct incl_file *incl_file; struct incl_file *incl_file;
struct dtc_file *newfile;
struct search_path search, *searchptr = NULL;
if (!filename) { assert(filename);
yyerror("No include file name given.");
return 0;
}
if (incl_depth++ >= MAX_INCLUDE_DEPTH) { if (incl_depth++ >= MAX_INCLUDE_DEPTH)
yyerror("Includes nested too deeply"); die("Includes nested too deeply");
return 0;
if (srcpos_file) {
search.dir = srcpos_file->dir;
search.next = NULL;
search.prev = NULL;
searchptr = &search;
} }
f = dtc_open_file(filename); newfile = dtc_open_file(filename, searchptr);
incl_file = malloc(sizeof(struct incl_file)); incl_file = xmalloc(sizeof(struct incl_file));
if (!incl_file) {
yyerror("Can not allocate include file space.");
return 0;
}
/* /*
* Save current context. * Save current context.
*/ */
incl_file->yy_prev_buf = YY_CURRENT_BUFFER; incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
incl_file->yy_prev_lineno = yylineno; incl_file->yy_prev_lineno = yylineno;
incl_file->filenum = srcpos_filenum; incl_file->file = srcpos_file;
incl_file->file = yyin;
incl_file->prev = incl_file_stack; incl_file->prev = incl_file_stack;
incl_file_stack = incl_file; incl_file_stack = incl_file;
...@@ -282,23 +279,21 @@ int push_input_file(const char *filename) ...@@ -282,23 +279,21 @@ int push_input_file(const char *filename)
/* /*
* Establish new context. * Establish new context.
*/ */
srcpos_filenum = lookup_file_name(filename, 0); srcpos_file = newfile;
yylineno = 1; yylineno = 1;
yyin = f; yyin = newfile->file;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
return 1;
} }
int pop_input_file(void) static int pop_input_file(void)
{ {
struct incl_file *incl_file; struct incl_file *incl_file;
if (incl_file_stack == 0) if (incl_file_stack == 0)
return 0; return 0;
fclose(yyin); dtc_close_file(srcpos_file);
/* /*
* Pop. * Pop.
...@@ -313,16 +308,13 @@ int pop_input_file(void) ...@@ -313,16 +308,13 @@ int pop_input_file(void)
yy_delete_buffer(YY_CURRENT_BUFFER); yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(incl_file->yy_prev_buf); yy_switch_to_buffer(incl_file->yy_prev_buf);
yylineno = incl_file->yy_prev_lineno; yylineno = incl_file->yy_prev_lineno;
srcpos_filenum = incl_file->filenum; srcpos_file = incl_file->file;
yyin = incl_file->file; yyin = incl_file->file ? incl_file->file->file : NULL;
/* /*
* Free old state. * Free old state.
*/ */
free(incl_file); free(incl_file);
if (YY_CURRENT_BUFFER == 0)
return 0;
return 1; return 1;
} }
...@@ -48,7 +48,8 @@ ...@@ -48,7 +48,8 @@
DT_BYTE = 264, DT_BYTE = 264,
DT_STRING = 265, DT_STRING = 265,
DT_LABEL = 266, DT_LABEL = 266,
DT_REF = 267 DT_REF = 267,
DT_INCBIN = 268
}; };
#endif #endif
/* Tokens. */ /* Tokens. */
...@@ -62,22 +63,23 @@ ...@@ -62,22 +63,23 @@
#define DT_STRING 265 #define DT_STRING 265
#define DT_LABEL 266 #define DT_LABEL 266
#define DT_REF 267 #define DT_REF 267
#define DT_INCBIN 268
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE typedef union YYSTYPE
#line 34 "dtc-parser.y" #line 37 "dtc-parser.y"
{ {
char *propnodename; char *propnodename;
char *literal; char *literal;
char *labelref; char *labelref;
unsigned int cbase; unsigned int cbase;
u8 byte; uint8_t byte;
struct data data; struct data data;
u64 addr; uint64_t addr;
cell_t cell; cell_t cell;
struct property *prop; struct property *prop;
struct property *proplist; struct property *proplist;
...@@ -86,7 +88,7 @@ typedef union YYSTYPE ...@@ -86,7 +88,7 @@ typedef union YYSTYPE
struct reserve_info *re; struct reserve_info *re;
} }
/* Line 1489 of yacc.c. */ /* Line 1489 of yacc.c. */
#line 90 "dtc-parser.tab.h" #line 92 "dtc-parser.tab.h"
YYSTYPE; YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_DECLARED 1
......
...@@ -21,14 +21,17 @@ ...@@ -21,14 +21,17 @@
%locations %locations
%{ %{
#include <stdio.h>
#include "dtc.h" #include "dtc.h"
#include "srcpos.h" #include "srcpos.h"
int yylex(void); extern int yylex(void);
unsigned long long eval_literal(const char *s, int base, int bits);
extern struct boot_info *the_boot_info; extern struct boot_info *the_boot_info;
extern int treesource_error;
static unsigned long long eval_literal(const char *s, int base, int bits);
%} %}
%union { %union {
...@@ -36,10 +39,10 @@ extern struct boot_info *the_boot_info; ...@@ -36,10 +39,10 @@ extern struct boot_info *the_boot_info;
char *literal; char *literal;
char *labelref; char *labelref;
unsigned int cbase; unsigned int cbase;
u8 byte; uint8_t byte;
struct data data; struct data data;
u64 addr; uint64_t addr;
cell_t cell; cell_t cell;
struct property *prop; struct property *prop;
struct property *proplist; struct property *proplist;
...@@ -58,6 +61,7 @@ extern struct boot_info *the_boot_info; ...@@ -58,6 +61,7 @@ extern struct boot_info *the_boot_info;
%token <data> DT_STRING %token <data> DT_STRING
%token <labelref> DT_LABEL %token <labelref> DT_LABEL
%token <labelref> DT_REF %token <labelref> DT_REF
%token DT_INCBIN
%type <data> propdata %type <data> propdata
%type <data> propdataprefix %type <data> propdataprefix
...@@ -84,11 +88,11 @@ extern struct boot_info *the_boot_info; ...@@ -84,11 +88,11 @@ extern struct boot_info *the_boot_info;
sourcefile: sourcefile:
DT_V1 ';' memreserves devicetree DT_V1 ';' memreserves devicetree
{ {
the_boot_info = build_boot_info($3, $4); the_boot_info = build_boot_info($3, $4, 0);
} }
| v0_memreserves devicetree | v0_memreserves devicetree
{ {
the_boot_info = build_boot_info($1, $2); the_boot_info = build_boot_info($1, $2, 0);
} }
; ;
...@@ -196,6 +200,34 @@ propdata: ...@@ -196,6 +200,34 @@ propdata:
{ {
$$ = data_add_marker($1, REF_PATH, $2); $$ = data_add_marker($1, REF_PATH, $2);
} }
| propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
{
struct search_path path = { srcpos_file->dir, NULL, NULL };
struct dtc_file *file = dtc_open_file($4.val, &path);
struct data d = empty_data;
if ($6 != 0)
if (fseek(file->file, $6, SEEK_SET) != 0)
yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6,
$4.val, strerror(errno));
d = data_copy_file(file->file, $8);
$$ = data_merge($1, d);
dtc_close_file(file);
}
| propdataprefix DT_INCBIN '(' DT_STRING ')'
{
struct search_path path = { srcpos_file->dir, NULL, NULL };
struct dtc_file *file = dtc_open_file($4.val, &path);
struct data d = empty_data;
d = data_copy_file(file->file, -1);
$$ = data_merge($1, d);
dtc_close_file(file);
}
| propdata DT_LABEL | propdata DT_LABEL
{ {
$$ = data_add_marker($1, LABEL, $2); $$ = data_add_marker($1, LABEL, $2);
...@@ -282,7 +314,7 @@ subnodes: ...@@ -282,7 +314,7 @@ subnodes:
} }
| subnode propdef | subnode propdef
{ {
yyerror("syntax error: properties must precede subnodes\n"); yyerror("syntax error: properties must precede subnodes");
YYERROR; YYERROR;
} }
; ;
...@@ -307,18 +339,29 @@ label: ...@@ -307,18 +339,29 @@ label:
%% %%
void yyerror (char const *s) void yyerrorf(char const *s, ...)
{ {
const char *fname = srcpos_filename_for_num(yylloc.filenum); const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
va_list va;
va_start(va, s);
if (strcmp(fname, "-") == 0) if (strcmp(fname, "-") == 0)
fname = "stdin"; fname = "stdin";
fprintf(stderr, "%s:%d %s\n", fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
fname, yylloc.first_line, s); vfprintf(stderr, s, va);
fprintf(stderr, "\n");
treesource_error = 1;
va_end(va);
}
void yyerror (char const *s)
{
yyerrorf("%s", s);
} }
unsigned long long eval_literal(const char *s, int base, int bits) static unsigned long long eval_literal(const char *s, int base, int bits)
{ {
unsigned long long val; unsigned long long val;
char *e; char *e;
......
...@@ -55,7 +55,7 @@ char *join_path(const char *path, const char *name) ...@@ -55,7 +55,7 @@ char *join_path(const char *path, const char *name)
return str; return str;
} }
void fill_fullpaths(struct node *tree, const char *prefix) static void fill_fullpaths(struct node *tree, const char *prefix)
{ {
struct node *child; struct node *child;
const char *unit; const char *unit;
...@@ -106,7 +106,7 @@ static void __attribute__ ((noreturn)) usage(void) ...@@ -106,7 +106,7 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
fprintf(stderr, "\t-v\n"); fprintf(stderr, "\t-v\n");
fprintf(stderr, "\t\tPrint DTC version and exit\n"); fprintf(stderr, "\t\tPrint DTC version and exit\n");
exit(2); exit(3);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
...@@ -118,10 +118,9 @@ int main(int argc, char *argv[]) ...@@ -118,10 +118,9 @@ int main(int argc, char *argv[])
int force = 0, check = 0; int force = 0, check = 0;
const char *arg; const char *arg;
int opt; int opt;
FILE *inf = NULL;
FILE *outf = NULL; FILE *outf = NULL;
int outversion = DEFAULT_FDT_VERSION; int outversion = DEFAULT_FDT_VERSION;
int boot_cpuid_phys = 0xfeedbeef; long long cmdline_boot_cpuid = -1;
quiet = 0; quiet = 0;
reservenum = 0; reservenum = 0;
...@@ -161,11 +160,11 @@ int main(int argc, char *argv[]) ...@@ -161,11 +160,11 @@ int main(int argc, char *argv[])
quiet++; quiet++;
break; break;
case 'b': case 'b':
boot_cpuid_phys = strtol(optarg, NULL, 0); cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
break; break;
case 'v': case 'v':
printf("Version: %s\n", DTC_VERSION); printf("Version: %s\n", DTC_VERSION);
exit(0); exit(0);
case 'h': case 'h':
default: default:
usage(); usage();
...@@ -180,31 +179,27 @@ int main(int argc, char *argv[]) ...@@ -180,31 +179,27 @@ int main(int argc, char *argv[])
arg = argv[optind]; arg = argv[optind];
/* minsize and padsize are mutually exclusive */ /* minsize and padsize are mutually exclusive */
if ((minsize) && (padsize)) { if (minsize && padsize)
die("Can't set both -p and -S\n"); die("Can't set both -p and -S\n");
}
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n", fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg); inform, outform, arg);
if (streq(inform, "dts")) { if (streq(inform, "dts"))
bi = dt_from_source(arg); bi = dt_from_source(arg);
} else if (streq(inform, "fs")) { else if (streq(inform, "fs"))
bi = dt_from_fs(arg); bi = dt_from_fs(arg);
} else if(streq(inform, "dtb")) { else if(streq(inform, "dtb"))
inf = dtc_open_file(arg); bi = dt_from_blob(arg);
bi = dt_from_blob(inf); else
} else {
die("Unknown input format \"%s\"\n", inform); die("Unknown input format \"%s\"\n", inform);
}
if (inf && (inf != stdin)) if (cmdline_boot_cpuid != -1)
fclose(inf); bi->boot_cpuid_phys = cmdline_boot_cpuid;
if (! bi || ! bi->dt) fill_fullpaths(bi->dt, "");
die("Couldn't read input tree\n"); process_checks(force, bi);
process_checks(force, bi, check, outversion, boot_cpuid_phys);
if (streq(outname, "-")) { if (streq(outname, "-")) {
outf = stdout; outf = stdout;
...@@ -218,9 +213,9 @@ int main(int argc, char *argv[]) ...@@ -218,9 +213,9 @@ int main(int argc, char *argv[])
if (streq(outform, "dts")) { if (streq(outform, "dts")) {
dt_to_source(outf, bi); dt_to_source(outf, bi);
} else if (streq(outform, "dtb")) { } else if (streq(outform, "dtb")) {
dt_to_blob(outf, bi, outversion, boot_cpuid_phys); dt_to_blob(outf, bi, outversion);
} else if (streq(outform, "asm")) { } else if (streq(outform, "asm")) {
dt_to_asm(outf, bi, outversion, boot_cpuid_phys); dt_to_asm(outf, bi, outversion);
} else if (streq(outform, "null")) { } else if (streq(outform, "null")) {
/* do nothing */ /* do nothing */
} else { } else {
......
...@@ -30,10 +30,8 @@ ...@@ -30,10 +30,8 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <netinet/in.h>
#include <endian.h>
#include <byteswap.h>
#include <libfdt_env.h>
#include <fdt.h> #include <fdt.h>
#define DEFAULT_FDT_VERSION 17 #define DEFAULT_FDT_VERSION 17
...@@ -75,25 +73,8 @@ static inline void *xrealloc(void *p, size_t len) ...@@ -75,25 +73,8 @@ static inline void *xrealloc(void *p, size_t len)
return new; return new;
} }
typedef uint8_t u8; typedef uint32_t cell_t;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef u32 cell_t;
#define cpu_to_be16(x) htons(x)
#define be16_to_cpu(x) ntohs(x)
#define cpu_to_be32(x) htonl(x)
#define be32_to_cpu(x) ntohl(x)
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be64(x) (x)
#define be64_to_cpu(x) (x)
#else
#define cpu_to_be64(x) bswap_64(x)
#define be64_to_cpu(x) bswap_64(x)
#endif
#define streq(a, b) (strcmp((a), (b)) == 0) #define streq(a, b) (strcmp((a), (b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
...@@ -118,7 +99,6 @@ struct marker { ...@@ -118,7 +99,6 @@ struct marker {
struct data { struct data {
int len; int len;
char *val; char *val;
int asize;
struct marker *markers; struct marker *markers;
}; };
...@@ -145,7 +125,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m, ...@@ -145,7 +125,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
struct data data_merge(struct data d1, struct data d2); struct data data_merge(struct data d1, struct data d2);
struct data data_append_cell(struct data d, cell_t word); struct data data_append_cell(struct data d, cell_t word);
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re); struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
struct data data_append_addr(struct data d, u64 addr); struct data data_append_addr(struct data d, uint64_t addr);
struct data data_append_byte(struct data d, uint8_t byte); struct data data_append_byte(struct data d, uint8_t byte);
struct data data_append_zeroes(struct data d, int len); struct data data_append_zeroes(struct data d, int len);
struct data data_append_align(struct data d, int align); struct data data_append_align(struct data d, int align);
...@@ -223,7 +203,7 @@ struct reserve_info { ...@@ -223,7 +203,7 @@ struct reserve_info {
char *label; char *label;
}; };
struct reserve_info *build_reserve_entry(u64 start, u64 len, char *label); struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label);
struct reserve_info *chain_reserve_entry(struct reserve_info *first, struct reserve_info *chain_reserve_entry(struct reserve_info *first,
struct reserve_info *list); struct reserve_info *list);
struct reserve_info *add_reserve_entry(struct reserve_info *list, struct reserve_info *add_reserve_entry(struct reserve_info *list,
...@@ -233,24 +213,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, ...@@ -233,24 +213,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct boot_info { struct boot_info {
struct reserve_info *reservelist; struct reserve_info *reservelist;
struct node *dt; /* the device tree */ struct node *dt; /* the device tree */
uint32_t boot_cpuid_phys;
}; };
struct boot_info *build_boot_info(struct reserve_info *reservelist, struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree); struct node *tree, uint32_t boot_cpuid_phys);
/* Checks */ /* Checks */
void process_checks(int force, struct boot_info *bi, void process_checks(int force, struct boot_info *bi);
int checkflag, int outversion, int boot_cpuid_phys);
/* Flattened trees */ /* Flattened trees */
void dt_to_blob(FILE *f, struct boot_info *bi, int version, void dt_to_blob(FILE *f, struct boot_info *bi, int version);
int boot_cpuid_phys); void dt_to_asm(FILE *f, struct boot_info *bi, int version);
void dt_to_asm(FILE *f, struct boot_info *bi, int version,
int boot_cpuid_phys);
struct boot_info *dt_from_blob(FILE *f); struct boot_info *dt_from_blob(const char *fname);
/* Tree source */ /* Tree source */
...@@ -264,6 +242,5 @@ struct boot_info *dt_from_fs(const char *dirname); ...@@ -264,6 +242,5 @@ struct boot_info *dt_from_fs(const char *dirname);
/* misc */ /* misc */
char *join_path(const char *path, const char *name); char *join_path(const char *path, const char *name);
void fill_fullpaths(struct node *tree, const char *prefix);
#endif /* _DTC_H */ #endif /* _DTC_H */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
*/ */
#include "dtc.h" #include "dtc.h"
#include "srcpos.h"
#define FTF_FULLPATH 0x1 #define FTF_FULLPATH 0x1
#define FTF_VARALIGN 0x2 #define FTF_VARALIGN 0x2
...@@ -162,28 +163,18 @@ static void asm_emit_data(void *e, struct data d) ...@@ -162,28 +163,18 @@ static void asm_emit_data(void *e, struct data d)
{ {
FILE *f = e; FILE *f = e;
int off = 0; int off = 0;
struct marker *m; struct marker *m = d.markers;
m = d.markers; for_each_marker_of_type(m, LABEL)
while (m) { emit_offset_label(f, m->ref, m->offset);
if (m->type == LABEL)
emit_offset_label(f, m->ref, m->offset);
m = m->next;
}
while ((d.len - off) >= sizeof(u32)) { while ((d.len - off) >= sizeof(uint32_t)) {
fprintf(f, "\t.long\t0x%x\n", fprintf(f, "\t.long\t0x%x\n",
be32_to_cpu(*((u32 *)(d.val+off)))); fdt32_to_cpu(*((uint32_t *)(d.val+off))));
off += sizeof(u32); off += sizeof(uint32_t);
}
if ((d.len - off) >= sizeof(u16)) {
fprintf(f, "\t.short\t0x%hx\n",
be16_to_cpu(*((u16 *)(d.val+off))));
off += sizeof(u16);
} }
if ((d.len - off) >= 1) { while ((d.len - off) >= 1) {
fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]); fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
off += 1; off += 1;
} }
...@@ -336,29 +327,28 @@ static void make_fdt_header(struct fdt_header *fdt, ...@@ -336,29 +327,28 @@ static void make_fdt_header(struct fdt_header *fdt,
memset(fdt, 0xff, sizeof(*fdt)); memset(fdt, 0xff, sizeof(*fdt));
fdt->magic = cpu_to_be32(FDT_MAGIC); fdt->magic = cpu_to_fdt32(FDT_MAGIC);
fdt->version = cpu_to_be32(vi->version); fdt->version = cpu_to_fdt32(vi->version);
fdt->last_comp_version = cpu_to_be32(vi->last_comp_version); fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
/* Reserve map should be doubleword aligned */ /* Reserve map should be doubleword aligned */
reserve_off = ALIGN(vi->hdr_size, 8); reserve_off = ALIGN(vi->hdr_size, 8);
fdt->off_mem_rsvmap = cpu_to_be32(reserve_off); fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
fdt->off_dt_struct = cpu_to_be32(reserve_off + reservesize); fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
fdt->off_dt_strings = cpu_to_be32(reserve_off + reservesize fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
+ dtsize); + dtsize);
fdt->totalsize = cpu_to_be32(reserve_off + reservesize + dtsize + strsize); fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
if (vi->flags & FTF_BOOTCPUID) if (vi->flags & FTF_BOOTCPUID)
fdt->boot_cpuid_phys = cpu_to_be32(boot_cpuid_phys); fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
if (vi->flags & FTF_STRTABSIZE) if (vi->flags & FTF_STRTABSIZE)
fdt->size_dt_strings = cpu_to_be32(strsize); fdt->size_dt_strings = cpu_to_fdt32(strsize);
if (vi->flags & FTF_STRUCTSIZE) if (vi->flags & FTF_STRUCTSIZE)
fdt->size_dt_struct = cpu_to_be32(dtsize); fdt->size_dt_struct = cpu_to_fdt32(dtsize);
} }
void dt_to_blob(FILE *f, struct boot_info *bi, int version, void dt_to_blob(FILE *f, struct boot_info *bi, int version)
int boot_cpuid_phys)
{ {
struct version_info *vi = NULL; struct version_info *vi = NULL;
int i; int i;
...@@ -383,26 +373,26 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version, ...@@ -383,26 +373,26 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
/* Make header */ /* Make header */
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len, make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
boot_cpuid_phys); bi->boot_cpuid_phys);
/* /*
* If the user asked for more space than is used, adjust the totalsize. * If the user asked for more space than is used, adjust the totalsize.
*/ */
if (minsize > 0) { if (minsize > 0) {
padlen = minsize - be32_to_cpu(fdt.totalsize); padlen = minsize - fdt32_to_cpu(fdt.totalsize);
if ((padlen < 0) && (quiet < 1)) if ((padlen < 0) && (quiet < 1))
fprintf(stderr, fprintf(stderr,
"Warning: blob size %d >= minimum size %d\n", "Warning: blob size %d >= minimum size %d\n",
be32_to_cpu(fdt.totalsize), minsize); fdt32_to_cpu(fdt.totalsize), minsize);
} }
if (padsize > 0) if (padsize > 0)
padlen = padsize; padlen = padsize;
if (padlen > 0) { if (padlen > 0) {
int tsize = be32_to_cpu(fdt.totalsize); int tsize = fdt32_to_cpu(fdt.totalsize);
tsize += padlen; tsize += padlen;
fdt.totalsize = cpu_to_be32(tsize); fdt.totalsize = cpu_to_fdt32(tsize);
} }
/* /*
...@@ -410,7 +400,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version, ...@@ -410,7 +400,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
* the reserve buffer, add the reserve map terminating zeroes, * the reserve buffer, add the reserve map terminating zeroes,
* the device tree itself, and finally the strings. * the device tree itself, and finally the strings.
*/ */
blob = data_append_data(blob, &fdt, sizeof(fdt)); blob = data_append_data(blob, &fdt, vi->hdr_size);
blob = data_append_align(blob, 8); blob = data_append_align(blob, 8);
blob = data_merge(blob, reservebuf); blob = data_merge(blob, reservebuf);
blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry)); blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
...@@ -449,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) ...@@ -449,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
} }
} }
void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys) void dt_to_asm(FILE *f, struct boot_info *bi, int version)
{ {
struct version_info *vi = NULL; struct version_info *vi = NULL;
int i; int i;
...@@ -489,7 +479,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys) ...@@ -489,7 +479,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
if (vi->flags & FTF_BOOTCPUID) if (vi->flags & FTF_BOOTCPUID)
fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n", fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
boot_cpuid_phys); bi->boot_cpuid_phys);
if (vi->flags & FTF_STRTABSIZE) if (vi->flags & FTF_STRTABSIZE)
fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n", fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
...@@ -579,15 +569,15 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len) ...@@ -579,15 +569,15 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
inb->ptr += len; inb->ptr += len;
} }
static u32 flat_read_word(struct inbuf *inb) static uint32_t flat_read_word(struct inbuf *inb)
{ {
u32 val; uint32_t val;
assert(((inb->ptr - inb->base) % sizeof(val)) == 0); assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
flat_read_chunk(inb, &val, sizeof(val)); flat_read_chunk(inb, &val, sizeof(val));
return be32_to_cpu(val); return fdt32_to_cpu(val);
} }
static void flat_realign(struct inbuf *inb, int align) static void flat_realign(struct inbuf *inb, int align)
...@@ -615,7 +605,7 @@ static char *flat_read_string(struct inbuf *inb) ...@@ -615,7 +605,7 @@ static char *flat_read_string(struct inbuf *inb)
inb->ptr += len; inb->ptr += len;
flat_realign(inb, sizeof(u32)); flat_realign(inb, sizeof(uint32_t));
return str; return str;
} }
...@@ -632,7 +622,7 @@ static struct data flat_read_data(struct inbuf *inb, int len) ...@@ -632,7 +622,7 @@ static struct data flat_read_data(struct inbuf *inb, int len)
flat_read_chunk(inb, d.val, len); flat_read_chunk(inb, d.val, len);
flat_realign(inb, sizeof(u32)); flat_realign(inb, sizeof(uint32_t));
return d; return d;
} }
...@@ -659,7 +649,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset) ...@@ -659,7 +649,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset)
static struct property *flat_read_property(struct inbuf *dtbuf, static struct property *flat_read_property(struct inbuf *dtbuf,
struct inbuf *strbuf, int flags) struct inbuf *strbuf, int flags)
{ {
u32 proplen, stroff; uint32_t proplen, stroff;
char *name; char *name;
struct data val; struct data val;
...@@ -693,8 +683,8 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) ...@@ -693,8 +683,8 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
p = inb->ptr; p = inb->ptr;
while (1) { while (1) {
flat_read_chunk(inb, &re, sizeof(re)); flat_read_chunk(inb, &re, sizeof(re));
re.address = be64_to_cpu(re.address); re.address = fdt64_to_cpu(re.address);
re.size = be64_to_cpu(re.size); re.size = fdt64_to_cpu(re.size);
if (re.size == 0) if (re.size == 0)
break; break;
...@@ -708,77 +698,37 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) ...@@ -708,77 +698,37 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
static char *nodename_from_path(const char *ppath, const char *cpath) static char *nodename_from_path(const char *ppath, const char *cpath)
{ {
const char *lslash;
int plen; int plen;
lslash = strrchr(cpath, '/'); plen = strlen(ppath);
if (! lslash)
return NULL;
plen = lslash - cpath;
if (streq(cpath, "/") && streq(ppath, ""))
return "";
if ((plen == 0) && streq(ppath, "/"))
return strdup(lslash+1);
if (! strneq(ppath, cpath, plen))
return NULL;
return strdup(lslash+1);
}
static const char PROPCHAR[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,._+*#?-";
static const char UNITCHAR[] = "0123456789abcdef,";
static int check_node_name(const char *name)
{
const char *atpos;
int basenamelen;
atpos = strrchr(name, '@'); if (!strneq(ppath, cpath, plen))
die("Path \"%s\" is not valid as a child of \"%s\"\n",
cpath, ppath);
if (atpos) /* root node is a special case */
basenamelen = atpos - name; if (!streq(ppath, "/"))
else plen++;
basenamelen = strlen(name);
if (strspn(name, PROPCHAR) < basenamelen)
return -1;
if (atpos return strdup(cpath + plen);
&& ((basenamelen + 1 + strspn(atpos+1, UNITCHAR)) < strlen(name)))
return -1;
return basenamelen;
} }
static struct node *unflatten_tree(struct inbuf *dtbuf, static struct node *unflatten_tree(struct inbuf *dtbuf,
struct inbuf *strbuf, struct inbuf *strbuf,
const char *parent_path, int flags) const char *parent_flatname, int flags)
{ {
struct node *node; struct node *node;
u32 val; char *flatname;
uint32_t val;
node = build_node(NULL, NULL); node = build_node(NULL, NULL);
if (flags & FTF_FULLPATH) { flatname = flat_read_string(dtbuf);
node->fullpath = flat_read_string(dtbuf);
node->name = nodename_from_path(parent_path, node->fullpath);
if (! node->name)
die("Path \"%s\" is not valid as a child of \"%s\"\n",
node->fullpath, parent_path);
} else {
node->name = flat_read_string(dtbuf);
node->fullpath = join_path(parent_path, node->name);
}
node->basenamelen = check_node_name(node->name); if (flags & FTF_FULLPATH)
if (node->basenamelen < 0) { node->name = nodename_from_path(parent_flatname, flatname);
fprintf(stderr, "Warning \"%s\" has incorrect format\n", node->name); else
} node->name = flatname;
do { do {
struct property *prop; struct property *prop;
...@@ -795,8 +745,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, ...@@ -795,8 +745,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
break; break;
case FDT_BEGIN_NODE: case FDT_BEGIN_NODE:
child = unflatten_tree(dtbuf,strbuf, node->fullpath, child = unflatten_tree(dtbuf,strbuf, flatname, flags);
flags);
add_child(node, child); add_child(node, child);
break; break;
...@@ -825,10 +774,11 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, ...@@ -825,10 +774,11 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
} }
struct boot_info *dt_from_blob(FILE *f) struct boot_info *dt_from_blob(const char *fname)
{ {
u32 magic, totalsize, version, size_str, size_dt; struct dtc_file *dtcf;
u32 off_dt, off_str, off_mem_rsvmap; uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
uint32_t off_dt, off_str, off_mem_rsvmap;
int rc; int rc;
char *blob; char *blob;
struct fdt_header *fdt; struct fdt_header *fdt;
...@@ -838,54 +788,56 @@ struct boot_info *dt_from_blob(FILE *f) ...@@ -838,54 +788,56 @@ struct boot_info *dt_from_blob(FILE *f)
int sizeleft; int sizeleft;
struct reserve_info *reservelist; struct reserve_info *reservelist;
struct node *tree; struct node *tree;
u32 val; uint32_t val;
int flags = 0; int flags = 0;
rc = fread(&magic, sizeof(magic), 1, f); dtcf = dtc_open_file(fname, NULL);
if (ferror(f))
rc = fread(&magic, sizeof(magic), 1, dtcf->file);
if (ferror(dtcf->file))
die("Error reading DT blob magic number: %s\n", die("Error reading DT blob magic number: %s\n",
strerror(errno)); strerror(errno));
if (rc < 1) { if (rc < 1) {
if (feof(f)) if (feof(dtcf->file))
die("EOF reading DT blob magic number\n"); die("EOF reading DT blob magic number\n");
else else
die("Mysterious short read reading magic number\n"); die("Mysterious short read reading magic number\n");
} }
magic = be32_to_cpu(magic); magic = fdt32_to_cpu(magic);
if (magic != FDT_MAGIC) if (magic != FDT_MAGIC)
die("Blob has incorrect magic number\n"); die("Blob has incorrect magic number\n");
rc = fread(&totalsize, sizeof(totalsize), 1, f); rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
if (ferror(f)) if (ferror(dtcf->file))
die("Error reading DT blob size: %s\n", strerror(errno)); die("Error reading DT blob size: %s\n", strerror(errno));
if (rc < 1) { if (rc < 1) {
if (feof(f)) if (feof(dtcf->file))
die("EOF reading DT blob size\n"); die("EOF reading DT blob size\n");
else else
die("Mysterious short read reading blob size\n"); die("Mysterious short read reading blob size\n");
} }
totalsize = be32_to_cpu(totalsize); totalsize = fdt32_to_cpu(totalsize);
if (totalsize < FDT_V1_SIZE) if (totalsize < FDT_V1_SIZE)
die("DT blob size (%d) is too small\n", totalsize); die("DT blob size (%d) is too small\n", totalsize);
blob = xmalloc(totalsize); blob = xmalloc(totalsize);
fdt = (struct fdt_header *)blob; fdt = (struct fdt_header *)blob;
fdt->magic = cpu_to_be32(magic); fdt->magic = cpu_to_fdt32(magic);
fdt->totalsize = cpu_to_be32(totalsize); fdt->totalsize = cpu_to_fdt32(totalsize);
sizeleft = totalsize - sizeof(magic) - sizeof(totalsize); sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
p = blob + sizeof(magic) + sizeof(totalsize); p = blob + sizeof(magic) + sizeof(totalsize);
while (sizeleft) { while (sizeleft) {
if (feof(f)) if (feof(dtcf->file))
die("EOF before reading %d bytes of DT blob\n", die("EOF before reading %d bytes of DT blob\n",
totalsize); totalsize);
rc = fread(p, 1, sizeleft, f); rc = fread(p, 1, sizeleft, dtcf->file);
if (ferror(f)) if (ferror(dtcf->file))
die("Error reading DT blob: %s\n", die("Error reading DT blob: %s\n",
strerror(errno)); strerror(errno));
...@@ -893,19 +845,11 @@ struct boot_info *dt_from_blob(FILE *f) ...@@ -893,19 +845,11 @@ struct boot_info *dt_from_blob(FILE *f)
p += rc; p += rc;
} }
off_dt = be32_to_cpu(fdt->off_dt_struct); off_dt = fdt32_to_cpu(fdt->off_dt_struct);
off_str = be32_to_cpu(fdt->off_dt_strings); off_str = fdt32_to_cpu(fdt->off_dt_strings);
off_mem_rsvmap = be32_to_cpu(fdt->off_mem_rsvmap); off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
version = be32_to_cpu(fdt->version); version = fdt32_to_cpu(fdt->version);
boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
fprintf(stderr, "\tmagic:\t\t\t0x%x\n", magic);
fprintf(stderr, "\ttotalsize:\t\t%d\n", totalsize);
fprintf(stderr, "\toff_dt_struct:\t\t0x%x\n", off_dt);
fprintf(stderr, "\toff_dt_strings:\t\t0x%x\n", off_str);
fprintf(stderr, "\toff_mem_rsvmap:\t\t0x%x\n", off_mem_rsvmap);
fprintf(stderr, "\tversion:\t\t0x%x\n", version );
fprintf(stderr, "\tlast_comp_version:\t0x%x\n",
be32_to_cpu(fdt->last_comp_version));
if (off_mem_rsvmap >= totalsize) if (off_mem_rsvmap >= totalsize)
die("Mem Reserve structure offset exceeds total size\n"); die("Mem Reserve structure offset exceeds total size\n");
...@@ -916,21 +860,17 @@ struct boot_info *dt_from_blob(FILE *f) ...@@ -916,21 +860,17 @@ struct boot_info *dt_from_blob(FILE *f)
if (off_str > totalsize) if (off_str > totalsize)
die("String table offset exceeds total size\n"); die("String table offset exceeds total size\n");
if (version >= 2)
fprintf(stderr, "\tboot_cpuid_phys:\t0x%x\n",
be32_to_cpu(fdt->boot_cpuid_phys));
size_str = -1;
if (version >= 3) { if (version >= 3) {
size_str = be32_to_cpu(fdt->size_dt_strings); uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
fprintf(stderr, "\tsize_dt_strings:\t%d\n", size_str);
if (off_str+size_str > totalsize) if (off_str+size_str > totalsize)
die("String table extends past total size\n"); die("String table extends past total size\n");
inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
} else {
inbuf_init(&strbuf, blob + off_str, blob + totalsize);
} }
if (version >= 17) { if (version >= 17) {
size_dt = be32_to_cpu(fdt->size_dt_struct); size_dt = fdt32_to_cpu(fdt->size_dt_struct);
fprintf(stderr, "\tsize_dt_struct:\t\t%d\n", size_dt);
if (off_dt+size_dt > totalsize) if (off_dt+size_dt > totalsize)
die("Structure block extends past total size\n"); die("Structure block extends past total size\n");
} }
...@@ -944,10 +884,6 @@ struct boot_info *dt_from_blob(FILE *f) ...@@ -944,10 +884,6 @@ struct boot_info *dt_from_blob(FILE *f)
inbuf_init(&memresvbuf, inbuf_init(&memresvbuf,
blob + off_mem_rsvmap, blob + totalsize); blob + off_mem_rsvmap, blob + totalsize);
inbuf_init(&dtbuf, blob + off_dt, blob + totalsize); inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
if (size_str >= 0)
inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
else
inbuf_init(&strbuf, blob + off_str, blob + totalsize);
reservelist = flat_read_mem_reserve(&memresvbuf); reservelist = flat_read_mem_reserve(&memresvbuf);
...@@ -964,5 +900,7 @@ struct boot_info *dt_from_blob(FILE *f) ...@@ -964,5 +900,7 @@ struct boot_info *dt_from_blob(FILE *f)
free(blob); free(blob);
return build_boot_info(reservelist, tree); dtc_close_file(dtcf);
return build_boot_info(reservelist, tree, boot_cpuid_phys);
} }
...@@ -31,8 +31,8 @@ static struct node *read_fstree(const char *dirname) ...@@ -31,8 +31,8 @@ static struct node *read_fstree(const char *dirname)
struct node *tree; struct node *tree;
d = opendir(dirname); d = opendir(dirname);
if (! d) if (!d)
die("opendir(): %s\n", strerror(errno)); die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
tree = build_node(NULL, NULL); tree = build_node(NULL, NULL);
...@@ -87,8 +87,6 @@ struct boot_info *dt_from_fs(const char *dirname) ...@@ -87,8 +87,6 @@ struct boot_info *dt_from_fs(const char *dirname)
tree = read_fstree(dirname); tree = read_fstree(dirname);
tree = name_node(tree, "", NULL); tree = name_node(tree, "", NULL);
fill_fullpaths(tree, ""); return build_boot_info(NULL, tree, 0);
return build_boot_info(NULL, tree);
} }
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define _B(n) ((unsigned long long)((uint8_t *)&x)[n])
static inline uint32_t fdt32_to_cpu(uint32_t x)
{
return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3);
}
#define cpu_to_fdt32(x) fdt32_to_cpu(x)
static inline uint64_t fdt64_to_cpu(uint64_t x)
{
return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
| (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
}
#define cpu_to_fdt64(x) fdt64_to_cpu(x)
#undef _B
#endif /* _LIBFDT_ENV_H */
...@@ -115,6 +115,7 @@ void add_child(struct node *parent, struct node *child) ...@@ -115,6 +115,7 @@ void add_child(struct node *parent, struct node *child)
struct node **p; struct node **p;
child->next_sibling = NULL; child->next_sibling = NULL;
child->parent = parent;
p = &parent->children; p = &parent->children;
while (*p) while (*p)
...@@ -123,7 +124,8 @@ void add_child(struct node *parent, struct node *child) ...@@ -123,7 +124,8 @@ void add_child(struct node *parent, struct node *child)
*p = child; *p = child;
} }
struct reserve_info *build_reserve_entry(u64 address, u64 size, char *label) struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size,
char *label)
{ {
struct reserve_info *new = xmalloc(sizeof(*new)); struct reserve_info *new = xmalloc(sizeof(*new));
...@@ -165,13 +167,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, ...@@ -165,13 +167,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
} }
struct boot_info *build_boot_info(struct reserve_info *reservelist, struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree) struct node *tree, uint32_t boot_cpuid_phys)
{ {
struct boot_info *bi; struct boot_info *bi;
bi = xmalloc(sizeof(*bi)); bi = xmalloc(sizeof(*bi));
bi->reservelist = reservelist; bi->reservelist = reservelist;
bi->dt = tree; bi->dt = tree;
bi->boot_cpuid_phys = boot_cpuid_phys;
return bi; return bi;
} }
...@@ -202,7 +205,7 @@ struct property *get_property(struct node *node, const char *propname) ...@@ -202,7 +205,7 @@ struct property *get_property(struct node *node, const char *propname)
cell_t propval_cell(struct property *prop) cell_t propval_cell(struct property *prop)
{ {
assert(prop->val.len == sizeof(cell_t)); assert(prop->val.len == sizeof(cell_t));
return be32_to_cpu(*((cell_t *)prop->val.val)); return fdt32_to_cpu(*((cell_t *)prop->val.val));
} }
struct node *get_subnode(struct node *node, const char *nodename) struct node *get_subnode(struct node *node, const char *nodename)
......
...@@ -20,86 +20,97 @@ ...@@ -20,86 +20,97 @@
#include "dtc.h" #include "dtc.h"
#include "srcpos.h" #include "srcpos.h"
/*
* Record the complete unique set of opened file names.
* Primarily used to cache source position file names.
*/
#define MAX_N_FILE_NAMES (100)
const char *file_names[MAX_N_FILE_NAMES];
static int n_file_names = 0;
/* /*
* Like yylineno, this is the current open file pos. * Like yylineno, this is the current open file pos.
*/ */
int srcpos_filenum = -1; struct dtc_file *srcpos_file;
static int dtc_open_one(struct dtc_file *file,
FILE *dtc_open_file(const char *fname) const char *search,
const char *fname)
{ {
FILE *f; char *fullname;
if (lookup_file_name(fname, 1) < 0) if (search) {
die("Too many files opened\n"); fullname = xmalloc(strlen(search) + strlen(fname) + 2);
if (streq(fname, "-")) strcpy(fullname, search);
f = stdin; strcat(fullname, "/");
else strcat(fullname, fname);
f = fopen(fname, "r"); } else {
fullname = strdup(fname);
}
if (! f) file->file = fopen(fullname, "r");
die("Couldn't open \"%s\": %s\n", fname, strerror(errno)); if (!file->file) {
free(fullname);
return 0;
}
return f; file->name = fullname;
return 1;
} }
struct dtc_file *dtc_open_file(const char *fname,
const struct search_path *search)
{
static const struct search_path default_search = { NULL, NULL, NULL };
/* struct dtc_file *file;
* Locate and optionally add filename fname in the file_names[] array. const char *slash;
*
* If the filename is currently not in the array and the boolean
* add_it is non-zero, an attempt to add the filename will be made.
*
* Returns;
* Index [0..MAX_N_FILE_NAMES) where the filename is kept
* -1 if the name can not be recorded
*/
int lookup_file_name(const char *fname, int add_it) file = xmalloc(sizeof(struct dtc_file));
{
int i;
for (i = 0; i < n_file_names; i++) { slash = strrchr(fname, '/');
if (strcmp(file_names[i], fname) == 0) if (slash) {
return i; char *dir = xmalloc(slash - fname + 1);
memcpy(dir, fname, slash - fname);
dir[slash - fname] = 0;
file->dir = dir;
} else {
file->dir = NULL;
} }
if (add_it) { if (streq(fname, "-")) {
if (n_file_names < MAX_N_FILE_NAMES) { file->name = "stdin";
file_names[n_file_names] = strdup(fname); file->file = stdin;
return n_file_names++; return file;
}
} }
return -1; if (fname[0] == '/') {
} file->file = fopen(fname, "r");
if (!file->file)
goto fail;
file->name = strdup(fname);
return file;
}
if (!search)
search = &default_search;
const char *srcpos_filename_for_num(int filenum) while (search) {
{ if (dtc_open_one(file, search->dir, fname))
if (0 <= filenum && filenum < n_file_names) { return file;
return file_names[filenum];
if (errno != ENOENT)
goto fail;
search = search->next;
} }
return 0; fail:
die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
} }
void dtc_close_file(struct dtc_file *file)
const char *srcpos_get_filename(void)
{ {
return srcpos_filename_for_num(srcpos_filenum); if (fclose(file->file))
die("Error closing \"%s\": %s\n", file->name, strerror(errno));
free(file->dir);
free(file);
} }
...@@ -22,13 +22,21 @@ ...@@ -22,13 +22,21 @@
* array of all opened filenames. * array of all opened filenames.
*/ */
#include <stdio.h>
struct dtc_file {
char *dir;
const char *name;
FILE *file;
};
#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED) #if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED)
typedef struct YYLTYPE { typedef struct YYLTYPE {
int first_line; int first_line;
int first_column; int first_column;
int last_line; int last_line;
int last_column; int last_column;
int filenum; struct dtc_file *file;
} YYLTYPE; } YYLTYPE;
#define YYLTYPE_IS_DECLARED 1 #define YYLTYPE_IS_DECLARED 1
...@@ -48,7 +56,7 @@ typedef struct YYLTYPE { ...@@ -48,7 +56,7 @@ typedef struct YYLTYPE {
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
(Current).filenum = YYRHSLOC (Rhs, N).filenum; \ (Current).file = YYRHSLOC (Rhs, N).file; \
} \ } \
else \ else \
{ \ { \
...@@ -56,20 +64,22 @@ typedef struct YYLTYPE { ...@@ -56,20 +64,22 @@ typedef struct YYLTYPE {
YYRHSLOC (Rhs, 0).last_line; \ YYRHSLOC (Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \ (Current).first_column = (Current).last_column = \
YYRHSLOC (Rhs, 0).last_column; \ YYRHSLOC (Rhs, 0).last_column; \
(Current).filenum = YYRHSLOC (Rhs, 0).filenum; \ (Current).file = YYRHSLOC (Rhs, 0).file; \
} \ } \
while (YYID (0)) while (YYID (0))
extern void yyerror(char const *); extern void yyerror(char const *);
extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2)));
extern int srcpos_filenum; extern struct dtc_file *srcpos_file;
extern int push_input_file(const char *filename); struct search_path {
extern int pop_input_file(void); const char *dir; /* NULL for current directory */
struct search_path *prev, *next;
};
extern FILE *dtc_open_file(const char *fname); extern struct dtc_file *dtc_open_file(const char *fname,
extern int lookup_file_name(const char *fname, int add_it); const struct search_path *search);
extern const char *srcpos_filename_for_num(int filenum); extern void dtc_close_file(struct dtc_file *file);
const char *srcpos_get_filename(void);
...@@ -23,20 +23,23 @@ ...@@ -23,20 +23,23 @@
extern FILE *yyin; extern FILE *yyin;
extern int yyparse(void); extern int yyparse(void);
extern void yyerror(char const *);
struct boot_info *the_boot_info; struct boot_info *the_boot_info;
int treesource_error;
struct boot_info *dt_from_source(const char *fname) struct boot_info *dt_from_source(const char *fname)
{ {
the_boot_info = NULL; the_boot_info = NULL;
treesource_error = 0;
push_input_file(fname); srcpos_file = dtc_open_file(fname, NULL);
yyin = srcpos_file->file;
if (yyparse() != 0) if (yyparse() != 0)
return NULL; die("Unable to parse input tree\n");
fill_fullpaths(the_boot_info->dt, ""); if (treesource_error)
die("Syntax error parsing input tree\n");
return the_boot_info; return the_boot_info;
} }
...@@ -144,7 +147,7 @@ static void write_propval_cells(FILE *f, struct data val) ...@@ -144,7 +147,7 @@ static void write_propval_cells(FILE *f, struct data val)
m = m->next; m = m->next;
} }
fprintf(f, "0x%x", be32_to_cpu(*cp++)); fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
if ((void *)cp >= propend) if ((void *)cp >= propend)
break; break;
fprintf(f, " "); fprintf(f, " ");
...@@ -173,7 +176,7 @@ static void write_propval_bytes(FILE *f, struct data val) ...@@ -173,7 +176,7 @@ static void write_propval_bytes(FILE *f, struct data val)
} }
fprintf(f, "%02hhx", *bp++); fprintf(f, "%02hhx", *bp++);
if ((void *)bp >= propend) if ((const void *)bp >= propend)
break; break;
fprintf(f, " "); fprintf(f, " ");
} }
......
#define DTC_VERSION "DTC 1.0.0-gd6f9b62f" #define DTC_VERSION "DTC 1.2.0"
/*
* Device Tree Source for AMCC Arches (dual 460GT board)
*
* (C) Copyright 2008 Applied Micro Circuits Corporation
* Victor Gallardo <vgallardo@amcc.com>
* Adam Graham <agraham@amcc.com>
*
* Based on the glacier.dts file
* Stefan Roese <sr@denx.de>
* Copyright 2008 DENX Software Engineering
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/dts-v1/;
/ {
#address-cells = <2>;
#size-cells = <1>;
model = "amcc,arches";
compatible = "amcc,arches";
dcr-parent = <&{/cpus/cpu@0}>;
aliases {
ethernet0 = &EMAC0;
ethernet1 = &EMAC1;
ethernet2 = &EMAC2;
serial0 = &UART0;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
model = "PowerPC,460GT";
reg = <0x00000000>;
clock-frequency = <0>; /* Filled in by U-Boot */
timebase-frequency = <0>; /* Filled in by U-Boot */
i-cache-line-size = <32>;
d-cache-line-size = <32>;
i-cache-size = <32768>;
d-cache-size = <32768>;
dcr-controller;
dcr-access-method = "native";
};
};
memory {
device_type = "memory";
reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
};
UIC0: interrupt-controller0 {
compatible = "ibm,uic-460gt","ibm,uic";
interrupt-controller;
cell-index = <0>;
dcr-reg = <0x0c0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
};
UIC1: interrupt-controller1 {
compatible = "ibm,uic-460gt","ibm,uic";
interrupt-controller;
cell-index = <1>;
dcr-reg = <0x0d0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
UIC2: interrupt-controller2 {
compatible = "ibm,uic-460gt","ibm,uic";
interrupt-controller;
cell-index = <2>;
dcr-reg = <0x0e0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
UIC3: interrupt-controller3 {
compatible = "ibm,uic-460gt","ibm,uic";
interrupt-controller;
cell-index = <3>;
dcr-reg = <0x0f0 0x009>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
interrupt-parent = <&UIC0>;
};
SDR0: sdr {
compatible = "ibm,sdr-460gt";
dcr-reg = <0x00e 0x002>;
};
CPR0: cpr {
compatible = "ibm,cpr-460gt";
dcr-reg = <0x00c 0x002>;
};
plb {
compatible = "ibm,plb-460gt", "ibm,plb4";
#address-cells = <2>;
#size-cells = <1>;
ranges;
clock-frequency = <0>; /* Filled in by U-Boot */
SDRAM0: sdram {
compatible = "ibm,sdram-460gt", "ibm,sdram-405gp";
dcr-reg = <0x010 0x002>;
};
MAL0: mcmal {
compatible = "ibm,mcmal-460gt", "ibm,mcmal2";
dcr-reg = <0x180 0x062>;
num-tx-chans = <3>;
num-rx-chans = <24>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-parent = <&UIC2>;
interrupts = < /*TXEOB*/ 0x6 0x4
/*RXEOB*/ 0x7 0x4
/*SERR*/ 0x3 0x4
/*TXDE*/ 0x4 0x4
/*RXDE*/ 0x5 0x4>;
desc-base-addr-high = <0x8>;
};
POB0: opb {
compatible = "ibm,opb-460gt", "ibm,opb";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
clock-frequency = <0>; /* Filled in by U-Boot */
EBC0: ebc {
compatible = "ibm,ebc-460gt", "ibm,ebc";
dcr-reg = <0x012 0x002>;
#address-cells = <2>;
#size-cells = <1>;
clock-frequency = <0>; /* Filled in by U-Boot */
/* ranges property is supplied by U-Boot */
interrupts = <0x6 0x4>;
interrupt-parent = <&UIC1>;
};
UART0: serial@ef600300 {
device_type = "serial";
compatible = "ns16550";
reg = <0xef600300 0x00000008>;
virtual-reg = <0xef600300>;
clock-frequency = <0>; /* Filled in by U-Boot */
current-speed = <0>; /* Filled in by U-Boot */
interrupt-parent = <&UIC1>;
interrupts = <0x1 0x4>;
};
IIC0: i2c@ef600700 {
compatible = "ibm,iic-460gt", "ibm,iic";
reg = <0xef600700 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x2 0x4>;
};
IIC1: i2c@ef600800 {
compatible = "ibm,iic-460gt", "ibm,iic";
reg = <0xef600800 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x3 0x4>;
};
TAH0: emac-tah@ef601350 {
compatible = "ibm,tah-460gt", "ibm,tah";
reg = <0xef601350 0x00000030>;
};
TAH1: emac-tah@ef601450 {
compatible = "ibm,tah-460gt", "ibm,tah";
reg = <0xef601450 0x00000030>;
};
EMAC0: ethernet@ef600e00 {
device_type = "network";
compatible = "ibm,emac-460gt", "ibm,emac4sync";
interrupt-parent = <&EMAC0>;
interrupts = <0x0 0x1>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
/*Wake*/ 0x1 &UIC2 0x14 0x4>;
reg = <0xef600e00 0x000000c4>;
local-mac-address = [000000000000]; /* Filled in by U-Boot */
mal-device = <&MAL0>;
mal-tx-channel = <0>;
mal-rx-channel = <0>;
cell-index = <0>;
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
phy-mode = "sgmii";
phy-map = <0xffffffff>;
gpcs-address = <0x0000000a>;
tah-device = <&TAH0>;
tah-channel = <0>;
has-inverted-stacr-oc;
has-new-stacr-staopc;
};
EMAC1: ethernet@ef600f00 {
device_type = "network";
compatible = "ibm,emac-460gt", "ibm,emac4sync";
interrupt-parent = <&EMAC1>;
interrupts = <0x0 0x1>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
/*Wake*/ 0x1 &UIC2 0x15 0x4>;
reg = <0xef600f00 0x000000c4>;
local-mac-address = [000000000000]; /* Filled in by U-Boot */
mal-device = <&MAL0>;
mal-tx-channel = <1>;
mal-rx-channel = <8>;
cell-index = <1>;
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
phy-mode = "sgmii";
phy-map = <0x00000000>;
gpcs-address = <0x0000000b>;
tah-device = <&TAH1>;
tah-channel = <1>;
has-inverted-stacr-oc;
has-new-stacr-staopc;
mdio-device = <&EMAC0>;
};
EMAC2: ethernet@ef601100 {
device_type = "network";
compatible = "ibm,emac-460gt", "ibm,emac4sync";
interrupt-parent = <&EMAC2>;
interrupts = <0x0 0x1>;
#interrupt-cells = <1>;
#address-cells = <0>;
#size-cells = <0>;
interrupt-map = </*Status*/ 0x0 &UIC2 0x12 0x4
/*Wake*/ 0x1 &UIC2 0x16 0x4>;
reg = <0xef601100 0x000000c4>;
local-mac-address = [000000000000]; /* Filled in by U-Boot */
mal-device = <&MAL0>;
mal-tx-channel = <2>;
mal-rx-channel = <16>;
cell-index = <2>;
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
phy-mode = "sgmii";
phy-map = <0x00000001>;
gpcs-address = <0x0000000C>;
has-inverted-stacr-oc;
has-new-stacr-staopc;
mdio-device = <&EMAC0>;
};
};
};
};
...@@ -130,24 +130,28 @@ ...@@ -130,24 +130,28 @@
dma-channel@0 { dma-channel@0 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>; reg = <0 0x80>;
cell-index = <0>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@80 { dma-channel@80 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>; reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@100 { dma-channel@100 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>; reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@180 { dma-channel@180 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>; reg = <0x180 0x28>;
cell-index = <3>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
......
/*
* GE Fanuc SBC610 Device Tree Source
*
* Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* Based on: SBS CM6 Device Tree Source
* Copyright 2007 SBS Technologies GmbH & Co. KG
* And: mpc8641_hpcn.dts (MPC8641 HPCN Device Tree Source)
* Copyright 2006 Freescale Semiconductor Inc.
*/
/*
* Compiled with dtc -I dts -O dtb -o gef_sbc610.dtb gef_sbc610.dts
*/
/dts-v1/;
/ {
model = "GEF_SBC610";
compatible = "gef,sbc610";
#address-cells = <1>;
#size-cells = <1>;
aliases {
ethernet0 = &enet0;
ethernet1 = &enet1;
serial0 = &serial0;
serial1 = &serial1;
pci0 = &pci0;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,8641@0 {
device_type = "cpu";
reg = <0>;
d-cache-line-size = <32>; // 32 bytes
i-cache-line-size = <32>; // 32 bytes
d-cache-size = <32768>; // L1, 32K
i-cache-size = <32768>; // L1, 32K
timebase-frequency = <0>; // From uboot
bus-frequency = <0>; // From uboot
clock-frequency = <0>; // From uboot
};
PowerPC,8641@1 {
device_type = "cpu";
reg = <1>;
d-cache-line-size = <32>; // 32 bytes
i-cache-line-size = <32>; // 32 bytes
d-cache-size = <32768>; // L1, 32K
i-cache-size = <32768>; // L1, 32K
timebase-frequency = <0>; // From uboot
bus-frequency = <0>; // From uboot
clock-frequency = <0>; // From uboot
};
};
memory {
device_type = "memory";
reg = <0x0 0x40000000>; // set by uboot
};
localbus@fef05000 {
#address-cells = <2>;
#size-cells = <1>;
compatible = "fsl,mpc8641-localbus", "simple-bus";
reg = <0xf8005000 0x1000>;
interrupts = <19 2>;
interrupt-parent = <&mpic>;
ranges = <0 0 0xff000000 0x01000000 // 16MB Boot flash
1 0 0xe8000000 0x08000000 // Paged Flash 0
2 0 0xe0000000 0x08000000 // Paged Flash 1
3 0 0xfc100000 0x00020000 // NVRAM
4 0 0xfc000000 0x00008000 // FPGA
5 0 0xfc008000 0x00008000 // AFIX FPGA
6 0 0xfd000000 0x00800000 // IO FPGA (8-bit)
7 0 0xfd800000 0x00800000>; // IO FPGA (32-bit)
fpga@4,0 {
compatible = "gef,fpga-regs";
reg = <0x4 0x0 0x40>;
};
gef_pic: pic@4,4000 {
#interrupt-cells = <1>;
interrupt-controller;
compatible = "gef,fpga-pic";
reg = <0x4 0x4000 0x20>;
interrupts = <0x8
0x9>;
interrupt-parent = <&mpic>;
};
};
soc@fef00000 {
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xfef00000 0x00100000>;
reg = <0xfef00000 0x100000>; // CCSRBAR 1M
bus-frequency = <0>;
i2c1: i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl-i2c";
reg = <0x3000 0x100>;
interrupts = <0x2b 0x2>;
interrupt-parent = <&mpic>;
dfsrr;
eti@6b {
compatible = "dallas,ds1682";
reg = <0x6b>;
};
};
i2c2: i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <0x2b 0x2>;
interrupt-parent = <&mpic>;
dfsrr;
};
dma@21300 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,mpc8641-dma", "fsl,eloplus-dma";
reg = <0x21300 0x4>;
ranges = <0x0 0x21100 0x200>;
cell-index = <0>;
dma-channel@0 {
compatible = "fsl,mpc8641-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
interrupt-parent = <&mpic>;
interrupts = <20 2>;
};
dma-channel@80 {
compatible = "fsl,mpc8641-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&mpic>;
interrupts = <21 2>;
};
dma-channel@100 {
compatible = "fsl,mpc8641-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&mpic>;
interrupts = <22 2>;
};
dma-channel@180 {
compatible = "fsl,mpc8641-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
interrupt-parent = <&mpic>;
interrupts = <23 2>;
};
};
mdio@24520 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,gianfar-mdio";
reg = <0x24520 0x20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&gef_pic>;
interrupts = <0x9 0x4>;
reg = <1>;
};
phy2: ethernet-phy@2 {
interrupt-parent = <&gef_pic>;
interrupts = <0x8 0x4>;
reg = <3>;
};
};
enet0: ethernet@24000 {
device_type = "network";
model = "eTSEC";
compatible = "gianfar";
reg = <0x24000 0x1000>;
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
phy-connection-type = "gmii";
};
enet1: ethernet@26000 {
device_type = "network";
model = "eTSEC";
compatible = "gianfar";
reg = <0x26000 0x1000>;
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <0x1f 0x2 0x20 0x2 0x21 0x2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy2>;
phy-connection-type = "gmii";
};
serial0: serial@4500 {
cell-index = <0>;
device_type = "serial";
compatible = "ns16550";
reg = <0x4500 0x100>;
clock-frequency = <0>;
interrupts = <0x2a 0x2>;
interrupt-parent = <&mpic>;
};
serial1: serial@4600 {
cell-index = <1>;
device_type = "serial";
compatible = "ns16550";
reg = <0x4600 0x100>;
clock-frequency = <0>;
interrupts = <0x1c 0x2>;
interrupt-parent = <&mpic>;
};
mpic: pic@40000 {
clock-frequency = <0>;
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
reg = <0x40000 0x40000>;
compatible = "chrp,open-pic";
device_type = "open-pic";
};
global-utilities@e0000 {
compatible = "fsl,mpc8641-guts";
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
};
pci0: pcie@fef08000 {
compatible = "fsl,mpc8641-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0xfef08000 0x1000>;
bus-range = <0x0 0xff>;
ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x40000000
0x01000000 0x0 0x00000000 0xfe000000 0x0 0x00400000>;
clock-frequency = <33333333>;
interrupt-parent = <&mpic>;
interrupts = <0x18 0x2>;
interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
interrupt-map = <
0x0000 0x0 0x0 0x1 &mpic 0x0 0x1
0x0000 0x0 0x0 0x2 &mpic 0x1 0x1
0x0000 0x0 0x0 0x3 &mpic 0x2 0x1
0x0000 0x0 0x0 0x4 &mpic 0x3 0x1
>;
pcie@0 {
reg = <0 0 0 0 0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x02000000 0x0 0x80000000
0x02000000 0x0 0x80000000
0x0 0x40000000
0x01000000 0x0 0x00000000
0x01000000 0x0 0x00000000
0x0 0x00400000>;
};
};
};
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#address-cells = <2>; #address-cells = <2>;
#size-cells = <1>; #size-cells = <1>;
model = "amcc,glacier"; model = "amcc,glacier";
compatible = "amcc,glacier", "amcc,canyonlands"; compatible = "amcc,glacier";
dcr-parent = <&{/cpus/cpu@0}>; dcr-parent = <&{/cpus/cpu@0}>;
aliases { aliases {
......
/*
* Device Tree for the MGCOGE plattform from keymile
*
* Copyright 2008 DENX Software Engineering GmbH
* Heiko Schocher <hs@denx.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
/dts-v1/;
/ {
model = "MGCOGE";
compatible = "keymile,mgcoge";
#address-cells = <1>;
#size-cells = <1>;
aliases {
ethernet0 = &eth0;
serial0 = &smc2;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,8247@0 {
device_type = "cpu";
reg = <0>;
d-cache-line-size = <32>;
i-cache-line-size = <32>;
d-cache-size = <16384>;
i-cache-size = <16384>;
timebase-frequency = <0>; /* Filled in by U-Boot */
clock-frequency = <0>; /* Filled in by U-Boot */
bus-frequency = <0>; /* Filled in by U-Boot */
};
};
localbus@f0010100 {
compatible = "fsl,mpc8247-localbus",
"fsl,pq2-localbus",
"simple-bus";
#address-cells = <2>;
#size-cells = <1>;
reg = <0xf0010100 0x40>;
ranges = <0 0 0xfe000000 0x00400000
5 0 0x50000000 0x20000000
>; /* Filled in by U-Boot */
flash@0,0 {
compatible = "cfi-flash";
reg = <0 0x0 0x400000>;
#address-cells = <1>;
#size-cells = <1>;
bank-width = <1>;
device-width = <1>;
partition@0 {
label = "u-boot";
reg = <0 0x40000>;
};
partition@40000 {
label = "env";
reg = <0x40000 0x20000>;
};
partition@60000 {
label = "kernel";
reg = <0x60000 0x220000>;
};
partition@280000 {
label = "dtb";
reg = <0x280000 0x20000>;
};
};
flash@5,0 {
compatible = "cfi-flash";
reg = <5 0x0 0x2000000>;
#address-cells = <1>;
#size-cells = <1>;
bank-width = <2>;
device-width = <2>;
partition@0 {
label = "ramdisk";
reg = <0 0x7a0000>;
};
partition@7a0000 {
label = "user";
reg = <0x7a0000 0x1860000>;
};
};
};
memory {
device_type = "memory";
reg = <0 0>; /* Filled in by U-Boot */
};
soc@f0000000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,mpc8247-immr", "fsl,pq2-soc", "simple-bus";
ranges = <0x00000000 0xf0000000 0x00053000>;
// Temporary until code stops depending on it.
device_type = "soc";
cpm@119c0 {
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
compatible = "fsl,mpc8247-cpm", "fsl,cpm2",
"simple-bus";
reg = <0x119c0 0x30>;
ranges;
muram {
compatible = "fsl,cpm-muram";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0 0x10000>;
data@0 {
compatible = "fsl,cpm-muram-data";
reg = <0x80 0x1f80 0x9800 0x800>;
};
};
brg@119f0 {
compatible = "fsl,mpc8247-brg",
"fsl,cpm2-brg",
"fsl,cpm-brg";
reg = <0x119f0 0x10 0x115f0 0x10>;
};
/* Monitor port/SMC2 */
smc2: serial@11a90 {
device_type = "serial";
compatible = "fsl,mpc8247-smc-uart",
"fsl,cpm2-smc-uart";
reg = <0x11a90 0x20 0x88fc 0x02>;
interrupts = <5 8>;
interrupt-parent = <&PIC>;
fsl,cpm-brg = <2>;
fsl,cpm-command = <0x21200000>;
current-speed = <0>; /* Filled in by U-Boot */
};
eth0: ethernet@11a60 {
device_type = "network";
compatible = "fsl,mpc8247-scc-enet",
"fsl,cpm2-scc-enet";
reg = <0x11a60 0x20 0x8300 0x100 0x11390 1>;
local-mac-address = [ 00 00 00 00 00 00 ]; /* Filled in by U-Boot */
interrupts = <43 8>;
interrupt-parent = <&PIC>;
linux,network-index = <0>;
fsl,cpm-command = <0xce00000>;
fixed-link = <0 0 10 0 0>;
};
};
PIC: interrupt-controller@10c00 {
#interrupt-cells = <2>;
interrupt-controller;
reg = <0x10c00 0x80>;
compatible = "fsl,mpc8247-pic", "fsl,pq2-pic";
};
};
};
此差异已折叠。
...@@ -403,7 +403,8 @@ ...@@ -403,7 +403,8 @@
#interrupt-cells = <1>; #interrupt-cells = <1>;
#size-cells = <2>; #size-cells = <2>;
#address-cells = <3>; #address-cells = <3>;
reg = <0x80008500 0x100>; reg = <0x80008500 0x100 /* internal registers */
0x80008300 0x8>; /* config space access registers */
compatible = "fsl,mpc5121-pci"; compatible = "fsl,mpc5121-pci";
device_type = "pci"; device_type = "pci";
}; };
......
...@@ -176,24 +176,28 @@ ...@@ -176,24 +176,28 @@
dma-channel@0 { dma-channel@0 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>; reg = <0 0x80>;
cell-index = <0>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@80 { dma-channel@80 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>; reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@100 { dma-channel@100 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>; reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@180 { dma-channel@180 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>; reg = <0x180 0x28>;
cell-index = <3>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
...@@ -359,7 +363,8 @@ ...@@ -359,7 +363,8 @@
#interrupt-cells = <1>; #interrupt-cells = <1>;
#size-cells = <2>; #size-cells = <2>;
#address-cells = <3>; #address-cells = <3>;
reg = <0xe0008500 0x100>; reg = <0xe0008500 0x100 /* internal registers */
0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci"; compatible = "fsl,mpc8349-pci";
device_type = "pci"; device_type = "pci";
}; };
......
...@@ -144,24 +144,28 @@ ...@@ -144,24 +144,28 @@
dma-channel@0 { dma-channel@0 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>; reg = <0 0x80>;
cell-index = <0>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@80 { dma-channel@80 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>; reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@100 { dma-channel@100 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>; reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
dma-channel@180 { dma-channel@180 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel"; compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>; reg = <0x180 0x28>;
cell-index = <3>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
interrupts = <71 8>; interrupts = <71 8>;
}; };
...@@ -314,7 +318,8 @@ ...@@ -314,7 +318,8 @@
#interrupt-cells = <1>; #interrupt-cells = <1>;
#size-cells = <2>; #size-cells = <2>;
#address-cells = <3>; #address-cells = <3>;
reg = <0xe0008500 0x100>; reg = <0xe0008500 0x100 /* internal registers */
0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci"; compatible = "fsl,mpc8349-pci";
device_type = "pci"; device_type = "pci";
}; };
......
...@@ -91,6 +91,8 @@ ...@@ -91,6 +91,8 @@
rtc@68 { rtc@68 {
compatible = "dallas,ds3232"; compatible = "dallas,ds3232";
reg = <0x68>; reg = <0x68>;
interrupts = <0 0x1>;
interrupt-parent = <&mpic>;
}; };
}; };
......
此差异已折叠。
此差异已折叠。
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#address-cells = <2>; #address-cells = <2>;
#size-cells = <1>; #size-cells = <1>;
model = "amcc,yosemite"; model = "amcc,yosemite";
compatible = "amcc,yosemite","amcc,bamboo"; compatible = "amcc,yosemite";
dcr-parent = <&{/cpus/cpu@0}>; dcr-parent = <&{/cpus/cpu@0}>;
aliases { aliases {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册