You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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 ...
This commit is contained in:
@@ -18,10 +18,6 @@ mpc52xx.txt
|
||||
- Linux 2.6.x on MPC52xx family
|
||||
mpc52xx-device-tree-bindings.txt
|
||||
- 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
|
||||
- info on sound support under Linux/PPC
|
||||
zImage_layout.txt
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
* 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";
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
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:
|
||||
- compatible : compatible list, contains 2 entries, first is
|
||||
"fsl,CHIP-dma-channel", where CHIP is the processor
|
||||
(mpc8349, mpc8350, etc.) and the second is
|
||||
"fsl,elo-dma-channel"
|
||||
"fsl,elo-dma-channel". However, see note below.
|
||||
- reg : <registers mapping for channel>
|
||||
- cell-index : dma channel index starts at 0.
|
||||
|
||||
@@ -82,7 +82,7 @@ Required properties:
|
||||
- compatible : compatible list, contains 2 entries, first is
|
||||
"fsl,CHIP-dma-channel", where CHIP is the processor
|
||||
(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.
|
||||
- reg : <registers mapping for channel>
|
||||
- interrupts : <interrupt mapping for DMA channel IRQ>
|
||||
@@ -125,3 +125,12 @@ Example:
|
||||
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:
|
||||
"rj-master" - r.j., SSI is clock master
|
||||
"ac97-slave" - AC97 mode, SSI is clock slave
|
||||
"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:
|
||||
- codec-handle : phandle to a 'codec' node that defines an audio
|
||||
@@ -36,3 +42,20 @@ Child 'codec' node required properties:
|
||||
Child 'codec' node optional properties:
|
||||
- clock-frequency : The frequency of the input clock, which typically
|
||||
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.
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
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.
|
||||
@@ -1,34 +0,0 @@
|
||||
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
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
int "Maximum zone order"
|
||||
range 9 64 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
|
||||
range 11 64
|
||||
default "11"
|
||||
help
|
||||
The kernel memory allocator divides physically contiguous memory
|
||||
@@ -806,6 +809,19 @@ config PIN_TLB
|
||||
endmenu
|
||||
|
||||
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
|
||||
hex
|
||||
default "0xc000000000000000"
|
||||
|
||||
@@ -51,6 +51,11 @@ config FTR_FIXUP_SELFTEST
|
||||
depends on DEBUG_KERNEL
|
||||
default n
|
||||
|
||||
config MSI_BITMAP_SELFTEST
|
||||
bool "Run self-tests of the MSI bitmap code."
|
||||
depends on DEBUG_KERNEL
|
||||
default n
|
||||
|
||||
config XMON
|
||||
bool "Include xmon kernel debugger"
|
||||
depends on DEBUG_KERNEL
|
||||
|
||||
@@ -63,7 +63,9 @@ override CC += -m$(CONFIG_WORD_SIZE)
|
||||
override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR)
|
||||
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_PPC32) := -ffixed-r2 -mmultiple
|
||||
@@ -102,7 +104,10 @@ endif
|
||||
KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
|
||||
|
||||
# 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,-mspe=no)
|
||||
KBUILD_CFLAGS += $(call cc-option,-mabi=no-spe)
|
||||
|
||||
# Enable unit-at-a-time mode when possible. It shrinks the
|
||||
# kernel considerably.
|
||||
|
||||
@@ -310,8 +310,11 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb
|
||||
$(obj)/vmlinux.strip: vmlinux
|
||||
$(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
|
||||
$(STRIP) -s -R .comment $< -o $@
|
||||
printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17
|
||||
|
||||
$(obj)/uImage: vmlinux $(wrapperbits)
|
||||
$(call if_changed,wrap,uboot)
|
||||
|
||||
+108
-36
@@ -11,7 +11,12 @@
|
||||
* as published by the Free Software Foundation; either 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 <stdlib.h>
|
||||
@@ -43,27 +48,29 @@ char rpaname[] = "IBM,RPA-Client-Config";
|
||||
*/
|
||||
#define N_RPA_DESCR 8
|
||||
unsigned int rpanote[N_RPA_DESCR] = {
|
||||
0, /* lparaffinity */
|
||||
64, /* min_rmo_size */
|
||||
1, /* lparaffinity */
|
||||
128, /* min_rmo_size */
|
||||
0, /* min_rmo_percent */
|
||||
40, /* max_pft_size */
|
||||
46, /* max_pft_size */
|
||||
1, /* splpar */
|
||||
-1, /* min_load */
|
||||
0, /* new_mem_def */
|
||||
1, /* ignore_my_client_config */
|
||||
1, /* new_mem_def */
|
||||
0, /* ignore_my_client_config */
|
||||
};
|
||||
|
||||
#define ROUNDUP(len) (((len) + 3) & ~3)
|
||||
|
||||
unsigned char buf[512];
|
||||
unsigned char notebuf[512];
|
||||
|
||||
#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1]))
|
||||
#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2))
|
||||
#define GET_16BE(b, off) (((b)[off] << 8) + ((b)[(off)+1]))
|
||||
#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, \
|
||||
buf[(off) + 1] = (v) & 0xff)
|
||||
#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \
|
||||
PUT_16BE((off) + 2, (v)))
|
||||
#define PUT_16BE(b, off, v) ((b)[off] = ((v) >> 8) & 0xff, \
|
||||
(b)[(off) + 1] = (v) & 0xff)
|
||||
#define PUT_32BE(b, off, v) (PUT_16BE((b), (off), (v) >> 16), \
|
||||
PUT_16BE((b), (off) + 2, (v)))
|
||||
|
||||
/* Structure of an ELF file */
|
||||
#define E_IDENT 0 /* ELF header */
|
||||
@@ -88,15 +95,71 @@ unsigned char buf[512];
|
||||
|
||||
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(¬ebuf[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 *)¬ebuf[note + 12], rpaname) != 0)
|
||||
continue;
|
||||
/* looks like an RPA note, return it */
|
||||
*nnp = notesize;
|
||||
return ¬ebuf[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
|
||||
main(int ac, char **av)
|
||||
{
|
||||
int fd, n, i;
|
||||
int ph, ps, np;
|
||||
int nnote, nnote2, ns;
|
||||
unsigned char *rpap;
|
||||
|
||||
if (ac != 2) {
|
||||
fprintf(stderr, "Usage: %s elf-file\n", av[0]);
|
||||
if (ac != 2 && ac != 3) {
|
||||
fprintf(stderr, "Usage: %s elf-file [rpanote.elf]\n", av[0]);
|
||||
exit(1);
|
||||
}
|
||||
fd = open(av[1], O_RDWR);
|
||||
@@ -107,6 +170,7 @@ main(int ac, char **av)
|
||||
|
||||
nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
|
||||
nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
|
||||
rpap = NULL;
|
||||
|
||||
n = read(fd, buf, sizeof(buf));
|
||||
if (n < 0) {
|
||||
@@ -124,16 +188,19 @@ main(int ac, char **av)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ph = GET_32BE(E_PHOFF);
|
||||
ps = GET_16BE(E_PHENTSIZE);
|
||||
np = GET_16BE(E_PHNUM);
|
||||
if (ac == 3)
|
||||
rpap = read_rpanote(av[2], &nnote2);
|
||||
|
||||
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)
|
||||
goto notelf;
|
||||
if (ph + (np + 2) * ps + nnote + nnote2 > n)
|
||||
goto nospace;
|
||||
|
||||
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",
|
||||
av[1]);
|
||||
exit(0);
|
||||
@@ -148,37 +215,42 @@ main(int ac, char **av)
|
||||
|
||||
/* fill in the program header entry */
|
||||
ns = ph + 2 * ps;
|
||||
PUT_32BE(ph + PH_TYPE, PT_NOTE);
|
||||
PUT_32BE(ph + PH_OFFSET, ns);
|
||||
PUT_32BE(ph + PH_FILESZ, nnote);
|
||||
PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
|
||||
PUT_32BE(buf, ph + PH_OFFSET, ns);
|
||||
PUT_32BE(buf, ph + PH_FILESZ, nnote);
|
||||
|
||||
/* fill in the note area we point to */
|
||||
/* XXX we should probably make this a proper section */
|
||||
PUT_32BE(ns, strlen(arch) + 1);
|
||||
PUT_32BE(ns + 4, N_DESCR * 4);
|
||||
PUT_32BE(ns + 8, 0x1275);
|
||||
PUT_32BE(buf, ns, strlen(arch) + 1);
|
||||
PUT_32BE(buf, ns + 4, N_DESCR * 4);
|
||||
PUT_32BE(buf, ns + 8, 0x1275);
|
||||
strcpy((char *) &buf[ns + 12], arch);
|
||||
ns += 12 + strlen(arch) + 1;
|
||||
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 */
|
||||
ph += ps;
|
||||
PUT_32BE(ph + PH_TYPE, PT_NOTE);
|
||||
PUT_32BE(ph + PH_OFFSET, ns);
|
||||
PUT_32BE(ph + PH_FILESZ, nnote2);
|
||||
PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
|
||||
PUT_32BE(buf, ph + PH_OFFSET, ns);
|
||||
PUT_32BE(buf, ph + PH_FILESZ, nnote2);
|
||||
|
||||
/* fill in the note area we point to */
|
||||
PUT_32BE(ns, strlen(rpaname) + 1);
|
||||
PUT_32BE(ns + 4, sizeof(rpanote));
|
||||
PUT_32BE(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(ns, rpanote[i]);
|
||||
if (rpap) {
|
||||
/* RPA note supplied in file, just copy the whole thing over */
|
||||
memcpy(buf + ns, rpap, nnote2);
|
||||
} else {
|
||||
PUT_32BE(buf, ns, strlen(rpaname) + 1);
|
||||
PUT_32BE(buf, ns + 4, sizeof(rpanote));
|
||||
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 */
|
||||
PUT_16BE(E_PHNUM, np + 2);
|
||||
PUT_16BE(buf, E_PHNUM, np + 2);
|
||||
|
||||
/* write back */
|
||||
lseek(fd, (long) 0, SEEK_SET);
|
||||
|
||||
@@ -5,21 +5,5 @@
|
||||
#
|
||||
DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \
|
||||
checks.c
|
||||
DTC_EXTRA = dtc.h srcpos.h
|
||||
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_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
|
||||
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,
|
||||
}
|
||||
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,
|
||||
struct node *node)
|
||||
{
|
||||
@@ -280,16 +316,29 @@ NODE_CHECK(explicit_phandles, NULL, ERROR);
|
||||
static void check_name_properties(struct check *c, struct node *root,
|
||||
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)
|
||||
return; /* No name property, that's fine */
|
||||
|
||||
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"
|
||||
" 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);
|
||||
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,
|
||||
struct node *node, struct property *prop)
|
||||
{
|
||||
struct marker *m = prop->val.markers;
|
||||
struct node *refnode;
|
||||
cell_t phandle;
|
||||
struct marker *m = prop->val.markers;
|
||||
struct node *refnode;
|
||||
cell_t phandle;
|
||||
|
||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||
assert(m->offset + sizeof(cell_t) <= prop->val.len);
|
||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||
assert(m->offset + sizeof(cell_t) <= prop->val.len);
|
||||
|
||||
refnode = get_node_by_ref(dt, m->ref);
|
||||
if (! refnode) {
|
||||
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
||||
m->ref);
|
||||
continue;
|
||||
}
|
||||
refnode = get_node_by_ref(dt, m->ref);
|
||||
if (! refnode) {
|
||||
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
|
||||
m->ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
phandle = get_node_phandle(dt, refnode);
|
||||
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_be32(phandle);
|
||||
}
|
||||
phandle = get_node_phandle(dt, refnode);
|
||||
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
|
||||
}
|
||||
}
|
||||
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
|
||||
&duplicate_node_names, &explicit_phandles);
|
||||
@@ -498,6 +547,7 @@ TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
|
||||
|
||||
static struct check *check_table[] = {
|
||||
&duplicate_node_names, &duplicate_property_names,
|
||||
&node_name_chars, &node_name_format, &property_name_chars,
|
||||
&name_is_string, &name_properties,
|
||||
&explicit_phandles,
|
||||
&phandle_references, &path_references,
|
||||
@@ -511,10 +561,7 @@ static struct check *check_table[] = {
|
||||
&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,
|
||||
int checkflag, int outversion, int boot_cpuid_phys)
|
||||
void process_checks(int force, struct boot_info *bi)
|
||||
{
|
||||
struct node *dt = bi->dt;
|
||||
int i;
|
||||
@@ -537,214 +584,4 @@ void process_checks(int force, struct boot_info *bi,
|
||||
"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)
|
||||
m = nm;
|
||||
}
|
||||
|
||||
assert(!d.val || d.asize);
|
||||
|
||||
if (d.val)
|
||||
free(d.val);
|
||||
}
|
||||
@@ -43,9 +41,6 @@ struct data data_grow_for(struct data d, int xlen)
|
||||
struct data nd;
|
||||
int newsize;
|
||||
|
||||
/* we must start with an allocated datum */
|
||||
assert(!d.val || d.asize);
|
||||
|
||||
if (xlen == 0)
|
||||
return d;
|
||||
|
||||
@@ -56,11 +51,8 @@ struct data data_grow_for(struct data d, int xlen)
|
||||
while ((d.len + xlen) > newsize)
|
||||
newsize *= 2;
|
||||
|
||||
nd.asize = newsize;
|
||||
nd.val = xrealloc(d.val, newsize);
|
||||
|
||||
assert(nd.asize >= (d.len + xlen));
|
||||
|
||||
return nd;
|
||||
}
|
||||
|
||||
@@ -83,16 +75,11 @@ static char get_oct_char(const char *s, int *i)
|
||||
long val;
|
||||
|
||||
x[3] = '\0';
|
||||
x[0] = s[(*i)];
|
||||
if (x[0]) {
|
||||
x[1] = s[(*i)+1];
|
||||
if (x[1])
|
||||
x[2] = s[(*i)+2];
|
||||
}
|
||||
strncpy(x, s + *i, 3);
|
||||
|
||||
val = strtol(x, &endx, 8);
|
||||
if ((endx - x) == 0)
|
||||
fprintf(stderr, "Empty \\nnn escape\n");
|
||||
|
||||
assert(endx > x);
|
||||
|
||||
(*i) += endx - x;
|
||||
return val;
|
||||
@@ -105,13 +92,11 @@ static char get_hex_char(const char *s, int *i)
|
||||
long val;
|
||||
|
||||
x[2] = '\0';
|
||||
x[0] = s[(*i)];
|
||||
if (x[0])
|
||||
x[1] = s[(*i)+1];
|
||||
strncpy(x, s + *i, 2);
|
||||
|
||||
val = strtol(x, &endx, 16);
|
||||
if ((endx - x) == 0)
|
||||
fprintf(stderr, "Empty \\x escape\n");
|
||||
if (!(endx > x))
|
||||
die("\\x used with no following hex digits\n");
|
||||
|
||||
(*i) += endx - x;
|
||||
return val;
|
||||
@@ -182,14 +167,29 @@ struct data data_copy_escape_string(const char *s, int len)
|
||||
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;
|
||||
fread(d.val, len, 1, f);
|
||||
if (maxlen == -1)
|
||||
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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
cell_t beword = cpu_to_be32(word);
|
||||
cell_t beword = cpu_to_fdt32(word);
|
||||
|
||||
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)
|
||||
{
|
||||
struct fdt_reserve_entry bere;
|
||||
|
||||
bere.address = cpu_to_be64(re->address);
|
||||
bere.size = cpu_to_be64(re->size);
|
||||
bere.address = cpu_to_fdt64(re->address);
|
||||
bere.size = cpu_to_fdt64(re->size);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
|
||||
PATHCHAR ({PROPNODECHAR}|[/])
|
||||
LABEL [a-zA-Z_][a-zA-Z0-9_]*
|
||||
STRING \"([^\\"]|\\.)*\"
|
||||
WS [[:space:]]
|
||||
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
|
||||
LINECOMMENT "//".*\n
|
||||
|
||||
%{
|
||||
#include "dtc.h"
|
||||
@@ -52,29 +56,26 @@ static int dts_version; /* = 0 */
|
||||
DPRINT("<V1>\n"); \
|
||||
BEGIN(V1); \
|
||||
}
|
||||
|
||||
static void push_input_file(const char *filename);
|
||||
static int pop_input_file(void);
|
||||
%}
|
||||
|
||||
%%
|
||||
<*>"/include/" BEGIN(INCLUDE);
|
||||
|
||||
<INCLUDE>\"[^"\n]*\" {
|
||||
yytext[strlen(yytext) - 1] = 0;
|
||||
if (!push_input_file(yytext + 1)) {
|
||||
/* Some unrecoverable error.*/
|
||||
exit(1);
|
||||
}
|
||||
BEGIN_DEFAULT();
|
||||
<*>"/include/"{WS}*{STRING} {
|
||||
char *name = strchr(yytext, '\"') + 1;
|
||||
yytext[yyleng-1] = '\0';
|
||||
push_input_file(name);
|
||||
}
|
||||
|
||||
|
||||
<*><<EOF>> {
|
||||
if (!pop_input_file()) {
|
||||
yyterminate();
|
||||
}
|
||||
}
|
||||
|
||||
<*>\"([^\\"]|\\.)*\" {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
<*>{STRING} {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("String: %s\n", yytext);
|
||||
yylval.data = data_copy_escape_string(yytext+1,
|
||||
@@ -84,7 +85,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<*>"/dts-v1/" {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Keyword: /dts-v1/\n");
|
||||
dts_version = 1;
|
||||
@@ -93,7 +94,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<*>"/memreserve/" {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Keyword: /memreserve/\n");
|
||||
BEGIN_DEFAULT();
|
||||
@@ -101,7 +102,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<*>{LABEL}: {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Label: %s\n", yytext);
|
||||
yylval.labelref = strdup(yytext);
|
||||
@@ -110,7 +111,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<INITIAL>[bodh]# {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
if (*yytext == 'b')
|
||||
yylval.cbase = 2;
|
||||
@@ -125,7 +126,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<INITIAL>[0-9a-fA-F]+ {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yylval.literal = strdup(yytext);
|
||||
DPRINT("Literal: '%s'\n", yylval.literal);
|
||||
@@ -133,7 +134,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<V1>[0-9]+|0[xX][0-9a-fA-F]+ {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yylval.literal = strdup(yytext);
|
||||
DPRINT("Literal: '%s'\n", yylval.literal);
|
||||
@@ -141,7 +142,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
\&{LABEL} { /* label reference */
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Ref: %s\n", yytext+1);
|
||||
yylval.labelref = strdup(yytext+1);
|
||||
@@ -149,7 +150,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
"&{/"{PATHCHAR}+\} { /* new-style path reference */
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yytext[yyleng-1] = '\0';
|
||||
DPRINT("Ref: %s\n", yytext+2);
|
||||
@@ -158,7 +159,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<INITIAL>"&/"{PATHCHAR}+ { /* old-style path reference */
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Ref: %s\n", yytext+1);
|
||||
yylval.labelref = strdup(yytext+1);
|
||||
@@ -166,7 +167,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<BYTESTRING>[0-9a-fA-F]{2} {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
yylval.byte = strtol(yytext, NULL, 16);
|
||||
DPRINT("Byte: %02x\n", (int)yylval.byte);
|
||||
@@ -174,7 +175,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<BYTESTRING>"]" {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("/BYTESTRING\n");
|
||||
BEGIN_DEFAULT();
|
||||
@@ -182,7 +183,7 @@ static int dts_version; /* = 0 */
|
||||
}
|
||||
|
||||
<PROPNODENAME>{PROPNODECHAR}+ {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("PropNodeName: %s\n", yytext);
|
||||
yylval.propnodename = strdup(yytext);
|
||||
@@ -190,20 +191,19 @@ static int dts_version; /* = 0 */
|
||||
return DT_PROPNODENAME;
|
||||
}
|
||||
|
||||
|
||||
<*>[[:space:]]+ /* eat whitespace */
|
||||
|
||||
<*>"/*"([^*]|\*+[^*/])*\*+"/" {
|
||||
yylloc.filenum = srcpos_filenum;
|
||||
"/incbin/" {
|
||||
yylloc.file = srcpos_file;
|
||||
yylloc.first_line = yylineno;
|
||||
DPRINT("Comment: %s\n", yytext);
|
||||
/* eat comments */
|
||||
DPRINT("Binary Include\n");
|
||||
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;
|
||||
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
|
||||
(unsigned)yytext[0]);
|
||||
@@ -227,14 +227,13 @@ static int dts_version; /* = 0 */
|
||||
*/
|
||||
|
||||
struct incl_file {
|
||||
int filenum;
|
||||
FILE *file;
|
||||
struct dtc_file *file;
|
||||
YY_BUFFER_STATE yy_prev_buf;
|
||||
int yy_prev_lineno;
|
||||
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;
|
||||
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 dtc_file *newfile;
|
||||
struct search_path search, *searchptr = NULL;
|
||||
|
||||
if (!filename) {
|
||||
yyerror("No include file name given.");
|
||||
return 0;
|
||||
assert(filename);
|
||||
|
||||
if (incl_depth++ >= MAX_INCLUDE_DEPTH)
|
||||
die("Includes nested too deeply");
|
||||
|
||||
if (srcpos_file) {
|
||||
search.dir = srcpos_file->dir;
|
||||
search.next = NULL;
|
||||
search.prev = NULL;
|
||||
searchptr = &search;
|
||||
}
|
||||
|
||||
if (incl_depth++ >= MAX_INCLUDE_DEPTH) {
|
||||
yyerror("Includes nested too deeply");
|
||||
return 0;
|
||||
}
|
||||
newfile = dtc_open_file(filename, searchptr);
|
||||
|
||||
f = dtc_open_file(filename);
|
||||
|
||||
incl_file = malloc(sizeof(struct incl_file));
|
||||
if (!incl_file) {
|
||||
yyerror("Can not allocate include file space.");
|
||||
return 0;
|
||||
}
|
||||
incl_file = xmalloc(sizeof(struct incl_file));
|
||||
|
||||
/*
|
||||
* Save current context.
|
||||
*/
|
||||
incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
|
||||
incl_file->yy_prev_lineno = yylineno;
|
||||
incl_file->filenum = srcpos_filenum;
|
||||
incl_file->file = yyin;
|
||||
incl_file->file = srcpos_file;
|
||||
incl_file->prev = incl_file_stack;
|
||||
|
||||
incl_file_stack = incl_file;
|
||||
@@ -282,23 +279,21 @@ int push_input_file(const char *filename)
|
||||
/*
|
||||
* Establish new context.
|
||||
*/
|
||||
srcpos_filenum = lookup_file_name(filename, 0);
|
||||
srcpos_file = newfile;
|
||||
yylineno = 1;
|
||||
yyin = f;
|
||||
yyin = newfile->file;
|
||||
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;
|
||||
|
||||
if (incl_file_stack == 0)
|
||||
return 0;
|
||||
|
||||
fclose(yyin);
|
||||
dtc_close_file(srcpos_file);
|
||||
|
||||
/*
|
||||
* Pop.
|
||||
@@ -313,16 +308,13 @@ int pop_input_file(void)
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
yy_switch_to_buffer(incl_file->yy_prev_buf);
|
||||
yylineno = incl_file->yy_prev_lineno;
|
||||
srcpos_filenum = incl_file->filenum;
|
||||
yyin = incl_file->file;
|
||||
srcpos_file = incl_file->file;
|
||||
yyin = incl_file->file ? incl_file->file->file : NULL;
|
||||
|
||||
/*
|
||||
* Free old state.
|
||||
*/
|
||||
free(incl_file);
|
||||
|
||||
if (YY_CURRENT_BUFFER == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,8 @@
|
||||
DT_BYTE = 264,
|
||||
DT_STRING = 265,
|
||||
DT_LABEL = 266,
|
||||
DT_REF = 267
|
||||
DT_REF = 267,
|
||||
DT_INCBIN = 268
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
@@ -62,22 +63,23 @@
|
||||
#define DT_STRING 265
|
||||
#define DT_LABEL 266
|
||||
#define DT_REF 267
|
||||
#define DT_INCBIN 268
|
||||
|
||||
|
||||
|
||||
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
typedef union YYSTYPE
|
||||
#line 34 "dtc-parser.y"
|
||||
#line 37 "dtc-parser.y"
|
||||
{
|
||||
char *propnodename;
|
||||
char *literal;
|
||||
char *labelref;
|
||||
unsigned int cbase;
|
||||
u8 byte;
|
||||
uint8_t byte;
|
||||
struct data data;
|
||||
|
||||
u64 addr;
|
||||
uint64_t addr;
|
||||
cell_t cell;
|
||||
struct property *prop;
|
||||
struct property *proplist;
|
||||
@@ -86,7 +88,7 @@ typedef union YYSTYPE
|
||||
struct reserve_info *re;
|
||||
}
|
||||
/* Line 1489 of yacc.c. */
|
||||
#line 90 "dtc-parser.tab.h"
|
||||
#line 92 "dtc-parser.tab.h"
|
||||
YYSTYPE;
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
|
||||
@@ -21,14 +21,17 @@
|
||||
%locations
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
int yylex(void);
|
||||
unsigned long long eval_literal(const char *s, int base, int bits);
|
||||
extern int yylex(void);
|
||||
|
||||
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 {
|
||||
@@ -36,10 +39,10 @@ extern struct boot_info *the_boot_info;
|
||||
char *literal;
|
||||
char *labelref;
|
||||
unsigned int cbase;
|
||||
u8 byte;
|
||||
uint8_t byte;
|
||||
struct data data;
|
||||
|
||||
u64 addr;
|
||||
uint64_t addr;
|
||||
cell_t cell;
|
||||
struct property *prop;
|
||||
struct property *proplist;
|
||||
@@ -58,6 +61,7 @@ extern struct boot_info *the_boot_info;
|
||||
%token <data> DT_STRING
|
||||
%token <labelref> DT_LABEL
|
||||
%token <labelref> DT_REF
|
||||
%token DT_INCBIN
|
||||
|
||||
%type <data> propdata
|
||||
%type <data> propdataprefix
|
||||
@@ -84,11 +88,11 @@ extern struct boot_info *the_boot_info;
|
||||
sourcefile:
|
||||
DT_V1 ';' memreserves devicetree
|
||||
{
|
||||
the_boot_info = build_boot_info($3, $4);
|
||||
the_boot_info = build_boot_info($3, $4, 0);
|
||||
}
|
||||
| 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:
|
||||
{
|
||||
$$ = 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
|
||||
{
|
||||
$$ = data_add_marker($1, LABEL, $2);
|
||||
@@ -282,7 +314,7 @@ subnodes:
|
||||
}
|
||||
| subnode propdef
|
||||
{
|
||||
yyerror("syntax error: properties must precede subnodes\n");
|
||||
yyerror("syntax error: properties must precede subnodes");
|
||||
YYERROR;
|
||||
}
|
||||
;
|
||||
@@ -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)
|
||||
fname = "stdin";
|
||||
|
||||
fprintf(stderr, "%s:%d %s\n",
|
||||
fname, yylloc.first_line, s);
|
||||
fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
|
||||
vfprintf(stderr, s, va);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
treesource_error = 1;
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
unsigned long long eval_literal(const char *s, int base, int bits)
|
||||
void yyerror (char const *s)
|
||||
{
|
||||
yyerrorf("%s", s);
|
||||
}
|
||||
|
||||
static unsigned long long eval_literal(const char *s, int base, int bits)
|
||||
{
|
||||
unsigned long long val;
|
||||
char *e;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user