pax_global_header00006660000000000000000000000064131330472420014511gustar00rootroot0000000000000052 comment=7c56ba516efa9ad1b6827ec3a90ac76b8f66f907 pdbg-pdbg-1.0/000077500000000000000000000000001313304724200131775ustar00rootroot00000000000000pdbg-pdbg-1.0/.build.sh000077500000000000000000000014241313304724200147140ustar00rootroot00000000000000#!/bin/bash CONTAINER=pdbg-build Dockerfile=$(cat << EOF FROM ubuntu:15.10 RUN apt-get update && apt-get install --no-install-recommends -yy \ make \ gcc-arm-linux-gnueabi \ libc-dev-armel-cross \ autoconf \ automake RUN groupadd -g ${GROUPS} ${USER} && useradd -d ${HOME} -m -u ${UID} -g ${GROUPS} ${USER} USER ${USER} ENV HOME ${HOME} RUN /bin/bash EOF ) docker pull ubuntu:15.10 docker build -t ${CONTAINER} - <<< "${Dockerfile}" docker run --rm=true --user="${USER}" \ -w "${PWD}" -v "${HOME}":"${HOME}" -t ${CONTAINER} \ ./bootstrap.sh docker run --rm=true --user="${USER}" \ -w "${PWD}" -v "${HOME}":"${HOME}" -t ${CONTAINER} \ ./configure --host=arm-linux-gnueabi docker run --rm=true --user="${USER}" \ -w "${PWD}" -v "${HOME}":"${HOME}" -t ${CONTAINER} \ make pdbg-pdbg-1.0/.gitignore000066400000000000000000000004301313304724200151640ustar00rootroot00000000000000*~ *.o *.d TAGS tags cscope.out INSTALL Makefile.in aclocal.m4 autom4te.cache/ compile config.h.in configure depcomp install-sh missing Makefile pdbg .deps .dirstamp stamp-h1 config.h config.log config.status libpdbg.a .libs config.guess config.sub *.la *.lo ltmain.sh libtool m4 pdbg-pdbg-1.0/.travis.yml000066400000000000000000000000621313304724200153060ustar00rootroot00000000000000services: - docker script: - ./.build.sh pdbg-pdbg-1.0/AUTHORS000066400000000000000000000000001313304724200142350ustar00rootroot00000000000000pdbg-pdbg-1.0/COPYING000066400000000000000000000261361313304724200142420ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pdbg-pdbg-1.0/ChangeLog000066400000000000000000000000001313304724200147370ustar00rootroot00000000000000pdbg-pdbg-1.0/Makefile.am000066400000000000000000000032331313304724200152340ustar00rootroot00000000000000GIT_SHA1 = `git --work-tree=$(top_srcdir) --git-dir=$(top_srcdir)/.git describe --always --long --dirty || echo unknown` include libfdt/Makefile.libfdt bin_PROGRAMS = pdbg ACLOCAL_AMFLAGS = -Im4 AM_CFLAGS = -I$(top_srcdir)/ccan/array_size -Wall -Werror pdbg_SOURCES = \ src/main.c pdbg_LDADD = fake.dtb.o p8-fsi.dtb.o p8-i2c.dtb.o p9w-fsi.dtb.o \ p9z-fsi.dtb.o p9r-fsi.dtb.o p9-kernel.dtb.o libpdbg.la libfdt.la \ -L.libs pdbg_LDFLAGS = -Wl,--whole-archive,-lpdbg,--no-whole-archive pdbg_CFLAGS = -I$(top_srcdir)/libpdbg -Wall -Werror -DGIT_SHA1=\"${GIT_SHA1}\" lib_LTLIBRARIES = libpdbg.la libfdt.la libfdt_la_CFLAGS = -I$(top_srcdir)/libfdt -DHAVE_LITTLE_ENDIAN libpdbg_la_CFLAGS = -I$(top_srcdir)/libfdt -DHAVE_LITTLE_ENDIAN -Wall -Werror libfdt_la_SOURCES = \ libfdt/fdt.c \ libfdt/fdt_ro.c \ libfdt/fdt_wip.c \ libfdt/fdt_sw.c \ libfdt/fdt_rw.c \ libfdt/fdt_strerror.c \ libfdt/fdt_empty_tree.c \ libfdt/fdt_addresses.c \ libfdt/fdt_overlay.c libpdbg_la_SOURCES = \ libpdbg/kernel.c \ libpdbg/fake.c \ libpdbg/chip.c \ libpdbg/p8chip.c \ libpdbg/p9chip.c \ libpdbg/bmcfsi.c \ libpdbg/cfam.c \ libpdbg/i2c.c \ libpdbg/adu.c \ libpdbg/device.c \ libpdbg/target.c %.dts: %.dts.m4 m4 -I$(dir $<) $< > $@ %.dtsi: %.dtsi.m4 m4 -I$(dir $<) $< > $@ p9w-fsi.dtb.o: p9w-fsi.dts p9-fsi.dtsi p9r-fsi.dtb.o: p9r-fsi.dts p9-fsi.dtsi p9z-fsi.dtb.o: p9z-fsi.dts p9-fsi.dtsi %.dtb.o: %.dts dtc -i$(dir $@) -I dts $< -O dtb > $@.tmp # We need to align the output as some processor/kernel # combinations can't deal with the alignment errors when # unflattening the device-tree dd if=$@.tmp of=$@ ibs=16 conv=sync rm $@.tmp $(OBJCOPY) -I binary -O @ARCH_FF@ $@ $@ pdbg-pdbg-1.0/NEWS000066400000000000000000000000001313304724200136640ustar00rootroot00000000000000pdbg-pdbg-1.0/README000077700000000000000000000000001313304724200153312README.mdustar00rootroot00000000000000pdbg-pdbg-1.0/README.md000066400000000000000000000203661313304724200144650ustar00rootroot00000000000000# PDBG pdbg is a simple application to allow debugging of the host POWER processors from the BMC. It works in a similar way to JTAG programmers for embedded system development in that it allows you to access GPRs, SPRs and system memory. A remote gdb sever is under development to allow integration with standard debugging tools. ## Building The output of autoconf is not included in the git tree so it needs to be generated using autoreconf. This can be done by running `./bootstrap.sh` in the top level directory. Static linking is supported and can be performed by adding `CFLAGS=-static` to the command line passed to configure. ## Usage Several backends are supported depending on which system you are using and are selected using the `-b` option: POWER8 Backends: - i2c (default): Uses an i2c connection between BMC and host processor - fsi: Uses a bit-banging GPIO backend which accesses BMC registers directly via /dev/mem/. Requires `-d p8` to specify you are running on a POWER8 system. POWER9 Backends: - kernel (default): Uses the in kernel OpenFSI driver provided by OpenBMC - fsi: Uses a bit-banging GPIO backend which accesses BMC registers directly via /dev/mem. Requiers `-d p9w/p9r/p9z` as appropriate for the system. When using the fsi backend POWER8 AMI based BMC's must first be put into debug mode to allow access to the relevant GPIOs: `ipmitool -H -U -P raw 0x3a 0x01` On POWER9 when using the fsi backend it is also a good idea to put the BMC into debug mode to prevent conflicts with the OpenFSI driver. On the BMC run: `systemctl start fsi-disable.service && systemctl stop host-failure-reboots@0.service` Usage is straight forward. Note that if the binary is not statically linked all commands need to be prefixed with LD\_LIBRARY\_PATH= in addition to the arguments for selecting a backend. ## Examples ``` $ ./pdbg --help Usage: ./pdbg [options] command ... Options: -p, --processor=processor-id -c, --chip=chiplet-id -t, --thread=thread -a, --all Run command on all possible processors/chips/threads (default) -b, --backend=backend fsi: An experimental backend that uses bit-banging to access the host processor via the FSI bus. i2c: The P8 only backend which goes via I2C. kernel: The default backend which goes the kernel FSI driver. -d, --device=backend device For I2C the device node used by the backend to access the bus. For FSI the system board type, one of p8 or p9w Defaults to /dev/i2c4 for I2C -s, --slave-address=backend device address Device slave address to use for the backend. Not used by FSI and defaults to 0x50 for I2C -V, --version -h, --help Commands: getcfam
putcfam
[] getscom
putscom
[] getmem
putmem
getvmem getgpr putgpr getnia putnia getspr putspr start step stop threadstatus probe ``` ### Probe chip/processor/thread numbers ``` $ ./pdbg -a probe BMC GPIO bit-banging FSI master CFAM hMFSI Port p1: POWER FSI2PIB POWER9 ADU c16: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c17: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c18: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c19: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c20: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c21: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c22: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c23: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread p0: POWER FSI2PIB POWER9 ADU c5: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c7: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c14: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c15: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c19: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c20: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c21: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread c22: POWER9 Chiplet t0: POWER9 Thread t1: POWER9 Thread t2: POWER9 Thread t3: POWER9 Thread Note that only selected targets will be shown above. If none are shown try adding '-a' to select all targets ``` Chiplet-IDs are core/chip numbers which should be passed as arguments to `-c` when performing operations such as getgpr that operate on particular cores. Processor-IDs should be passed as arguments to `-p` to operate on different processor chips. Specifying no targets is an error and will result in the following error message: ``` Note that only selected targets will be shown above. If none are shown try adding '-a' to select all targets ``` If the above error occurs even though targets were specified it means the specified targets were not found when probing the system. ### Read SCOM register ``` $ ./pdbg -a getscom 0xf000f p0:0xf000f = 0x220ea04980000000 p1:0xf000f = 0x220ea04980800000 ``` ### Write SCOM register on secondary processor `$ ./pdbg -p1 putscom 0x8013c02 0x0` ### Get thread status ``` $ ./pdbg -a threadstatus p0t: 0 1 2 3 4 5 6 7 c22: A A A A c21: A A A A c20: A A A A c19: A A A A c15: A A A A c14: A A A A c07: A A A A c05: A A A A p1t: 0 1 2 3 4 5 6 7 c23: A A A A c22: A A A A c21: A A A A c20: A A A A c19: A A A A c18: A A A A c17: A A A A c16: A A A A ``` ### Stop thread execution on thread 0-4 of processor 0 core/chip 22 Reading thread register values requires all threads on a given core to be in the quiesced state. ``` $ ./pdbg -p0 -c22 -t0 -t1 -t2 -t3 stop $ ./pdbg -p0 -c22 -t0 -t1 -t2 -t3 threadstatus p0t: 0 1 2 3 4 5 6 7 c22: Q Q Q Q ``` ### Read GPR on thread 0 of processor 0 core/chip 22 ``` $ ./pdbg -p0 -c22 -t0 getgpr 2 p0:c22:t0:gpr02: 0xc000000000f09900 ``` ### Read SPR 8 (LR) on thread 0 of processor 0 core/chip 22 ``` $ ./pdbg -p0 -c22 -t0 getspr 8 p0:c22:t0:spr008: 0xc0000000008a97f0 ``` ### Restart thread 0-4 execution on processor 0 core/chip 22 ``` ./pdbg -p0 -c22 -t0 -t1 -t2 -t3 start ./pdbg -p0 -c22 -t0 -t1 -t2 -t3 threadstatus p0t: 0 1 2 3 4 5 6 7 c22: A A A A ``` pdbg-pdbg-1.0/bootstrap.sh000077500000000000000000000000311313304724200155450ustar00rootroot00000000000000#!/bin/sh autoreconf -i pdbg-pdbg-1.0/ccan/000077500000000000000000000000001313304724200141035ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/array_size/000077500000000000000000000000001313304724200162535ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/array_size/LICENSE000066400000000000000000000143571313304724200172720ustar00rootroot00000000000000Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. pdbg-pdbg-1.0/ccan/array_size/_info000066400000000000000000000020061313304724200172660ustar00rootroot00000000000000#include #include #include "config.h" /** * array_size - routine for safely deriving the size of a visible array. * * This provides a simple ARRAY_SIZE() macro, which (given a good compiler) * will also break compile if you try to use it on a pointer. * * This can ensure your code is robust to changes, without needing a gratuitous * macro or constant. * * Example: * // Outputs "Initialized 32 values" * #include * #include * #include * * // We currently use 32 random values. * static unsigned int vals[32]; * * int main(void) * { * unsigned int i; * for (i = 0; i < ARRAY_SIZE(vals); i++) * vals[i] = random(); * printf("Initialized %u values\n", i); * return 0; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/build_assert\n"); return 0; } return 1; } pdbg-pdbg-1.0/ccan/array_size/array_size.h000066400000000000000000000015711313304724200206000ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_ARRAY_SIZE_H #define CCAN_ARRAY_SIZE_H #include "config.h" #include /** * ARRAY_SIZE - get the number of elements in a visible array * @arr: the array whose size you want. * * This does not work on pointers, or arrays declared as [], or * function parameters. With correct compiler support, such usage * will cause a build error (see build_assert). */ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr)) #if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF /* Two gcc extensions. * &a[0] degrades to a pointer: a different type from an array */ #define _array_size_chk(arr) \ BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \ typeof(&(arr)[0]))) #else #define _array_size_chk(arr) 0 #endif #endif /* CCAN_ALIGNOF_H */ pdbg-pdbg-1.0/ccan/array_size/test/000077500000000000000000000000001313304724200172325ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/array_size/test/compile_fail-function-param.c000066400000000000000000000007651313304724200247520ustar00rootroot00000000000000#include #include struct foo { unsigned int a, b; }; int check_parameter(const struct foo array[4]); int check_parameter(const struct foo array[4]) { #ifdef FAIL return (ARRAY_SIZE(array) == 4); #if !HAVE_TYPEOF || !HAVE_BUILTIN_TYPES_COMPATIBLE_P #error "Unfortunately we don't fail if _array_size_chk is a noop." #endif #else return sizeof(array) == 4 * sizeof(struct foo); #endif } int main(int argc, char *argv[]) { return check_parameter(NULL); } pdbg-pdbg-1.0/ccan/array_size/test/compile_fail.c000066400000000000000000000005021313304724200220160ustar00rootroot00000000000000#include int main(int argc, char *argv[8]) { char array[100]; #ifdef FAIL return ARRAY_SIZE(argv) + ARRAY_SIZE(array); #if !HAVE_TYPEOF || !HAVE_BUILTIN_TYPES_COMPATIBLE_P #error "Unfortunately we don't fail if _array_size_chk is a noop." #endif #else return ARRAY_SIZE(array); #endif } pdbg-pdbg-1.0/ccan/array_size/test/run.c000066400000000000000000000014241313304724200202030ustar00rootroot00000000000000#include #include static char array1[1]; static int array2[2]; static unsigned long array3[3][5]; struct foo { unsigned int a, b; char string[100]; }; static struct foo array4[4]; /* Make sure they can be used in initializers. */ static int array1_size = ARRAY_SIZE(array1); static int array2_size = ARRAY_SIZE(array2); static int array3_size = ARRAY_SIZE(array3); static int array4_size = ARRAY_SIZE(array4); int main(int argc, char *argv[]) { (void)argc; (void)argv; plan_tests(8); ok1(array1_size == 1); ok1(array2_size == 2); ok1(array3_size == 3); ok1(array4_size == 4); ok1(ARRAY_SIZE(array1) == 1); ok1(ARRAY_SIZE(array2) == 2); ok1(ARRAY_SIZE(array3) == 3); ok1(ARRAY_SIZE(array4) == 4); return exit_status(); } pdbg-pdbg-1.0/ccan/build_assert/000077500000000000000000000000001313304724200165635ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/build_assert/LICENSE000066400000000000000000000143571313304724200176020ustar00rootroot00000000000000Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. pdbg-pdbg-1.0/ccan/build_assert/_info000066400000000000000000000025061313304724200176030ustar00rootroot00000000000000#include #include #include "config.h" /** * build_assert - routines for build-time assertions * * This code provides routines which will cause compilation to fail should some * assertion be untrue: such failures are preferable to run-time assertions, * but much more limited since they can only depends on compile-time constants. * * These assertions are most useful when two parts of the code must be kept in * sync: it is better to avoid such cases if possible, but seconds best is to * detect invalid changes at build time. * * For example, a tricky piece of code might rely on a certain element being at * the start of the structure. To ensure that future changes don't break it, * you would catch such changes in your code like so: * * Example: * #include * #include * * struct foo { * char string[5]; * int x; * }; * * static char *foo_string(struct foo *foo) * { * // This trick requires that the string be first in the structure * BUILD_ASSERT(offsetof(struct foo, string) == 0); * return (char *)foo; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) /* Nothing. */ return 0; return 1; } pdbg-pdbg-1.0/ccan/build_assert/build_assert.h000066400000000000000000000023141313304724200214140ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_BUILD_ASSERT_H #define CCAN_BUILD_ASSERT_H /** * BUILD_ASSERT - assert a build-time dependency. * @cond: the compile-time condition which must be true. * * Your compile will fail if the condition isn't true, or can't be evaluated * by the compiler. This can only be used within a function. * * Example: * #include * ... * static char *foo_to_char(struct foo *foo) * { * // This code needs string to be at start of foo. * BUILD_ASSERT(offsetof(struct foo, string) == 0); * return (char *)foo; * } */ #define BUILD_ASSERT(cond) \ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) /** * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. * @cond: the compile-time condition which must be true. * * Your compile will fail if the condition isn't true, or can't be evaluated * by the compiler. This can be used in an expression: its value is "0". * * Example: * #define foo_to_char(foo) \ * ((char *)(foo) \ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) */ #define BUILD_ASSERT_OR_ZERO(cond) \ (sizeof(char [1 - 2*!(cond)]) - 1) #endif /* CCAN_BUILD_ASSERT_H */ pdbg-pdbg-1.0/ccan/build_assert/test/000077500000000000000000000000001313304724200175425ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/build_assert/test/compile_fail-expr.c000066400000000000000000000002341313304724200233040ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL return BUILD_ASSERT_OR_ZERO(1 == 0); #else return 0; #endif } pdbg-pdbg-1.0/ccan/build_assert/test/compile_fail.c000066400000000000000000000002071313304724200223300ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL BUILD_ASSERT(1 == 0); #endif return 0; } pdbg-pdbg-1.0/ccan/build_assert/test/compile_ok.c000066400000000000000000000001641313304724200220300ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { BUILD_ASSERT(1 == 1); return 0; } pdbg-pdbg-1.0/ccan/build_assert/test/run-BUILD_ASSERT_OR_ZERO.c000066400000000000000000000003271313304724200236710ustar00rootroot00000000000000#include #include int main(int argc, char *argv[]) { (void)argc; (void)argv; plan_tests(1); ok1(BUILD_ASSERT_OR_ZERO(1 == 1) == 0); return exit_status(); } pdbg-pdbg-1.0/ccan/check_type/000077500000000000000000000000001313304724200162215ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/check_type/LICENSE000066400000000000000000000143571313304724200172400ustar00rootroot00000000000000Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. pdbg-pdbg-1.0/ccan/check_type/_info000066400000000000000000000015111313304724200172340ustar00rootroot00000000000000#include #include #include "config.h" /** * check_type - routines for compile time type checking * * C has fairly weak typing: ints get automatically converted to longs, signed * to unsigned, etc. There are some cases where this is best avoided, and * these macros provide methods for evoking warnings (or build errors) when * a precise type isn't used. * * On compilers which don't support typeof() these routines are less effective, * since they have to use sizeof() which can only distiguish between types of * different size. * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { #if !HAVE_TYPEOF printf("ccan/build_assert\n"); #endif return 0; } return 1; } pdbg-pdbg-1.0/ccan/check_type/check_type.h000066400000000000000000000045051313304724200205140ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_CHECK_TYPE_H #define CCAN_CHECK_TYPE_H #include "config.h" /** * check_type - issue a warning or build failure if type is not correct. * @expr: the expression whose type we should check (not evaluated). * @type: the exact type we expect the expression to be. * * This macro is usually used within other macros to try to ensure that a macro * argument is of the expected type. No type promotion of the expression is * done: an unsigned int is not the same as an int! * * check_type() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // They should always pass a 64-bit value to _set_some_value! * #define set_some_value(expr) \ * _set_some_value((check_type((expr), uint64_t), (expr))) */ /** * check_types_match - issue a warning or build failure if types are not same. * @expr1: the first expression (not evaluated). * @expr2: the second expression (not evaluated). * * This macro is usually used within other macros to try to ensure that * arguments are of identical types. No type promotion of the expressions is * done: an unsigned int is not the same as an int! * * check_types_match() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // Do subtraction to get to enclosing type, but make sure that * // pointer is of correct type for that member. * #define container_of(mbr_ptr, encl_type, mbr) \ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ * ((encl_type *) \ * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) */ #if HAVE_TYPEOF #define check_type(expr, type) \ ((typeof(expr) *)0 != (type *)0) #define check_types_match(expr1, expr2) \ ((typeof(expr1) *)0 != (typeof(expr2) *)0) #else #include /* Without typeof, we can only test the sizes. */ #define check_type(expr, type) \ BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type)) #define check_types_match(expr1, expr2) \ BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2)) #endif /* HAVE_TYPEOF */ #endif /* CCAN_CHECK_TYPE_H */ pdbg-pdbg-1.0/ccan/check_type/test/000077500000000000000000000000001313304724200172005ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/check_type/test/compile_fail-check_type.c000066400000000000000000000002051313304724200241000ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL check_type(argc, char); #endif return 0; } pdbg-pdbg-1.0/ccan/check_type/test/compile_fail-check_type_unsigned.c000066400000000000000000000003751313304724200260040ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL #if HAVE_TYPEOF check_type(argc, unsigned int); #else /* This doesn't work without typeof, so just fail */ #error "Fail without typeof" #endif #endif return 0; } pdbg-pdbg-1.0/ccan/check_type/test/compile_fail-check_types_match.c000066400000000000000000000002421313304724200254400ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { unsigned char x = argc; #ifdef FAIL check_types_match(argc, x); #endif return x; } pdbg-pdbg-1.0/ccan/check_type/test/run.c000066400000000000000000000011151313304724200201460ustar00rootroot00000000000000#include #include int main(int argc, char *argv[]) { int x = 0, y = 0; (void)argc; (void)argv; plan_tests(9); ok1(check_type(argc, int) == 0); ok1(check_type(&argc, int *) == 0); ok1(check_types_match(argc, argc) == 0); ok1(check_types_match(argc, x) == 0); ok1(check_types_match(&argc, &x) == 0); ok1(check_type(x++, int) == 0); ok(x == 0, "check_type does not evaluate expression"); ok1(check_types_match(x++, y++) == 0); ok(x == 0 && y == 0, "check_types_match does not evaluate expressions"); return exit_status(); } pdbg-pdbg-1.0/ccan/container_of/000077500000000000000000000000001313304724200165515ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/container_of/LICENSE000066400000000000000000000143571313304724200175700ustar00rootroot00000000000000Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. pdbg-pdbg-1.0/ccan/container_of/_info000066400000000000000000000024741313304724200175750ustar00rootroot00000000000000#include #include #include "config.h" /** * container_of - routine for upcasting * * It is often convenient to create code where the caller registers a pointer * to a generic structure and a callback. The callback might know that the * pointer points to within a larger structure, and container_of gives a * convenient and fairly type-safe way of returning to the enclosing structure. * * This idiom is an alternative to providing a void * pointer for every * callback. * * Example: * #include * #include * * struct timer { * void *members; * }; * * struct info { * int my_stuff; * struct timer timer; * }; * * static void register_timer(struct timer *timer) * { * //... * } * * static void my_timer_callback(struct timer *timer) * { * struct info *info = container_of(timer, struct info, timer); * printf("my_stuff is %u\n", info->my_stuff); * } * * int main(void) * { * struct info info = { .my_stuff = 1 }; * * register_timer(&info.timer); * // ... * return 0; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/check_type\n"); return 0; } return 1; } pdbg-pdbg-1.0/ccan/container_of/container_of.h000066400000000000000000000061201313304724200213670ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_CONTAINER_OF_H #define CCAN_CONTAINER_OF_H #include #include "config.h" #include /** * container_of - get pointer to enclosing structure * @member_ptr: pointer to the structure member * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * return container_of(foo, struct info, my_foo); * } */ #define container_of(member_ptr, containing_type, member) \ ((containing_type *) \ ((char *)(member_ptr) \ - container_off(containing_type, member)) \ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) /** * container_off - get offset to enclosing structure * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does * typechecking and figures out the offset to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * size_t off = container_off(struct info, my_foo); * return (void *)((char *)foo - off); * } */ #define container_off(containing_type, member) \ offsetof(containing_type, member) /** * container_of_var - get pointer to enclosing structure using a variable * @member_ptr: pointer to the structure member * @container_var: a pointer of same type as this member's container * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * static struct info *foo_to_i(struct foo *foo) * { * struct info *i = container_of_var(foo, i, my_foo); * return i; * } */ #if HAVE_TYPEOF #define container_of_var(member_ptr, container_var, member) \ container_of(member_ptr, typeof(*container_var), member) #else #define container_of_var(member_ptr, container_var, member) \ ((void *)((char *)(member_ptr) - \ container_off_var(container_var, member))) #endif /** * container_off_var - get offset of a field in enclosing structure * @container_var: a pointer to a container structure * @member: the name of a member within the structure. * * Given (any) pointer to a structure and a its member name, this * macro does pointer subtraction to return offset of member in a * structure memory layout. * */ #if HAVE_TYPEOF #define container_off_var(var, member) \ container_off(typeof(*var), member) #else #define container_off_var(var, member) \ ((char *)&(var)->member - (char *)(var)) #endif #endif /* CCAN_CONTAINER_OF_H */ pdbg-pdbg-1.0/ccan/container_of/test/000077500000000000000000000000001313304724200175305ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/container_of/test/compile_fail-bad-type.c000066400000000000000000000005511313304724200240230ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }; int *intp = &foo.a; char *p; #ifdef FAIL /* p is a char *, but this gives a struct foo * */ p = container_of(intp, struct foo, a); #else p = (char *)intp; #endif return p == NULL; } pdbg-pdbg-1.0/ccan/container_of/test/compile_fail-types.c000066400000000000000000000006321313304724200234620ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }, *foop; int *intp = &foo.a; #ifdef FAIL /* b is a char, but intp is an int * */ foop = container_of(intp, struct foo, b); #else foop = NULL; #endif (void) foop; /* Suppress unused-but-set-variable warning. */ return intp == NULL; } pdbg-pdbg-1.0/ccan/container_of/test/compile_fail-var-types.c000066400000000000000000000007561313304724200242570ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }, *foop; int *intp = &foo.a; #ifdef FAIL /* b is a char, but intp is an int * */ foop = container_of_var(intp, foop, b); #if !HAVE_TYPEOF #error "Unfortunately we don't fail if we don't have typeof." #endif #else foop = NULL; #endif (void) foop; /* Suppress unused-but-set-variable warning. */ return intp == NULL; } pdbg-pdbg-1.0/ccan/container_of/test/run.c000066400000000000000000000011161313304724200204770ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }; int *intp = &foo.a; char *charp = &foo.b; (void)argc; (void)argv; plan_tests(6); ok1(container_of(intp, struct foo, a) == &foo); ok1(container_of(charp, struct foo, b) == &foo); ok1(container_of_var(intp, &foo, a) == &foo); ok1(container_of_var(charp, &foo, b) == &foo); ok1(container_off(struct foo, a) == 0); ok1(container_off(struct foo, b) == offsetof(struct foo, b)); return exit_status(); } pdbg-pdbg-1.0/ccan/endian/000077500000000000000000000000001313304724200153415ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/endian/LICENSE000077700000000000000000000000001313304724200210642../../licenses/CC0ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/endian/_info000066400000000000000000000026131313304724200163600ustar00rootroot00000000000000#include "config.h" #include #include /** * endian - endian conversion macros for simple types * * Portable protocols (such as on-disk formats, or network protocols) * are often defined to be a particular endian: little-endian (least * significant bytes first) or big-endian (most significant bytes * first). * * Similarly, some CPUs lay out values in memory in little-endian * order (most commonly, Intel's 8086 and derivatives), or big-endian * order (almost everyone else). * * This module provides conversion routines, inspired by the linux kernel. * It also provides leint32_t, beint32_t etc typedefs, which are annotated for * the sparse checker. * * Example: * #include * #include * #include * * // * int main(int argc, char *argv[]) * { * uint32_t value; * * if (argc != 2) * errx(1, "Usage: %s ", argv[0]); * * value = atoi(argv[1]); * printf("native: %08x\n", value); * printf("little-endian: %08x\n", cpu_to_le32(value)); * printf("big-endian: %08x\n", cpu_to_be32(value)); * printf("byte-reversed: %08x\n", bswap_32(value)); * exit(0); * } * * License: License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) /* Nothing */ return 0; return 1; } pdbg-pdbg-1.0/ccan/endian/endian.h000066400000000000000000000217201313304724200167520ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_ENDIAN_H #define CCAN_ENDIAN_H #include #include "config.h" /** * BSWAP_16 - reverse bytes in a constant uint16_t value. * @val: constant value whose bytes to swap. * * Designed to be usable in constant-requiring initializers. * * Example: * struct mystruct { * char buf[BSWAP_16(0x1234)]; * }; */ #define BSWAP_16(val) \ ((((uint16_t)(val) & 0x00ff) << 8) \ | (((uint16_t)(val) & 0xff00) >> 8)) /** * BSWAP_32 - reverse bytes in a constant uint32_t value. * @val: constant value whose bytes to swap. * * Designed to be usable in constant-requiring initializers. * * Example: * struct mystruct { * char buf[BSWAP_32(0xff000000)]; * }; */ #define BSWAP_32(val) \ ((((uint32_t)(val) & 0x000000ff) << 24) \ | (((uint32_t)(val) & 0x0000ff00) << 8) \ | (((uint32_t)(val) & 0x00ff0000) >> 8) \ | (((uint32_t)(val) & 0xff000000) >> 24)) /** * BSWAP_64 - reverse bytes in a constant uint64_t value. * @val: constantvalue whose bytes to swap. * * Designed to be usable in constant-requiring initializers. * * Example: * struct mystruct { * char buf[BSWAP_64(0xff00000000000000ULL)]; * }; */ #define BSWAP_64(val) \ ((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \ | (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \ | (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \ | (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \ | (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \ | (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \ | (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \ | (((uint64_t)(val) & 0xff00000000000000ULL) >> 56)) #if HAVE_BYTESWAP_H #include #else /** * bswap_16 - reverse bytes in a uint16_t value. * @val: value whose bytes to swap. * * Example: * // Output contains "1024 is 4 as two bytes reversed" * printf("1024 is %u as two bytes reversed\n", bswap_16(1024)); */ static inline uint16_t bswap_16(uint16_t val) { return BSWAP_16(val); } /** * bswap_32 - reverse bytes in a uint32_t value. * @val: value whose bytes to swap. * * Example: * // Output contains "1024 is 262144 as four bytes reversed" * printf("1024 is %u as four bytes reversed\n", bswap_32(1024)); */ static inline uint32_t bswap_32(uint32_t val) { return BSWAP_32(val); } #endif /* !HAVE_BYTESWAP_H */ #if !HAVE_BSWAP_64 /** * bswap_64 - reverse bytes in a uint64_t value. * @val: value whose bytes to swap. * * Example: * // Output contains "1024 is 1125899906842624 as eight bytes reversed" * printf("1024 is %llu as eight bytes reversed\n", * (unsigned long long)bswap_64(1024)); */ static inline uint64_t bswap_64(uint64_t val) { return BSWAP_64(val); } #endif /* Sanity check the defines. We don't handle weird endianness. */ #if !HAVE_LITTLE_ENDIAN && !HAVE_BIG_ENDIAN #error "Unknown endian" #elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN #error "Can't compile for both big and little endian." #endif #ifdef __CHECKER__ /* sparse needs forcing to remove bitwise attribute from ccan/short_types */ #define ENDIAN_CAST __attribute__((force)) #define ENDIAN_TYPE __attribute__((bitwise)) #else #define ENDIAN_CAST #define ENDIAN_TYPE #endif typedef uint64_t ENDIAN_TYPE leint64_t; typedef uint64_t ENDIAN_TYPE beint64_t; typedef uint32_t ENDIAN_TYPE leint32_t; typedef uint32_t ENDIAN_TYPE beint32_t; typedef uint16_t ENDIAN_TYPE leint16_t; typedef uint16_t ENDIAN_TYPE beint16_t; #if HAVE_LITTLE_ENDIAN /** * CPU_TO_LE64 - convert a constant uint64_t value to little-endian * @native: constant to convert */ #define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)(native)) /** * CPU_TO_LE32 - convert a constant uint32_t value to little-endian * @native: constant to convert */ #define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)(native)) /** * CPU_TO_LE16 - convert a constant uint16_t value to little-endian * @native: constant to convert */ #define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)(native)) /** * LE64_TO_CPU - convert a little-endian uint64_t constant * @le_val: little-endian constant to convert */ #define LE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val)) /** * LE32_TO_CPU - convert a little-endian uint32_t constant * @le_val: little-endian constant to convert */ #define LE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val)) /** * LE16_TO_CPU - convert a little-endian uint16_t constant * @le_val: little-endian constant to convert */ #define LE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val)) #else /* ... HAVE_BIG_ENDIAN */ #define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)BSWAP_64(native)) #define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)BSWAP_32(native)) #define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)BSWAP_16(native)) #define LE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val) #define LE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val) #define LE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val) #endif /* HAVE_BIG_ENDIAN */ #if HAVE_BIG_ENDIAN /** * CPU_TO_BE64 - convert a constant uint64_t value to big-endian * @native: constant to convert */ #define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)(native)) /** * CPU_TO_BE32 - convert a constant uint32_t value to big-endian * @native: constant to convert */ #define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)(native)) /** * CPU_TO_BE16 - convert a constant uint16_t value to big-endian * @native: constant to convert */ #define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)(native)) /** * BE64_TO_CPU - convert a big-endian uint64_t constant * @le_val: big-endian constant to convert */ #define BE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val)) /** * BE32_TO_CPU - convert a big-endian uint32_t constant * @le_val: big-endian constant to convert */ #define BE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val)) /** * BE16_TO_CPU - convert a big-endian uint16_t constant * @le_val: big-endian constant to convert */ #define BE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val)) #else /* ... HAVE_LITTLE_ENDIAN */ #define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)BSWAP_64(native)) #define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)BSWAP_32(native)) #define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)BSWAP_16(native)) #define BE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val) #define BE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val) #define BE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val) #endif /* HAVE_LITTE_ENDIAN */ /** * cpu_to_le64 - convert a uint64_t value to little-endian * @native: value to convert */ static inline leint64_t cpu_to_le64(uint64_t native) { return CPU_TO_LE64(native); } /** * cpu_to_le32 - convert a uint32_t value to little-endian * @native: value to convert */ static inline leint32_t cpu_to_le32(uint32_t native) { return CPU_TO_LE32(native); } /** * cpu_to_le16 - convert a uint16_t value to little-endian * @native: value to convert */ static inline leint16_t cpu_to_le16(uint16_t native) { return CPU_TO_LE16(native); } /** * le64_to_cpu - convert a little-endian uint64_t value * @le_val: little-endian value to convert */ static inline uint64_t le64_to_cpu(leint64_t le_val) { return LE64_TO_CPU(le_val); } /** * le32_to_cpu - convert a little-endian uint32_t value * @le_val: little-endian value to convert */ static inline uint32_t le32_to_cpu(leint32_t le_val) { return LE32_TO_CPU(le_val); } /** * le16_to_cpu - convert a little-endian uint16_t value * @le_val: little-endian value to convert */ static inline uint16_t le16_to_cpu(leint16_t le_val) { return LE16_TO_CPU(le_val); } /** * cpu_to_be64 - convert a uint64_t value to big endian. * @native: value to convert */ static inline beint64_t cpu_to_be64(uint64_t native) { return CPU_TO_BE64(native); } /** * cpu_to_be32 - convert a uint32_t value to big endian. * @native: value to convert */ static inline beint32_t cpu_to_be32(uint32_t native) { return CPU_TO_BE32(native); } /** * cpu_to_be16 - convert a uint16_t value to big endian. * @native: value to convert */ static inline beint16_t cpu_to_be16(uint16_t native) { return CPU_TO_BE16(native); } /** * be64_to_cpu - convert a big-endian uint64_t value * @be_val: big-endian value to convert */ static inline uint64_t be64_to_cpu(beint64_t be_val) { return BE64_TO_CPU(be_val); } /** * be32_to_cpu - convert a big-endian uint32_t value * @be_val: big-endian value to convert */ static inline uint32_t be32_to_cpu(beint32_t be_val) { return BE32_TO_CPU(be_val); } /** * be16_to_cpu - convert a big-endian uint16_t value * @be_val: big-endian value to convert */ static inline uint16_t be16_to_cpu(beint16_t be_val) { return BE16_TO_CPU(be_val); } /* Whichever they include first, they get these definitions. */ #ifdef CCAN_SHORT_TYPES_H /** * be64/be32/be16 - 64/32/16 bit big-endian representation. */ typedef beint64_t be64; typedef beint32_t be32; typedef beint16_t be16; /** * le64/le32/le16 - 64/32/16 bit little-endian representation. */ typedef leint64_t le64; typedef leint32_t le32; typedef leint16_t le16; #endif #endif /* CCAN_ENDIAN_H */ pdbg-pdbg-1.0/ccan/endian/test/000077500000000000000000000000001313304724200163205ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/endian/test/compile_ok-constant.c000066400000000000000000000002741313304724200224370ustar00rootroot00000000000000#include struct foo { char one[BSWAP_16(0xFF00)]; char two[BSWAP_32(0xFF000000)]; char three[BSWAP_64(0xFF00000000000000ULL)]; }; int main(void) { return 0; } pdbg-pdbg-1.0/ccan/endian/test/run.c000066400000000000000000000052141313304724200172720ustar00rootroot00000000000000#include #include #include #include int main(void) { union { uint64_t u64; unsigned char u64_bytes[8]; } u64; union { uint32_t u32; unsigned char u32_bytes[4]; } u32; union { uint16_t u16; unsigned char u16_bytes[2]; } u16; plan_tests(48); /* Straight swap tests. */ u64.u64_bytes[0] = 0x00; u64.u64_bytes[1] = 0x11; u64.u64_bytes[2] = 0x22; u64.u64_bytes[3] = 0x33; u64.u64_bytes[4] = 0x44; u64.u64_bytes[5] = 0x55; u64.u64_bytes[6] = 0x66; u64.u64_bytes[7] = 0x77; u64.u64 = bswap_64(u64.u64); ok1(u64.u64_bytes[7] == 0x00); ok1(u64.u64_bytes[6] == 0x11); ok1(u64.u64_bytes[5] == 0x22); ok1(u64.u64_bytes[4] == 0x33); ok1(u64.u64_bytes[3] == 0x44); ok1(u64.u64_bytes[2] == 0x55); ok1(u64.u64_bytes[1] == 0x66); ok1(u64.u64_bytes[0] == 0x77); u32.u32_bytes[0] = 0x00; u32.u32_bytes[1] = 0x11; u32.u32_bytes[2] = 0x22; u32.u32_bytes[3] = 0x33; u32.u32 = bswap_32(u32.u32); ok1(u32.u32_bytes[3] == 0x00); ok1(u32.u32_bytes[2] == 0x11); ok1(u32.u32_bytes[1] == 0x22); ok1(u32.u32_bytes[0] == 0x33); u16.u16_bytes[0] = 0x00; u16.u16_bytes[1] = 0x11; u16.u16 = bswap_16(u16.u16); ok1(u16.u16_bytes[1] == 0x00); ok1(u16.u16_bytes[0] == 0x11); /* Endian tests. */ u64.u64 = cpu_to_le64(0x0011223344556677ULL); ok1(u64.u64_bytes[0] == 0x77); ok1(u64.u64_bytes[1] == 0x66); ok1(u64.u64_bytes[2] == 0x55); ok1(u64.u64_bytes[3] == 0x44); ok1(u64.u64_bytes[4] == 0x33); ok1(u64.u64_bytes[5] == 0x22); ok1(u64.u64_bytes[6] == 0x11); ok1(u64.u64_bytes[7] == 0x00); ok1(le64_to_cpu(u64.u64) == 0x0011223344556677ULL); u64.u64 = cpu_to_be64(0x0011223344556677ULL); ok1(u64.u64_bytes[7] == 0x77); ok1(u64.u64_bytes[6] == 0x66); ok1(u64.u64_bytes[5] == 0x55); ok1(u64.u64_bytes[4] == 0x44); ok1(u64.u64_bytes[3] == 0x33); ok1(u64.u64_bytes[2] == 0x22); ok1(u64.u64_bytes[1] == 0x11); ok1(u64.u64_bytes[0] == 0x00); ok1(be64_to_cpu(u64.u64) == 0x0011223344556677ULL); u32.u32 = cpu_to_le32(0x00112233); ok1(u32.u32_bytes[0] == 0x33); ok1(u32.u32_bytes[1] == 0x22); ok1(u32.u32_bytes[2] == 0x11); ok1(u32.u32_bytes[3] == 0x00); ok1(le32_to_cpu(u32.u32) == 0x00112233); u32.u32 = cpu_to_be32(0x00112233); ok1(u32.u32_bytes[3] == 0x33); ok1(u32.u32_bytes[2] == 0x22); ok1(u32.u32_bytes[1] == 0x11); ok1(u32.u32_bytes[0] == 0x00); ok1(be32_to_cpu(u32.u32) == 0x00112233); u16.u16 = cpu_to_le16(0x0011); ok1(u16.u16_bytes[0] == 0x11); ok1(u16.u16_bytes[1] == 0x00); ok1(le16_to_cpu(u16.u16) == 0x0011); u16.u16 = cpu_to_be16(0x0011); ok1(u16.u16_bytes[1] == 0x11); ok1(u16.u16_bytes[0] == 0x00); ok1(be16_to_cpu(u16.u16) == 0x0011); exit(exit_status()); } pdbg-pdbg-1.0/ccan/list/000077500000000000000000000000001313304724200150565ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/list/LICENSE000066400000000000000000000017771313304724200160770ustar00rootroot00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pdbg-pdbg-1.0/ccan/list/_info000066400000000000000000000027011313304724200160730ustar00rootroot00000000000000#include #include #include "config.h" /** * list - double linked list routines * * The list header contains routines for manipulating double linked lists. * It defines two types: struct list_head used for anchoring lists, and * struct list_node which is usually embedded in the structure which is placed * in the list. * * Example: * #include * #include * #include * #include * * struct parent { * const char *name; * struct list_head children; * unsigned int num_children; * }; * * struct child { * const char *name; * struct list_node list; * }; * * int main(int argc, char *argv[]) * { * struct parent p; * struct child *c; * unsigned int i; * * if (argc < 2) * errx(1, "Usage: %s parent children...", argv[0]); * * p.name = argv[1]; * list_head_init(&p.children); * p.num_children = 0; * for (i = 2; i < argc; i++) { * c = malloc(sizeof(*c)); * c->name = argv[i]; * list_add(&p.children, &c->list); * p.num_children++; * } * * printf("%s has %u children:", p.name, p.num_children); * list_for_each(&p.children, c, list) * printf("%s ", c->name); * printf("\n"); * return 0; * } * * License: BSD-MIT * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/container_of\n"); return 0; } return 1; } pdbg-pdbg-1.0/ccan/list/list.c000066400000000000000000000017501313304724200162000ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */ #include #include #include "list.h" static void *corrupt(const char *abortstr, const struct list_node *head, const struct list_node *node, unsigned int count) { if (abortstr) { fprintf(stderr, "%s: prev corrupt in node %p (%u) of %p\n", abortstr, node, count, head); abort(); } return NULL; } struct list_node *list_check_node(const struct list_node *node, const char *abortstr) { const struct list_node *p, *n; int count = 0; for (p = node, n = node->next; n != node; p = n, n = n->next) { count++; if (n->prev != p) return corrupt(abortstr, node, n, count); } /* Check prev on head node. */ if (node->prev != p) return corrupt(abortstr, node, node, 0); return (struct list_node *)node; } struct list_head *list_check(const struct list_head *h, const char *abortstr) { if (!list_check_node(&h->n, abortstr)) return NULL; return (struct list_head *)h; } pdbg-pdbg-1.0/ccan/list/list.h000066400000000000000000000355551313304724200162170ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */ #ifndef CCAN_LIST_H #define CCAN_LIST_H #include #include #include #include /** * struct list_node - an entry in a doubly-linked list * @next: next entry (self if empty) * @prev: previous entry (self if empty) * * This is used as an entry in a linked list. * Example: * struct child { * const char *name; * // Linked list of all us children. * struct list_node list; * }; */ struct list_node { struct list_node *next, *prev; }; /** * struct list_head - the head of a doubly-linked list * @h: the list_head (containing next and prev pointers) * * This is used as the head of a linked list. * Example: * struct parent { * const char *name; * struct list_head children; * unsigned int num_children; * }; */ struct list_head { struct list_node n; }; /** * list_check - check head of a list for consistency * @h: the list_head * @abortstr: the location to print on aborting, or NULL. * * Because list_nodes have redundant information, consistency checking between * the back and forward links can be done. This is useful as a debugging check. * If @abortstr is non-NULL, that will be printed in a diagnostic if the list * is inconsistent, and the function will abort. * * Returns the list head if the list is consistent, NULL if not (it * can never return NULL if @abortstr is set). * * See also: list_check_node() * * Example: * static void dump_parent(struct parent *p) * { * struct child *c; * * printf("%s (%u children):\n", p->name, p->num_children); * list_check(&p->children, "bad child list"); * list_for_each(&p->children, c, list) * printf(" -> %s\n", c->name); * } */ struct list_head *list_check(const struct list_head *h, const char *abortstr); /** * list_check_node - check node of a list for consistency * @n: the list_node * @abortstr: the location to print on aborting, or NULL. * * Check consistency of the list node is in (it must be in one). * * See also: list_check() * * Example: * static void dump_child(const struct child *c) * { * list_check_node(&c->list, "bad child list"); * printf("%s\n", c->name); * } */ struct list_node *list_check_node(const struct list_node *n, const char *abortstr); #ifdef CCAN_LIST_DEBUG #define list_debug(h) list_check((h), __func__) #define list_debug_node(n) list_check_node((n), __func__) #else #define list_debug(h) (h) #define list_debug_node(n) (n) #endif /** * LIST_HEAD_INIT - initializer for an empty list_head * @name: the name of the list. * * Explicit initializer for an empty list. * * See also: * LIST_HEAD, list_head_init() * * Example: * static struct list_head my_list = LIST_HEAD_INIT(my_list); */ #define LIST_HEAD_INIT(name) { { &name.n, &name.n } } /** * LIST_HEAD - define and initialize an empty list_head * @name: the name of the list. * * The LIST_HEAD macro defines a list_head and initializes it to an empty * list. It can be prepended by "static" to define a static list_head. * * See also: * LIST_HEAD_INIT, list_head_init() * * Example: * static LIST_HEAD(my_global_list); */ #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) /** * list_head_init - initialize a list_head * @h: the list_head to set to the empty list * * Example: * ... * struct parent *parent = malloc(sizeof(*parent)); * * list_head_init(&parent->children); * parent->num_children = 0; */ static inline void list_head_init(struct list_head *h) { h->n.next = h->n.prev = &h->n; } /** * list_add - add an entry at the start of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * struct child *child = malloc(sizeof(*child)); * * child->name = "marvin"; * list_add(&parent->children, &child->list); * parent->num_children++; */ static inline void list_add(struct list_head *h, struct list_node *n) { n->next = h->n.next; n->prev = &h->n; h->n.next->prev = n; h->n.next = n; (void)list_debug(h); } /** * list_add_before - add an entry before another entry. * @h: the list_head to add the node to (we use it for debug purposes, can be NULL) * @n: the list_node to add to the list. * @p: the list_node of the other entry * * The list_node does not need to be initialized; it will be overwritten. */ static inline void list_add_before(struct list_head *h, struct list_node *n, struct list_node *p) { n->next = p; n->prev = p->prev; p->prev = n; n->prev->next = n; if (h) (void)list_debug(h); } /** * list_add_tail - add an entry at the end of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * list_add_tail(&parent->children, &child->list); * parent->num_children++; */ static inline void list_add_tail(struct list_head *h, struct list_node *n) { n->next = &h->n; n->prev = h->n.prev; h->n.prev->next = n; h->n.prev = n; (void)list_debug(h); } /** * list_empty - is a list empty? * @h: the list_head * * If the list is empty, returns true. * * Example: * assert(list_empty(&parent->children) == (parent->num_children == 0)); */ static inline bool list_empty(const struct list_head *h) { (void)list_debug(h); return h->n.next == &h->n; } /** * list_empty_nocheck - is a list empty? * @h: the list_head * * If the list is empty, returns true. This doesn't perform any * debug check for list consistency, so it can be called without * locks, racing with the list being modified. This is ok for * checks where an incorrect result is not an issue (optimized * bail out path for example). */ static inline bool list_empty_nocheck(const struct list_head *h) { return h->n.next == &h->n; } /** * list_del - delete an entry from an (unknown) linked list. * @n: the list_node to delete from the list. * * Note that this leaves @n in an undefined state; it can be added to * another list, but not deleted again. * * See also: * list_del_from() * * Example: * list_del(&child->list); * parent->num_children--; */ static inline void list_del(struct list_node *n) { (void)list_debug_node(n); n->next->prev = n->prev; n->prev->next = n->next; #ifdef CCAN_LIST_DEBUG /* Catch use-after-del. */ n->next = n->prev = NULL; #endif } /** * list_del_from - delete an entry from a known linked list. * @h: the list_head the node is in. * @n: the list_node to delete from the list. * * This explicitly indicates which list a node is expected to be in, * which is better documentation and can catch more bugs. * * See also: list_del() * * Example: * list_del_from(&parent->children, &child->list); * parent->num_children--; */ static inline void list_del_from(struct list_head *h, struct list_node *n) { #ifdef CCAN_LIST_DEBUG { /* Thorough check: make sure it was in list! */ struct list_node *i; for (i = h->n.next; i != n; i = i->next) assert(i != &h->n); } #endif /* CCAN_LIST_DEBUG */ /* Quick test that catches a surprising number of bugs. */ assert(!list_empty(h)); list_del(n); } /** * list_entry - convert a list_node back into the structure containing it. * @n: the list_node * @type: the type of the entry * @member: the list_node member of the type * * Example: * // First list entry is children.next; convert back to child. * child = list_entry(parent->children.n.next, struct child, list); * * See Also: * list_top(), list_for_each() */ #define list_entry(n, type, member) container_of(n, type, member) /** * list_top - get the first entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *first; * first = list_top(&parent->children, struct child, list); * if (!first) * printf("Empty list!\n"); */ #define list_top(h, type, member) \ ((type *)list_top_((h), list_off_(type, member))) static inline const void *list_top_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.next - off; } /** * list_pop - get the first entry in a list and dequeue it * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type */ #define list_pop(h, type, member) \ ((type *)list_pop_((h), list_off_(type, member))) static inline const void *list_pop_(struct list_head *h, size_t off) { struct list_node *n; if (list_empty(h)) return NULL; n = h->n.next; list_del(n); return (const char *)n - off; } /** * list_tail - get the last entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *last; * last = list_tail(&parent->children, struct child, list); * if (!last) * printf("Empty list!\n"); */ #define list_tail(h, type, member) \ ((type *)list_tail_((h), list_off_(type, member))) static inline const void *list_tail_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.prev - off; } /** * list_for_each - iterate through a list. * @h: the list_head (warning: evaluated multiple times!) * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each(h, i, member) \ list_for_each_off(h, i, list_off_var_(i, member)) /** * list_for_each_rev - iterate through a list backwards. * @h: the list_head * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each_rev(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each_rev(h, i, member) \ for (i = container_of_var(list_debug(h)->n.prev, i, member); \ &i->member != &(h)->n; \ i = container_of_var(i->member.prev, i, member)) /** * list_for_each_safe - iterate through a list, maybe during deletion * @h: the list_head * @i: the structure containing the list_node * @nxt: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. The extra variable * @nxt is used to hold the next element, so you can delete @i from the list. * * Example: * struct child *next; * list_for_each_safe(&parent->children, child, next, list) { * list_del(&child->list); * parent->num_children--; * } */ #define list_for_each_safe(h, i, nxt, member) \ list_for_each_safe_off(h, i, nxt, list_off_var_(i, member)) /** * list_for_each_off - iterate through a list of memory regions. * @h: the list_head * @i: the pointer to a memory region which contains list node data. * @off: offset(relative to @i) at which list node data resides. * * This is a low-level wrapper to iterate @i over the entire list, used to * implement all oher, more high-level, for-each constructs. It's a for loop, * so you can break and continue as normal. * * WARNING! Being the low-level macro that it is, this wrapper doesn't know * nor care about the type of @i. The only assumtion made is that @i points * to a chunk of memory that at some @offset, relative to @i, contains a * properly filled `struct node_list' which in turn contains pointers to * memory chunks and it's turtles all the way down. With all that in mind * remember that given the wrong pointer/offset couple this macro will * happily churn all you memory until SEGFAULT stops it, in other words * caveat emptor. * * It is worth mentioning that one of legitimate use-cases for that wrapper * is operation on opaque types with known offset for `struct list_node' * member(preferably 0), because it allows you not to disclose the type of * @i. * * Example: * list_for_each_off(&parent->children, child, * offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_off(h, i, off) \ for (i = list_node_to_off_(list_debug(h)->n.next, (off)); \ list_node_from_off_((void *)i, (off)) != &(h)->n; \ i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \ (off))) /** * list_for_each_safe_off - iterate through a list of memory regions, maybe * during deletion * @h: the list_head * @i: the pointer to a memory region which contains list node data. * @nxt: the structure containing the list_node * @off: offset(relative to @i) at which list node data resides. * * For details see `list_for_each_off' and `list_for_each_safe' * descriptions. * * Example: * list_for_each_safe_off(&parent->children, child, * next, offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_safe_off(h, i, nxt, off) \ for (i = list_node_to_off_(list_debug(h)->n.next, (off)), \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ (off)); \ list_node_from_off_(i, (off)) != &(h)->n; \ i = nxt, \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ (off))) /* Other -off variants. */ #define list_entry_off(n, type, off) \ ((type *)list_node_from_off_((n), (off))) #define list_head_off(h, type, off) \ ((type *)list_head_off((h), (off))) #define list_tail_off(h, type, off) \ ((type *)list_tail_((h), (off))) #define list_add_off(h, n, off) \ list_add((h), list_node_from_off_((n), (off))) #define list_del_off(n, off) \ list_del(list_node_from_off_((n), (off))) #define list_del_from_off(h, n, off) \ list_del_from(h, list_node_from_off_((n), (off))) /* Offset helper functions so we only single-evaluate. */ static inline void *list_node_to_off_(struct list_node *node, size_t off) { return (void *)((char *)node - off); } static inline struct list_node *list_node_from_off_(void *ptr, size_t off) { return (struct list_node *)((char *)ptr + off); } /* Get the offset of the member, but make sure it's a list_node. */ #define list_off_(type, member) \ (container_off(type, member) + \ check_type(((type *)0)->member, struct list_node)) #define list_off_var_(var, member) \ (container_off_var(var, member) + \ check_type(var->member, struct list_node)) #endif /* CCAN_LIST_H */ pdbg-pdbg-1.0/ccan/list/test/000077500000000000000000000000001313304724200160355ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/list/test/compile_ok-constant.c000066400000000000000000000015641313304724200221570ustar00rootroot00000000000000#include #include #include #include #include struct child { const char *name; struct list_node list; }; static bool children(const struct list_head *list) { return !list_empty(list); } static const struct child *first_child(const struct list_head *list) { return list_top(list, struct child, list); } static const struct child *last_child(const struct list_head *list) { return list_tail(list, struct child, list); } static void check_children(const struct list_head *list) { list_check(list, "bad child list"); } static void print_children(const struct list_head *list) { const struct child *c; list_for_each(list, c, list) printf("%s\n", c->name); } int main(void) { LIST_HEAD(h); children(&h); first_child(&h); last_child(&h); check_children(&h); print_children(&h); return 0; } pdbg-pdbg-1.0/ccan/list/test/helper.c000066400000000000000000000024261313304724200174640ustar00rootroot00000000000000#include #include #include #include #include "helper.h" #define ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING \ (42) struct opaque { struct list_node list; size_t secret_offset; char secret_drawer[42]; }; static bool not_randomized = true; struct opaque *create_opaque_blob(void) { struct opaque *blob = calloc(1, sizeof(struct opaque)); if (not_randomized) { srandom((int)time(NULL)); not_randomized = false; } blob->secret_offset = random() % (sizeof(blob->secret_drawer)); blob->secret_drawer[blob->secret_offset] = ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING; return blob; } bool if_blobs_know_the_secret(struct opaque *blob) { bool answer = true; int i; for (i = 0; i < sizeof(blob->secret_drawer) / sizeof(blob->secret_drawer[0]); i++) if (i != blob->secret_offset) answer = answer && (blob->secret_drawer[i] == 0); else answer = answer && (blob->secret_drawer[blob->secret_offset] == ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING); return answer; } void destroy_opaque_blob(struct opaque *blob) { free(blob); } pdbg-pdbg-1.0/ccan/list/test/helper.h000066400000000000000000000003711313304724200174660ustar00rootroot00000000000000/* These are in a separate C file so we can test undefined structures. */ struct opaque; typedef struct opaque opaque_t; opaque_t *create_opaque_blob(void); bool if_blobs_know_the_secret(opaque_t *blob); void destroy_opaque_blob(opaque_t *blob); pdbg-pdbg-1.0/ccan/list/test/run-check-corrupt.c000066400000000000000000000041151313304724200215550ustar00rootroot00000000000000#include #include #include #include #include #include /* We don't actually want it to exit... */ static jmp_buf aborted; #define abort() longjmp(aborted, 1) #define fprintf my_fprintf static char printf_buffer[1000]; static int my_fprintf(FILE *stream, const char *format, ...) { va_list ap; int ret; (void)stream; va_start(ap, format); ret = vsnprintf(printf_buffer, sizeof(printf_buffer), format, ap); va_end(ap); return ret; } #include #include #include int main(int argc, char *argv[]) { struct list_head list; struct list_node n1; char expect[100]; (void)argc; (void)argv; plan_tests(9); /* Empty list. */ list.n.next = &list.n; list.n.prev = &list.n; ok1(list_check(&list, NULL) == &list); /* Bad back ptr */ list.n.prev = &n1; /* Non-aborting version. */ ok1(list_check(&list, NULL) == NULL); /* Aborting version. */ sprintf(expect, "test message: prev corrupt in node %p (0) of %p\n", &list, &list); if (setjmp(aborted) == 0) { list_check(&list, "test message"); fail("list_check on empty with bad back ptr didn't fail!"); } else { ok1(strcmp(printf_buffer, expect) == 0); } /* n1 in list. */ list.n.next = &n1; list.n.prev = &n1; n1.prev = &list.n; n1.next = &list.n; ok1(list_check(&list, NULL) == &list); ok1(list_check_node(&n1, NULL) == &n1); /* Bad back ptr */ n1.prev = &n1; ok1(list_check(&list, NULL) == NULL); ok1(list_check_node(&n1, NULL) == NULL); /* Aborting version. */ sprintf(expect, "test message: prev corrupt in node %p (1) of %p\n", &n1, &list); if (setjmp(aborted) == 0) { list_check(&list, "test message"); fail("list_check on n1 bad back ptr didn't fail!"); } else { ok1(strcmp(printf_buffer, expect) == 0); } sprintf(expect, "test message: prev corrupt in node %p (0) of %p\n", &n1, &n1); if (setjmp(aborted) == 0) { list_check_node(&n1, "test message"); fail("list_check_node on n1 bad back ptr didn't fail!"); } else { ok1(strcmp(printf_buffer, expect) == 0); } return exit_status(); } pdbg-pdbg-1.0/ccan/list/test/run-list_del_from-assert.c000066400000000000000000000014361313304724200231300ustar00rootroot00000000000000#define CCAN_LIST_DEBUG 1 #include #include #include #include #include #include #include int main(int argc, char *argv[]) { struct list_head list1, list2; struct list_node n1, n2, n3; pid_t child; int status; (void)argc; (void)argv; plan_tests(1); list_head_init(&list1); list_head_init(&list2); list_add(&list1, &n1); list_add(&list2, &n2); list_add_tail(&list2, &n3); child = fork(); if (child) { wait(&status); } else { close(2); /* Close stderr so we don't print confusing assert */ /* This should abort. */ list_del_from(&list1, &n3); exit(0); } ok1(WIFSIGNALED(status) && WTERMSIG(status) == SIGABRT); list_del_from(&list2, &n3); return exit_status(); } pdbg-pdbg-1.0/ccan/list/test/run-single-eval.c000066400000000000000000000112041313304724200212070ustar00rootroot00000000000000/* Make sure macros only evaluate their args once. */ #include #include #include struct parent { const char *name; struct list_head children; unsigned int num_children; int eval_count; }; struct child { const char *name; struct list_node list; }; static LIST_HEAD(static_list); #define ref(obj, counter) ((counter)++, (obj)) int main(int argc, char *argv[]) { struct parent parent; struct child c1, c2, c3, *c, *n; unsigned int i; unsigned int static_count = 0, parent_count = 0, list_count = 0, node_count = 0; struct list_head list = LIST_HEAD_INIT(list); (void)argc; (void)argv; plan_tests(74); /* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */ ok1(list_empty(ref(&static_list, static_count))); ok1(static_count == 1); ok1(list_check(ref(&static_list, static_count), NULL)); ok1(static_count == 2); ok1(list_empty(ref(&list, list_count))); ok1(list_count == 1); ok1(list_check(ref(&list, list_count), NULL)); ok1(list_count == 2); parent.num_children = 0; list_head_init(ref(&parent.children, parent_count)); ok1(parent_count == 1); /* Test list_head_init */ ok1(list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 2); ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 3); c2.name = "c2"; list_add(ref(&parent.children, parent_count), &c2.list); ok1(parent_count == 4); /* Test list_add and !list_empty. */ ok1(!list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 5); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &parent.children.n); ok1(parent.children.n.next == &c2.list); ok1(parent.children.n.prev == &c2.list); /* Test list_check */ ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 6); c1.name = "c1"; list_add(ref(&parent.children, parent_count), &c1.list); ok1(parent_count == 7); /* Test list_add and !list_empty. */ ok1(!list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 8); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &c1.list); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c2.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); /* Test list_check */ ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 9); c3.name = "c3"; list_add_tail(ref(&parent.children, parent_count), &c3.list); ok1(parent_count == 10); /* Test list_add_tail and !list_empty. */ ok1(!list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 11); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c3.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); ok1(c2.list.next == &c3.list); ok1(c2.list.prev == &c1.list); ok1(c3.list.next == &parent.children.n); ok1(c3.list.prev == &c2.list); /* Test list_check */ ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 12); /* Test list_check_node */ ok1(list_check_node(&c1.list, NULL)); ok1(list_check_node(&c2.list, NULL)); ok1(list_check_node(&c3.list, NULL)); /* Test list_top */ ok1(list_top(ref(&parent.children, parent_count), struct child, list) == &c1); ok1(parent_count == 13); /* Test list_tail */ ok1(list_tail(ref(&parent.children, parent_count), struct child, list) == &c3); ok1(parent_count == 14); /* Test list_for_each. */ i = 0; list_for_each(&parent.children, c, list) { switch (i++) { case 0: ok1(c == &c1); break; case 1: ok1(c == &c2); break; case 2: ok1(c == &c3); break; } if (i > 2) break; } ok1(i == 3); /* Test list_for_each_safe, list_del and list_del_from. */ i = 0; list_for_each_safe(&parent.children, c, n, list) { switch (i++) { case 0: ok1(c == &c1); list_del(ref(&c->list, node_count)); ok1(node_count == 1); break; case 1: ok1(c == &c2); list_del_from(ref(&parent.children, parent_count), ref(&c->list, node_count)); ok1(node_count == 2); break; case 2: ok1(c == &c3); list_del_from(ref(&parent.children, parent_count), ref(&c->list, node_count)); ok1(node_count == 3); break; } ok1(list_check(ref(&parent.children, parent_count), NULL)); if (i > 2) break; } ok1(i == 3); ok1(parent_count == 19); ok1(list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 20); /* Test list_top/list_tail on empty list. */ ok1(list_top(ref(&parent.children, parent_count), struct child, list) == NULL); ok1(parent_count == 21); ok1(list_tail(ref(&parent.children, parent_count), struct child, list) == NULL); ok1(parent_count == 22); return exit_status(); } pdbg-pdbg-1.0/ccan/list/test/run-with-debug.c000066400000000000000000000001641313304724200210430ustar00rootroot00000000000000/* Just like run.c, but with all debug checks enabled. */ #define CCAN_LIST_DEBUG 1 #include pdbg-pdbg-1.0/ccan/list/test/run.c000066400000000000000000000112431313304724200170060ustar00rootroot00000000000000#include #include #include #include #include "helper.h" struct parent { const char *name; struct list_head children; unsigned int num_children; }; struct child { const char *name; struct list_node list; }; static LIST_HEAD(static_list); int main(int argc, char *argv[]) { struct parent parent; struct child c1, c2, c3, *c, *n; unsigned int i; struct list_head list = LIST_HEAD_INIT(list); opaque_t *q, *nq; struct list_head opaque_list = LIST_HEAD_INIT(opaque_list); (void)argc; (void)argv; plan_tests(65); /* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */ ok1(list_empty(&static_list)); ok1(list_check(&static_list, NULL)); ok1(list_empty(&list)); ok1(list_check(&list, NULL)); parent.num_children = 0; list_head_init(&parent.children); /* Test list_head_init */ ok1(list_empty(&parent.children)); ok1(list_check(&parent.children, NULL)); c2.name = "c2"; list_add(&parent.children, &c2.list); /* Test list_add and !list_empty. */ ok1(!list_empty(&parent.children)); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &parent.children.n); ok1(parent.children.n.next == &c2.list); ok1(parent.children.n.prev == &c2.list); /* Test list_check */ ok1(list_check(&parent.children, NULL)); c1.name = "c1"; list_add(&parent.children, &c1.list); /* Test list_add and !list_empty. */ ok1(!list_empty(&parent.children)); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &c1.list); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c2.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); /* Test list_check */ ok1(list_check(&parent.children, NULL)); c3.name = "c3"; list_add_tail(&parent.children, &c3.list); /* Test list_add_tail and !list_empty. */ ok1(!list_empty(&parent.children)); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c3.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); ok1(c2.list.next == &c3.list); ok1(c2.list.prev == &c1.list); ok1(c3.list.next == &parent.children.n); ok1(c3.list.prev == &c2.list); /* Test list_check */ ok1(list_check(&parent.children, NULL)); /* Test list_check_node */ ok1(list_check_node(&c1.list, NULL)); ok1(list_check_node(&c2.list, NULL)); ok1(list_check_node(&c3.list, NULL)); /* Test list_top */ ok1(list_top(&parent.children, struct child, list) == &c1); /* Test list_tail */ ok1(list_tail(&parent.children, struct child, list) == &c3); /* Test list_for_each. */ i = 0; list_for_each(&parent.children, c, list) { switch (i++) { case 0: ok1(c == &c1); break; case 1: ok1(c == &c2); break; case 2: ok1(c == &c3); break; } if (i > 2) break; } ok1(i == 3); /* Test list_for_each_rev. */ i = 0; list_for_each_rev(&parent.children, c, list) { switch (i++) { case 0: ok1(c == &c3); break; case 1: ok1(c == &c2); break; case 2: ok1(c == &c1); break; } if (i > 2) break; } ok1(i == 3); /* Test list_for_each_safe, list_del and list_del_from. */ i = 0; list_for_each_safe(&parent.children, c, n, list) { switch (i++) { case 0: ok1(c == &c1); list_del(&c->list); break; case 1: ok1(c == &c2); list_del_from(&parent.children, &c->list); break; case 2: ok1(c == &c3); list_del_from(&parent.children, &c->list); break; } ok1(list_check(&parent.children, NULL)); if (i > 2) break; } ok1(i == 3); ok1(list_empty(&parent.children)); /* Test list_for_each_off. */ list_add_tail(&opaque_list, (struct list_node *)create_opaque_blob()); list_add_tail(&opaque_list, (struct list_node *)create_opaque_blob()); list_add_tail(&opaque_list, (struct list_node *)create_opaque_blob()); i = 0; list_for_each_off(&opaque_list, q, 0) { i++; ok1(if_blobs_know_the_secret(q)); } ok1(i == 3); /* Test list_for_each_safe_off, list_del_off and list_del_from_off. */ i = 0; list_for_each_safe_off(&opaque_list, q, nq, 0) { switch (i++) { case 0: ok1(if_blobs_know_the_secret(q)); list_del_off(q, 0); destroy_opaque_blob(q); break; case 1: ok1(if_blobs_know_the_secret(q)); list_del_from_off(&opaque_list, q, 0); destroy_opaque_blob(q); break; case 2: ok1(c == &c3); list_del_from_off(&opaque_list, q, 0); destroy_opaque_blob(q); break; } ok1(list_check(&opaque_list, NULL)); if (i > 2) break; } ok1(i == 3); ok1(list_empty(&opaque_list)); /* Test list_top/list_tail on empty list. */ ok1(list_top(&parent.children, struct child, list) == NULL); ok1(list_tail(&parent.children, struct child, list) == NULL); return exit_status(); } pdbg-pdbg-1.0/ccan/short_types/000077500000000000000000000000001313304724200164665ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/short_types/LICENSE000066400000000000000000000143571313304724200175050ustar00rootroot00000000000000Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. pdbg-pdbg-1.0/ccan/short_types/_info000066400000000000000000000051631313304724200175100ustar00rootroot00000000000000#include "config.h" #include #include /** * short_types - shorter names for standard integer types * * "C is a Spartan language, and so should your naming be." * -- Linus Torvalds * * The short_types header provides for convenient abbreviations for the * posixly-damned uint32_t types. If ccan/endian/endian.h is included, * it also provides be32/le32 for explicitly annotating types of specific * endian. * * Include this header, if only to stop people using these identifiers * for other things! * * Example: * #include * #include * #include * #include * * // Print nonsensical numerical comparison of POSIX vs. short_types. * #define stringify_1(x) #x * #define stringify(x) stringify_1(x) * * static void evaluate(size_t size, const char *posix, const char *sht, * unsigned int *posix_total, unsigned int *sht_total, * unsigned int *size_total) * { * printf("\t%ssigned %s: POSIX %zu%%, short %zu%%\n", * sht[0] == 'u' ? "un" : "", * sht+1, * strlen(posix)*100 / size, * strlen(sht)*100 / size); * *posix_total += strlen(posix); * *sht_total += strlen(sht); * *size_total += size; * } * * #define EVALUATE(psx, short, pt, st, t) \ * evaluate(sizeof(psx), stringify(psx), stringify(sht), pt, st, t) * * int main(void) * { * unsigned int posix_total = 0, sht_total = 0, size_total = 0; * * printf("Comparing size of type vs size of name:\n"); * * EVALUATE(uint8_t, u8, &posix_total, &sht_total, &size_total); * EVALUATE(int8_t, s8, &posix_total, &sht_total, &size_total); * EVALUATE(uint16_t, u16, &posix_total, &sht_total, &size_total); * EVALUATE(int16_t, s16, &posix_total, &sht_total, &size_total); * EVALUATE(uint32_t, u32, &posix_total, &sht_total, &size_total); * EVALUATE(int32_t, s32, &posix_total, &sht_total, &size_total); * EVALUATE(uint64_t, u64, &posix_total, &sht_total, &size_total); * EVALUATE(int64_t, s64, &posix_total, &sht_total, &size_total); * * printf("Conclusion:\n" * "\tPOSIX is %u%% LESS efficient than binary.\n" * "\tshort_types.h is %u%% MORE efficient than binary.\n", * (posix_total - size_total) * 100 / size_total, * (size_total - sht_total) * 100 / size_total); * return 0; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { return 0; } if (strcmp(argv[1], "testdepends") == 0) { printf("ccan/endian\n"); return 0; } return 1; } pdbg-pdbg-1.0/ccan/short_types/short_types.h000066400000000000000000000014311313304724200212210ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_SHORT_TYPES_H #define CCAN_SHORT_TYPES_H #include /** * u64/s64/u32/s32/u16/s16/u8/s8 - short names for explicitly-sized types. */ typedef uint64_t u64; typedef int64_t s64; typedef uint32_t u32; typedef int32_t s32; typedef uint16_t u16; typedef int16_t s16; typedef uint8_t u8; typedef int8_t s8; /* Whichever they include first, they get these definitions. */ #ifdef CCAN_ENDIAN_H /** * be64/be32/be16 - 64/32/16 bit big-endian representation. */ typedef beint64_t be64; typedef beint32_t be32; typedef beint16_t be16; /** * le64/le32/le16 - 64/32/16 bit little-endian representation. */ typedef leint64_t le64; typedef leint32_t le32; typedef leint16_t le16; #endif #endif /* CCAN_SHORT_TYPES_H */ pdbg-pdbg-1.0/ccan/short_types/test/000077500000000000000000000000001313304724200174455ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/short_types/test/run-endian.c000066400000000000000000000005351313304724200216540ustar00rootroot00000000000000#include #include #include #include #include int main(void) { plan_tests(6); ok1(sizeof(be64) == 8); ok1(sizeof(be32) == 4); ok1(sizeof(be16) == 2); ok1(sizeof(le64) == 8); ok1(sizeof(le32) == 4); ok1(sizeof(le16) == 2); return exit_status(); } pdbg-pdbg-1.0/ccan/short_types/test/run.c000066400000000000000000000010251313304724200204130ustar00rootroot00000000000000#include #include #include #include int main(void) { plan_tests(16); ok1(sizeof(u64) == 8); ok1(sizeof(s64) == 8); ok1(sizeof(u32) == 4); ok1(sizeof(s32) == 4); ok1(sizeof(u16) == 2); ok1(sizeof(s16) == 2); ok1(sizeof(u8) == 1); ok1(sizeof(s8) == 1); /* Signedness tests. */ ok1((u64)-1 > 0); ok1((u32)-1 > 0); ok1((u16)-1 > 0); ok1((u8)-1 > 0); ok1((s64)-1 < 0); ok1((s32)-1 < 0); ok1((s16)-1 < 0); ok1((s8)-1 < 0); return exit_status(); } pdbg-pdbg-1.0/ccan/str/000077500000000000000000000000001313304724200147135ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/str/LICENSE000066400000000000000000000143571313304724200157320ustar00rootroot00000000000000Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. pdbg-pdbg-1.0/ccan/str/_info000066400000000000000000000025101313304724200157260ustar00rootroot00000000000000#include #include #include "config.h" /** * str - string helper routines * * This is a grab bag of functions for string operations, designed to enhance * the standard string.h. * * Note that if you define CCAN_STR_DEBUG, you will get extra compile * checks on common misuses of the following functions (they will now * be out-of-line, so there is a runtime penalty!). * * strstr, strchr, strrchr: * Return const char * if first argument is const (gcc only). * * isalnum, isalpha, isascii, isblank, iscntrl, isdigit, isgraph, * islower, isprint, ispunct, isspace, isupper, isxdigit: * Static and runtime check that input is EOF or an *unsigned* * char, as per C standard (really!). * * Example: * #include * #include * * int main(int argc, char *argv[]) * { * if (argv[1] && streq(argv[1], "--verbose")) * printf("verbose set\n"); * if (argv[1] && strstarts(argv[1], "--")) * printf("Some option set\n"); * if (argv[1] && strends(argv[1], "cow-powers")) * printf("Magic option set\n"); * return 0; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/build_assert\n"); return 0; } return 1; } pdbg-pdbg-1.0/ccan/str/str.c000066400000000000000000000004331313304724200156670ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #include size_t strcount(const char *haystack, const char *needle) { size_t i = 0, nlen = strlen(needle); while ((haystack = strstr(haystack, needle)) != NULL) { i++; haystack += nlen; } return i; } pdbg-pdbg-1.0/ccan/str/str.h000066400000000000000000000064301313304724200156770ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_STR_H #define CCAN_STR_H #include "config.h" #include #include #include #include /** * streq - Are two strings equal? * @a: first string * @b: first string * * This macro is arguably more readable than "!strcmp(a, b)". * * Example: * if (streq(somestring, "")) * printf("String is empty!\n"); */ #define streq(a,b) (strcmp((a),(b)) == 0) /** * strstarts - Does this string start with this prefix? * @str: string to test * @prefix: prefix to look for at start of str * * Example: * if (strstarts(somestring, "foo")) * printf("String %s begins with 'foo'!\n", somestring); */ #define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0) /** * strends - Does this string end with this postfix? * @str: string to test * @postfix: postfix to look for at end of str * * Example: * if (strends(somestring, "foo")) * printf("String %s end with 'foo'!\n", somestring); */ static inline bool strends(const char *str, const char *postfix) { if (strlen(str) < strlen(postfix)) return false; return streq(str + strlen(str) - strlen(postfix), postfix); } /** * stringify - Turn expression into a string literal * @expr: any C expression * * Example: * #define PRINT_COND_IF_FALSE(cond) \ * ((cond) || printf("%s is false!", stringify(cond))) */ #define stringify(expr) stringify_1(expr) /* Double-indirection required to stringify expansions */ #define stringify_1(expr) #expr /** * strcount - Count number of (non-overlapping) occurrences of a substring. * @haystack: a C string * @needle: a substring * * Example: * assert(strcount("aaa aaa", "a") == 6); * assert(strcount("aaa aaa", "ab") == 0); * assert(strcount("aaa aaa", "aa") == 2); */ size_t strcount(const char *haystack, const char *needle); /** * STR_MAX_CHARS - Maximum possible size of numeric string for this type. * @type_or_expr: a pointer or integer type or expression. * * This provides enough space for a nul-terminated string which represents the * largest possible value for the type or expression. * * Note: The implementation adds extra space so hex values or negative * values will fit (eg. sprintf(... "%p"). ) * * Example: * char str[STR_MAX_CHARS(int)]; * * sprintf(str, "%i", 7); */ #define STR_MAX_CHARS(type_or_expr) \ ((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \ + STR_MAX_CHARS_TCHECK_(type_or_expr)) #if HAVE_TYPEOF /* Only a simple type can have 0 assigned, so test that. */ #define STR_MAX_CHARS_TCHECK_(type_or_expr) \ ({ typeof(type_or_expr) x = 0; (void)x; 0; }) #else #define STR_MAX_CHARS_TCHECK_(type_or_expr) 0 #endif /* These checks force things out of line, hence they are under DEBUG. */ #ifdef CCAN_STR_DEBUG #if HAVE_TYPEOF /* With GNU magic, we can make const-respecting standard string functions. */ #undef strstr #undef strchr #undef strrchr /* + 0 is needed to decay array into pointer. */ #define strstr(haystack, needle) \ ((typeof((haystack) + 0))str_strstr((haystack), (needle))) #define strchr(haystack, c) \ ((typeof((haystack) + 0))str_strchr((haystack), (c))) #define strrchr(haystack, c) \ ((typeof((haystack) + 0))str_strrchr((haystack), (c))) #endif #endif /* CCAN_STR_DEBUG */ #endif /* CCAN_STR_H */ pdbg-pdbg-1.0/ccan/str/test/000077500000000000000000000000001313304724200156725ustar00rootroot00000000000000pdbg-pdbg-1.0/ccan/str/test/compile_fail-STR_MAX_CHARS.c000066400000000000000000000004561313304724200225610ustar00rootroot00000000000000#include struct s { int val; }; int main(int argc, char *argv[]) { struct s #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check STR_MAX_CHARS. #endif #else /* A pointer is OK. */ * #endif val; char str[STR_MAX_CHARS(val)]; str[0] = '\0'; return str[0] ? 0 : 1; } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isalnum.c000066400000000000000000000005611313304724200221310ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isalnum. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isalnum(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isalpha.c000066400000000000000000000005611313304724200221020ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isalpha. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isalpha(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isascii.c000066400000000000000000000005611313304724200221050ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isascii. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isascii(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isblank.c000066400000000000000000000006531313304724200221060ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF || !HAVE_ISBLANK #error We need typeof to check isblank. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif #if HAVE_ISBLANK return isblank(c); #else return c; #endif } pdbg-pdbg-1.0/ccan/str/test/compile_fail-iscntrl.c000066400000000000000000000005611313304724200221370ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check iscntrl. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return iscntrl(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isdigit.c000066400000000000000000000005611313304724200221150ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isdigit. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isdigit(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-islower.c000066400000000000000000000005611313304724200221450ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check islower. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return islower(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isprint.c000066400000000000000000000005611313304724200221510ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isprint. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isprint(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-ispunct.c000066400000000000000000000005611313304724200221460ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check ispunct. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return ispunct(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isspace.c000066400000000000000000000005611313304724200221100ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isspace. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isspace(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isupper.c000066400000000000000000000005611313304724200221500ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isupper. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isupper(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-isxdigit.c000066400000000000000000000005631313304724200223070ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isxdigit. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isxdigit(c); } pdbg-pdbg-1.0/ccan/str/test/compile_fail-strchr.c000066400000000000000000000004211313304724200217610ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check strstr. #endif #else const #endif char *ret; const char *str = "hello"; ret = strchr(str, 'l'); return ret ? 0 : 1; } pdbg-pdbg-1.0/ccan/str/test/compile_fail-strrchr.c000066400000000000000000000004221313304724200221440ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check strstr. #endif #else const #endif char *ret; const char *str = "hello"; ret = strrchr(str, 'l'); return ret ? 0 : 1; } pdbg-pdbg-1.0/ccan/str/test/compile_fail-strstr.c000066400000000000000000000004241313304724200220200ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check strstr. #endif #else const #endif char *ret; const char *str = "hello"; ret = strstr(str, "hell"); return ret ? 0 : 1; } pdbg-pdbg-1.0/ccan/str/test/debug.c000066400000000000000000000003241313304724200171230ustar00rootroot00000000000000/* We can't use the normal "#include the .c file" trick, since this is contaminated by str.h's macro overrides. So we put it in all tests like this. */ #define CCAN_STR_DEBUG 1 #include pdbg-pdbg-1.0/ccan/str/test/run-STR_MAX_CHARS.c000066400000000000000000000034131313304724200207360ustar00rootroot00000000000000#include #include #include #include #include int main(int argc, char *argv[]) { char *str = (char*)malloc(sizeof(char)*1000); struct { uint8_t u1byte; int8_t s1byte; uint16_t u2byte; int16_t s2byte; uint32_t u4byte; int32_t s4byte; uint64_t u8byte; int64_t s8byte; void *ptr; } types; (void)argc; (void)argv; assert(str); plan_tests(13); memset(&types, 0xFF, sizeof(types)); /* Hex versions */ sprintf(str, "0x%llx", (unsigned long long)types.u1byte); ok1(strlen(str) < STR_MAX_CHARS(types.u1byte)); sprintf(str, "0x%llx", (unsigned long long)types.u2byte); ok1(strlen(str) < STR_MAX_CHARS(types.u2byte)); sprintf(str, "0x%llx", (unsigned long long)types.u4byte); ok1(strlen(str) < STR_MAX_CHARS(types.u4byte)); sprintf(str, "0x%llx", (unsigned long long)types.u8byte); ok1(strlen(str) < STR_MAX_CHARS(types.u8byte)); /* Decimal versions */ sprintf(str, "%u", types.u1byte); ok1(strlen(str) < STR_MAX_CHARS(types.u1byte)); sprintf(str, "%d", types.s1byte); ok1(strlen(str) < STR_MAX_CHARS(types.s1byte)); sprintf(str, "%u", types.u2byte); ok1(strlen(str) < STR_MAX_CHARS(types.u2byte)); sprintf(str, "%d", types.s2byte); ok1(strlen(str) < STR_MAX_CHARS(types.s2byte)); sprintf(str, "%u", types.u4byte); ok1(strlen(str) < STR_MAX_CHARS(types.u4byte)); sprintf(str, "%d", types.s4byte); ok1(strlen(str) < STR_MAX_CHARS(types.s4byte)); sprintf(str, "%llu", (unsigned long long)types.u8byte); ok1(strlen(str) < STR_MAX_CHARS(types.u8byte)); sprintf(str, "%lld", (long long)types.s8byte); ok1(strlen(str) < STR_MAX_CHARS(types.s8byte)); /* Pointer version. */ sprintf(str, "%p", types.ptr); ok1(strlen(str) < STR_MAX_CHARS(types.ptr)); free(str); return exit_status(); } pdbg-pdbg-1.0/ccan/str/test/run.c000066400000000000000000000051651313304724200166510ustar00rootroot00000000000000#include #include #include #include #include #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) static const char *substrings[] = { "far", "bar", "baz", "b", "ba", "z", "ar", NULL }; #define NUM_SUBSTRINGS (ARRAY_SIZE(substrings) - 1) static char *strdup_rev(const char *s) { char *ret = strdup(s); unsigned int i; for (i = 0; i < strlen(s); i++) ret[i] = s[strlen(s) - i - 1]; return ret; } int main(int argc, char *argv[]) { unsigned int i, j, n; char *strings[NUM_SUBSTRINGS * NUM_SUBSTRINGS]; (void)argc; (void)argv; n = 0; for (i = 0; i < NUM_SUBSTRINGS; i++) { for (j = 0; j < NUM_SUBSTRINGS; j++) { strings[n] = malloc(strlen(substrings[i]) + strlen(substrings[j]) + 1); sprintf(strings[n++], "%s%s", substrings[i], substrings[j]); } } plan_tests(n * n * 5 + 16); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { unsigned int k, identical = 0; char *reva, *revb; /* Find first difference. */ for (k = 0; strings[i][k]==strings[j][k]; k++) { if (k == strlen(strings[i])) { identical = 1; break; } } if (identical) ok1(streq(strings[i], strings[j])); else ok1(!streq(strings[i], strings[j])); /* Postfix test should be equivalent to prefix * test on reversed string. */ reva = strdup_rev(strings[i]); revb = strdup_rev(strings[j]); if (!strings[i][k]) { ok1(strstarts(strings[j], strings[i])); ok1(strends(revb, reva)); } else { ok1(!strstarts(strings[j], strings[i])); ok1(!strends(revb, reva)); } if (!strings[j][k]) { ok1(strstarts(strings[i], strings[j])); ok1(strends(reva, revb)); } else { ok1(!strstarts(strings[i], strings[j])); ok1(!strends(reva, revb)); } free(reva); free(revb); } } for (i = 0; i < n; i++) free(strings[i]); ok1(streq(stringify(NUM_SUBSTRINGS), "((sizeof(substrings) / sizeof(substrings[0])) - 1)")); ok1(streq(stringify(ARRAY_SIZE(substrings)), "(sizeof(substrings) / sizeof(substrings[0]))")); ok1(streq(stringify(i == 0), "i == 0")); ok1(strcount("aaaaaa", "b") == 0); ok1(strcount("aaaaaa", "a") == 6); ok1(strcount("aaaaaa", "aa") == 3); ok1(strcount("aaaaaa", "aaa") == 2); ok1(strcount("aaaaaa", "aaaa") == 1); ok1(strcount("aaaaaa", "aaaaa") == 1); ok1(strcount("aaaaaa", "aaaaaa") == 1); ok1(strcount("aaa aaa", "b") == 0); ok1(strcount("aaa aaa", "a") == 6); ok1(strcount("aaa aaa", "aa") == 2); ok1(strcount("aaa aaa", "aaa") == 2); ok1(strcount("aaa aaa", "aaaa") == 0); ok1(strcount("aaa aaa", "aaaaa") == 0); return exit_status(); } pdbg-pdbg-1.0/configure.ac000066400000000000000000000010731313304724200154660ustar00rootroot00000000000000AC_INIT([pdbg], [1.0]) AM_INIT_AUTOMAKE([subdir-objects]) AC_PROG_CC AC_PROG_LIBTOOL AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) AC_LANG(C) AC_SUBST([ARCH_FF]) AC_CHECK_TOOL([OBJDUMP], [objdump]) AC_CHECK_TOOL([OBJCOPY], [objcopy]) AC_SUBST([OBJCOPY]) AC_COMPILE_IFELSE( [AC_LANG_SOURCE([[]])], ARCH_FF=$(${OBJDUMP} -f conftest.$OBJEXT | sed -ne "s/.*file format //p" -e "s/.*architecture: \(.*\),.*/\1/p" | tr "\n" " " | sed -e "s/ / -B /"), AC_MSG_FAILURE([Unable to determine architecture output file format])) AC_OUTPUT pdbg-pdbg-1.0/fake.dts000066400000000000000000000005061313304724200146220ustar00rootroot00000000000000/dts-v1/; / { #address-cells = <0x1>; #size-cells = <0x0>; fsi@0 { #address-cells = <0x2>; #size-cells = <0x1>; compatible = "ibm,fake-fsi"; reg = <0x0 0x0 0x0>; index = <0x0>; status = "hidden"; pib@0 { compatible = "ibm,fake-pib"; reg = <0x0 0x0 0x0>; index = <0x0>; }; }; }; pdbg-pdbg-1.0/libfdt/000077500000000000000000000000001313304724200144435ustar00rootroot00000000000000pdbg-pdbg-1.0/libfdt/Makefile.libfdt000066400000000000000000000006531313304724200173520ustar00rootroot00000000000000# Makefile.libfdt # # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h LIBFDT_VERSION = version.lds LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ fdt_addresses.c fdt_overlay.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) pdbg-pdbg-1.0/libfdt/TODO000066400000000000000000000001251313304724200151310ustar00rootroot00000000000000- Tree traversal functions - Graft function - Complete libfdt.h documenting comments pdbg-pdbg-1.0/libfdt/fdt.c000066400000000000000000000147611313304724200153750ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_check_header(const void *fdt) { if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION; if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION; } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { /* Unfinished sequential-write blob */ if (fdt_size_dt_struct(fdt) == 0) return -FDT_ERR_BADSTATE; } else { return -FDT_ERR_BADMAGIC; } return 0; } const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { unsigned absoffset = offset + fdt_off_dt_struct(fdt); if ((absoffset < offset) || ((absoffset + len) < absoffset) || (absoffset + len) > fdt_totalsize(fdt)) return NULL; if (fdt_version(fdt) >= 0x11) if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; return _fdt_offset_ptr(fdt, offset); } uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const fdt32_t *tagp, *lenp; uint32_t tag; int offset = startoffset; const char *p; *nextoffset = -FDT_ERR_TRUNCATED; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); if (!tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; *nextoffset = -FDT_ERR_BADSTRUCTURE; switch (tag) { case FDT_BEGIN_NODE: /* skip name */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); if (!p) return FDT_END; /* premature end */ break; case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (!lenp) return FDT_END; /* premature end */ /* skip-name offset, length and value */ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + fdt32_to_cpu(*lenp); break; case FDT_END: case FDT_END_NODE: case FDT_NOP: break; default: return FDT_END; } if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) return FDT_END; /* premature end */ *nextoffset = FDT_TAGALIGN(offset); return tag; } int _fdt_check_node_offset(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) return -FDT_ERR_BADOFFSET; return offset; } int _fdt_check_prop_offset(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) return -FDT_ERR_BADOFFSET; return offset; } int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; uint32_t tag; if (offset >= 0) if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) return nextoffset; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_PROP: case FDT_NOP: break; case FDT_BEGIN_NODE: if (depth) (*depth)++; break; case FDT_END_NODE: if (depth && ((--(*depth)) < 0)) return nextoffset; break; case FDT_END: if ((nextoffset >= 0) || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) return -FDT_ERR_NOTFOUND; else return nextoffset; } } while (tag != FDT_BEGIN_NODE); return offset; } int fdt_first_subnode(const void *fdt, int offset) { int depth = 0; offset = fdt_next_node(fdt, offset, &depth); if (offset < 0 || depth != 1) return -FDT_ERR_NOTFOUND; return offset; } int fdt_next_subnode(const void *fdt, int offset) { int depth = 1; /* * With respect to the parent, the depth of the next subnode will be * the same as the last. */ do { offset = fdt_next_node(fdt, offset, &depth); if (offset < 0 || depth < 1) return -FDT_ERR_NOTFOUND; } while (depth > 1); return offset; } const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) { int len = strlen(s) + 1; const char *last = strtab + tabsize - len; const char *p; for (p = strtab; p <= last; p++) if (memcmp(p, s, len) == 0) return p; return NULL; } int fdt_move(const void *fdt, void *buf, int bufsize) { FDT_CHECK_HEADER(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; memmove(buf, fdt, fdt_totalsize(fdt)); return 0; } pdbg-pdbg-1.0/libfdt/fdt.h000066400000000000000000000076661313304724200154100ustar00rootroot00000000000000#ifndef _FDT_H #define _FDT_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright 2012 Kim Phillips, Freescale Semiconductor. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __ASSEMBLY__ struct fdt_header { fdt32_t magic; /* magic word FDT_MAGIC */ fdt32_t totalsize; /* total size of DT block */ fdt32_t off_dt_struct; /* offset to structure */ fdt32_t off_dt_strings; /* offset to strings */ fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ fdt32_t version; /* format version */ fdt32_t last_comp_version; /* last compatible version */ /* version 2 fields below */ fdt32_t boot_cpuid_phys; /* Which physical CPU id we're booting on */ /* version 3 fields below */ fdt32_t size_dt_strings; /* size of the strings block */ /* version 17 fields below */ fdt32_t size_dt_struct; /* size of the structure block */ }; struct fdt_reserve_entry { fdt64_t address; fdt64_t size; }; struct fdt_node_header { fdt32_t tag; char name[0]; }; struct fdt_property { fdt32_t tag; fdt32_t len; fdt32_t nameoff; char data[0]; }; #endif /* !__ASSEMBLY */ #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ #define FDT_TAGSIZE sizeof(fdt32_t) #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ #define FDT_END_NODE 0x2 /* End node */ #define FDT_PROP 0x3 /* Property: name off, size, content */ #define FDT_NOP 0x4 /* nop */ #define FDT_END 0x9 #define FDT_V1_SIZE (7*sizeof(fdt32_t)) #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) #define FDT_V16_SIZE FDT_V3_SIZE #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) #endif /* _FDT_H */ pdbg-pdbg-1.0/libfdt/fdt_addresses.c000066400000000000000000000062311313304724200174230ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2014 David Gibson * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_address_cells(const void *fdt, int nodeoffset) { const fdt32_t *ac; int val; int len; ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); if (!ac) return 2; if (len != sizeof(*ac)) return -FDT_ERR_BADNCELLS; val = fdt32_to_cpu(*ac); if ((val <= 0) || (val > FDT_MAX_NCELLS)) return -FDT_ERR_BADNCELLS; return val; } int fdt_size_cells(const void *fdt, int nodeoffset) { const fdt32_t *sc; int val; int len; sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); if (!sc) return 2; if (len != sizeof(*sc)) return -FDT_ERR_BADNCELLS; val = fdt32_to_cpu(*sc); if ((val < 0) || (val > FDT_MAX_NCELLS)) return -FDT_ERR_BADNCELLS; return val; } pdbg-pdbg-1.0/libfdt/fdt_empty_tree.c000066400000000000000000000055271313304724200176320ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2012 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_create_empty_tree(void *buf, int bufsize) { int err; err = fdt_create(buf, bufsize); if (err) return err; err = fdt_finish_reservemap(buf); if (err) return err; err = fdt_begin_node(buf, ""); if (err) return err; err = fdt_end_node(buf); if (err) return err; err = fdt_finish(buf); if (err) return err; return fdt_open_into(buf, buf, bufsize); } pdbg-pdbg-1.0/libfdt/fdt_overlay.c000066400000000000000000000414671313304724200171410ustar00rootroot00000000000000#include "libfdt_env.h" #include #include #include "libfdt_internal.h" /** * overlay_get_target_phandle - retrieves the target phandle of a fragment * @fdto: pointer to the device tree overlay blob * @fragment: node offset of the fragment in the overlay * * overlay_get_target_phandle() retrieves the target phandle of an * overlay fragment when that fragment uses a phandle (target * property) instead of a path (target-path property). * * returns: * the phandle pointed by the target property * 0, if the phandle was not found * -1, if the phandle was malformed */ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) { const uint32_t *val; int len; val = fdt_getprop(fdto, fragment, "target", &len); if (!val) return 0; if ((len != sizeof(*val)) || (*val == (uint32_t)-1)) return (uint32_t)-1; return fdt32_to_cpu(*val); } /** * overlay_get_target - retrieves the offset of a fragment's target * @fdt: Base device tree blob * @fdto: Device tree overlay blob * @fragment: node offset of the fragment in the overlay * * overlay_get_target() retrieves the target offset in the base * device tree of a fragment, no matter how the actual targetting is * done (through a phandle or a path) * * returns: * the targetted node offset in the base device tree * Negative error code on error */ static int overlay_get_target(const void *fdt, const void *fdto, int fragment) { uint32_t phandle; const char *path; int path_len; /* Try first to do a phandle based lookup */ phandle = overlay_get_target_phandle(fdto, fragment); if (phandle == (uint32_t)-1) return -FDT_ERR_BADPHANDLE; if (phandle) return fdt_node_offset_by_phandle(fdt, phandle); /* And then a path based lookup */ path = fdt_getprop(fdto, fragment, "target-path", &path_len); if (!path) { /* * If we haven't found either a target or a * target-path property in a node that contains a * __overlay__ subnode (we wouldn't be called * otherwise), consider it a improperly written * overlay */ if (path_len == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; return path_len; } return fdt_path_offset(fdt, path); } /** * overlay_phandle_add_offset - Increases a phandle by an offset * @fdt: Base device tree blob * @node: Device tree overlay blob * @name: Name of the property to modify (phandle or linux,phandle) * @delta: offset to apply * * overlay_phandle_add_offset() increments a node phandle by a given * offset. * * returns: * 0 on success. * Negative error code on error */ static int overlay_phandle_add_offset(void *fdt, int node, const char *name, uint32_t delta) { const uint32_t *val; uint32_t adj_val; int len; val = fdt_getprop(fdt, node, name, &len); if (!val) return len; if (len != sizeof(*val)) return -FDT_ERR_BADPHANDLE; adj_val = fdt32_to_cpu(*val); if ((adj_val + delta) < adj_val) return -FDT_ERR_NOPHANDLES; adj_val += delta; if (adj_val == (uint32_t)-1) return -FDT_ERR_NOPHANDLES; return fdt_setprop_inplace_u32(fdt, node, name, adj_val); } /** * overlay_adjust_node_phandles - Offsets the phandles of a node * @fdto: Device tree overlay blob * @node: Offset of the node we want to adjust * @delta: Offset to shift the phandles of * * overlay_adjust_node_phandles() adds a constant to all the phandles * of a given node. This is mainly use as part of the overlay * application process, when we want to update all the overlay * phandles to not conflict with the overlays of the base device tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_adjust_node_phandles(void *fdto, int node, uint32_t delta) { int child; int ret; ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); if (ret && ret != -FDT_ERR_NOTFOUND) return ret; ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); if (ret && ret != -FDT_ERR_NOTFOUND) return ret; fdt_for_each_subnode(child, fdto, node) { ret = overlay_adjust_node_phandles(fdto, child, delta); if (ret) return ret; } return 0; } /** * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay * @fdto: Device tree overlay blob * @delta: Offset to shift the phandles of * * overlay_adjust_local_phandles() adds a constant to all the * phandles of an overlay. This is mainly use as part of the overlay * application process, when we want to update all the overlay * phandles to not conflict with the overlays of the base device tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) { /* * Start adjusting the phandles from the overlay root */ return overlay_adjust_node_phandles(fdto, 0, delta); } /** * overlay_update_local_node_references - Adjust the overlay references * @fdto: Device tree overlay blob * @tree_node: Node offset of the node to operate on * @fixup_node: Node offset of the matching local fixups node * @delta: Offset to shift the phandles of * * overlay_update_local_nodes_references() update the phandles * pointing to a node within the device tree overlay by adding a * constant delta. * * This is mainly used as part of a device tree application process, * where you want the device tree overlays phandles to not conflict * with the ones from the base device tree before merging them. * * returns: * 0 on success * Negative error code on failure */ static int overlay_update_local_node_references(void *fdto, int tree_node, int fixup_node, uint32_t delta) { int fixup_prop; int fixup_child; int ret; fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { const uint32_t *fixup_val; const char *tree_val; const char *name; int fixup_len; int tree_len; int i; fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, &name, &fixup_len); if (!fixup_val) return fixup_len; if (fixup_len % sizeof(uint32_t)) return -FDT_ERR_BADOVERLAY; tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); if (!tree_val) { if (tree_len == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; return tree_len; } for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { uint32_t adj_val, poffset; poffset = fdt32_to_cpu(fixup_val[i]); /* * phandles to fixup can be unaligned. * * Use a memcpy for the architectures that do * not support unaligned accesses. */ memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); adj_val = fdt32_to_cpu(adj_val); adj_val += delta; adj_val = cpu_to_fdt32(adj_val); ret = fdt_setprop_inplace_namelen_partial(fdto, tree_node, name, strlen(name), poffset, &adj_val, sizeof(adj_val)); if (ret == -FDT_ERR_NOSPACE) return -FDT_ERR_BADOVERLAY; if (ret) return ret; } } fdt_for_each_subnode(fixup_child, fdto, fixup_node) { const char *fixup_child_name = fdt_get_name(fdto, fixup_child, NULL); int tree_child; tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name); if (ret == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; if (tree_child < 0) return tree_child; ret = overlay_update_local_node_references(fdto, tree_child, fixup_child, delta); if (ret) return ret; } return 0; } /** * overlay_update_local_references - Adjust the overlay references * @fdto: Device tree overlay blob * @delta: Offset to shift the phandles of * * overlay_update_local_references() update all the phandles pointing * to a node within the device tree overlay by adding a constant * delta to not conflict with the base overlay. * * This is mainly used as part of a device tree application process, * where you want the device tree overlays phandles to not conflict * with the ones from the base device tree before merging them. * * returns: * 0 on success * Negative error code on failure */ static int overlay_update_local_references(void *fdto, uint32_t delta) { int fixups; fixups = fdt_path_offset(fdto, "/__local_fixups__"); if (fixups < 0) { /* There's no local phandles to adjust, bail out */ if (fixups == -FDT_ERR_NOTFOUND) return 0; return fixups; } /* * Update our local references from the root of the tree */ return overlay_update_local_node_references(fdto, 0, fixups, delta); } /** * overlay_fixup_one_phandle - Set an overlay phandle to the base one * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * @symbols_off: Node offset of the symbols node in the base device tree * @path: Path to a node holding a phandle in the overlay * @path_len: number of path characters to consider * @name: Name of the property holding the phandle reference in the overlay * @name_len: number of name characters to consider * @poffset: Offset within the overlay property where the phandle is stored * @label: Label of the node referenced by the phandle * * overlay_fixup_one_phandle() resolves an overlay phandle pointing to * a node in the base device tree. * * This is part of the device tree overlay application process, when * you want all the phandles in the overlay to point to the actual * base dt nodes. * * returns: * 0 on success * Negative error code on failure */ static int overlay_fixup_one_phandle(void *fdt, void *fdto, int symbols_off, const char *path, uint32_t path_len, const char *name, uint32_t name_len, int poffset, const char *label) { const char *symbol_path; uint32_t phandle; int symbol_off, fixup_off; int prop_len; if (symbols_off < 0) return symbols_off; symbol_path = fdt_getprop(fdt, symbols_off, label, &prop_len); if (!symbol_path) return prop_len; symbol_off = fdt_path_offset(fdt, symbol_path); if (symbol_off < 0) return symbol_off; phandle = fdt_get_phandle(fdt, symbol_off); if (!phandle) return -FDT_ERR_NOTFOUND; fixup_off = fdt_path_offset_namelen(fdto, path, path_len); if (fixup_off == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; if (fixup_off < 0) return fixup_off; phandle = cpu_to_fdt32(phandle); return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, name, name_len, poffset, &phandle, sizeof(phandle)); }; /** * overlay_fixup_phandle - Set an overlay phandle to the base one * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * @symbols_off: Node offset of the symbols node in the base device tree * @property: Property offset in the overlay holding the list of fixups * * overlay_fixup_phandle() resolves all the overlay phandles pointed * to in a __fixups__ property, and updates them to match the phandles * in use in the base device tree. * * This is part of the device tree overlay application process, when * you want all the phandles in the overlay to point to the actual * base dt nodes. * * returns: * 0 on success * Negative error code on failure */ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, int property) { const char *value; const char *label; int len; value = fdt_getprop_by_offset(fdto, property, &label, &len); if (!value) { if (len == -FDT_ERR_NOTFOUND) return -FDT_ERR_INTERNAL; return len; } do { const char *path, *name, *fixup_end; const char *fixup_str = value; uint32_t path_len, name_len; uint32_t fixup_len; char *sep, *endptr; int poffset, ret; fixup_end = memchr(value, '\0', len); if (!fixup_end) return -FDT_ERR_BADOVERLAY; fixup_len = fixup_end - fixup_str; len -= fixup_len + 1; value += fixup_len + 1; path = fixup_str; sep = memchr(fixup_str, ':', fixup_len); if (!sep || *sep != ':') return -FDT_ERR_BADOVERLAY; path_len = sep - path; if (path_len == (fixup_len - 1)) return -FDT_ERR_BADOVERLAY; fixup_len -= path_len + 1; name = sep + 1; sep = memchr(name, ':', fixup_len); if (!sep || *sep != ':') return -FDT_ERR_BADOVERLAY; name_len = sep - name; if (!name_len) return -FDT_ERR_BADOVERLAY; poffset = strtoul(sep + 1, &endptr, 10); if ((*endptr != '\0') || (endptr <= (sep + 1))) return -FDT_ERR_BADOVERLAY; ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, path, path_len, name, name_len, poffset, label); if (ret) return ret; } while (len > 0); return 0; } /** * overlay_fixup_phandles - Resolve the overlay phandles to the base * device tree * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * * overlay_fixup_phandles() resolves all the overlay phandles pointing * to nodes in the base device tree. * * This is one of the steps of the device tree overlay application * process, when you want all the phandles in the overlay to point to * the actual base dt nodes. * * returns: * 0 on success * Negative error code on failure */ static int overlay_fixup_phandles(void *fdt, void *fdto) { int fixups_off, symbols_off; int property; /* We can have overlays without any fixups */ fixups_off = fdt_path_offset(fdto, "/__fixups__"); if (fixups_off == -FDT_ERR_NOTFOUND) return 0; /* nothing to do */ if (fixups_off < 0) return fixups_off; /* And base DTs without symbols */ symbols_off = fdt_path_offset(fdt, "/__symbols__"); if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) return symbols_off; fdt_for_each_property_offset(property, fdto, fixups_off) { int ret; ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); if (ret) return ret; } return 0; } /** * overlay_apply_node - Merges a node into the base device tree * @fdt: Base Device Tree blob * @target: Node offset in the base device tree to apply the fragment to * @fdto: Device tree overlay blob * @node: Node offset in the overlay holding the changes to merge * * overlay_apply_node() merges a node into a target base device tree * node pointed. * * This is part of the final step in the device tree overlay * application process, when all the phandles have been adjusted and * resolved and you just have to merge overlay into the base device * tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_apply_node(void *fdt, int target, void *fdto, int node) { int property; int subnode; fdt_for_each_property_offset(property, fdto, node) { const char *name; const void *prop; int prop_len; int ret; prop = fdt_getprop_by_offset(fdto, property, &name, &prop_len); if (prop_len == -FDT_ERR_NOTFOUND) return -FDT_ERR_INTERNAL; if (prop_len < 0) return prop_len; ret = fdt_setprop(fdt, target, name, prop, prop_len); if (ret) return ret; } fdt_for_each_subnode(subnode, fdto, node) { const char *name = fdt_get_name(fdto, subnode, NULL); int nnode; int ret; nnode = fdt_add_subnode(fdt, target, name); if (nnode == -FDT_ERR_EXISTS) { nnode = fdt_subnode_offset(fdt, target, name); if (nnode == -FDT_ERR_NOTFOUND) return -FDT_ERR_INTERNAL; } if (nnode < 0) return nnode; ret = overlay_apply_node(fdt, nnode, fdto, subnode); if (ret) return ret; } return 0; } /** * overlay_merge - Merge an overlay into its base device tree * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * * overlay_merge() merges an overlay into its base device tree. * * This is the final step in the device tree overlay application * process, when all the phandles have been adjusted and resolved and * you just have to merge overlay into the base device tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_merge(void *fdt, void *fdto) { int fragment; fdt_for_each_subnode(fragment, fdto, 0) { int overlay; int target; int ret; /* * Each fragments will have an __overlay__ node. If * they don't, it's not supposed to be merged */ overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); if (overlay == -FDT_ERR_NOTFOUND) continue; if (overlay < 0) return overlay; target = overlay_get_target(fdt, fdto, fragment); if (target < 0) return target; ret = overlay_apply_node(fdt, target, fdto, overlay); if (ret) return ret; } return 0; } int fdt_overlay_apply(void *fdt, void *fdto) { uint32_t delta = fdt_get_max_phandle(fdt); int ret; FDT_CHECK_HEADER(fdt); FDT_CHECK_HEADER(fdto); ret = overlay_adjust_local_phandles(fdto, delta); if (ret) goto err; ret = overlay_update_local_references(fdto, delta); if (ret) goto err; ret = overlay_fixup_phandles(fdt, fdto); if (ret) goto err; ret = overlay_merge(fdt, fdto); if (ret) goto err; /* * The overlay has been damaged, erase its magic. */ fdt_set_magic(fdto, ~0); return 0; err: /* * The overlay might have been damaged, erase its magic. */ fdt_set_magic(fdto, ~0); /* * The base device tree might have been damaged, erase its * magic. */ fdt_set_magic(fdt, ~0); return ret; } pdbg-pdbg-1.0/libfdt/fdt_ro.c000066400000000000000000000400601313304724200160640ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int _fdt_nodename_eq(const void *fdt, int offset, const char *s, int len) { const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); if (! p) /* short match */ return 0; if (memcmp(p, s, len) != 0) return 0; if (p[len] == '\0') return 1; else if (!memchr(s, '@', len) && (p[len] == '@')) return 1; else return 0; } const char *fdt_string(const void *fdt, int stroffset) { return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; } static int _fdt_string_eq(const void *fdt, int stroffset, const char *s, int len) { const char *p = fdt_string(fdt, stroffset); return (strlen(p) == len) && (memcmp(p, s, len) == 0); } uint32_t fdt_get_max_phandle(const void *fdt) { uint32_t max_phandle = 0; int offset; for (offset = fdt_next_node(fdt, -1, NULL);; offset = fdt_next_node(fdt, offset, NULL)) { uint32_t phandle; if (offset == -FDT_ERR_NOTFOUND) return max_phandle; if (offset < 0) return (uint32_t)-1; phandle = fdt_get_phandle(fdt, offset); if (phandle == (uint32_t)-1) continue; if (phandle > max_phandle) max_phandle = phandle; } return 0; } int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); return 0; } int fdt_num_mem_rsv(const void *fdt) { int i = 0; while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) i++; return i; } static int _nextprop(const void *fdt, int offset) { uint32_t tag; int nextoffset; do { tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: if (nextoffset >= 0) return -FDT_ERR_BADSTRUCTURE; else return nextoffset; case FDT_PROP: return offset; } offset = nextoffset; } while (tag == FDT_NOP); return -FDT_ERR_NOTFOUND; } int fdt_subnode_offset_namelen(const void *fdt, int offset, const char *name, int namelen) { int depth; FDT_CHECK_HEADER(fdt); for (depth = 0; (offset >= 0) && (depth >= 0); offset = fdt_next_node(fdt, offset, &depth)) if ((depth == 1) && _fdt_nodename_eq(fdt, offset, name, namelen)) return offset; if (depth < 0) return -FDT_ERR_NOTFOUND; return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name) { return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) { const char *end = path + namelen; const char *p = path; int offset = 0; FDT_CHECK_HEADER(fdt); /* see if we have an alias */ if (*path != '/') { const char *q = memchr(path, '/', end - p); if (!q) q = end; p = fdt_get_alias_namelen(fdt, p, q - p); if (!p) return -FDT_ERR_BADPATH; offset = fdt_path_offset(fdt, p); p = q; } while (p < end) { const char *q; while (*p == '/') { p++; if (p == end) return offset; } q = memchr(p, '/', end - p); if (! q) q = end; offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); if (offset < 0) return offset; p = q; } return offset; } int fdt_path_offset(const void *fdt, const char *path) { return fdt_path_offset_namelen(fdt, path, strlen(path)); } const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) { const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); int err; if (((err = fdt_check_header(fdt)) != 0) || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) goto fail; if (len) *len = strlen(nh->name); return nh->name; fail: if (len) *len = err; return NULL; } int fdt_first_property_offset(const void *fdt, int nodeoffset) { int offset; if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) return offset; return _nextprop(fdt, offset); } int fdt_next_property_offset(const void *fdt, int offset) { if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) return offset; return _nextprop(fdt, offset); } const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp) { int err; const struct fdt_property *prop; if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { if (lenp) *lenp = err; return NULL; } prop = _fdt_offset_ptr(fdt, offset); if (lenp) *lenp = fdt32_to_cpu(prop->len); return prop; } const struct fdt_property *fdt_get_property_namelen(const void *fdt, int offset, const char *name, int namelen, int *lenp) { for (offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { offset = -FDT_ERR_INTERNAL; break; } if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) return prop; } if (lenp) *lenp = offset; return NULL; } const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp) { return fdt_get_property_namelen(fdt, nodeoffset, name, strlen(name), lenp); } const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp) { const struct fdt_property *prop; prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); if (! prop) return NULL; return prop->data; } const void *fdt_getprop_by_offset(const void *fdt, int offset, const char **namep, int *lenp) { const struct fdt_property *prop; prop = fdt_get_property_by_offset(fdt, offset, lenp); if (!prop) return NULL; if (namep) *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); return prop->data; } const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp) { return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); } uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { const fdt32_t *php; int len; /* FIXME: This is a bit sub-optimal, since we potentially scan * over all the properties twice. */ php = fdt_getprop(fdt, nodeoffset, "phandle", &len); if (!php || (len != sizeof(*php))) { php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); if (!php || (len != sizeof(*php))) return 0; } return fdt32_to_cpu(*php); } const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen) { int aliasoffset; aliasoffset = fdt_path_offset(fdt, "/aliases"); if (aliasoffset < 0) return NULL; return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); } const char *fdt_get_alias(const void *fdt, const char *name) { return fdt_get_alias_namelen(fdt, name, strlen(name)); } int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { int pdepth = 0, p = 0; int offset, depth, namelen; const char *name; FDT_CHECK_HEADER(fdt); if (buflen < 2) return -FDT_ERR_NOSPACE; for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { while (pdepth > depth) { do { p--; } while (buf[p-1] != '/'); pdepth--; } if (pdepth >= depth) { name = fdt_get_name(fdt, offset, &namelen); if (!name) return namelen; if ((p + namelen + 1) <= buflen) { memcpy(buf + p, name, namelen); p += namelen; buf[p++] = '/'; pdepth++; } } if (offset == nodeoffset) { if (pdepth < (depth + 1)) return -FDT_ERR_NOSPACE; if (p > 1) /* special case so that root path is "/", not "" */ p--; buf[p] = '\0'; return 0; } } if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) return -FDT_ERR_BADOFFSET; else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADSTRUCTURE; return offset; /* error from fdt_next_node() */ } int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth) { int offset, depth; int supernodeoffset = -FDT_ERR_INTERNAL; FDT_CHECK_HEADER(fdt); if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { if (depth == supernodedepth) supernodeoffset = offset; if (offset == nodeoffset) { if (nodedepth) *nodedepth = depth; if (supernodedepth > depth) return -FDT_ERR_NOTFOUND; else return supernodeoffset; } } if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) return -FDT_ERR_BADOFFSET; else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADSTRUCTURE; return offset; /* error from fdt_next_node() */ } int fdt_node_depth(const void *fdt, int nodeoffset) { int nodedepth; int err; err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); if (err) return (err < 0) ? err : -FDT_ERR_INTERNAL; return nodedepth; } int fdt_parent_offset(const void *fdt, int nodeoffset) { int nodedepth = fdt_node_depth(fdt, nodeoffset); if (nodedepth < 0) return nodedepth; return fdt_supernode_atdepth_offset(fdt, nodeoffset, nodedepth - 1, NULL); } int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen) { int offset; const void *val; int len; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't * find what we want, we scan over them again making our way * to the next node. Still it's the easiest to implement * approach; performance can come later. */ for (offset = fdt_next_node(fdt, startoffset, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { val = fdt_getprop(fdt, offset, propname, &len); if (val && (len == proplen) && (memcmp(val, propval, len) == 0)) return offset; } return offset; /* error from fdt_next_node() */ } int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { int offset; if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we * potentially scan each property of a node in * fdt_get_phandle(), then if that didn't find what * we want, we scan over them again making our way to the next * node. Still it's the easiest to implement approach; * performance can come later. */ for (offset = fdt_next_node(fdt, -1, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { if (fdt_get_phandle(fdt, offset) == phandle) return offset; } return offset; /* error from fdt_next_node() */ } int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) { int len = strlen(str); const char *p; while (listlen >= len) { if (memcmp(str, strlist, len+1) == 0) return 1; p = memchr(strlist, '\0', listlen); if (!p) return 0; /* malformed strlist.. */ listlen -= (p-strlist) + 1; strlist = p + 1; } return 0; } int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) { const char *list, *end; int length, count = 0; list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) return length; end = list + length; while (list < end) { length = strnlen(list, end - list) + 1; /* Abort if the last string isn't properly NUL-terminated. */ if (list + length > end) return -FDT_ERR_BADVALUE; list += length; count++; } return count; } int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, const char *string) { int length, len, idx = 0; const char *list, *end; list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) return length; len = strlen(string) + 1; end = list + length; while (list < end) { length = strnlen(list, end - list) + 1; /* Abort if the last string isn't properly NUL-terminated. */ if (list + length > end) return -FDT_ERR_BADVALUE; if (length == len && memcmp(list, string, length) == 0) return idx; list += length; idx++; } return -FDT_ERR_NOTFOUND; } const char *fdt_stringlist_get(const void *fdt, int nodeoffset, const char *property, int idx, int *lenp) { const char *list, *end; int length; list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) { if (lenp) *lenp = length; return NULL; } end = list + length; while (list < end) { length = strnlen(list, end - list) + 1; /* Abort if the last string isn't properly NUL-terminated. */ if (list + length > end) { if (lenp) *lenp = -FDT_ERR_BADVALUE; return NULL; } if (idx == 0) { if (lenp) *lenp = length - 1; return list; } list += length; idx--; } if (lenp) *lenp = -FDT_ERR_NOTFOUND; return NULL; } int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible) { const void *prop; int len; prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; return !fdt_stringlist_contains(prop, len, compatible); } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible) { int offset, err; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if * that didn't find what we want, we scan over them again * making our way to the next node. Still it's the easiest to * implement approach; performance can come later. */ for (offset = fdt_next_node(fdt, startoffset, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { err = fdt_node_check_compatible(fdt, offset, compatible); if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) return err; else if (err == 0) return offset; } return offset; /* error from fdt_next_node() */ } pdbg-pdbg-1.0/libfdt/fdt_rw.c000066400000000000000000000313411313304724200160760ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int _fdt_blocks_misordered(const void *fdt, int mem_rsv_size, int struct_size) { return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) || (fdt_off_dt_struct(fdt) < (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) || (fdt_off_dt_strings(fdt) < (fdt_off_dt_struct(fdt) + struct_size)) || (fdt_totalsize(fdt) < (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } static int _fdt_rw_check_header(void *fdt) { FDT_CHECK_HEADER(fdt); if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), fdt_size_dt_struct(fdt))) return -FDT_ERR_BADLAYOUT; if (fdt_version(fdt) > 17) fdt_set_version(fdt, 17); return 0; } #define FDT_RW_CHECK_HEADER(fdt) \ { \ int __err; \ if ((__err = _fdt_rw_check_header(fdt)) != 0) \ return __err; \ } static inline int _fdt_data_size(void *fdt) { return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) { char *p = splicepoint; char *end = (char *)fdt + _fdt_data_size(fdt); if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) return -FDT_ERR_BADOFFSET; if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; memmove(p + newlen, p + oldlen, end - p - oldlen); return 0; } static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, int oldn, int newn) { int delta = (newn - oldn) * sizeof(*p); int err; err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); if (err) return err; fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } static int _fdt_splice_struct(void *fdt, void *p, int oldlen, int newlen) { int delta = newlen - oldlen; int err; if ((err = _fdt_splice(fdt, p, oldlen, newlen))) return err; fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } static int _fdt_splice_string(void *fdt, int newlen) { void *p = (char *)fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); int err; if ((err = _fdt_splice(fdt, p, 0, newlen))) return err; fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); return 0; } static int _fdt_find_add_string(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); const char *p; char *new; int len = strlen(s) + 1; int err; p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); if (p) /* found it */ return (p - strtab); new = strtab + fdt_size_dt_strings(fdt); err = _fdt_splice_string(fdt, len); if (err) return err; memcpy(new, s, len); return (new - strtab); } int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) { struct fdt_reserve_entry *re; int err; FDT_RW_CHECK_HEADER(fdt); re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); err = _fdt_splice_mem_rsv(fdt, re, 0, 1); if (err) return err; re->address = cpu_to_fdt64(address); re->size = cpu_to_fdt64(size); return 0; } int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); FDT_RW_CHECK_HEADER(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; return _fdt_splice_mem_rsv(fdt, re, 1, 0); } static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { int oldlen; int err; *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (! (*prop)) return oldlen; if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), FDT_TAGALIGN(len)))) return err; (*prop)->len = cpu_to_fdt32(len); return 0; } static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { int proplen; int nextoffset; int namestroff; int err; if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) return nextoffset; namestroff = _fdt_find_add_string(fdt, name); if (namestroff < 0) return namestroff; *prop = _fdt_offset_ptr_w(fdt, nextoffset); proplen = sizeof(**prop) + FDT_TAGALIGN(len); err = _fdt_splice_struct(fdt, *prop, 0, proplen); if (err) return err; (*prop)->tag = cpu_to_fdt32(FDT_PROP); (*prop)->nameoff = cpu_to_fdt32(namestroff); (*prop)->len = cpu_to_fdt32(len); return 0; } int fdt_set_name(void *fdt, int nodeoffset, const char *name) { char *namep; int oldlen, newlen; int err; FDT_RW_CHECK_HEADER(fdt); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); if (!namep) return oldlen; newlen = strlen(name); err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), FDT_TAGALIGN(newlen+1)); if (err) return err; memcpy(namep, name, newlen+1); return 0; } int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len) { struct fdt_property *prop; int err; FDT_RW_CHECK_HEADER(fdt); err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); if (err == -FDT_ERR_NOTFOUND) err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); if (err) return err; memcpy(prop->data, val, len); return 0; } int fdt_appendprop(void *fdt, int nodeoffset, const char *name, const void *val, int len) { struct fdt_property *prop; int err, oldlen, newlen; FDT_RW_CHECK_HEADER(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (prop) { newlen = len + oldlen; err = _fdt_splice_struct(fdt, prop->data, FDT_TAGALIGN(oldlen), FDT_TAGALIGN(newlen)); if (err) return err; prop->len = cpu_to_fdt32(newlen); memcpy(prop->data + oldlen, val, len); } else { err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); if (err) return err; memcpy(prop->data, val, len); } return 0; } int fdt_delprop(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; int len, proplen; FDT_RW_CHECK_HEADER(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (! prop) return len; proplen = sizeof(*prop) + FDT_TAGALIGN(len); return _fdt_splice_struct(fdt, prop, proplen, 0); } int fdt_add_subnode_namelen(void *fdt, int parentoffset, const char *name, int namelen) { struct fdt_node_header *nh; int offset, nextoffset; int nodelen; int err; uint32_t tag; fdt32_t *endtag; FDT_RW_CHECK_HEADER(fdt); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) return -FDT_ERR_EXISTS; else if (offset != -FDT_ERR_NOTFOUND) return offset; /* Try to place the new node after the parent's properties */ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); } while ((tag == FDT_PROP) || (tag == FDT_NOP)); nh = _fdt_offset_ptr_w(fdt, offset); nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; err = _fdt_splice_struct(fdt, nh, 0, nodelen); if (err) return err; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); memcpy(nh->name, name, namelen); endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); *endtag = cpu_to_fdt32(FDT_END_NODE); return offset; } int fdt_add_subnode(void *fdt, int parentoffset, const char *name) { return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_del_node(void *fdt, int nodeoffset) { int endoffset; FDT_RW_CHECK_HEADER(fdt); endoffset = _fdt_node_end_offset(fdt, nodeoffset); if (endoffset < 0) return endoffset; return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), endoffset - nodeoffset, 0); } static void _fdt_packblocks(const char *old, char *new, int mem_rsv_size, int struct_size) { int mem_rsv_off, struct_off, strings_off; mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); struct_off = mem_rsv_off + mem_rsv_size; strings_off = struct_off + struct_size; memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); fdt_set_off_mem_rsvmap(new, mem_rsv_off); memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); fdt_set_off_dt_struct(new, struct_off); fdt_set_size_dt_struct(new, struct_size); memmove(new + strings_off, old + fdt_off_dt_strings(old), fdt_size_dt_strings(old)); fdt_set_off_dt_strings(new, strings_off); fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } int fdt_open_into(const void *fdt, void *buf, int bufsize) { int err; int mem_rsv_size, struct_size; int newsize; const char *fdtstart = fdt; const char *fdtend = fdtstart + fdt_totalsize(fdt); char *tmp; FDT_CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); if (fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); } else { struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; if (struct_size < 0) return struct_size; } if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { /* no further work necessary */ err = fdt_move(fdt, buf, bufsize); if (err) return err; fdt_set_version(buf, 17); fdt_set_size_dt_struct(buf, struct_size); fdt_set_totalsize(buf, bufsize); return 0; } /* Need to reorder */ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + struct_size + fdt_size_dt_strings(fdt); if (bufsize < newsize) return -FDT_ERR_NOSPACE; /* First attempt to build converted tree at beginning of buffer */ tmp = buf; /* But if that overlaps with the old tree... */ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { /* Try right after the old tree instead */ tmp = (char *)(uintptr_t)fdtend; if ((tmp + newsize) > ((char *)buf + bufsize)) return -FDT_ERR_NOSPACE; } _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); memmove(buf, tmp, newsize); fdt_set_magic(buf, FDT_MAGIC); fdt_set_totalsize(buf, bufsize); fdt_set_version(buf, 17); fdt_set_last_comp_version(buf, 16); fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); return 0; } int fdt_pack(void *fdt) { int mem_rsv_size; FDT_RW_CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); fdt_set_totalsize(fdt, _fdt_data_size(fdt)); return 0; } pdbg-pdbg-1.0/libfdt/fdt_strerror.c000066400000000000000000000070341313304724200173320ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" struct fdt_errtabent { const char *str; }; #define FDT_ERRTABENT(val) \ [(val)] = { .str = #val, } static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_NOTFOUND), FDT_ERRTABENT(FDT_ERR_EXISTS), FDT_ERRTABENT(FDT_ERR_NOSPACE), FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADPATH), FDT_ERRTABENT(FDT_ERR_BADPHANDLE), FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_TRUNCATED), FDT_ERRTABENT(FDT_ERR_BADMAGIC), FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), FDT_ERRTABENT(FDT_ERR_INTERNAL), FDT_ERRTABENT(FDT_ERR_BADNCELLS), FDT_ERRTABENT(FDT_ERR_BADVALUE), FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) const char *fdt_strerror(int errval) { if (errval > 0) return ""; else if (errval == 0) return ""; else if (errval > -FDT_ERRTABSIZE) { const char *s = fdt_errtable[-errval].str; if (s) return s; } return ""; } pdbg-pdbg-1.0/libfdt/fdt_sw.c000066400000000000000000000173101313304724200160770ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int _fdt_sw_check_header(void *fdt) { if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADMAGIC; /* FIXME: should check more details about the header state */ return 0; } #define FDT_SW_CHECK_HEADER(fdt) \ { \ int err; \ if ((err = _fdt_sw_check_header(fdt)) != 0) \ return err; \ } static void *_fdt_grab_space(void *fdt, size_t len) { int offset = fdt_size_dt_struct(fdt); int spaceleft; spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - fdt_size_dt_strings(fdt); if ((offset + len < offset) || (offset + len > spaceleft)) return NULL; fdt_set_size_dt_struct(fdt, offset + len); return _fdt_offset_ptr_w(fdt, offset); } int fdt_create(void *buf, int bufsize) { void *fdt = buf; if (bufsize < sizeof(struct fdt_header)) return -FDT_ERR_NOSPACE; memset(buf, 0, bufsize); fdt_set_magic(fdt, FDT_SW_MAGIC); fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_totalsize(fdt, bufsize); fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), sizeof(struct fdt_reserve_entry))); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); fdt_set_off_dt_strings(fdt, bufsize); return 0; } int fdt_resize(void *fdt, void *buf, int bufsize) { size_t headsize, tailsize; char *oldtail, *newtail; FDT_SW_CHECK_HEADER(fdt); headsize = fdt_off_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); if ((headsize + tailsize) > bufsize) return -FDT_ERR_NOSPACE; oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; newtail = (char *)buf + bufsize - tailsize; /* Two cases to avoid clobbering data if the old and new * buffers partially overlap */ if (buf <= fdt) { memmove(buf, fdt, headsize); memmove(newtail, oldtail, tailsize); } else { memmove(newtail, oldtail, tailsize); memmove(buf, fdt, headsize); } fdt_set_off_dt_strings(buf, bufsize); fdt_set_totalsize(buf, bufsize); return 0; } int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; int offset; FDT_SW_CHECK_HEADER(fdt); if (fdt_size_dt_struct(fdt)) return -FDT_ERR_BADSTATE; offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; re = (struct fdt_reserve_entry *)((char *)fdt + offset); re->address = cpu_to_fdt64(addr); re->size = cpu_to_fdt64(size); fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); return 0; } int fdt_finish_reservemap(void *fdt) { return fdt_add_reservemap_entry(fdt, 0, 0); } int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; int namelen = strlen(name) + 1; FDT_SW_CHECK_HEADER(fdt); nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); if (! nh) return -FDT_ERR_NOSPACE; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memcpy(nh->name, name, namelen); return 0; } int fdt_end_node(void *fdt) { fdt32_t *en; FDT_SW_CHECK_HEADER(fdt); en = _fdt_grab_space(fdt, FDT_TAGSIZE); if (! en) return -FDT_ERR_NOSPACE; *en = cpu_to_fdt32(FDT_END_NODE); return 0; } static int _fdt_find_add_string(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_totalsize(fdt); const char *p; int strtabsize = fdt_size_dt_strings(fdt); int len = strlen(s) + 1; int struct_top, offset; p = _fdt_find_string(strtab - strtabsize, strtabsize, s); if (p) return p - strtab; /* Add it */ offset = -strtabsize - len; struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); if (fdt_totalsize(fdt) + offset < struct_top) return 0; /* no more room :( */ memcpy(strtab + offset, s, len); fdt_set_size_dt_strings(fdt, strtabsize + len); return offset; } int fdt_property(void *fdt, const char *name, const void *val, int len) { struct fdt_property *prop; int nameoff; FDT_SW_CHECK_HEADER(fdt); nameoff = _fdt_find_add_string(fdt, name); if (nameoff == 0) return -FDT_ERR_NOSPACE; prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); if (! prop) return -FDT_ERR_NOSPACE; prop->tag = cpu_to_fdt32(FDT_PROP); prop->nameoff = cpu_to_fdt32(nameoff); prop->len = cpu_to_fdt32(len); memcpy(prop->data, val, len); return 0; } int fdt_finish(void *fdt) { char *p = (char *)fdt; fdt32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; FDT_SW_CHECK_HEADER(fdt); /* Add terminator */ end = _fdt_grab_space(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); /* Relocate the string table */ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); fdt_set_off_dt_strings(fdt, newstroffset); /* Walk the structure, correcting string offsets */ offset = 0; while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = _fdt_offset_ptr_w(fdt, offset); int nameoff; nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } if (nextoffset < 0) return nextoffset; /* Finally, adjust the header */ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_magic(fdt, FDT_MAGIC); return 0; } pdbg-pdbg-1.0/libfdt/fdt_wip.c000066400000000000000000000100771313304724200162500ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, const char *name, int namelen, uint32_t idx, const void *val, int len) { void *propval; int proplen; propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, &proplen); if (!propval) return proplen; if (proplen < (len + idx)) return -FDT_ERR_NOSPACE; memcpy((char *)propval + idx, val, len); return 0; } int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len) { const void *propval; int proplen; propval = fdt_getprop(fdt, nodeoffset, name, &proplen); if (! propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, strlen(name), 0, val, len); } static void _fdt_nop_region(void *start, int len) { fdt32_t *p; for (p = start; (char *)p < ((char *)start + len); p++) *p = cpu_to_fdt32(FDT_NOP); } int fdt_nop_property(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; int len; prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (! prop) return len; _fdt_nop_region(prop, len + sizeof(*prop)); return 0; } int _fdt_node_end_offset(void *fdt, int offset) { int depth = 0; while ((offset >= 0) && (depth >= 0)) offset = fdt_next_node(fdt, offset, &depth); return offset; } int fdt_nop_node(void *fdt, int nodeoffset) { int endoffset; endoffset = _fdt_node_end_offset(fdt, nodeoffset); if (endoffset < 0) return endoffset; _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset); return 0; } pdbg-pdbg-1.0/libfdt/libfdt.h000066400000000000000000002011441313304724200160620ustar00rootroot00000000000000#ifndef _LIBFDT_H #define _LIBFDT_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #define FDT_FIRST_SUPPORTED_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 /* FDT_ERR_EXISTS: Attempted to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device * tree, but its buffer did not have sufficient space to * contain the expanded tree. Use fdt_open_into() to move the * device tree to a buffer with more space. */ /* Error codes: codes for bad parameters */ #define FDT_ERR_BADOFFSET 4 /* FDT_ERR_BADOFFSET: Function was passed a structure block * offset which is out-of-bounds, or which points to an * unsuitable part of the structure for the operation. */ #define FDT_ERR_BADPATH 5 /* FDT_ERR_BADPATH: Function was passed a badly formatted path * (e.g. missing a leading / for a function which requires an * absolute path) */ #define FDT_ERR_BADPHANDLE 6 /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. * This can be caused either by an invalid phandle property * length, or the phandle value was either 0 or -1, which are * not permitted. */ #define FDT_ERR_BADSTATE 7 /* FDT_ERR_BADSTATE: Function was passed an incomplete device * tree created by the sequential-write functions, which is * not sufficiently complete for the requested operation. */ /* Error codes: codes for bad device tree blobs */ #define FDT_ERR_TRUNCATED 8 /* FDT_ERR_TRUNCATED: Structure block of the given device tree * ends without an FDT_END tag. */ #define FDT_ERR_BADMAGIC 9 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a * device tree at all - it is missing the flattened device * tree magic number. */ #define FDT_ERR_BADVERSION 10 /* FDT_ERR_BADVERSION: Given device tree has a version which * can't be handled by the requested operation. For * read-write functions, this may mean that fdt_open_into() is * required to convert the tree to the expected version. */ #define FDT_ERR_BADSTRUCTURE 11 /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt * structure block or other serious error (e.g. misnested * nodes, or subnodes preceding properties). */ #define FDT_ERR_BADLAYOUT 12 /* FDT_ERR_BADLAYOUT: For read-write functions, the given * device tree has it's sub-blocks in an order that the * function can't handle (memory reserve map, then structure, * then strings). Use fdt_open_into() to reorganize the tree * into a form suitable for the read-write operations. */ /* "Can't happen" error indicating a bug in libfdt */ #define FDT_ERR_INTERNAL 13 /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. * Should never be returned, if it is, it indicates a bug in * libfdt itself. */ /* Errors in device tree content */ #define FDT_ERR_BADNCELLS 14 /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells * or similar property with a bad format or value */ #define FDT_ERR_BADVALUE 15 /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected * value. For example: a property expected to contain a string list * is not NUL-terminated within the length of its value. */ #define FDT_ERR_BADOVERLAY 16 /* FDT_ERR_BADOVERLAY: The device tree overlay, while * correctly structured, cannot be applied due to some * unexpected or missing value, property or node. */ #define FDT_ERR_NOPHANDLES 17 /* FDT_ERR_NOPHANDLES: The device tree doesn't have any * phandle available anymore without causing an overflow */ #define FDT_ERR_MAX 17 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ /**********************************************************************/ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) { return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); } uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); /**********************************************************************/ /* Traversal functions */ /**********************************************************************/ int fdt_next_node(const void *fdt, int offset, int *depth); /** * fdt_first_subnode() - get offset of first direct subnode * * @fdt: FDT blob * @offset: Offset of node to check * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none */ int fdt_first_subnode(const void *fdt, int offset); /** * fdt_next_subnode() - get offset of next direct subnode * * After first calling fdt_first_subnode(), call this function repeatedly to * get direct subnodes of a parent node. * * @fdt: FDT blob * @offset: Offset of previous subnode * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more * subnodes */ int fdt_next_subnode(const void *fdt, int offset); /** * fdt_for_each_subnode - iterate over all subnodes of a parent * * @node: child node (int, lvalue) * @fdt: FDT blob (const void *) * @parent: parent node (int) * * This is actually a wrapper around a for loop and would be used like so: * * fdt_for_each_subnode(node, fdt, parent) { * Use node * ... * } * * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { * Error handling * } * * Note that this is implemented as a macro and @node is used as * iterator in the loop. The parent variable be constant or even a * literal. * */ #define fdt_for_each_subnode(node, fdt, parent) \ for (node = fdt_first_subnode(fdt, parent); \ node >= 0; \ node = fdt_next_subnode(fdt, node)) /**********************************************************************/ /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) #define fdt_version(fdt) (fdt_get_header(fdt, version)) #define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) #define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) #define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic); __fdt_set_hdr(totalsize); __fdt_set_hdr(off_dt_struct); __fdt_set_hdr(off_dt_strings); __fdt_set_hdr(off_mem_rsvmap); __fdt_set_hdr(version); __fdt_set_hdr(last_comp_version); __fdt_set_hdr(boot_cpuid_phys); __fdt_set_hdr(size_dt_strings); __fdt_set_hdr(size_dt_struct); #undef __fdt_set_hdr /** * fdt_check_header - sanity check a device tree or possible device tree * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what * appears to be a flattened device tree with sane information in its * header. * * returns: * 0, if the buffer appears to contain a valid device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings, as above */ int fdt_check_header(const void *fdt); /** * fdt_move - move a device tree around in memory * @fdt: pointer to the device tree to move * @buf: pointer to memory where the device is to be moved * @bufsize: size of the memory space at buf * * fdt_move() relocates, if possible, the device tree blob located at * fdt to the buffer at buf of size bufsize. The buffer may overlap * with the existing device tree blob at fdt. Therefore, * fdt_move(fdt, fdt, fdt_totalsize(fdt)) * should always succeed. * * returns: * 0, on success * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_move(const void *fdt, void *buf, int bufsize); /**********************************************************************/ /* Read-only functions */ /**********************************************************************/ /** * fdt_string - retrieve a string from the strings block of a device tree * @fdt: pointer to the device tree blob * @stroffset: offset of the string within the strings block (native endian) * * fdt_string() retrieves a pointer to a single string from the * strings block of the device tree blob at fdt. * * returns: * a pointer to the string, on success * NULL, if stroffset is out of bounds */ const char *fdt_string(const void *fdt, int stroffset); /** * fdt_get_max_phandle - retrieves the highest phandle in a tree * @fdt: pointer to the device tree blob * * fdt_get_max_phandle retrieves the highest phandle in the given * device tree. This will ignore badly formatted phandles, or phandles * with a value of 0 or -1. * * returns: * the highest phandle on success * 0, if no phandle was found in the device tree * -1, if an error occurred */ uint32_t fdt_get_max_phandle(const void *fdt); /** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob * * Returns the number of entries in the device tree blob's memory * reservation map. This does not include the terminating 0,0 entry * or any other (0,0) entries reserved for expansion. * * returns: * the number of entries */ int fdt_num_mem_rsv(const void *fdt); /** * fdt_get_mem_rsv - retrieve one memory reserve map entry * @fdt: pointer to the device tree blob * @address, @size: pointers to 64-bit variables * * On success, *address and *size will contain the address and size of * the n-th reserve map entry from the device tree blob, in * native-endian format. * * returns: * 0, on success * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); /** * fdt_subnode_offset_namelen - find a subnode based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * @namelen: number of characters of name to consider * * Identical to fdt_subnode_offset(), but only examine the first * namelen characters of name for matching the subnode name. This is * useful for finding subnodes based on a portion of a larger string, * such as a full path. */ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, const char *name, int namelen); /** * fdt_subnode_offset - find a subnode of a given node * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * * fdt_subnode_offset() finds a subnode of the node at structure block * offset parentoffset with the given name. name may include a unit * address, in which case fdt_subnode_offset() will find the subnode * with that unit address, or the unit address may be omitted, in * which case fdt_subnode_offset() will find an arbitrary subnode * whose name excluding unit address matches the given name. * * returns: * structure block offset of the requested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); /** * fdt_path_offset_namelen - find a tree node by its full path * @fdt: pointer to the device tree blob * @path: full path of the node to locate * @namelen: number of characters of path to consider * * Identical to fdt_path_offset(), but only consider the first namelen * characters of path as the path name. */ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); /** * fdt_path_offset - find a tree node by its full path * @fdt: pointer to the device tree blob * @path: full path of the node to locate * * fdt_path_offset() finds a node of a given path in the device tree. * Each path component may omit the unit address portion, but the * results of this are undefined if any such path component is * ambiguous (that is if there are multiple nodes at the relevant * level matching the given component, differentiated only by unit * address). * * returns: * structure block offset of the node with the requested path (>=0), on * success * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_path_offset(const void *fdt, const char *path); /** * fdt_get_name - retrieve the name of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the starting node * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_name() retrieves the name (including unit address) of the * device tree node at structure block offset nodeoffset. If lenp is * non-NULL, the length of this name is also returned, in the integer * pointed to by lenp. * * returns: * pointer to the node's name, on success * If lenp is non-NULL, *lenp contains the length of that name * (>=0) * NULL, on error * if lenp is non-NULL *lenp contains an error code (<0): * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); /** * fdt_first_property_offset - find the offset of a node's first property * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of a node * * fdt_first_property_offset() finds the first property of the node at * the given structure block offset. * * returns: * structure block offset of the property (>=0), on success * -FDT_ERR_NOTFOUND, if the requested node has no properties * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_first_property_offset(const void *fdt, int nodeoffset); /** * fdt_next_property_offset - step through a node's properties * @fdt: pointer to the device tree blob * @offset: structure block offset of a property * * fdt_next_property_offset() finds the property immediately after the * one at the given structure block offset. This will be a property * of the same node as the given property. * * returns: * structure block offset of the next property (>=0), on success * -FDT_ERR_NOTFOUND, if the given property is the last in its node * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_next_property_offset(const void *fdt, int offset); /** * fdt_for_each_property_offset - iterate over all properties of a node * * @property_offset: property offset (int, lvalue) * @fdt: FDT blob (const void *) * @node: node offset (int) * * This is actually a wrapper around a for loop and would be used like so: * * fdt_for_each_property_offset(property, fdt, node) { * Use property * ... * } * * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { * Error handling * } * * Note that this is implemented as a macro and property is used as * iterator in the loop. The node variable can be constant or even a * literal. */ #define fdt_for_each_property_offset(property, fdt, node) \ for (property = fdt_first_property_offset(fdt, node); \ property >= 0; \ property = fdt_next_property_offset(fdt, property)) /** * fdt_get_property_by_offset - retrieve the property at a given offset * @fdt: pointer to the device tree blob * @offset: offset of the property to retrieve * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_property_by_offset() retrieves a pointer to the * fdt_property structure within the device tree blob at the given * offset. If lenp is non-NULL, the length of the property value is * also returned, in the integer pointed to by lenp. * * returns: * pointer to the structure representing the property * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp); /** * fdt_get_property_namelen - find a property based on substring * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @namelen: number of characters of name to consider * @lenp: pointer to an integer variable (will be overwritten) or NULL * * Identical to fdt_get_property(), but only examine the first namelen * characters of name for matching the property name. */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); /** * fdt_get_property - find a given property in a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_property() retrieves a pointer to the fdt_property * structure within the device tree blob corresponding to the property * named 'name' of the node at offset nodeoffset. If lenp is * non-NULL, the length of the property value is also returned, in the * integer pointed to by lenp. * * returns: * pointer to the structure representing the property * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp); static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, const char *name, int *lenp) { return (struct fdt_property *)(uintptr_t) fdt_get_property(fdt, nodeoffset, name, lenp); } /** * fdt_getprop_by_offset - retrieve the value of a property at a given offset * @fdt: pointer to the device tree blob * @ffset: offset of the property to read * @namep: pointer to a string variable (will be overwritten) or NULL * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop_by_offset() retrieves a pointer to the value of the * property at structure block offset 'offset' (this will be a pointer * to within the device blob itself, not a copy of the value). If * lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. If namep is non-NULL, * the property's namne will also be returned in the char * pointed to * by namep (this will be a pointer to within the device tree's string * block, not a new copy of the name). * * returns: * pointer to the property's value * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * if namep is non-NULL *namep contiains a pointer to the property * name. * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const void *fdt_getprop_by_offset(const void *fdt, int offset, const char **namep, int *lenp); /** * fdt_getprop_namelen - get property value based on substring * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @namelen: number of characters of name to consider * @lenp: pointer to an integer variable (will be overwritten) or NULL * * Identical to fdt_getprop(), but only examine the first namelen * characters of name for matching the property name. */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, const char *name, int namelen, int *lenp) { return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, namelen, lenp); } /** * fdt_getprop - retrieve the value of a given property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop() retrieves a pointer to the value of the property * named 'name' of the node at offset nodeoffset (this will be a * pointer to within the device blob itself, not a copy of the value). * If lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. * * returns: * pointer to the property's value * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp); static inline void *fdt_getprop_w(void *fdt, int nodeoffset, const char *name, int *lenp) { return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); } /** * fdt_get_phandle - retrieve the phandle of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the node * * fdt_get_phandle() retrieves the phandle of the device tree node at * structure block offset nodeoffset. * * returns: * the phandle of the node at nodeoffset, on success (!= 0, != -1) * 0, if the node has no phandle, or another error occurs */ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); /** * fdt_get_alias_namelen - get alias based on substring * @fdt: pointer to the device tree blob * @name: name of the alias th look up * @namelen: number of characters of name to consider * * Identical to fdt_get_alias(), but only examine the first namelen * characters of name for matching the alias name. */ const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen); /** * fdt_get_alias - retrieve the path referenced by a given alias * @fdt: pointer to the device tree blob * @name: name of the alias th look up * * fdt_get_alias() retrieves the value of a given alias. That is, the * value of the property named 'name' in the node /aliases. * * returns: * a pointer to the expansion of the alias named 'name', if it exists * NULL, if the given alias or the /aliases node does not exist */ const char *fdt_get_alias(const void *fdt, const char *name); /** * fdt_get_path - determine the full path of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose path to find * @buf: character buffer to contain the returned path (will be overwritten) * @buflen: size of the character buffer at buf * * fdt_get_path() computes the full path of the node at offset * nodeoffset, and records that path in the buffer at buf. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * 0, on success * buf contains the absolute path of the node at * nodeoffset, as a NUL-terminated string. * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) * characters and will not fit in the given buffer. * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); /** * fdt_supernode_atdepth_offset - find a specific ancestor of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * @supernodedepth: depth of the ancestor to find * @nodedepth: pointer to an integer variable (will be overwritten) or NULL * * fdt_supernode_atdepth_offset() finds an ancestor of the given node * at a specific depth from the root (where the root itself has depth * 0, its immediate subnodes depth 1 and so forth). So * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); * will always return 0, the offset of the root node. If the node at * nodeoffset has depth D, then: * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); * will return nodeoffset itself. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of * nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth); /** * fdt_node_depth - find the depth of a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * * fdt_node_depth() finds the depth of a given node. The root node * has depth 0, its immediate subnodes depth 1 and so forth. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * depth of the node at nodeoffset (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_depth(const void *fdt, int nodeoffset); /** * fdt_parent_offset - find the parent of a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * * fdt_parent_offset() locates the parent node of a given node (that * is, it finds the offset of the node which contains the node at * nodeoffset as a subnode). * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset, *twice*. * * returns: * structure block offset of the parent of the node at nodeoffset * (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_parent_offset(const void *fdt, int nodeoffset); /** * fdt_node_offset_by_prop_value - find nodes with a given property value * @fdt: pointer to the device tree blob * @startoffset: only find nodes after this offset * @propname: property name to check * @propval: property value to search for * @proplen: length of the value in propval * * fdt_node_offset_by_prop_value() returns the offset of the first * node after startoffset, which has a property named propname whose * value is of length proplen and has value equal to propval; or if * startoffset is -1, the very first such node in the tree. * * To iterate through all nodes matching the criterion, the following * idiom can be used: * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, * propval, proplen); * while (offset != -FDT_ERR_NOTFOUND) { * // other code here * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, * propval, proplen); * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: * structure block offset of the located node (>= 0, >startoffset), * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen); /** * fdt_node_offset_by_phandle - find the node with a given phandle * @fdt: pointer to the device tree blob * @phandle: phandle value * * fdt_node_offset_by_phandle() returns the offset of the node * which has the given phandle value. If there is more than one node * in the tree with the given phandle (an invalid tree), results are * undefined. * * returns: * structure block offset of the located node (>= 0), on success * -FDT_ERR_NOTFOUND, no node with that phandle exists * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); /** * fdt_node_check_compatible: check a node's compatible property * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @compatible: string to match against * * * fdt_node_check_compatible() returns 0 if the given node contains a * 'compatible' property with the given string as one of its elements, * it returns non-zero otherwise, or on error. * * returns: * 0, if the node has a 'compatible' property listing the given string * 1, if the node has a 'compatible' property, but it does not list * the given string * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible); /** * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value * @fdt: pointer to the device tree blob * @startoffset: only find nodes after this offset * @compatible: 'compatible' string to match against * * fdt_node_offset_by_compatible() returns the offset of the first * node after startoffset, which has a 'compatible' property which * lists the given compatible string; or if startoffset is -1, the * very first such node in the tree. * * To iterate through all nodes matching the criterion, the following * idiom can be used: * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); * while (offset != -FDT_ERR_NOTFOUND) { * // other code here * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: * structure block offset of the located node (>= 0, >startoffset), * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible); /** * fdt_stringlist_contains - check a string list property for a string * @strlist: Property containing a list of strings to check * @listlen: Length of property * @str: String to search for * * This is a utility function provided for convenience. The list contains * one or more strings, each terminated by \0, as is found in a device tree * "compatible" property. * * @return: 1 if the string is found in the list, 0 not found, or invalid list */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); /** * fdt_stringlist_count - count the number of strings in a string list * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list * @return: * the number of strings in the given property * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist */ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); /** * fdt_stringlist_search - find a string in a string list and return its index * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list * @string: string to look up in the string list * * Note that it is possible for this function to succeed on property values * that are not NUL-terminated. That's because the function will stop after * finding the first occurrence of @string. This can for example happen with * small-valued cell properties, such as #address-cells, when searching for * the empty string. * * @return: * the index of the string in the list of strings * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist or does not contain * the given string */ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, const char *string); /** * fdt_stringlist_get() - obtain the string at a given index in a string list * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list * @index: index of the string to return * @lenp: return location for the string length or an error code on failure * * Note that this will successfully extract strings from properties with * non-NUL-terminated values. For example on small-valued cell properties * this function will return the empty string. * * If non-NULL, the length of the string (on success) or a negative error-code * (on failure) will be stored in the integer pointer to by lenp. * * @return: * A pointer to the string at the given index in the string list or NULL on * failure. On success the length of the string will be stored in the memory * location pointed to by the lenp parameter, if non-NULL. On failure one of * the following negative error codes will be returned in the lenp parameter * (if non-NULL): * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist */ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, const char *property, int index, int *lenp); /**********************************************************************/ /* Read-only functions (addressing related) */ /**********************************************************************/ /** * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells * * This is the maximum value for #address-cells, #size-cells and * similar properties that will be processed by libfdt. IEE1275 * requires that OF implementations handle values up to 4. * Implementations may support larger values, but in practice higher * values aren't used. */ #define FDT_MAX_NCELLS 4 /** * fdt_address_cells - retrieve address size for a bus represented in the tree * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to find the address size for * * When the node has a valid #address-cells property, returns its value. * * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_address_cells(const void *fdt, int nodeoffset); /** * fdt_size_cells - retrieve address range size for a bus represented in the * tree * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to find the address range size for * * When the node has a valid #size-cells property, returns its value. * * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_size_cells(const void *fdt, int nodeoffset); /**********************************************************************/ /* Write-in-place functions */ /**********************************************************************/ /** * fdt_setprop_inplace_namelen_partial - change a property's value, * but not its size * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @namelen: number of characters of name to consider * @idx: index of the property to change in the array * @val: pointer to data to replace the property value with * @len: length of the property value * * Identical to fdt_setprop_inplace(), but modifies the given property * starting from the given index, and using only the first characters * of the name. It is useful when you want to manipulate only one value of * an array and you have a string that doesn't end with \0. */ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, const char *name, int namelen, uint32_t idx, const void *val, int len); /** * fdt_setprop_inplace - change a property's value, but not its size * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: pointer to data to replace the property value with * @len: length of the property value * * fdt_setprop_inplace() replaces the value of a given property with * the data in val, of length len. This function cannot change the * size of a property, and so will only work if len is equal to the * current length of the property. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if len is not equal to the property's current length * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value to replace the property with * * fdt_setprop_inplace_u32() replaces the value of a given property * with the 32-bit integer value in val, converting val to big-endian * if necessary. This function cannot change the size of a property, * and so will only work if the property already exists and has length * 4. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 64-bit integer value to replace the property with * * fdt_setprop_inplace_u64() replaces the value of a given property * with the 64-bit integer value in val, converting val to big-endian * if necessary. This function cannot change the size of a property, * and so will only work if the property already exists and has length * 8. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_inplace_cell - change the value of a single-cell property * * This is an alternative name for fdt_setprop_inplace_u32() */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); } /** * fdt_nop_property - replace a property with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * * fdt_nop_property() will replace a given property's representation * in the blob with FDT_NOP tags, effectively removing it from the * tree. * * This function will alter only the bytes in the blob which contain * the property, and will not alter or move any other part of the * tree. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_property(void *fdt, int nodeoffset, const char *name); /** * fdt_nop_node - replace a node (subtree) with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to nop * * fdt_nop_node() will replace a given node's representation in the * blob, including all its subnodes, if any, with FDT_NOP tags, * effectively removing it from the tree. * * This function will alter only the bytes in the blob which contain * the node and its properties and subnodes, and will not alter or * move any other part of the tree. * * returns: * 0, on success * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_node(void *fdt, int nodeoffset); /**********************************************************************/ /* Sequential write functions */ /**********************************************************************/ int fdt_create(void *buf, int bufsize); int fdt_resize(void *fdt, void *buf, int bufsize); int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_property(fdt, name, &tmp, sizeof(tmp)); } static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_property(fdt, name, &tmp, sizeof(tmp)); } static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { return fdt_property_u32(fdt, name, val); } #define fdt_property_string(fdt, name, str) \ fdt_property(fdt, name, str, strlen(str)+1) int fdt_end_node(void *fdt); int fdt_finish(void *fdt); /**********************************************************************/ /* Read-write functions */ /**********************************************************************/ int fdt_create_empty_tree(void *buf, int bufsize); int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); /** * fdt_add_mem_rsv - add one memory reserve map entry * @fdt: pointer to the device tree blob * @address, @size: 64-bit values (native endian) * * Adds a reserve map entry to the given blob reserving a region at * address address of length size. * * This function will insert data into the reserve map and will * therefore change the indexes of some entries in the table. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new reservation entry * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); /** * fdt_del_mem_rsv - remove a memory reserve map entry * @fdt: pointer to the device tree blob * @n: entry to remove * * fdt_del_mem_rsv() removes the n-th memory reserve map entry from * the blob. * * This function will delete data from the reservation table and will * therefore change the indexes of some entries in the table. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there * are less than n+1 reserve map entries) * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_mem_rsv(void *fdt, int n); /** * fdt_set_name - change the name of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of a node * @name: name to give the node * * fdt_set_name() replaces the name (including unit address, if any) * of the given node with the given string. NOTE: this function can't * efficiently check if the new name is unique amongst the given * node's siblings; results are undefined if this function is invoked * with a name equal to one of the given node's siblings. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob * to contain the new name * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_set_name(void *fdt, int nodeoffset, const char *name); /** * fdt_setprop - create or change a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: pointer to data to set the property value to * @len: length of the property value * * fdt_setprop() sets the value of the named property in the given * node to the given value and length, creating the property if it * does not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** * fdt_setprop_u32 - set a property to a 32-bit integer * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value for the property (native endian) * * fdt_setprop_u32() sets the value of the named property in the given * node to the given 32-bit integer value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_u64 - set a property to a 64-bit integer * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 64-bit integer value for the property (native endian) * * fdt_setprop_u64() sets the value of the named property in the given * node to the given 64-bit integer value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_cell - set a property to a single cell value * * This is an alternative name for fdt_setprop_u32() */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { return fdt_setprop_u32(fdt, nodeoffset, name, val); } /** * fdt_setprop_string - set a property to a string value * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @str: string value for the property * * fdt_setprop_string() sets the value of the named property in the * given node to the given string value (using the length of the * string to determine the new length of the property), or creates a * new property with that value if it does not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_setprop_string(fdt, nodeoffset, name, str) \ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** * fdt_appendprop - append to or create a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to append to * @val: pointer to data to append to the property value * @len: length of the data to append to the property value * * fdt_appendprop() appends the value to the named property in the * given node, creating the property if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** * fdt_appendprop_u32 - append a 32-bit integer value to a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value to append to the property (native endian) * * fdt_appendprop_u32() appends the given 32-bit integer value * (converting to big-endian if necessary) to the value of the named * property in the given node, or creates a new property with that * value if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_appendprop_u64 - append a 64-bit integer value to a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 64-bit integer value to append to the property (native endian) * * fdt_appendprop_u64() appends the given 64-bit integer value * (converting to big-endian if necessary) to the value of the named * property in the given node, or creates a new property with that * value if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_appendprop_cell - append a single cell value to a property * * This is an alternative name for fdt_appendprop_u32() */ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { return fdt_appendprop_u32(fdt, nodeoffset, name, val); } /** * fdt_appendprop_string - append a string to a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @str: string value to append to the property * * fdt_appendprop_string() appends the given string to the value of * the named property in the given node, or creates a new property * with that value if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_appendprop_string(fdt, nodeoffset, name, str) \ fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** * fdt_delprop - delete a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * * fdt_del_property() will delete the given property. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_delprop(void *fdt, int nodeoffset, const char *name); /** * fdt_add_subnode_namelen - creates a new node based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * @namelen: number of characters of name to consider * * Identical to fdt_add_subnode(), but use only the first namelen * characters of name as the name of the new node. This is useful for * creating subnodes based on a portion of a larger string, such as a * full path. */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, const char *name, int namelen); /** * fdt_add_subnode - creates a new node * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * * fdt_add_subnode() creates a new node as a subnode of the node at * structure block offset parentoffset, with the given name (which * should include the unit address, if any). * * This function will insert data into the blob, and will therefore * change the offsets of some existing nodes. * returns: * structure block offset of the created nodeequested subnode (>=0), on * success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE * tag * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of * the given name * -FDT_ERR_NOSPACE, if there is insufficient free space in the * blob to contain the new node * -FDT_ERR_NOSPACE * -FDT_ERR_BADLAYOUT * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); /** * fdt_del_node - delete a node (subtree) * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to nop * * fdt_del_node() will remove the given node, including all its * subnodes if any, from the blob. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_node(void *fdt, int nodeoffset); /** * fdt_overlay_apply - Applies a DT overlay on a base DT * @fdt: pointer to the base device tree blob * @fdto: pointer to the device tree overlay blob * * fdt_overlay_apply() will apply the given device tree overlay on the * given base device tree. * * Expect the base device tree to be modified, even if the function * returns an error. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there's not enough space in the base device tree * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or * properties in the base DT * -FDT_ERR_BADPHANDLE, * -FDT_ERR_BADOVERLAY, * -FDT_ERR_NOPHANDLES, * -FDT_ERR_INTERNAL, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADOFFSET, * -FDT_ERR_BADPATH, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADSTATE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_overlay_apply(void *fdt, void *fdto); /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ const char *fdt_strerror(int errval); #endif /* _LIBFDT_H */ pdbg-pdbg-1.0/libfdt/libfdt_env.h000066400000000000000000000077621313304724200167440ustar00rootroot00000000000000#ifndef _LIBFDT_ENV_H #define _LIBFDT_ENV_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright 2012 Kim Phillips, Freescale Semiconductor. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #ifdef __CHECKER__ #define __force __attribute__((force)) #define __bitwise __attribute__((bitwise)) #else #define __force #define __bitwise #endif typedef uint16_t __bitwise fdt16_t; typedef uint32_t __bitwise fdt32_t; typedef uint64_t __bitwise fdt64_t; #define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) #define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) #define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) #define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) static inline uint16_t fdt16_to_cpu(fdt16_t x) { return (__force uint16_t)CPU_TO_FDT16(x); } static inline fdt16_t cpu_to_fdt16(uint16_t x) { return (__force fdt16_t)CPU_TO_FDT16(x); } static inline uint32_t fdt32_to_cpu(fdt32_t x) { return (__force uint32_t)CPU_TO_FDT32(x); } static inline fdt32_t cpu_to_fdt32(uint32_t x) { return (__force fdt32_t)CPU_TO_FDT32(x); } static inline uint64_t fdt64_to_cpu(fdt64_t x) { return (__force uint64_t)CPU_TO_FDT64(x); } static inline fdt64_t cpu_to_fdt64(uint64_t x) { return (__force fdt64_t)CPU_TO_FDT64(x); } #undef CPU_TO_FDT64 #undef CPU_TO_FDT32 #undef CPU_TO_FDT16 #undef EXTRACT_BYTE #endif /* _LIBFDT_ENV_H */ pdbg-pdbg-1.0/libfdt/libfdt_internal.h000066400000000000000000000071321313304724200177570ustar00rootroot00000000000000#ifndef _LIBFDT_INTERNAL_H #define _LIBFDT_INTERNAL_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #define FDT_CHECK_HEADER(fdt) \ { \ int __err; \ if ((__err = fdt_check_header(fdt)) != 0) \ return __err; \ } int _fdt_check_node_offset(const void *fdt, int offset); int _fdt_check_prop_offset(const void *fdt, int offset); const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); int _fdt_node_end_offset(void *fdt, int nodeoffset); static inline const void *_fdt_offset_ptr(const void *fdt, int offset) { return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; } static inline void *_fdt_offset_ptr_w(void *fdt, int offset) { return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); } static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) { const struct fdt_reserve_entry *rsv_table = (const struct fdt_reserve_entry *) ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); return rsv_table + n; } static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) { return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); } #define FDT_SW_MAGIC (~FDT_MAGIC) #endif /* _LIBFDT_INTERNAL_H */ pdbg-pdbg-1.0/libfdt/version.lds000066400000000000000000000024551313304724200166420ustar00rootroot00000000000000LIBFDT_1.2 { global: fdt_next_node; fdt_check_header; fdt_move; fdt_string; fdt_num_mem_rsv; fdt_get_mem_rsv; fdt_subnode_offset_namelen; fdt_subnode_offset; fdt_path_offset_namelen; fdt_path_offset; fdt_get_name; fdt_get_property_namelen; fdt_get_property; fdt_getprop_namelen; fdt_getprop; fdt_get_phandle; fdt_get_alias_namelen; fdt_get_alias; fdt_get_path; fdt_supernode_atdepth_offset; fdt_node_depth; fdt_parent_offset; fdt_node_offset_by_prop_value; fdt_node_offset_by_phandle; fdt_node_check_compatible; fdt_node_offset_by_compatible; fdt_setprop_inplace; fdt_nop_property; fdt_nop_node; fdt_create; fdt_add_reservemap_entry; fdt_finish_reservemap; fdt_begin_node; fdt_property; fdt_end_node; fdt_finish; fdt_open_into; fdt_pack; fdt_add_mem_rsv; fdt_del_mem_rsv; fdt_set_name; fdt_setprop; fdt_delprop; fdt_add_subnode_namelen; fdt_add_subnode; fdt_del_node; fdt_strerror; fdt_offset_ptr; fdt_next_tag; fdt_appendprop; fdt_create_empty_tree; fdt_first_property_offset; fdt_get_property_by_offset; fdt_getprop_by_offset; fdt_next_property_offset; fdt_first_subnode; fdt_next_subnode; fdt_address_cells; fdt_size_cells; fdt_stringlist_contains; fdt_resize; fdt_overlay_apply; local: *; }; pdbg-pdbg-1.0/libpdbg/000077500000000000000000000000001313304724200146025ustar00rootroot00000000000000pdbg-pdbg-1.0/libpdbg/adu.c000066400000000000000000000250301313304724200155170ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "operations.h" #include "bitutils.h" /* P8 ADU SCOM Register Definitions */ #define P8_ALTD_CONTROL_REG 0x0 #define P8_ALTD_CMD_REG 0x1 #define P8_ALTD_STATUS_REG 0x2 #define P8_ALTD_DATA_REG 0x3 /* P9 ADU SCOM Register Definitions */ #define P9_ALTD_CONTROL_REG 0x0 #define P9_ALTD_CMD_REG 0x1 #define P9_ALTD_STATUS_REG 0x3 #define P9_ALTD_DATA_REG 0x4 /* Common ALTD_CMD_REG fields */ #define FBC_ALTD_START_OP PPC_BIT(2) #define FBC_ALTD_CLEAR_STATUS PPC_BIT(3) #define FBC_ALTD_RESET_AD_PCB PPC_BIT(4) #define FBC_ALTD_SCOPE PPC_BITMASK(16, 18) #define FBC_ALTD_AUTO_INC PPC_BIT(19) #define FBC_ALTD_DROP_PRIORITY PPC_BITMASK(20, 21) #define FBC_LOCKED PPC_BIT(11) /* P9_ALTD_CMD_REG fields */ #define P9_TTYPE_TREAD PPC_BIT(5) #define P9_TTYPE_TWRITE 0 #define P9_FBC_ALTD_TTYPE PPC_BITMASK(25, 31) #define P9_TTYPE_DMA_PARTIAL_READ 0b000110 #define P9_TTYPE_DMA_PARTIAL_WRITE 0b100110 #define P9_FBC_ALTD_TSIZE PPC_BITMASK(32, 39) #define P9_FBC_ALTD_ADDRESS PPC_BITMASK(8, 63) #define DROP_PRIORITY_LOW 0ULL #define DROP_PRIORITY_MEDIUM 1ULL #define DROP_PRIORITY_HIGH 2ULL #define SCOPE_NODAL 0 #define SCOPE_GROUP 1 #define SCOPE_SYSTEM 2 #define SCOPE_REMOTE 3 /* P8_ALTD_CONTROL_REG fields */ #define P8_FBC_ALTD_TTYPE PPC_BITMASK(0, 5) #define P8_TTYPE_TREAD PPC_BIT(6) #define P8_TTYPE_TWRITE 0 #define P8_FBC_ALTD_TSIZE PPC_BITMASK(7, 13) #define P8_FBC_ALTD_ADDRESS PPC_BITMASK(14, 63) #define P8_TTYPE_CI_PARTIAL_WRITE 0b110111 #define P8_TTYPE_CI_PARTIAL_OOO_WRITE 0b110110 #define P8_TTYPE_DMA_PARTIAL_WRITE 0b100110 #define P8_TTYPE_CI_PARTIAL_READ 0b110100 #define P8_TTYPE_DMA_PARTIAL_READ 0b110101 #define P8_TTYPE_PBOPERATION 0b111111 /* P8/P9_ALTD_STATUS_REG fields */ #define FBC_ALTD_ADDR_DONE PPC_BIT(2) #define FBC_ALTD_DATA_DONE PPC_BIT(3) #define FBC_ALTD_PBINIT_MISSING PPC_BIT(18) int adu_getmem(struct target *adu_target, uint64_t start_addr, uint8_t *output, uint64_t size) { struct adu *adu; int rc = 0; uint64_t addr; assert(!strcmp(adu_target->class, "adu")); adu = target_to_adu(adu_target); /* We read data in 8-byte aligned chunks */ for (addr = 8*(start_addr / 8); addr < start_addr + size; addr += 8) { uint64_t data; if (adu->getmem(adu, addr, &data)) return -1; /* ADU returns data in big-endian form in the register */ data = __builtin_bswap64(data); if (addr < start_addr) { memcpy(output, ((uint8_t *) &data) + (start_addr - addr), 8 - (start_addr - addr)); output += 8 - (start_addr - addr); } else if (addr + 8 > start_addr + size) { memcpy(output, &data, start_addr + size - addr); } else { memcpy(output, &data, 8); output += 8; } } return rc; } int adu_putmem(struct target *adu_target, uint64_t start_addr, uint8_t *input, uint64_t size) { struct adu *adu; int rc = 0, tsize; uint64_t addr, data, end_addr; assert(!strcmp(adu_target->class, "adu")); adu = target_to_adu(adu_target); end_addr = start_addr + size; for (addr = start_addr; addr < end_addr; addr += tsize, input += tsize) { if ((addr % 8) || (addr + 8 > end_addr)) { /* If the address is not 64-bit aligned we * copy in a byte at a time until it is. */ tsize = 1; /* Copy the input data in with correct alignment */ data = ((uint64_t) *input) << 8*(8 - (addr % 8) - 1); } else { tsize = 8; memcpy(&data, input, sizeof(data)); data = __builtin_bswap64(data); } adu->putmem(adu, addr, data, tsize); } return rc; } static int adu_lock(struct adu *adu) { uint64_t val; CHECK_ERR(pib_read(&adu->target, P8_ALTD_CMD_REG, &val)); if (val & FBC_LOCKED) PR_INFO("ADU already locked! Ignoring.\n"); val |= FBC_LOCKED; CHECK_ERR(pib_write(&adu->target, P8_ALTD_CMD_REG, val)); return 0; } static int adu_unlock(struct adu *adu) { uint64_t val; CHECK_ERR(pib_read(&adu->target, P8_ALTD_CMD_REG, &val)); if (!(val & FBC_LOCKED)) { PR_INFO("ADU already unlocked!\n"); return 0; } val &= ~FBC_LOCKED; CHECK_ERR(pib_write(&adu->target, P8_ALTD_CMD_REG, val)); return 0; } static int adu_reset(struct adu *adu) { uint64_t val; CHECK_ERR(pib_read(&adu->target, P8_ALTD_CMD_REG, &val)); val |= FBC_ALTD_CLEAR_STATUS | FBC_ALTD_RESET_AD_PCB; CHECK_ERR(pib_write(&adu->target, P8_ALTD_CMD_REG, val)); return 0; } static int p8_adu_getmem(struct adu *adu, uint64_t addr, uint64_t *data) { uint64_t ctrl_reg, cmd_reg, val; CHECK_ERR(adu_lock(adu)); ctrl_reg = P8_TTYPE_TREAD; ctrl_reg = SETFIELD(P8_FBC_ALTD_TTYPE, ctrl_reg, P8_TTYPE_DMA_PARTIAL_READ); ctrl_reg = SETFIELD(P8_FBC_ALTD_TSIZE, ctrl_reg, 8); CHECK_ERR(pib_read(&adu->target, P8_ALTD_CMD_REG, &cmd_reg)); cmd_reg |= FBC_ALTD_START_OP; cmd_reg = SETFIELD(FBC_ALTD_SCOPE, cmd_reg, SCOPE_SYSTEM); cmd_reg = SETFIELD(FBC_ALTD_DROP_PRIORITY, cmd_reg, DROP_PRIORITY_MEDIUM); retry: /* Clear status bits */ CHECK_ERR(adu_reset(adu)); /* Set the address */ ctrl_reg = SETFIELD(P8_FBC_ALTD_ADDRESS, ctrl_reg, addr); CHECK_ERR(pib_write(&adu->target, P8_ALTD_CONTROL_REG, ctrl_reg)); /* Start the command */ CHECK_ERR(pib_write(&adu->target, P8_ALTD_CMD_REG, cmd_reg)); /* Wait for completion */ do { CHECK_ERR(pib_read(&adu->target, P8_ALTD_STATUS_REG, &val)); } while (!val); if( !(val & FBC_ALTD_ADDR_DONE) || !(val & FBC_ALTD_DATA_DONE)) { /* PBINIT_MISSING is expected occasionally so just retry */ if (val & FBC_ALTD_PBINIT_MISSING) goto retry; else { PR_ERROR("Unable to read memory. " \ "ALTD_STATUS_REG = 0x%016" PRIx64 "\n", val); return -1; } } /* Read data */ CHECK_ERR(pib_read(&adu->target, P8_ALTD_DATA_REG, data)); adu_unlock(adu); return 0; } int p8_adu_putmem(struct adu *adu, uint64_t addr, uint64_t data, int size) { int rc = 0; uint64_t cmd_reg, ctrl_reg, val; CHECK_ERR(adu_lock(adu)); ctrl_reg = P8_TTYPE_TWRITE; ctrl_reg = SETFIELD(P8_FBC_ALTD_TTYPE, ctrl_reg, P8_TTYPE_DMA_PARTIAL_WRITE); ctrl_reg = SETFIELD(P8_FBC_ALTD_TSIZE, ctrl_reg, size); CHECK_ERR(pib_read(&adu->target, P8_ALTD_CMD_REG, &cmd_reg)); cmd_reg |= FBC_ALTD_START_OP; cmd_reg = SETFIELD(FBC_ALTD_SCOPE, cmd_reg, SCOPE_SYSTEM); cmd_reg = SETFIELD(FBC_ALTD_DROP_PRIORITY, cmd_reg, DROP_PRIORITY_MEDIUM); /* Clear status bits */ CHECK_ERR(adu_reset(adu)); /* Set the address */ ctrl_reg = SETFIELD(P8_FBC_ALTD_ADDRESS, ctrl_reg, addr); retry: CHECK_ERR(pib_write(&adu->target, P8_ALTD_CONTROL_REG, ctrl_reg)); /* Write the data */ CHECK_ERR(pib_write(&adu->target, P8_ALTD_DATA_REG, data)); /* Start the command */ CHECK_ERR(pib_write(&adu->target, P8_ALTD_CMD_REG, cmd_reg)); /* Wait for completion */ do { CHECK_ERR(pib_read(&adu->target, P8_ALTD_STATUS_REG, &val)); } while (!val); if( !(val & FBC_ALTD_ADDR_DONE) || !(val & FBC_ALTD_DATA_DONE)) { /* PBINIT_MISSING is expected occasionally so just retry */ if (val & FBC_ALTD_PBINIT_MISSING) goto retry; else { PR_ERROR("Unable to write memory. " \ "P8_ALTD_STATUS_REG = 0x%016" PRIx64 "\n", val); rc = -1; } } adu_unlock(adu); return rc; } static int p9_adu_getmem(struct adu *adu, uint64_t addr, uint64_t *data) { uint64_t ctrl_reg, cmd_reg, val; cmd_reg = P9_TTYPE_TREAD; cmd_reg = SETFIELD(P9_FBC_ALTD_TTYPE, cmd_reg, P9_TTYPE_DMA_PARTIAL_READ); /* For a read size is apparently always 0 */ cmd_reg = SETFIELD(P9_FBC_ALTD_TSIZE, cmd_reg, 0); cmd_reg |= FBC_ALTD_START_OP; cmd_reg = SETFIELD(FBC_ALTD_SCOPE, cmd_reg, SCOPE_REMOTE); cmd_reg = SETFIELD(FBC_ALTD_DROP_PRIORITY, cmd_reg, DROP_PRIORITY_LOW); retry: /* Clear status bits */ CHECK_ERR(adu_reset(adu)); /* Set the address */ ctrl_reg = SETFIELD(P9_FBC_ALTD_ADDRESS, 0, addr); CHECK_ERR(pib_write(&adu->target, P9_ALTD_CONTROL_REG, ctrl_reg)); /* Start the command */ CHECK_ERR(pib_write(&adu->target, P9_ALTD_CMD_REG, cmd_reg)); /* Wait for completion */ do { CHECK_ERR(pib_read(&adu->target, P9_ALTD_STATUS_REG, &val)); } while (!val); if( !(val & FBC_ALTD_ADDR_DONE) || !(val & FBC_ALTD_DATA_DONE)) { /* PBINIT_MISSING is expected occasionally so just retry */ if (val & FBC_ALTD_PBINIT_MISSING) goto retry; else { PR_ERROR("Unable to read memory. " \ "ALTD_STATUS_REG = 0x%016" PRIx64 "\n", val); return -1; } } /* Read data */ CHECK_ERR(pib_read(&adu->target, P9_ALTD_DATA_REG, data)); return 0; } static int p9_adu_putmem(struct adu *adu, uint64_t addr, uint64_t data, int size) { uint64_t ctrl_reg, cmd_reg, val; /* Format to tsize. This is the "secondary encode" and is shifted left on for writes. */ size <<= 1; cmd_reg = P9_TTYPE_TWRITE; cmd_reg = SETFIELD(P9_FBC_ALTD_TTYPE, cmd_reg, P9_TTYPE_DMA_PARTIAL_WRITE); cmd_reg = SETFIELD(P9_FBC_ALTD_TSIZE, cmd_reg, size); cmd_reg |= FBC_ALTD_START_OP; cmd_reg = SETFIELD(FBC_ALTD_SCOPE, cmd_reg, SCOPE_REMOTE); cmd_reg = SETFIELD(FBC_ALTD_DROP_PRIORITY, cmd_reg, DROP_PRIORITY_LOW); /* Clear status bits */ CHECK_ERR(adu_reset(adu)); /* Set the address */ ctrl_reg = SETFIELD(P9_FBC_ALTD_ADDRESS, 0, addr); retry: CHECK_ERR(pib_write(&adu->target, P9_ALTD_CONTROL_REG, ctrl_reg)); /* Write the data */ CHECK_ERR(pib_write(&adu->target, P9_ALTD_DATA_REG, data)); /* Start the command */ CHECK_ERR(pib_write(&adu->target, P9_ALTD_CMD_REG, cmd_reg)); /* Wait for completion */ do { CHECK_ERR(pib_read(&adu->target, P9_ALTD_STATUS_REG, &val)); } while (!val); if( !(val & FBC_ALTD_ADDR_DONE) || !(val & FBC_ALTD_DATA_DONE)) { /* PBINIT_MISSING is expected occasionally so just retry */ if (val & FBC_ALTD_PBINIT_MISSING) goto retry; else { PR_ERROR("Unable to read memory. " \ "ALTD_STATUS_REG = 0x%016" PRIx64 "\n", val); return -1; } } return 0; } struct adu p8_adu = { .target = { .name = "POWER8 ADU", .compatible = "ibm,power8-adu", .class = "adu", }, .getmem = p8_adu_getmem, .putmem = p8_adu_putmem, }; DECLARE_HW_UNIT(p8_adu); struct adu p9_adu = { .target = { .name = "POWER9 ADU", .compatible = "ibm,power9-adu", .class = "adu", }, .getmem = p9_adu_getmem, .putmem = p9_adu_putmem, }; DECLARE_HW_UNIT(p9_adu); pdbg-pdbg-1.0/libpdbg/backend.h000066400000000000000000000015311313304724200163420ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __BACKEND_H #define __BACKEND_H /* We only support slave 0 at the moment */ #define SLAVE_ID 0x0 /* backend initialisation */ struct scom_backend *fsi_init(void); /* i2c backend initialisation */ struct scom_backend *i2c_init(char *bus, int addr); #endif pdbg-pdbg-1.0/libpdbg/bitutils.h000066400000000000000000000032011313304724200166060ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __BITUTILS_H #define __BITUTILS_H /* PPC bit number conversion */ #ifdef __ASSEMBLY__ #define PPC_BIT(bit) (0x8000000000000000 >> (bit)) #define PPC_BIT32(bit) (0x80000000 >> (bit)) #define PPC_BIT8(bit) (0x80 >> (bit)) #else #define PPC_BIT(bit) (0x8000000000000000UL >> (bit)) #define PPC_BIT32(bit) (0x80000000UL >> (bit)) #define PPC_BIT8(bit) (0x80UL >> (bit)) #endif #define PPC_BITMASK(bs,be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) #define PPC_BITMASK32(bs,be) ((PPC_BIT32(bs) - PPC_BIT32(be))|PPC_BIT32(bs)) #define PPC_BITLSHIFT(be) (63 - (be)) #define PPC_BITLSHIFT32(be) (31 - (be)) /* * PPC bitmask field manipulation */ /* Find left shift from first set bit in mask */ #define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1) /* Extract field fname from val */ #define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m)) /* Set field fname of oval to fval * NOTE: oval isn't modified, the combined result is returned */ #define SETFIELD(m, v, val) \ (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m))) #endif /* __BITUTILS_H */ pdbg-pdbg-1.0/libpdbg/bmcfsi.c000066400000000000000000000265021313304724200162160ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "bitutils.h" #include "operations.h" #include "device.h" #include "target.h" #define GPIO_BASE 0x1e780000 #define GPIO_DATA 0x0 #define GPIO_DIR 0x4 #define CRC_LEN 4 /* Defines a GPIO. The Aspeed devices dont have consistent stride * between registers so we need to encode register bit number and base * address offset */ struct gpio_pin { uint32_t offset; int bit; }; enum gpio { GPIO_FSI_CLK = 0, GPIO_FSI_DAT = 1, GPIO_FSI_DAT_EN = 2, GPIO_FSI_ENABLE = 3, GPIO_CRONUS_SEL = 4, }; /* Pointer to the GPIO pins to use for this system */ #define FSI_CLK &gpio_pins[GPIO_FSI_CLK] #define FSI_DAT &gpio_pins[GPIO_FSI_DAT] #define FSI_DAT_EN &gpio_pins[GPIO_FSI_DAT_EN] #define FSI_ENABLE &gpio_pins[GPIO_FSI_ENABLE] #define CRONUS_SEL &gpio_pins[GPIO_CRONUS_SEL] static struct gpio_pin gpio_pins[GPIO_CRONUS_SEL + 1]; /* FSI result symbols */ enum fsi_result { FSI_MERR_TIMEOUT = -2, FSI_MERR_C = -1, FSI_ACK = 0x0, FSI_BUSY = 0x1, FSI_ERR_A = 0x2, FSI_ERR_C = 0x3, }; static int clock_delay = 0; #define FSI_DATA0_REG 0x1000 #define FSI_DATA1_REG 0x1001 #define FSI_CMD_REG 0x1002 #define FSI_CMD_REG_WRITE PPC_BIT32(0) #define FSI_RESET_REG 0x1006 #define FSI_RESET_CMD PPC_BIT32(0) #define FSI_SET_PIB_RESET_REG 0x1007 #define FSI_SET_PIB_RESET PPC_BIT32(0) /* For some reason the FSI2PIB engine dies with frequent * access. Letting it have a bit of a rest seems to stop the * problem. This sets the number of usecs to sleep between SCOM * accesses. */ #define FSI2PIB_RELAX 50 /* FSI private data */ static void *gpio_reg = NULL; static int mem_fd = 0; static void fsi_reset(struct fsi *fsi); static uint32_t readl(void *addr) { asm volatile("" : : : "memory"); return *(volatile uint32_t *) addr; } static void writel(uint32_t val, void *addr) { asm volatile("" : : : "memory"); *(volatile uint32_t *) addr = val; } static int __attribute__((unused)) get_direction(struct gpio_pin *pin) { void *offset = gpio_reg + pin->offset + GPIO_DIR; return !!(readl(offset) & (1ULL << pin->bit)); } static void set_direction_out(struct gpio_pin *pin) { uint32_t x; void *offset = gpio_reg + pin->offset + GPIO_DIR; x = readl(offset); x |= 1ULL << pin->bit; writel(x, offset); } static void set_direction_in(struct gpio_pin *pin) { uint32_t x; void *offset = gpio_reg + pin->offset + GPIO_DIR; x = readl(offset); x &= ~(1ULL << pin->bit); writel(x, offset); } static int read_gpio(struct gpio_pin *pin) { void *offset = gpio_reg + pin->offset + GPIO_DATA; return (readl(offset) >> pin->bit) & 0x1; } static void write_gpio(struct gpio_pin *pin, int val) { uint32_t x; void *offset = gpio_reg + pin->offset + GPIO_DATA; x = readl(offset); if (val) x |= 1ULL << pin->bit; else x &= ~(1ULL << pin->bit); writel(x, offset); } static inline void clock_cycle(struct gpio_pin *pin, int num_clks) { int i; volatile int j; /* Need to introduce delays when inlining this function */ for (j = 0; j < clock_delay; j++); for (i = 0; i < num_clks; i++) { write_gpio(pin, 0); write_gpio(pin, 1); } for (j = 0; j < clock_delay; j++); } static uint8_t crc4(uint8_t c, int b) { uint8_t m = 0; c &= 0xf; m = b ^ ((c >> 3) & 0x1); m = (m << 2) | (m << 1) | (m); c <<= 1; c ^= m; return c & 0xf; } /* FSI bits should be reading on the falling edge. Read a bit and * clock the next one out. */ static inline unsigned int fsi_read_bit(void) { int x; x = read_gpio(FSI_DAT); clock_cycle(FSI_CLK, 1); /* The FSI hardware is active low (ie. inverted) */ return !(x & 1); } static inline void fsi_send_bit(uint64_t bit) { write_gpio(FSI_DAT, !bit); clock_cycle(FSI_CLK, 1); } /* Format a CFAM address into an FSI slaveId, command and address. */ static uint64_t fsi_abs_ar(uint32_t addr, int read) { uint32_t slave_id = (addr >> 21) & 0x3; /* Reformat the address. I'm not sure I fully understand this * yet but we basically shift the bottom byte and add 0b01 * (for the write word?) */ addr = ((addr & 0x1ffc00) | ((addr & 0x3ff) << 2)) << 1; addr |= 0x3; addr |= slave_id << 26; addr |= (0x8ULL | !!(read)) << 22; return addr; } static uint64_t fsi_d_poll(uint8_t slave_id) { return slave_id << 3 | 0x2; } static void fsi_break(void) { set_direction_out(FSI_CLK); set_direction_out(FSI_DAT); write_gpio(FSI_DAT_EN, 1); /* Crank things - not sure if we need this yet */ write_gpio(FSI_CLK, 1); write_gpio(FSI_DAT, 1); /* Data standby state */ /* Send break command */ write_gpio(FSI_DAT, 0); clock_cycle(FSI_CLK, 256); } /* Send a sequence, including start bit and crc */ static void fsi_send_seq(uint64_t seq, int len) { int i; uint8_t crc; set_direction_out(FSI_CLK); set_direction_out(FSI_DAT); write_gpio(FSI_DAT_EN, 1); write_gpio(FSI_DAT, 1); clock_cycle(FSI_CLK, 50); /* Send the start bit */ write_gpio(FSI_DAT, 0); clock_cycle(FSI_CLK, 1); /* crc includes start bit */ crc = crc4(0, 1); for (i = 63; i >= 64 - len; i--) { crc = crc4(crc, !!(seq & (1ULL << i))); fsi_send_bit(seq & (1ULL << i)); } /* Send the CRC */ for (i = 3; i >= 0; i--) fsi_send_bit(crc & (1ULL << i)); write_gpio(FSI_CLK, 0); } /* Read a response. Only supports upto 60 bits at the moment. */ static enum fsi_result fsi_read_resp(uint64_t *result, int len) { int i, x; uint8_t crc; uint64_t resp = 0; uint8_t ack = 0; write_gpio(FSI_DAT_EN, 0); set_direction_in(FSI_DAT); /* Wait for start bit */ for (i = 0; i < 512; i++) { x = fsi_read_bit(); if (x) break; } if (i == 512) { PR_DEBUG("Timeout waiting for start bit\n"); return FSI_MERR_TIMEOUT; } crc = crc4(0, 1); /* Read the response code (ACK, ERR_A, etc.) */ for (i = 0; i < 4; i++) { ack <<= 1; ack |= fsi_read_bit(); crc = crc4(crc, ack & 0x1); } /* A non-ACK response has no data but should include a CRC */ if (ack != FSI_ACK) len = 7; for (; i < len + CRC_LEN; i++) { resp <<= 1; resp |= fsi_read_bit(); crc = crc4(crc, resp & 0x1); } if (crc != 0) { fprintf(stderr, "CRC error: 0x%" PRIx64 "\n", resp); return FSI_MERR_C; } write_gpio(FSI_CLK, 0); /* Strip the CRC off */ *result = resp >> 4; return ack & 0x3; } static enum fsi_result fsi_d_poll_wait(uint8_t slave_id, uint64_t *resp, int len) { int i; uint64_t seq; enum fsi_result rc; /* Poll for response if busy */ for (i = 0; i < 512; i++) { seq = fsi_d_poll(slave_id) << 59; fsi_send_seq(seq, 5); if ((rc = fsi_read_resp(resp, len)) != FSI_BUSY) break; } return rc; } static int fsi_getcfam(struct fsi *fsi, uint32_t addr, uint32_t *value) { uint64_t seq; uint64_t resp; enum fsi_result rc; /* Format of the read sequence is: * 6666555555555544444444443333333333222222222211111111110000000000 * 3210987654321098765432109876543210987654321098765432109876543210 * * ii1001aaaaaaaaaaaaaaaaaaa011cccc * * Where: * ii = slaveId * a = address bit * 011 = write word size * d = data bit * c = crc bit * * When applying the sequence it should be inverted (active * low) */ seq = fsi_abs_ar(addr, 1) << 36; fsi_send_seq(seq, 28); if ((rc = fsi_read_resp(&resp, 36)) == FSI_BUSY) rc = fsi_d_poll_wait(0, &resp, 36); if (rc != FSI_ACK) { PR_DEBUG("getcfam error. Response: 0x%01x\n", rc); rc = -1; } *value = resp & 0xffffffff; return rc; } static int fsi_putcfam(struct fsi *fsi, uint32_t addr, uint32_t data) { uint64_t seq; uint64_t resp; enum fsi_result rc; /* Format of the sequence is: * 6666555555555544444444443333333333222222222211111111110000000000 * 3210987654321098765432109876543210987654321098765432109876543210 * * ii1000aaaaaaaaaaaaaaaaaaa011ddddddddddddddddddddddddddddddddcccc * * Where: * ii = slaveId * a = address bit * 011 = write word size * d = data bit * c = crc bit * * When applying the sequence it should be inverted (active * low) */ seq = fsi_abs_ar(addr, 0) << 36; seq |= ((uint64_t) data & 0xffffffff) << (4); fsi_send_seq(seq, 60); if ((rc = fsi_read_resp(&resp, 4)) == FSI_BUSY) rc = fsi_d_poll_wait(0, &resp, 4); if (rc != FSI_ACK) PR_DEBUG("putcfam error. Response: 0x%01x\n", rc); else rc = 0; return rc; } static void fsi_reset(struct fsi *fsi) { uint32_t val; fsi_break(); /* Clear own id on the master CFAM to access hMFSI ports */ fsi_getcfam(fsi, 0x800, &val); val &= ~(PPC_BIT32(6) | PPC_BIT32(7)); fsi_putcfam(fsi, 0x800, val); } void fsi_destroy(struct target *target) { set_direction_out(FSI_CLK); set_direction_out(FSI_DAT); write_gpio(FSI_DAT_EN, 1); /* Crank things - this is needed to use this tool for kicking off system boot */ write_gpio(FSI_CLK, 1); write_gpio(FSI_DAT, 1); /* Data standby state */ clock_cycle(FSI_CLK, 5000); write_gpio(FSI_DAT_EN, 0); write_gpio(FSI_CLK, 0); write_gpio(FSI_ENABLE, 0); write_gpio(CRONUS_SEL, 0); } int bmcfsi_probe(struct target *target) { struct fsi *fsi = target_to_fsi(target); if (!mem_fd) { mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (mem_fd < 0) { perror("Unable to open /dev/mem"); exit(1); } } if (!gpio_reg) { gpio_pins[GPIO_FSI_CLK].offset = dt_prop_get_u32_index(target->dn, "fsi_clk", 0); gpio_pins[GPIO_FSI_CLK].bit = dt_prop_get_u32_index(target->dn, "fsi_clk", 1); gpio_pins[GPIO_FSI_DAT].offset = dt_prop_get_u32_index(target->dn, "fsi_dat", 0); gpio_pins[GPIO_FSI_DAT].bit = dt_prop_get_u32_index(target->dn, "fsi_dat", 1); gpio_pins[GPIO_FSI_DAT_EN].offset = dt_prop_get_u32_index(target->dn, "fsi_dat_en", 0); gpio_pins[GPIO_FSI_DAT_EN].bit = dt_prop_get_u32_index(target->dn, "fsi_dat_en", 1); gpio_pins[GPIO_FSI_ENABLE].offset = dt_prop_get_u32_index(target->dn, "fsi_enable", 0); gpio_pins[GPIO_FSI_ENABLE].bit = dt_prop_get_u32_index(target->dn, "fsi_enable", 1); gpio_pins[GPIO_CRONUS_SEL].offset = dt_prop_get_u32_index(target->dn, "cronus_sel", 0); gpio_pins[GPIO_CRONUS_SEL].bit = dt_prop_get_u32_index(target->dn, "cronus_sel", 1); clock_delay = dt_prop_get_u32(target->dn, "clock_delay"); /* We only have to do this init once per backend */ gpio_reg = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, GPIO_BASE); if (gpio_reg == MAP_FAILED) { perror("Unable to map GPIO register memory"); exit(-1); } set_direction_out(CRONUS_SEL); set_direction_out(FSI_ENABLE); set_direction_out(FSI_DAT_EN); write_gpio(FSI_ENABLE, 1); write_gpio(CRONUS_SEL, 1); fsi_reset(fsi); } return 0; } struct fsi bmcfsi = { .target = { .name = "BMC GPIO bit-banging FSI master", .compatible = "ibm,bmcfsi", .class = "fsi", .probe = bmcfsi_probe, }, .read = fsi_getcfam, .write = fsi_putcfam, }; DECLARE_HW_UNIT(bmcfsi); pdbg-pdbg-1.0/libpdbg/cfam.c000066400000000000000000000207561313304724200156660ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Most of the PIB2OPB code is based on code from skiboot. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "target.h" #include "bitutils.h" #include "operations.h" #undef PR_DEBUG #define PR_DEBUG(...) #define FSI_DATA0_REG 0x0 #define FSI_DATA1_REG 0x1 #define FSI_CMD_REG 0x2 #define FSI_CMD_REG_WRITE PPC_BIT32(0) #define FSI_RESET_REG 0x6 #define FSI_RESET_CMD PPC_BIT32(0) #define FSI_SET_PIB_RESET_REG 0x7 #define FSI_SET_PIB_RESET PPC_BIT32(0) /* For some reason the FSI2PIB engine dies with frequent * access. Letting it have a bit of a rest seems to stop the * problem. This sets the number of usecs to sleep between SCOM * accesses. */ #define FSI2PIB_RELAX 50 /* * Bridge registers on XSCOM that allow generatoin * of OPB cycles */ #define PIB2OPB_REG_CMD 0x0 #define OPB_CMD_WRITE 0x80000000 #define OPB_CMD_READ 0x00000000 #define OPB_CMD_8BIT 0x00000000 #define OPB_CMD_16BIT 0x20000000 #define OPB_CMD_32BIT 0x60000000 #define PIB2OPB_REG_STAT 0x1 #define OPB_STAT_ANY_ERR 0x80000000 #define OPB_STAT_ERR_OPB 0x7FEC0000 #define OPB_STAT_ERRACK 0x00100000 #define OPB_STAT_BUSY 0x00010000 #define OPB_STAT_READ_VALID 0x00020000 #define OPB_STAT_ERR_CMFSI 0x0000FC00 #define OPB_STAT_ERR_HMFSI 0x000000FC #define OPB_STAT_ERR_BASE (OPB_STAT_ANY_ERR | \ OPB_STAT_ERR_OPB | \ OPB_STAT_ERRACK) #define PIB2OPB_REG_LSTAT 0x2 #define PIB2OPB_REG_RESET 0x4 #define PIB2OPB_REG_cRSIC 0x5 #define PIB2OPB_REG_cRSIM 0x6 #define PIB2OPB_REG_cRSIS 0x7 #define PIB2OPB_REG_hRSIC 0x8 #define PIB2OPB_REG_hRSIM 0x9 #define PIB2OPB_REG_hRSIS 0xA #define OPB_ERR_XSCOM_ERR -1; #define OPB_ERR_TIMEOUT_ERR -1; #define OPB_ERR_BAD_OPB_ADDR -1; /* We try up to 1.2ms for an OPB access */ #define MFSI_OPB_MAX_TRIES 1200 static int fsi2pib_getscom(struct pib *pib, uint64_t addr, uint64_t *value) { uint32_t result; usleep(FSI2PIB_RELAX); /* Get scom works by putting the address in FSI_CMD_REG and * reading the result from FST_DATA[01]_REG. */ CHECK_ERR(fsi_write(&pib->target, FSI_RESET_REG, FSI_RESET_CMD)); CHECK_ERR(fsi_write(&pib->target, FSI_CMD_REG, addr)); CHECK_ERR(fsi_read(&pib->target, FSI_DATA0_REG, &result)); *value = ((uint64_t) result) << 32; CHECK_ERR(fsi_read(&pib->target, FSI_DATA1_REG, &result)); *value |= result; return 0; } static int fsi2pib_putscom(struct pib *pib, uint64_t addr, uint64_t value) { usleep(FSI2PIB_RELAX); CHECK_ERR(fsi_write(&pib->target, FSI_RESET_REG, FSI_RESET_CMD)); CHECK_ERR(fsi_write(&pib->target, FSI_DATA0_REG, (value >> 32) & 0xffffffff)); CHECK_ERR(fsi_write(&pib->target, FSI_DATA1_REG, value & 0xffffffff)); CHECK_ERR(fsi_write(&pib->target, FSI_CMD_REG, FSI_CMD_REG_WRITE | addr)); return 0; } struct pib fsi_pib = { .target = { .name = "POWER FSI2PIB", .compatible = "ibm,fsi-pib", .class = "pib", }, .read = fsi2pib_getscom, .write = fsi2pib_putscom, }; DECLARE_HW_UNIT(fsi_pib); static uint64_t opb_poll(struct opb *opb, uint32_t *read_data) { unsigned long retries = MFSI_OPB_MAX_TRIES; uint64_t sval; uint32_t stat; int64_t rc; /* We try again every 10us for a bit more than 1ms */ for (;;) { /* Read OPB status register */ rc = pib_read(&opb->target, PIB2OPB_REG_STAT, &sval); if (rc) { /* Do something here ? */ PR_ERROR("XSCOM error %" PRId64 " read OPB STAT\n", rc); return -1; } PR_DEBUG(" STAT=0x%16llx...\n", sval); stat = sval >> 32; /* Complete */ if (!(stat & OPB_STAT_BUSY)) break; if (retries-- == 0) { /* This isn't supposed to happen (HW timeout) */ PR_ERROR("OPB POLL timeout !\n"); return -1; } usleep(1); } /* * TODO: Add the full error analysis that skiboot has. For now * we just reset things so we can continue. Also need to * improve error handling as we expect these occasionally when * probing the system. */ if (stat & OPB_STAT_ANY_ERR) { pib_write(&opb->target, PIB2OPB_REG_RESET, PPC_BIT(0)); pib_write(&opb->target, PIB2OPB_REG_STAT, PPC_BIT(0)); PR_DEBUG("OPB Error. Status 0x%08x\n", stat); rc = -1; } else if (read_data) { if (!(stat & OPB_STAT_READ_VALID)) { PR_DEBUG("Read successful but no data !\n"); rc = -1; } *read_data = sval & 0xffffffff; } return rc; } static int p8_opb_read(struct opb *opb, uint32_t addr, uint32_t *data) { uint64_t opb_cmd = OPB_CMD_READ | OPB_CMD_32BIT; int64_t rc; if (addr > 0x00ffffff) return OPB_ERR_BAD_OPB_ADDR; /* Turn the address into a byte address */ addr = (addr & 0xffff00) | ((addr & 0xff) << 2); opb_cmd |= addr; opb_cmd <<= 32; PR_DEBUG("MFSI_OPB_READ: Writing 0x%16llx\n", opb_cmd); rc = pib_write(&opb->target, PIB2OPB_REG_CMD, opb_cmd); if (rc) { PR_ERROR("XSCOM error %" PRId64 " writing OPB CMD\n", rc); return OPB_ERR_XSCOM_ERR; } return opb_poll(opb, data); } static int p8_opb_write(struct opb *opb, uint32_t addr, uint32_t data) { uint64_t opb_cmd = OPB_CMD_WRITE | OPB_CMD_32BIT; int64_t rc; if (addr > 0x00ffffff) return OPB_ERR_BAD_OPB_ADDR; addr = (addr & 0xffff00) | ((addr & 0xff) << 2); opb_cmd |= addr; opb_cmd <<= 32; opb_cmd |= data; PR_DEBUG("MFSI_OPB_WRITE: Writing 0x%16llx\n", opb_cmd); rc = pib_write(&opb->target, PIB2OPB_REG_CMD, opb_cmd); if (rc) { PR_ERROR("XSCOM error %" PRId64 " writing OPB CMD\n", rc); return OPB_ERR_XSCOM_ERR; } return opb_poll(opb, NULL); } struct opb p8_opb = { .target = { .name = "POWER8 OPB", .compatible = "ibm,power8-opb", .class = "opb", }, .read = p8_opb_read, .write = p8_opb_write, }; DECLARE_HW_UNIT(p8_opb); enum chip_type get_chip_type(uint64_t chip_id) { switch(GETFIELD(PPC_BITMASK32(12, 19), chip_id)) { case 0xea: return CHIP_P8; case 0xd3: return CHIP_P8NV; case 0xd1: return CHIP_P9; default: return CHIP_UNKNOWN; } } static int p8_hmfsi_read(struct fsi *fsi, uint32_t addr, uint32_t *data) { return opb_read(&fsi->target, addr, data); } static int p8_hmfsi_write(struct fsi *fsi, uint32_t addr, uint32_t data) { return opb_write(&fsi->target, addr, data); } static int p8_hmfsi_probe(struct target *target) { struct fsi *fsi = target_to_fsi(target); uint32_t value; int rc; if ((rc = opb_read(&fsi->target, 0xc09, &value))) return rc; fsi->chip_type = get_chip_type(value); PR_DEBUG("Found chip type %x\n", fsi->chip_type); if (fsi->chip_type == CHIP_UNKNOWN) return -1; return 0; } struct fsi p8_opb_hmfsi = { .target = { .name = "POWER8 OPB attached hMFSI", .compatible = "ibm,power8-opb-hmfsi", .class = "fsi", .probe = p8_hmfsi_probe, }, .read = p8_hmfsi_read, .write = p8_hmfsi_write, }; DECLARE_HW_UNIT(p8_opb_hmfsi); static int cfam_hmfsi_read(struct fsi *fsi, uint32_t addr, uint32_t *data) { struct target *parent_fsi = fsi->target.dn->parent->target; addr += dt_get_address(fsi->target.dn, 0, NULL); return fsi_read(parent_fsi, addr, data); } static int cfam_hmfsi_write(struct fsi *fsi, uint32_t addr, uint32_t data) { struct target *parent_fsi = fsi->target.dn->parent->target; addr += dt_get_address(fsi->target.dn, 0, NULL); return fsi_write(parent_fsi, addr, data); } static int cfam_hmfsi_probe(struct target *target) { struct fsi *fsi = target_to_fsi(target); struct target *fsi_parent = target->dn->parent->target; uint32_t value, port; int rc; /* Enable the port in the upstream control register */ port = dt_prop_get_u32(target->dn, "port"); fsi_read(fsi_parent, 0x3404, &value); value |= 1 << (31 - port); if ((rc = fsi_write(fsi_parent, 0x3404, value))) { PR_ERROR("Unale to enable HMFSI port %d\n", port); return rc; } if ((rc = fsi_read(&fsi->target, 0xc09, &value))) return rc; fsi->chip_type = get_chip_type(value); PR_DEBUG("Found chip type %x\n", fsi->chip_type); if (fsi->chip_type == CHIP_UNKNOWN) return -1; return 0; } struct fsi cfam_hmfsi = { .target = { .name = "CFAM hMFSI Port", .compatible = "ibm,fsi-hmfsi", .class = "fsi", .probe = cfam_hmfsi_probe, }, .read = cfam_hmfsi_read, .write = cfam_hmfsi_write, }; DECLARE_HW_UNIT(cfam_hmfsi); pdbg-pdbg-1.0/libpdbg/chip.c000066400000000000000000000143611313304724200156760ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "target.h" #include "operations.h" #include "bitutils.h" static uint64_t mfspr(uint64_t reg, uint64_t spr) { if (reg > 31) PR_ERROR("Invalid register specified\n"); return MFSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6); } static uint64_t mtspr(uint64_t spr, uint64_t reg) { if (reg > 31) PR_ERROR("Invalid register specified\n"); return MTSPR_OPCODE | (reg << 21) | ((spr & 0x1f) << 16) | ((spr & 0x3e0) << 6); } static uint64_t mfnia(uint64_t reg) { if (reg > 31) PR_ERROR("Invalid register specified\n"); return MFNIA_OPCODE | (reg << 21); } static uint64_t mtnia(uint64_t reg) { if (reg > 31) PR_ERROR("Invalid register specified\n"); return MTNIA_OPCODE | (reg << 21); } static uint64_t mfmsr(uint64_t reg) { if (reg > 31) PR_ERROR("Invalid register specified\n"); return MFMSR_OPCODE | (reg << 21); } static uint64_t mtmsr(uint64_t reg) { if (reg > 31) PR_ERROR("Invalid register specified\n"); return MTMSR_OPCODE | (reg << 21); } static uint64_t ld(uint64_t rt, uint64_t ds, uint64_t ra) { if ((rt > 31) | (ra > 31) | (ds > 0x3fff)) PR_ERROR("Invalid register specified\n"); return LD_OPCODE | (rt << 21) | (ra << 16) | (ds << 2); } uint64_t thread_status(struct thread *thread) { return thread->status; } /* * Single step the thread count instructions. */ int ram_step_thread(struct target *thread_target, int count) { struct thread *thread; assert(!strcmp(thread_target->class, "thread")); thread = target_to_thread(thread_target); return thread->step(thread, count); } int ram_start_thread(struct target *thread_target) { struct thread *thread; assert(!strcmp(thread_target->class, "thread")); thread = target_to_thread(thread_target); return thread->start(thread); } int ram_stop_thread(struct target *thread_target) { struct thread *thread; assert(!strcmp(thread_target->class, "thread")); thread = target_to_thread(thread_target); return thread->stop(thread); } /* * RAMs the opcodes in *opcodes and store the results of each opcode * into *results. *results must point to an array the same size as * *opcodes. Each entry from *results is put into SCR0 prior to * executing an opcode so that it may also be used to pass in * data. Note that only register r0 is saved and restored so opcodes * must not touch other registers. */ static int ram_instructions(struct thread *thread, uint64_t *opcodes, uint64_t *results, int len, unsigned int lpar) { uint64_t opcode = 0, r0 = 0, r1 = 0, scratch = 0; int i; int exception = 0; CHECK_ERR(thread->ram_setup(thread)); /* RAM instructions */ for (i = -2; i < len + 2; i++) { if (i == -2) opcode = mtspr(277, 1); else if (i == -1) /* Save r0 (assumes opcodes don't touch other registers) */ opcode = mtspr(277, 0); else if (i < len) { scratch = results[i]; opcode = opcodes[i]; } else if (i == len) { /* Restore r0 */ scratch = r0; opcode = mfspr(0, 277); } else if (i == len + 1) { /* Restore r1 */ scratch = r1; opcode = mfspr(0, 277); } CHECK_ERR(thread->ram_instruction(thread, opcode, &scratch)); if (i == -2) r1 = scratch; else if (i == -1) r0 = scratch; else if (i < len) results[i] = scratch; } CHECK_ERR(thread->ram_destroy(thread)); return exception; } /* * Get gpr value. Chip must be stopped. */ int ram_getgpr(struct thread *thread, int gpr, uint64_t *value) { uint64_t opcodes[] = {mtspr(277, gpr)}; uint64_t results[] = {0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); *value = results[0]; return 0; } int ram_putgpr(struct thread *thread, int gpr, uint64_t value) { uint64_t opcodes[] = {mfspr(gpr, 277)}; uint64_t results[] = {value}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); return 0; } int ram_getnia(struct thread *thread, uint64_t *value) { uint64_t opcodes[] = {mfnia(0), mtspr(277, 0)}; uint64_t results[] = {0, 0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); *value = results[1]; return 0; } int ram_putnia(struct thread *thread, uint64_t value) { uint64_t opcodes[] = {mfspr(0, 277), mtnia(0)}; uint64_t results[] = {value, 0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); return 0; } int ram_getspr(struct thread *thread, int spr, uint64_t *value) { uint64_t opcodes[] = {mfspr(0, spr), mtspr(277, 0)}; uint64_t results[] = {0, 0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); *value = results[1]; return 0; } int ram_putspr(struct thread *thread, int spr, uint64_t value) { uint64_t opcodes[] = {mfspr(0, 277), mtspr(spr, 0)}; uint64_t results[] = {value, 0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); return 0; } int ram_getmsr(struct thread *thread, uint64_t *value) { uint64_t opcodes[] = {mfmsr(0), mtspr(277, 0)}; uint64_t results[] = {0, 0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); *value = results[1]; return 0; } int ram_putmsr(struct thread *thread, uint64_t value) { uint64_t opcodes[] = {mfspr(0, 277), mtmsr(0)}; uint64_t results[] = {value, 0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); return 0; } int ram_getmem(struct thread *thread, uint64_t addr, uint64_t *value) { uint64_t opcodes[] = {mfspr(0, 277), mfspr(1, 277), ld(0, 0, 1), mtspr(277, 0)}; uint64_t results[] = {0xdeaddeaddeaddead, addr, 0, 0}; CHECK_ERR(ram_instructions(thread, opcodes, results, ARRAY_SIZE(opcodes), 0)); *value = results[3]; return 0; } pdbg-pdbg-1.0/libpdbg/compiler.h000066400000000000000000000030301313304724200165610ustar00rootroot00000000000000/* Copyright 2013-2014 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __COMPILER_H #define __COMPILER_H #ifndef __ASSEMBLY__ #include /* Macros for various compiler bits and pieces */ #define __packed __attribute__((packed)) #define __align(x) __attribute__((__aligned__(x))) #define __unused __attribute__((unused)) #define __used __attribute__((used)) #define __section(x) __attribute__((__section__(x))) #define __noreturn __attribute__((noreturn)) /* not __const as this has a different meaning (const) */ #define __attrconst __attribute__((const)) #define __warn_unused_result __attribute__((warn_unused_result)) #if 0 /* Provided by gcc stddef.h */ #define offsetof(type,m) __builtin_offsetof(type,m) #endif #define __nomcount __attribute__((no_instrument_function)) /* Compiler barrier */ static inline void barrier(void) { asm volatile("" : : : "memory"); } #endif /* __ASSEMBLY__ */ /* Stringification macro */ #define __tostr(x) #x #define tostr(x) __tostr(x) #endif /* __COMPILER_H */ pdbg-pdbg-1.0/libpdbg/device.c000066400000000000000000000474161313304724200162210ustar00rootroot00000000000000/* Copyright 2013-2014 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "device.h" #include #include #include #include #include #include #include #undef PR_DEBUG #define PR_DEBUG(...) #define zalloc(size) calloc(1, size) #define prerror printf #define is_rodata(p) false /* Used to give unique handles. */ u32 last_phandle = 0; struct dt_node *dt_root; struct dt_node *dt_chosen; static const char *take_name(const char *name) { if (!is_rodata(name) && !(name = strdup(name))) { prerror("Failed to allocate copy of name"); abort(); } return name; } static void free_name(const char *name) { if (!is_rodata(name)) free((char *)name); } static struct dt_node *new_node(const char *name) { struct dt_node *node = malloc(sizeof *node); if (!node) { prerror("Failed to allocate node\n"); abort(); } node->name = take_name(name); node->parent = NULL; list_head_init(&node->properties); list_head_init(&node->children); /* FIXME: locking? */ node->phandle = ++last_phandle; return node; } struct dt_node *dt_new_root(const char *name) { return new_node(name); } static const char *get_unitname(const struct dt_node *node) { const char *c = strchr(node->name, '@'); if (!c) return NULL; return c + 1; } int dt_cmp_subnodes(const struct dt_node *a, const struct dt_node *b) { const char *a_unit = get_unitname(a); const char *b_unit = get_unitname(b); ptrdiff_t basenamelen = a_unit - a->name; /* sort hex unit addresses by number */ if (a_unit && b_unit && !strncmp(a->name, b->name, basenamelen)) { unsigned long long a_num, b_num; char *a_end, *b_end; a_num = strtoul(a_unit, &a_end, 16); b_num = strtoul(b_unit, &b_end, 16); /* only compare if the unit addr parsed correctly */ if (*a_end == 0 && *b_end == 0) return (a_num > b_num) - (a_num < b_num); } return strcmp(a->name, b->name); } bool dt_attach_root(struct dt_node *parent, struct dt_node *root) { struct dt_node *node; assert(!root->parent); if (list_empty(&parent->children)) { list_add(&parent->children, &root->list); root->parent = parent; return true; } dt_for_each_child(parent, node) { int cmp = dt_cmp_subnodes(node, root); /* Look for duplicates */ if (cmp == 0) { prerror("DT: %s failed, duplicate %s\n", __func__, root->name); return false; } /* insert before the first node that's larger * the the node we're inserting */ if (cmp > 0) break; } list_add_before(&parent->children, &root->list, &node->list); root->parent = parent; return true; } static inline void dt_destroy(struct dt_node *dn) { if (!dn) return; free_name(dn->name); free(dn); } struct dt_node *dt_new(struct dt_node *parent, const char *name) { struct dt_node *new; assert(parent); new = new_node(name); if (!dt_attach_root(parent, new)) { dt_destroy(new); return NULL; } return new; } struct dt_node *dt_new_addr(struct dt_node *parent, const char *name, uint64_t addr) { char *lname; struct dt_node *new; size_t len; assert(parent); len = strlen(name) + STR_MAX_CHARS(addr) + 2; lname = malloc(len); if (!lname) return NULL; snprintf(lname, len, "%s@%llx", name, (long long)addr); new = new_node(lname); free(lname); if (!dt_attach_root(parent, new)) { dt_destroy(new); return NULL; } return new; } struct dt_node *dt_new_2addr(struct dt_node *parent, const char *name, uint64_t addr0, uint64_t addr1) { char *lname; struct dt_node *new; size_t len; assert(parent); len = strlen(name) + 2*STR_MAX_CHARS(addr0) + 3; lname = malloc(len); if (!lname) return NULL; snprintf(lname, len, "%s@%llx,%llx", name, (long long)addr0, (long long)addr1); new = new_node(lname); free(lname); if (!dt_attach_root(parent, new)) { dt_destroy(new); return NULL; } return new; } static struct dt_node *__dt_copy(struct dt_node *node, struct dt_node *parent, bool root) { struct dt_property *prop, *new_prop; struct dt_node *new_node, *child; new_node = dt_new(parent, node->name); if (!new_node) return NULL; list_for_each(&node->properties, prop, list) { new_prop = dt_add_property(new_node, prop->name, prop->prop, prop->len); if (!new_prop) goto fail; } list_for_each(&node->children, child, list) { child = __dt_copy(child, new_node, false); if (!child) goto fail; } return new_node; fail: /* dt_free will recurse for us, so only free when we unwind to the * top-level failure */ if (root) dt_free(new_node); return NULL; } struct dt_node *dt_copy(struct dt_node *node, struct dt_node *parent) { return __dt_copy(node, parent, true); } char *dt_get_path(const struct dt_node *node) { unsigned int len = 0; const struct dt_node *n; char *path, *p; /* Dealing with NULL is for test/debug purposes */ if (!node) return strdup(""); for (n = node; n; n = n->parent) { len += strlen(n->name); if (n->parent || n == node) len++; } path = zalloc(len + 1); assert(path); p = path + len; for (n = node; n; n = n->parent) { len = strlen(n->name); p -= len; memcpy(p, n->name, len); if (n->parent || n == node) *(--p) = '/'; } assert(p == path); return p; } static const char *__dt_path_split(const char *p, const char **namep, unsigned int *namel, const char **addrp, unsigned int *addrl) { const char *at, *sl; *namel = *addrl = 0; /* Skip initial '/' */ while (*p == '/') p++; /* Check empty path */ if (*p == 0) return p; at = strchr(p, '@'); sl = strchr(p, '/'); if (sl == NULL) sl = p + strlen(p); if (sl < at) at = NULL; if (at) { *addrp = at + 1; *addrl = sl - at - 1; } *namep = p; *namel = at ? (at - p) : (sl - p); return sl; } struct dt_node *dt_find_by_path(struct dt_node *root, const char *path) { struct dt_node *n; const char *pn, *pa = NULL, *p = path, *nn = NULL, *na = NULL; unsigned int pnl, pal, nnl, nal; bool match; /* Walk path components */ while (*p) { /* Extract next path component */ p = __dt_path_split(p, &pn, &pnl, &pa, &pal); if (pnl == 0 && pal == 0) break; /* Compare with each child node */ match = false; list_for_each(&root->children, n, list) { match = true; __dt_path_split(n->name, &nn, &nnl, &na, &nal); if (pnl && (pnl != nnl || strncmp(pn, nn, pnl))) match = false; if (pal && (pal != nal || strncmp(pa, na, pal))) match = false; if (match) { root = n; break; } } /* No child match */ if (!match) return NULL; } return root; } struct dt_node *dt_find_by_name(struct dt_node *root, const char *name) { struct dt_node *child, *match; list_for_each(&root->children, child, list) { if (!strcmp(child->name, name)) return child; match = dt_find_by_name(child, name); if (match) return match; } return NULL; } struct dt_node *dt_find_by_phandle(struct dt_node *root, u32 phandle) { struct dt_node *node; dt_for_each_node(root, node) if (node->phandle == phandle) return node; return NULL; } static struct dt_property *new_property(struct dt_node *node, const char *name, size_t size) { struct dt_property *p = malloc(sizeof(*p) + size); char *path; if (!p) { path = dt_get_path(node); prerror("Failed to allocate property \"%s\" for %s of %zu bytes\n", name, path, size); free(path); abort(); } if (dt_find_property(node, name)) { path = dt_get_path(node); prerror("Duplicate property \"%s\" in node %s\n", name, path); free(path); abort(); } p->name = take_name(name); p->len = size; list_add_tail(&node->properties, &p->list); return p; } struct dt_property *dt_add_property(struct dt_node *node, const char *name, const void *val, size_t size) { struct dt_property *p; /* * Filter out phandle properties, we re-generate them * when flattening */ if (strcmp(name, "linux,phandle") == 0 || strcmp(name, "phandle") == 0) { assert(size == 4); node->phandle = *(const u32 *)val; if (node->phandle >= last_phandle) last_phandle = node->phandle; return NULL; } p = new_property(node, name, size); if (size) memcpy(p->prop, val, size); return p; } void dt_resize_property(struct dt_property **prop, size_t len) { size_t new_len = sizeof(**prop) + len; *prop = realloc(*prop, new_len); /* Fix up linked lists in case we moved. (note: not an empty list). */ (*prop)->list.next->prev = &(*prop)->list; (*prop)->list.prev->next = &(*prop)->list; } struct dt_property *dt_add_property_string(struct dt_node *node, const char *name, const char *value) { return dt_add_property(node, name, value, strlen(value)+1); } struct dt_property *dt_add_property_nstr(struct dt_node *node, const char *name, const char *value, unsigned int vlen) { struct dt_property *p; char *tmp = zalloc(vlen + 1); if (!tmp) return NULL; strncpy(tmp, value, vlen); p = dt_add_property(node, name, tmp, strlen(tmp)+1); free(tmp); return p; } struct dt_property *__dt_add_property_cells(struct dt_node *node, const char *name, int count, ...) { struct dt_property *p; u32 *val; unsigned int i; va_list args; p = new_property(node, name, count * sizeof(u32)); val = (u32 *)p->prop; va_start(args, count); for (i = 0; i < count; i++) val[i] = cpu_to_fdt32(va_arg(args, u32)); va_end(args); return p; } struct dt_property *__dt_add_property_u64s(struct dt_node *node, const char *name, int count, ...) { struct dt_property *p; u64 *val; unsigned int i; va_list args; p = new_property(node, name, count * sizeof(u64)); val = (u64 *)p->prop; va_start(args, count); for (i = 0; i < count; i++) val[i] = cpu_to_fdt64(va_arg(args, u64)); va_end(args); return p; } struct dt_property *__dt_add_property_strings(struct dt_node *node, const char *name, int count, ...) { struct dt_property *p; unsigned int i, size; va_list args; const char *sstr; char *s; va_start(args, count); for (i = size = 0; i < count; i++) { sstr = va_arg(args, const char *); if (sstr) size += strlen(sstr) + 1; } va_end(args); if (!size) size = 1; p = new_property(node, name, size); s = (char *)p->prop; *s = 0; va_start(args, count); for (i = 0; i < count; i++) { sstr = va_arg(args, const char *); if (sstr) { strcpy(s, sstr); s = s + strlen(sstr) + 1; } } va_end(args); return p; } void dt_del_property(struct dt_node *node, struct dt_property *prop) { list_del_from(&node->properties, &prop->list); free_name(prop->name); free(prop); } u32 dt_property_get_cell(const struct dt_property *prop, u32 index) { assert(prop->len >= (index+1)*sizeof(u32)); /* Always aligned, so this works. */ return fdt32_to_cpu(((const u32 *)prop->prop)[index]); } /* First child of this node. */ struct dt_node *dt_first(const struct dt_node *root) { return list_top(&root->children, struct dt_node, list); } /* Return next node, or NULL. */ struct dt_node *dt_next(const struct dt_node *root, const struct dt_node *prev) { /* Children? */ if (!list_empty(&prev->children)) return dt_first(prev); do { /* More siblings? */ if (prev->list.next != &prev->parent->children.n) return list_entry(prev->list.next, struct dt_node,list); /* No more siblings, move up to parent. */ prev = prev->parent; } while (prev != root); return NULL; } struct dt_property *__dt_find_property(struct dt_node *node, const char *name) { struct dt_property *i; list_for_each(&node->properties, i, list) if (strcmp(i->name, name) == 0) return i; return NULL; } struct dt_property *dt_find_property(const struct dt_node *node, const char *name) { struct dt_property *i; list_for_each(&node->properties, i, list) if (strcmp(i->name, name) == 0) return i; return NULL; } void dt_check_del_prop(struct dt_node *node, const char *name) { struct dt_property *p; p = __dt_find_property(node, name); if (p) dt_del_property(node, p); } const struct dt_property *dt_require_property(const struct dt_node *node, const char *name, int wanted_len) { const struct dt_property *p = dt_find_property(node, name); if (!p) { const char *path = dt_get_path(node); prerror("DT: Missing required property %s/%s\n", path, name); assert(false); } if (wanted_len >= 0 && p->len != wanted_len) { const char *path = dt_get_path(node); prerror("DT: Unexpected property length %s/%s\n", path, name); prerror("DT: Expected len: %d got len: %zu\n", wanted_len, p->len); assert(false); } return p; } bool dt_has_node_property(const struct dt_node *node, const char *name, const char *val) { const struct dt_property *p = dt_find_property(node, name); if (!p) return false; if (!val) return true; return p->len == strlen(val) + 1 && memcmp(p->prop, val, p->len) == 0; } bool dt_prop_find_string(const struct dt_property *p, const char *s) { const char *c, *end; if (!p) return false; c = p->prop; end = c + p->len; while(c < end) { if (!strcasecmp(s, c)) return true; c += strlen(c) + 1; } return false; } bool dt_node_is_compatible(const struct dt_node *node, const char *compat) { const struct dt_property *p = dt_find_property(node, "compatible"); return dt_prop_find_string(p, compat); } struct dt_node *dt_find_compatible_node(struct dt_node *root, struct dt_node *prev, const char *compat) { struct dt_node *node; node = prev ? dt_next(root, prev) : root; for (; node; node = dt_next(root, node)) if (dt_node_is_compatible(node, compat)) return node; return NULL; } u64 dt_prop_get_u64(const struct dt_node *node, const char *prop) { const struct dt_property *p = dt_require_property(node, prop, 8); return ((u64)dt_property_get_cell(p, 0) << 32) | dt_property_get_cell(p, 1); } u64 dt_prop_get_u64_def(const struct dt_node *node, const char *prop, u64 def) { const struct dt_property *p = dt_find_property(node, prop); if (!p) return def; return ((u64)dt_property_get_cell(p, 0) << 32) | dt_property_get_cell(p, 1); } u32 dt_prop_get_u32(const struct dt_node *node, const char *prop) { const struct dt_property *p = dt_require_property(node, prop, 4); return dt_property_get_cell(p, 0); } u32 dt_prop_get_u32_def(const struct dt_node *node, const char *prop, u32 def) { const struct dt_property *p = dt_find_property(node, prop); if (!p) return def; return dt_property_get_cell(p, 0); } u32 dt_prop_get_u32_index(const struct dt_node *node, const char *prop, u32 index) { const struct dt_property *p = dt_require_property(node, prop, -1); return dt_property_get_cell(p, index); } const void *dt_prop_get(const struct dt_node *node, const char *prop) { const struct dt_property *p = dt_require_property(node, prop, -1); return p->prop; } const void *dt_prop_get_def(const struct dt_node *node, const char *prop, void *def) { const struct dt_property *p = dt_find_property(node, prop); return p ? p->prop : def; } const void *dt_prop_get_def_size(const struct dt_node *node, const char *prop, void *def, size_t *len) { const struct dt_property *p = dt_find_property(node, prop); *len = 0; if (p) *len = p->len; return p ? p->prop : def; } u32 dt_prop_get_cell(const struct dt_node *node, const char *prop, u32 cell) { const struct dt_property *p = dt_require_property(node, prop, -1); return dt_property_get_cell(p, cell); } u32 dt_prop_get_cell_def(const struct dt_node *node, const char *prop, u32 cell, u32 def) { const struct dt_property *p = dt_find_property(node, prop); if (!p) return def; return dt_property_get_cell(p, cell); } void dt_free(struct dt_node *node) { struct dt_node *child; struct dt_property *p; while ((child = list_top(&node->children, struct dt_node, list))) dt_free(child); while ((p = list_pop(&node->properties, struct dt_property, list))) { free_name(p->name); free(p); } if (node->parent) list_del_from(&node->parent->children, &node->list); dt_destroy(node); } int dt_expand_node(struct dt_node *node, const void *fdt, int fdt_node) { const struct fdt_property *prop; int offset, nextoffset, err; struct dt_node *child; const char *name; uint32_t tag; if (((err = fdt_check_header(fdt)) != 0) || ((err = _fdt_check_node_offset(fdt, fdt_node)) < 0)) { prerror("FDT: Error %d parsing node 0x%x\n", err, fdt_node); return -1; } nextoffset = err; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_PROP: prop = _fdt_offset_ptr(fdt, offset); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); dt_add_property(node, name, prop->data, fdt32_to_cpu(prop->len)); break; case FDT_BEGIN_NODE: name = fdt_get_name(fdt, offset, NULL); child = dt_new_root(name); assert(child); nextoffset = dt_expand_node(child, fdt, offset); /* * This may fail in case of duplicate, keep it * going for now, we may ultimately want to * assert */ (void)dt_attach_root(node, child); break; case FDT_END: return -1; } } while (tag != FDT_END_NODE); return nextoffset; } void dt_expand(const void *fdt) { PR_DEBUG("FDT: Parsing fdt @%p\n", fdt); if (dt_expand_node(dt_root, fdt, 0) < 0) abort(); } u64 dt_get_number(const void *pdata, unsigned int cells) { const u32 *p = pdata; u64 ret = 0; while(cells--) ret = (ret << 32) | be32_to_cpu(*(p++)); return ret; } u32 dt_n_address_cells(const struct dt_node *node) { if (!node->parent) return 0; return dt_prop_get_u32_def(node->parent, "#address-cells", 2); } u32 dt_n_size_cells(const struct dt_node *node) { if (!node->parent) return 0; return dt_prop_get_u32_def(node->parent, "#size-cells", 1); } u64 dt_get_address(const struct dt_node *node, unsigned int index, u64 *out_size) { const struct dt_property *p; u32 na = dt_n_address_cells(node); u32 ns = dt_n_size_cells(node); u32 pos, n; p = dt_require_property(node, "reg", -1); n = (na + ns) * sizeof(u32); pos = n * index; assert((pos + n) <= p->len); if (out_size) *out_size = dt_get_number(p->prop + pos + na * sizeof(u32), ns); return dt_get_number(p->prop + pos, na); } static u32 __dt_get_chip_id(const struct dt_node *node) { const struct dt_property *prop; for (; node; node = node->parent) { prop = dt_find_property(node, "ibm,chip-id"); if (prop) return dt_property_get_cell(prop, 0); } return 0xffffffff; } u32 dt_get_chip_id(const struct dt_node *node) { u32 id = __dt_get_chip_id(node); assert(id != 0xffffffff); return id; } struct dt_node *dt_find_compatible_node_on_chip(struct dt_node *root, struct dt_node *prev, const char *compat, uint32_t chip_id) { struct dt_node *node; node = prev ? dt_next(root, prev) : root; for (; node; node = dt_next(root, node)) { u32 cid = __dt_get_chip_id(node); if (cid == chip_id && dt_node_is_compatible(node, compat)) return node; } return NULL; } unsigned int dt_count_addresses(const struct dt_node *node) { const struct dt_property *p; u32 na = dt_n_address_cells(node); u32 ns = dt_n_size_cells(node); u32 n; p = dt_require_property(node, "reg", -1); n = (na + ns) * sizeof(u32); if (n == 0) return 0; return p->len / n; } u64 dt_translate_address(const struct dt_node *node, unsigned int index, u64 *out_size) { /* XXX TODO */ return dt_get_address(node, index, out_size); } bool dt_node_is_enabled(struct dt_node *node) { const struct dt_property *p = dt_find_property(node, "status"); if (!p) return true; return p->len > 1 && p->prop[0] == 'o' && p->prop[1] == 'k'; } pdbg-pdbg-1.0/libpdbg/device.h000066400000000000000000000211701313304724200162130ustar00rootroot00000000000000/* Copyright 2013-2014 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __DEVICE_H #define __DEVICE_H #include #include #include "compiler.h" /* Any property or node with this prefix will not be passed to the kernel. */ #define DT_PRIVATE "skiboot," /* * An in-memory representation of a node in the device tree. * * This is trivially flattened into an fdt. * * Note that the add_* routines will make a copy of the name if it's not * a read-only string (ie. usually a string literal). */ struct dt_property { struct list_node list; const char *name; size_t len; char prop[/* len */]; }; struct dt_node { const char *name; struct list_node list; struct list_head properties; struct list_head children; struct dt_node *parent; u32 phandle; struct target *target; }; /* This is shared with device_tree.c .. make it static when * the latter is gone (hopefully soon) */ extern u32 last_phandle; extern struct dt_node *dt_root; extern struct dt_node *dt_chosen; /* Create a root node: ie. a parentless one. */ struct dt_node *dt_new_root(const char *name); /* Graft a root node into this tree. */ bool dt_attach_root(struct dt_node *parent, struct dt_node *root); /* Add a child node. */ struct dt_node *dt_new(struct dt_node *parent, const char *name); struct dt_node *dt_new_addr(struct dt_node *parent, const char *name, uint64_t unit_addr); struct dt_node *dt_new_2addr(struct dt_node *parent, const char *name, uint64_t unit_addr0, uint64_t unit_addr1); /* Copy node to new parent, including properties and subnodes */ struct dt_node *dt_copy(struct dt_node *node, struct dt_node *parent); /* Add a property node, various forms. */ struct dt_property *dt_add_property(struct dt_node *node, const char *name, const void *val, size_t size); struct dt_property *dt_add_property_string(struct dt_node *node, const char *name, const char *value); struct dt_property *dt_add_property_nstr(struct dt_node *node, const char *name, const char *value, unsigned int vlen); /* Given out enough GCC extensions, we will achieve enlightenment! */ #define dt_add_property_strings(node, name, ...) \ __dt_add_property_strings((node), ((name)), \ sizeof((const char *[]) { __VA_ARGS__ })/sizeof(const char *), \ __VA_ARGS__) struct dt_property *__dt_add_property_strings(struct dt_node *node, const char *name, int count, ...); /* Given out enough GCC extensions, we will achieve enlightenment! */ #define dt_add_property_cells(node, name, ...) \ __dt_add_property_cells((node), ((name)), \ sizeof((u32[]) { __VA_ARGS__ })/sizeof(u32), \ __VA_ARGS__) struct dt_property *__dt_add_property_cells(struct dt_node *node, const char *name, int count, ...); #define dt_add_property_u64s(node, name, ...) \ __dt_add_property_u64s((node), ((name)), \ sizeof((u64[]) { __VA_ARGS__ })/sizeof(u64), \ __VA_ARGS__) struct dt_property *__dt_add_property_u64s(struct dt_node *node, const char *name, int count, ...); static inline struct dt_property *dt_add_property_u64(struct dt_node *node, const char *name, u64 val) { return dt_add_property_cells(node, name, (u32)(val >> 32), (u32)val); } void dt_del_property(struct dt_node *node, struct dt_property *prop); void dt_check_del_prop(struct dt_node *node, const char *name); /* Warning: moves *prop! */ void dt_resize_property(struct dt_property **prop, size_t len); u32 dt_property_get_cell(const struct dt_property *prop, u32 index); /* First child of this node. */ struct dt_node *dt_first(const struct dt_node *root); /* Return next node, or NULL. */ struct dt_node *dt_next(const struct dt_node *root, const struct dt_node *prev); /* Iterate nodes */ #define dt_for_each_node(root, node) \ for (node = dt_first(root); node; node = dt_next(root, node)) #define dt_for_each_child(parent, node) \ list_for_each(&parent->children, node, list) /* Find a string in a string list */ bool dt_prop_find_string(const struct dt_property *p, const char *s); /* Check a compatible property */ bool dt_node_is_compatible(const struct dt_node *node, const char *compat); /* Find a node based on compatible property */ struct dt_node *dt_find_compatible_node(struct dt_node *root, struct dt_node *prev, const char *compat); #define dt_for_each_compatible(root, node, compat) \ for (node = NULL; \ (node = dt_find_compatible_node(root, node, compat)) != NULL;) struct dt_node *dt_find_compatible_node_on_chip(struct dt_node *root, struct dt_node *prev, const char *compat, uint32_t chip_id); #define dt_for_each_compatible_on_chip(root, node, compat, chip_id) \ for (node = NULL; \ (node = dt_find_compatible_node_on_chip(root, node,\ compat, chip_id)) != NULL;) /* Check status property */ bool dt_node_is_enabled(struct dt_node *node); /* Build the full path for a node. Return a new block of memory, caller * shall free() it */ char *dt_get_path(const struct dt_node *node); /* Find a node by path */ struct dt_node *dt_find_by_path(struct dt_node *root, const char *path); /* Find a child node by name */ struct dt_node *dt_find_by_name(struct dt_node *root, const char *name); /* Find a node by phandle */ struct dt_node *dt_find_by_phandle(struct dt_node *root, u32 phandle); /* Find a property by name. */ struct dt_property *dt_find_property(const struct dt_node *node,\ const char *name); const struct dt_property *dt_require_property(const struct dt_node *node, const char *name, int wanted_len); /* non-const variant */ struct dt_property *__dt_find_property(struct dt_node *node, const char *name); /* Find a property by name, check if it's the same as val. */ bool dt_has_node_property(const struct dt_node *node, const char *name, const char *val); /* Free a node (and any children). */ void dt_free(struct dt_node *node); /* Parse an initial fdt */ void dt_expand(const void *fdt); int dt_expand_node(struct dt_node *node, const void *fdt, int fdt_node) __warn_unused_result; /* Simplified accessors */ u64 dt_prop_get_u64(const struct dt_node *node, const char *prop); u64 dt_prop_get_u64_def(const struct dt_node *node, const char *prop, u64 def); u32 dt_prop_get_u32(const struct dt_node *node, const char *prop); u32 dt_prop_get_u32_def(const struct dt_node *node, const char *prop, u32 def); u32 dt_prop_get_u32_index(const struct dt_node *node, const char *prop, u32 index); const void *dt_prop_get(const struct dt_node *node, const char *prop); const void *dt_prop_get_def(const struct dt_node *node, const char *prop, void *def); const void *dt_prop_get_def_size(const struct dt_node *node, const char *prop, void *def, size_t *len); u32 dt_prop_get_cell(const struct dt_node *node, const char *prop, u32 cell); u32 dt_prop_get_cell_def(const struct dt_node *node, const char *prop, u32 cell, u32 def); /* Parsing helpers */ u32 dt_n_address_cells(const struct dt_node *node); u32 dt_n_size_cells(const struct dt_node *node); u64 dt_get_number(const void *pdata, unsigned int cells); /* Find an ibm,chip-id property in this node; if not found, walk up the parent * nodes. Returns -1 if no chip-id property exists. */ u32 dt_get_chip_id(const struct dt_node *node); /* Address accessors ("reg" properties parsing). No translation, * only support "simple" address forms (1 or 2 cells). Asserts * if address doesn't exist */ u64 dt_get_address(const struct dt_node *node, unsigned int index, u64 *out_size); /* Count "reg" property entries */ unsigned int dt_count_addresses(const struct dt_node *node); /* Address translation * * WARNING: Current implementation is simplified and will not * handle complex address formats with address space indicators * nor will it handle "ranges" translations yet... (XX TODO) */ u64 dt_translate_address(const struct dt_node *node, unsigned int index, u64 *out_size); /* compare function used to sort child nodes by name when added to the * tree. This is mainly here for testing. */ int dt_cmp_subnodes(const struct dt_node *a, const struct dt_node *b); #endif /* __DEVICE_H */ pdbg-pdbg-1.0/libpdbg/fake.c000066400000000000000000000033271313304724200156610ustar00rootroot00000000000000/* copyright 2016 ibm corp. * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * http://www.apache.org/licenses/license-2.0 * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or * implied. * see the license for the specific language governing permissions and * limitations under the license. */ #include "operations.h" #include #include static int fake_fsi_read(struct fsi *fsi, uint32_t addr, uint32_t *value) { *value = 0xfeed0cfa; printf("fake_fsi_read(0x%04" PRIx32 ", 0x%04" PRIx32 ")\n", addr, *value); return 0; } static int fake_fsi_write(struct fsi *fsi, uint32_t addr, uint32_t value) { printf("fake_fsi_write(0x%04" PRIx32 ", 0x%04" PRIx32 ")\n", addr, value); return 0; } struct fsi fake_fsi = { .target = { .name = "Fake FSI", .compatible = "ibm,fake-fsi", .class = "fsi", }, .read = fake_fsi_read, .write = fake_fsi_write, }; DECLARE_HW_UNIT(fake_fsi); static int fake_pib_read(struct pib *pib, uint64_t addr, uint64_t *value) { *value = 0xdeadbeef; printf("fake_pib_read(0x%08" PRIx64 ", 0x%08" PRIx64 ")\n", addr, *value); return 0; } static int fake_pib_write(struct pib *pib, uint64_t addr, uint64_t value) { printf("fake_pib_write(0x%08" PRIx64 ", 0x%08" PRIx64 ")\n", addr, value); return 0; } struct pib fake_pib = { .target = { .name = "Fake PIB", .compatible = "ibm,fake-pib", .class = "pib", }, .read = fake_pib_read, .write = fake_pib_write, }; DECLARE_HW_UNIT(fake_pib); pdbg-pdbg-1.0/libpdbg/fsi2pib.c000066400000000000000000000044261313304724200163120ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "target.h" #include "bitutils.h" #include "operations.h" #define FSI_DATA0_REG 0x1000 #define FSI_DATA1_REG 0x1001 #define FSI_CMD_REG 0x1002 #define FSI_CMD_REG_WRITE PPC_BIT32(0) #define FSI_RESET_REG 0x1006 #define FSI_RESET_CMD PPC_BIT32(0) #define FSI_SET_PIB_RESET_REG 0x1007 #define FSI_SET_PIB_RESET PPC_BIT32(0) /* For some reason the FSI2PIB engine dies with frequent * access. Letting it have a bit of a rest seems to stop the * problem. This sets the number of usecs to sleep between SCOM * accesses. */ #define FSI2PIB_RELAX 50 static int fsi2pib_getscom(struct target *target, uint64_t addr, uint64_t *value) { uint64_t result; usleep(FSI2PIB_RELAX); /* Get scom works by putting the address in FSI_CMD_REG and * reading the result from FST_DATA[01]_REG. */ CHECK_ERR(write_next_target(target, FSI_CMD_REG, addr)); CHECK_ERR(read_next_target(target, FSI_DATA0_REG, &result)); *value = result << 32; CHECK_ERR(read_next_target(target, FSI_DATA1_REG, &result)); *value |= result; return 0; } static int fsi2pib_putscom(struct target *target, uint64_t addr, uint64_t value) { usleep(FSI2PIB_RELAX); CHECK_ERR(write_next_target(target, FSI_RESET_REG, FSI_RESET_CMD)); CHECK_ERR(write_next_target(target, FSI_DATA0_REG, (value >> 32) & 0xffffffff)); CHECK_ERR(write_next_target(target, FSI_DATA1_REG, value & 0xffffffff)); CHECK_ERR(write_next_target(target, FSI_CMD_REG, FSI_CMD_REG_WRITE | addr)); return 0; } int fsi2pib_target_init(struct target *target, const char *name, uint64_t base, struct target *next) { target->name = name; target->read = fsi2pib_getscom; target->write = fsi2pib_putscom; target->base = base; target->next = next; return -1; } pdbg-pdbg-1.0/libpdbg/i2c.c000066400000000000000000000074471313304724200154370ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include "bitutils.h" #include "operations.h" struct i2c_data { int addr; int fd; }; static int i2c_set_addr(int fd, int addr) { if (ioctl(fd, I2C_SLAVE, addr) < 0) { PR_ERROR("Unable to set i2c slave address\n"); return -1; } return 0; } static int i2c_set_scom_addr(struct i2c_data *i2c_data, uint32_t addr) { uint8_t data[4]; addr <<= 1; data[3] = GETFIELD(PPC_BITMASK32(0, 7), addr); data[2] = GETFIELD(PPC_BITMASK32(8, 15), addr); data[1] = GETFIELD(PPC_BITMASK32(16, 23), addr); data[0] = GETFIELD(PPC_BITMASK32(23, 31), addr); if (write(i2c_data->fd, data, sizeof(data)) != 4) { PR_ERROR("Error writing address bytes\n"); return -1; } return 0; } static int i2c_getscom(struct pib *pib, uint64_t addr, uint64_t *value) { struct i2c_data *i2c_data = pib->priv; uint64_t data; CHECK_ERR(i2c_set_scom_addr(i2c_data, addr)); if (read(i2c_data->fd, &data, sizeof(data)) != 8) { PR_ERROR("Error reading data\n"); return -1; } *value = le64toh(data); return 0; } static int i2c_putscom(struct pib *pib, uint64_t addr, uint64_t value) { struct i2c_data *i2c_data = pib->priv; uint8_t data[12]; /* Setup scom address */ addr <<= 1; data[3] = GETFIELD(PPC_BITMASK32(0, 7), addr); data[2] = GETFIELD(PPC_BITMASK32(8, 15), addr); data[1] = GETFIELD(PPC_BITMASK32(16, 23), addr); data[0] = GETFIELD(PPC_BITMASK32(23, 31), addr); /* Add data value */ data[11] = GETFIELD(PPC_BITMASK(0, 7), value); data[10] = GETFIELD(PPC_BITMASK(8, 15), value); data[9] = GETFIELD(PPC_BITMASK(16, 23), value); data[8] = GETFIELD(PPC_BITMASK(23, 31), value); data[7] = GETFIELD(PPC_BITMASK(32, 39), value); data[6] = GETFIELD(PPC_BITMASK(40, 47), value); data[5] = GETFIELD(PPC_BITMASK(48, 55), value); data[4] = GETFIELD(PPC_BITMASK(56, 63), value); /* Write value */ if (write(i2c_data->fd, data, sizeof(data)) != 12) { PR_ERROR("Error writing data bytes\n"); return -1; } return 0; } #if 0 /* TODO: At present we don't have a generic destroy method as there aren't many * use cases for it. So for the moment we can just let the OS close the file * descriptor on exit. */ static void i2c_destroy(struct pib *pib) { struct i2c_data *i2c_data = pib->priv; close(i2c_data->fd); free(i2c_data); } #endif /* * Initialise a i2c backend on the given bus at the given bus address. */ int i2c_target_probe(struct target *target) { struct pib *pib = target_to_pib(target); struct i2c_data *i2c_data; const char *bus; int addr; bus = "/dev/i2c4"; addr = dt_get_address(pib->target.dn, 0, NULL); assert(addr); i2c_data = malloc(sizeof(*i2c_data)); if (!i2c_data) exit(1); i2c_data->addr = addr; i2c_data->fd = open(bus, O_RDWR); if (i2c_data->fd < 0) { perror("Error opening bus"); return -1; } if (i2c_set_addr(i2c_data->fd, addr) < 0) return -1; pib->priv = i2c_data; return 0; } struct pib p8_i2c_pib = { .target = { .name = "POWER8 I2C Slave", .compatible = "ibm,power8-i2c-slave", .class = "pib", .probe = i2c_target_probe, }, .read = i2c_getscom, .write = i2c_putscom, }; DECLARE_HW_UNIT(p8_i2c_pib); pdbg-pdbg-1.0/libpdbg/kernel.c000066400000000000000000000064411313304724200162330ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "bitutils.h" #include "operations.h" #include "target.h" #define FSI_SCAN_PATH "/sys/bus/platform/devices/gpio-fsi/fsi0/rescan" #define FSI_CFAM_PATH "/sys/devices/platform/gpio-fsi/fsi0/slave@00:00/raw" int fsi_fd; static int kernel_fsi_getcfam(struct fsi *fsi, uint32_t addr64, uint32_t *value) { int rc; uint32_t tmp, addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); rc = lseek(fsi_fd, addr, SEEK_SET); if (rc < 0) { warn("Failed to seek %s", FSI_CFAM_PATH); return errno; } rc = read(fsi_fd, &tmp, 4); if (rc < 0) { if ((addr64 & 0xfff) != 0xc09) /* We expect reads of 0xc09 to occasionally * fail as the probing code uses it to see * if anything is present on the link. */ warn("Failed to read from 0x%08" PRIx32 " (%016" PRIx32 ")", (uint32_t) addr, addr64); return errno; } *value = be32toh(tmp); return 0; } static int kernel_fsi_putcfam(struct fsi *fsi, uint32_t addr64, uint32_t data) { int rc; uint32_t tmp, addr = (addr64 & 0x7ffc00) | ((addr64 & 0x3ff) << 2); rc = lseek(fsi_fd, addr, SEEK_SET); if (rc < 0) { warn("Failed to seek %s", FSI_CFAM_PATH); return errno; } tmp = htobe32(data); rc = write(fsi_fd, &tmp, 4); if (rc < 0) { warn("Failed to write to 0x%08" PRIx32 " (%016" PRIx32 ")", addr, addr64); return errno; } return 0; } #if 0 /* TODO: At present we don't have a generic destroy method as there aren't many * use cases for it. So for the moment we can just let the OS close the file * descriptor on exit. */ static void kernel_fsi_destroy(struct target *target) { close(fsi_fd); } #endif static void kernel_fsi_scan_devices(void) { const char one = '1'; int rc, fd; fd = open(FSI_SCAN_PATH, O_WRONLY | O_SYNC); if (fd < 0) err(errno, "Unable to open %s", FSI_SCAN_PATH); rc = write(fd, &one, sizeof(one)); if (rc < 0) err(errno, "Unable to write to %s", FSI_SCAN_PATH); close(fd); } int kernel_fsi_probe(struct target *target) { if (!fsi_fd) { int tries = 5; while (tries) { /* Open first raw device */ fsi_fd = open(FSI_CFAM_PATH, O_RDWR | O_SYNC); if (fsi_fd >= 0) return 0; tries--; /* Scan */ kernel_fsi_scan_devices(); sleep(1); } if (fsi_fd < 0) { err(errno, "Unable to open %s", FSI_CFAM_PATH); return -1; } } return -1; } struct fsi kernel_fsi = { .target = { .name = "Kernel based FSI master", .compatible = "ibm,kernel-fsi", .class = "fsi", .probe = kernel_fsi_probe, }, .read = kernel_fsi_getcfam, .write = kernel_fsi_putcfam, }; DECLARE_HW_UNIT(kernel_fsi); pdbg-pdbg-1.0/libpdbg/operations.h000066400000000000000000000052741313304724200171460ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __OPERATIONS_H #define __OPERATIONS_H #include "target.h" /* Error codes */ #define EFSI 1 #define CHECK_ERR(x) do { \ if (x) { \ PR_DEBUG("%s: %d\n", __FUNCTION__, __LINE__); \ return x; \ } \ } while(0) #define THREADS_PER_CORE 8 #define FSI2PIB_BASE 0x1000 /* Alter display unit functions */ int adu_getmem(struct target *target, uint64_t addr, uint8_t *output, uint64_t size); int adu_putmem(struct target *target, uint64_t start_addr, uint8_t *input, uint64_t size); /* Functions to ram instructions */ #define THREAD_STATUS_DISABLED PPC_BIT(0) #define THREAD_STATUS_ACTIVE PPC_BIT(63) #define THREAD_STATUS_STATE PPC_BITMASK(61, 62) #define THREAD_STATUS_DOZE PPC_BIT(62) #define THREAD_STATUS_NAP PPC_BIT(61) #define THREAD_STATUS_SLEEP PPC_BITMASK(61, 62) #define THREAD_STATUS_QUIESCE PPC_BIT(60) /* Opcodes for instruction ramming */ #define OPCODE_MASK 0xfc0003ffUL #define MTNIA_OPCODE 0x00000002UL #define MFNIA_OPCODE 0x00000004UL #define MFMSR_OPCODE 0x7c0000a6UL #define MTMSR_OPCODE 0x7c000124UL #define MFSPR_OPCODE 0x7c0002a6UL #define MTSPR_OPCODE 0x7c0003a6UL #define LD_OPCODE 0xe8000000UL int ram_getgpr(struct thread *thread, int gpr, uint64_t *value); int ram_putgpr(struct thread *thread, int gpr, uint64_t value); int ram_getnia(struct thread *thread, uint64_t *value); int ram_putnia(struct thread *thread, uint64_t value); int ram_getspr(struct thread *thread, int spr, uint64_t *value); int ram_putspr(struct thread *thread, int spr, uint64_t value); int ram_getmsr(struct thread *thread, uint64_t *value); int ram_putmsr(struct thread *thread, uint64_t value); int ram_getmem(struct thread *thread, uint64_t addr, uint64_t *value); uint64_t thread_status(struct thread *thread); int ram_stop_thread(struct target *thread); int ram_step_thread(struct target *thread, int count); int ram_start_thread(struct target *thread); void fsi_destroy(struct target *target); /* GDB server functionality */ int gdbserver_start(uint16_t port); enum fsi_system_type {FSI_SYSTEM_P8, FSI_SYSTEM_P9W, FSI_SYSTEM_P9R, FSI_SYSTEM_P9Z}; enum chip_type get_chip_type(uint64_t chip_id); #endif pdbg-pdbg-1.0/libpdbg/p8chip.c000066400000000000000000000236401313304724200161460ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "target.h" #include "operations.h" #include "bitutils.h" #define RAS_STATUS_TIMEOUT 100 #define DIRECT_CONTROLS_REG 0x0 #define DIRECT_CONTROL_SP_STEP PPC_BIT(61) #define DIRECT_CONTROL_SP_START PPC_BIT(62) #define DIRECT_CONTROL_SP_STOP PPC_BIT(63) #define RAS_MODE_REG 0x1 #define MR_THREAD_IN_DEBUG PPC_BIT(43) #define MR_DO_SINGLE_MODE PPC_BIT(50) #define RAS_STATUS_REG 0x2 #define RAS_STATUS_SRQ_EMPTY PPC_BIT(8) #define RAS_STATUS_LSU_QUIESCED PPC_BIT(9) #define RAS_STATUS_INST_COMPLETE PPC_BIT(12) #define RAS_STATUS_THREAD_ACTIVE PPC_BIT(48) #define RAS_STATUS_TS_QUIESCE PPC_BIT(49) #define POW_STATUS_REG 0x4 #define PMC_POW_STATE PPC_BITMASK(4, 5) #define CORE_POW_STATE PPC_BITMASK(23, 25) #define THREAD_ACTIVE_REG 0x1310e #define THREAD_ACTIVE PPC_BITMASK(0, 7) #define RAM_THREAD_ACTIVE PPC_BITMASK(8, 15) #define SPR_MODE_REG 0x13281 #define SPR_MODE_SPRC_WR_EN PPC_BIT(3) #define SPR_MODE_SPRC_SEL PPC_BITMASK(16, 19) #define SPR_MODE_SPRC_T_SEL PPC_BITMASK(20, 27) #define L0_SCOM_SPRC_REG 0x13280 #define SCOM_SPRC_SCRATCH_SPR 0x40 #define SCR0_REG 0x13283 #define RAM_MODE_REG 0x13c00 #define RAM_MODE_ENABLE PPC_BIT(0) #define RAM_CTRL_REG 0x13c01 #define RAM_THREAD_SELECT PPC_BITMASK(0, 2) #define RAM_INSTR PPC_BITMASK(3, 34) #define RAM_STATUS_REG 0x13c02 #define RAM_CONTROL_RECOV PPC_BIT(0) #define RAM_STATUS PPC_BIT(1) #define RAM_EXCEPTION PPC_BIT(2) #define LSU_EMPTY PPC_BIT(3) #define SCOM_EX_GP3 0xf0012 #define PMSPCWKUPFSP_REG 0xf010d #define FSP_SPECIAL_WAKEUP PPC_BIT(0) #define EX_PM_GP0_REG 0xf0100 #define SPECIAL_WKUP_DONE PPC_BIT(31) /* How long (in us) to wait for a special wakeup to complete */ #define SPECIAL_WKUP_TIMEOUT 10 static int assert_special_wakeup(struct chiplet *chip) { int i = 0; uint64_t gp0; /* Assert special wakeup to prevent low power states */ CHECK_ERR(pib_write(&chip->target, PMSPCWKUPFSP_REG, FSP_SPECIAL_WAKEUP)); /* Poll for completion */ do { usleep(1); CHECK_ERR(pib_read(&chip->target, EX_PM_GP0_REG, &gp0)); if (i++ > SPECIAL_WKUP_TIMEOUT) { PR_ERROR("Timeout waiting for special wakeup on %s@0x%08" PRIx64 "\n", chip->target.name, dt_get_address(chip->target.dn, 0, NULL)); return -1; } } while (!(gp0 & SPECIAL_WKUP_DONE)); return 0; } #if 0 /* TODO: Work out when to do this. */ static int deassert_special_wakeup(struct chiplet *chip) { /* Assert special wakeup to prevent low power states */ CHECK_ERR(pib_write(&chip->target, PMSPCWKUPFSP_REG, 0)); return 0; } #endif static uint64_t get_thread_status(struct thread *thread) { uint64_t val, mode_reg, thread_status = thread->status; /* Need to activete debug mode to get complete status */ CHECK_ERR(pib_read(&thread->target, RAS_MODE_REG, &mode_reg)); mode_reg |= MR_THREAD_IN_DEBUG; CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, mode_reg)); /* Read status */ CHECK_ERR(pib_read(&thread->target, RAS_STATUS_REG, &val)); thread_status = SETFIELD(THREAD_STATUS_ACTIVE, thread_status, !!(val & RAS_STATUS_THREAD_ACTIVE)); thread_status = SETFIELD(THREAD_STATUS_QUIESCE, thread_status, !!(val & RAS_STATUS_TS_QUIESCE)); /* Read POW status */ CHECK_ERR(pib_read(&thread->target, POW_STATUS_REG, &val)); thread_status = SETFIELD(THREAD_STATUS_STATE, thread_status, GETFIELD(PMC_POW_STATE, val)); /* Clear debug mode */ mode_reg &= ~MR_THREAD_IN_DEBUG; CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, mode_reg)); return thread_status; } static int p8_thread_step(struct thread *thread, int count) { int i; uint64_t ras_mode, ras_status; /* Activate single-step mode */ CHECK_ERR(pib_read(&thread->target, RAS_MODE_REG, &ras_mode)); ras_mode |= MR_DO_SINGLE_MODE; CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, ras_mode)); /* Step the core */ for (i = 0; i < count; i++) { CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_STEP)); /* Wait for step to complete */ do { CHECK_ERR(pib_read(&thread->target, RAS_STATUS_REG, &ras_status)); } while (!(ras_status & RAS_STATUS_INST_COMPLETE)); } /* Deactivate single-step mode */ ras_mode &= ~MR_DO_SINGLE_MODE; CHECK_ERR(pib_write(&thread->target, RAS_MODE_REG, ras_mode)); return 0; } static int p8_thread_stop(struct thread *thread) { int i = 0; uint64_t val; struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target); do { /* Quiese active thread */ CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_STOP)); /* Wait for thread to quiese */ CHECK_ERR(pib_read(&chip->target, RAS_STATUS_REG, &val)); if (i++ > RAS_STATUS_TIMEOUT) { PR_ERROR("Unable to quiesce thread %d (0x%016" PRIx64 ").\n", thread->id, val); PR_ERROR("Continuing anyway.\n"); if (val & PPC_BIT(48)) { PR_ERROR("Unable to continue\n"); } break; } /* We can continue ramming if either the * thread is not active or the SRQ/LSU/TS bits * are set. */ } while ((val & RAS_STATUS_THREAD_ACTIVE) && !((val & RAS_STATUS_SRQ_EMPTY) && (val & RAS_STATUS_LSU_QUIESCED) && (val & RAS_STATUS_TS_QUIESCE))); /* Make the threads RAM thread active */ CHECK_ERR(pib_read(&chip->target, THREAD_ACTIVE_REG, &val)); val |= PPC_BIT(8) >> thread->id; CHECK_ERR(pib_write(&chip->target, THREAD_ACTIVE_REG, val)); return 0; } static int p8_thread_start(struct thread *thread) { uint64_t val; struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target); /* Activate thread */ CHECK_ERR(pib_write(&thread->target, DIRECT_CONTROLS_REG, DIRECT_CONTROL_SP_START)); /* Restore thread active */ CHECK_ERR(pib_read(&chip->target, THREAD_ACTIVE_REG, &val)); val &= ~(PPC_BIT(8) >> thread->id); val |= PPC_BIT(thread->id); CHECK_ERR(pib_write(&chip->target, THREAD_ACTIVE_REG, val)); return 0; } static int p8_ram_setup(struct thread *thread) { struct dt_node *dn; struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target); uint64_t ram_mode, val; /* We can only ram a thread if all the threads on the core/chip are * quiesced */ dt_for_each_compatible(chip->target.dn, dn, "ibm,power8-thread") { struct thread *tmp; tmp = target_to_thread(dn->target); if (!(get_thread_status(tmp) & THREAD_STATUS_QUIESCE)) return 1; } if (!(thread_status(thread) & THREAD_STATUS_ACTIVE)) return 2; /* Activate RAM mode */ CHECK_ERR(pib_read(&chip->target, RAM_MODE_REG, &ram_mode)); ram_mode |= RAM_MODE_ENABLE; CHECK_ERR(pib_write(&chip->target, RAM_MODE_REG, ram_mode)); /* Setup SPRC to use SPRD */ val = SPR_MODE_SPRC_WR_EN; val = SETFIELD(SPR_MODE_SPRC_SEL, val, 1 << (3 - 0)); val = SETFIELD(SPR_MODE_SPRC_T_SEL, val, 1 << (7 - thread->id)); CHECK_ERR(pib_write(&chip->target, SPR_MODE_REG, val)); CHECK_ERR(pib_write(&chip->target, L0_SCOM_SPRC_REG, SCOM_SPRC_SCRATCH_SPR)); return 0; } static int p8_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t *scratch) { struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target); uint64_t val; CHECK_ERR(pib_write(&chip->target, SCR0_REG, *scratch)); /* ram instruction */ val = SETFIELD(RAM_THREAD_SELECT, 0ULL, thread->id); val = SETFIELD(RAM_INSTR, val, opcode); CHECK_ERR(pib_write(&chip->target, RAM_CTRL_REG, val)); /* wait for completion */ do { CHECK_ERR(pib_read(&chip->target, RAM_STATUS_REG, &val)); } while (!((val & PPC_BIT(1)) || ((val & PPC_BIT(2)) && (val & PPC_BIT(3))))); if (!(val & PPC_BIT(1))) { if (GETFIELD(PPC_BITMASK(2,3), val) == 0x3) { return 1; } else { PR_ERROR("RAMMING failed with status 0x%" PRIx64 "\n", val); return 2; } } /* Save the results */ CHECK_ERR(pib_read(&chip->target, SCR0_REG, scratch)); return 0; } static int p8_ram_destroy(struct thread *thread) { struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target); uint64_t ram_mode; /* Disable RAM mode */ CHECK_ERR(pib_read(&chip->target, RAM_MODE_REG, &ram_mode)); ram_mode &= ~RAM_MODE_ENABLE; CHECK_ERR(pib_write(&chip->target, RAM_MODE_REG, ram_mode)); return 0; } /* * Initialise all viable threads for ramming on the given chiplet. */ static int p8_thread_probe(struct target *target) { struct thread *thread = target_to_thread(target); thread->id = (dt_get_address(target->dn, 0, NULL) >> 4) & 0xf; thread->status = get_thread_status(thread); return 0; } struct thread p8_thread = { .target = { .name = "POWER8 Thread", .compatible = "ibm,power8-thread", .class = "thread", .probe = p8_thread_probe, }, .step = p8_thread_step, .start = p8_thread_start, .stop = p8_thread_stop, .ram_setup = p8_ram_setup, .ram_instruction = p8_ram_instruction, .ram_destroy = p8_ram_destroy, }; DECLARE_HW_UNIT(p8_thread); static int p8_chiplet_probe(struct target *target) { uint64_t value; struct chiplet *chiplet = target_to_chiplet(target); /* Work out if this chip is actually present */ if (pib_read(target, SCOM_EX_GP3, &value)) { PR_DEBUG("Error reading chip GP3 register\n"); return -1; } if (!GETFIELD(PPC_BIT(0), value)) return -1; assert_special_wakeup(chiplet); return 0; } struct chiplet p8_chiplet = { .target = { .name = "POWER8 Chiplet", .compatible = "ibm,power8-core", .class = "chiplet", .probe = p8_chiplet_probe, }, }; DECLARE_HW_UNIT(p8_chiplet); pdbg-pdbg-1.0/libpdbg/p9chip.c000066400000000000000000000134431313304724200161470ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "target.h" #include "operations.h" #include "bitutils.h" #define P9_RAS_STATUS 0x10a02 #define P9_THREAD_INFO 0x10a9b #define P9_DIRECT_CONTROL 0x10a9c #define P9_RAS_MODEREG 0x10a9d #define P9_RAM_MODEREG 0x10a4e #define P9_RAM_CTRL 0x10a4f #define P9_RAM_STATUS 0x10a50 #define P9_SCOMC 0x10a80 #define P9_SPR_MODE 0x10a84 #define P9_SCR0_REG 0x10a86 /* PCB Slave Registers */ #define NET_CTRL0 0xf0040 #define NET_CTRL0_CHIPLET_ENABLE PPC_BIT(0) #define PPM_GPMMR 0xf0100 #define PPM_SPWKUP_OTR 0xf010a #define SPECIAL_WKUP_DONE PPC_BIT(1) #define RAS_STATUS_TIMEOUT 100 #define SPECIAL_WKUP_TIMEOUT 10 static uint64_t thread_read(struct thread *thread, uint64_t addr, uint64_t *data) { struct target *chip = require_target_parent(&thread->target); return pib_read(chip, addr, data); } static uint64_t thread_write(struct thread *thread, uint64_t addr, uint64_t data) { struct target *chip = require_target_parent(&thread->target); return pib_write(chip, addr, data); } static uint64_t p9_get_thread_status(struct thread *thread) { uint64_t value, status = THREAD_STATUS_ACTIVE; thread_read(thread, P9_RAS_STATUS, &value); if (GETFIELD(PPC_BITMASK(8*thread->id, 3 + 8*thread->id), value) == 0xf) status |= THREAD_STATUS_QUIESCE; return status; } static int p9_thread_probe(struct target *target) { struct thread *thread = target_to_thread(target); thread->id = dt_prop_get_u32(target->dn, "tid"); thread->status = p9_get_thread_status(thread); return 0; } static int p9_thread_start(struct thread *thread) { thread_write(thread, P9_DIRECT_CONTROL, PPC_BIT(6 + 8*thread->id)); thread_write(thread, P9_RAS_MODEREG, 0); return 0; } static int p9_thread_stop(struct thread *thread) { int i = 0; thread_write(thread, P9_DIRECT_CONTROL, PPC_BIT(7 + 8*thread->id)); while(!(p9_get_thread_status(thread) & THREAD_STATUS_QUIESCE)) { if (i++ > RAS_STATUS_TIMEOUT) { PR_ERROR("Unable to quiesce thread\n"); break; } } /* Fence interrupts. We can't do a read-modify-write here due to an * errata */ thread_write(thread, P9_RAS_MODEREG, PPC_BIT(57)); return 0; } static int p9_ram_setup(struct thread *thread) { struct dt_node *dn; struct chiplet *chip = target_to_chiplet(thread->target.dn->parent->target); /* We can only ram a thread if all the threads on the core/chip are * quiesced */ dt_for_each_compatible(chip->target.dn, dn, "ibm,power9-thread") { struct thread *tmp; /* If this thread wasn't enabled it may not yet have been probed so do that now. This will also update the thread status */ p9_thread_probe(dn->target); tmp = target_to_thread(dn->target); if (tmp->status != (THREAD_STATUS_QUIESCE | THREAD_STATUS_ACTIVE)) return 1; } /* Enable ram mode */ CHECK_ERR(thread_write(thread, P9_RAM_MODEREG, PPC_BIT(0))); /* Setup SPRC to use SPRD */ CHECK_ERR(thread_write(thread, P9_SPR_MODE, 0x00000ff000000000)); CHECK_ERR(thread_write(thread, P9_SCOMC, 0x0)); return 0; } static int p9_ram_instruction(struct thread *thread, uint64_t opcode, uint64_t *scratch) { uint64_t predecode, value; switch(opcode & OPCODE_MASK) { case MTNIA_OPCODE: predecode = 8; /* Not currently supported as we can only MTNIA from LR */ PR_ERROR("MTNIA is not currently supported\n"); break; case MFNIA_OPCODE: opcode = 0x1ac804; predecode = 2; break; case MTMSR_OPCODE: predecode = 8; break; default: predecode = 0; } CHECK_ERR(thread_write(thread, P9_SCR0_REG, *scratch)); value = SETFIELD(PPC_BITMASK(0, 1), 0ull, thread->id); value = SETFIELD(PPC_BITMASK(2, 5), value, predecode); value = SETFIELD(PPC_BITMASK(8, 39), value, opcode); CHECK_ERR(thread_write(thread, P9_RAM_CTRL, value)); do { CHECK_ERR(thread_read(thread, P9_RAM_STATUS, &value)); if (((value & PPC_BIT(0)) || (value & PPC_BIT(2)))) return 1; } while (!(value & PPC_BIT(1) && !(value & PPC_BIT(3)))); CHECK_ERR(thread_read(thread, P9_SCR0_REG, scratch)); return 0; } static int p9_ram_destroy(struct thread *thread) { /* Disable ram mode */ CHECK_ERR(thread_write(thread, P9_RAM_MODEREG, 0)); return 0; } struct thread p9_thread = { .target = { .name = "POWER9 Thread", .compatible = "ibm,power9-thread", .class = "thread", .probe = p9_thread_probe, }, .start = p9_thread_start, .stop = p9_thread_stop, .ram_setup = p9_ram_setup, .ram_instruction = p9_ram_instruction, .ram_destroy = p9_ram_destroy, }; DECLARE_HW_UNIT(p9_thread); static int p9_chiplet_probe(struct target *target) { int i = 0; uint64_t value; if (pib_read(target, NET_CTRL0, &value)) return -1; if (!(value & NET_CTRL0_CHIPLET_ENABLE)) return -1; CHECK_ERR(pib_write(target, PPM_SPWKUP_OTR, PPC_BIT(0))); do { usleep(1); CHECK_ERR(pib_read(target, PPM_GPMMR, &value)); if (i++ > SPECIAL_WKUP_TIMEOUT) { PR_ERROR("Timeout waiting for special wakeup on %s@0x%08" PRIx64 "\n", target->name, dt_get_address(target->dn, 0, NULL)); break; } } while (!(value & SPECIAL_WKUP_DONE)); return 0; } struct chiplet p9_chiplet = { .target = { .name = "POWER9 Chiplet", .compatible = "ibm,power9-core", .class = "chiplet", .probe = p9_chiplet_probe, }, }; DECLARE_HW_UNIT(p9_chiplet); pdbg-pdbg-1.0/libpdbg/target.c000066400000000000000000000150431313304724200162370ustar00rootroot00000000000000#include #include #include #include #include #include "target.h" #include "device.h" #undef PR_DEBUG #define PR_DEBUG(...) struct list_head empty_list = LIST_HEAD_INIT(empty_list); struct list_head target_classes = LIST_HEAD_INIT(target_classes); /* Work out the address to access based on the current target and * final class name */ static struct dt_node *get_class_target_addr(struct dt_node *dn, const char *name, uint64_t *addr) { /* Check class */ while (strcmp(dn->target->class, name)) { /* Keep walking the tree translating addresses */ *addr += dt_get_address(dn, 0, NULL); dn = dn->parent; /* The should always be a parent. If there isn't it * means we traversed up the whole device tree and * didn't find a parent matching the given class. */ assert(dn); assert(dn->target); } return dn; } int pib_read(struct target *pib_dt, uint64_t addr, uint64_t *data) { struct pib *pib; struct dt_node *dn = pib_dt->dn; int rc; dn = get_class_target_addr(dn, "pib", &addr); pib_dt = dn->target; pib = target_to_pib(pib_dt); rc = pib->read(pib, addr, data); // printf("pib_read 0x%016llx = 0x%016llx\n", addr, *data); return rc; } int pib_write(struct target *pib_dt, uint64_t addr, uint64_t data) { struct pib *pib; struct dt_node *dn = pib_dt->dn; int rc; dn = get_class_target_addr(dn, "pib", &addr); pib_dt = dn->target; pib = target_to_pib(pib_dt); rc = pib->write(pib, addr, data); // printf("pib_write 0x%016llx = 0x%016llx\n", addr, data); return rc; } int opb_read(struct target *opb_dt, uint32_t addr, uint32_t *data) { struct opb *opb; struct dt_node *dn = opb_dt->dn; uint64_t addr64 = addr; dn = get_class_target_addr(dn, "opb", &addr64); opb_dt = dn->target; opb = target_to_opb(opb_dt); return opb->read(opb, addr64, data); } int opb_write(struct target *opb_dt, uint32_t addr, uint32_t data) { struct opb *opb; struct dt_node *dn = opb_dt->dn; uint64_t addr64 = addr; dn = get_class_target_addr(dn, "opb", &addr64); opb_dt = dn->target; opb = target_to_opb(opb_dt); return opb->write(opb, addr64, data); } int fsi_read(struct target *fsi_dt, uint32_t addr, uint32_t *data) { struct fsi *fsi; struct dt_node *dn = fsi_dt->dn; uint64_t addr64 = addr; dn = get_class_target_addr(dn, "fsi", &addr64); fsi_dt = dn->target; fsi = target_to_fsi(fsi_dt); return fsi->read(fsi, addr64, data); } int fsi_write(struct target *fsi_dt, uint32_t addr, uint32_t data) { struct fsi *fsi; struct dt_node *dn = fsi_dt->dn; uint64_t addr64 = addr; dn = get_class_target_addr(dn, "fsi", &addr64); fsi_dt = dn->target; fsi = target_to_fsi(fsi_dt); return fsi->write(fsi, addr64, data); } struct target *require_target_parent(struct target *target) { struct dt_node *dn; assert((dn = target->dn)); return dn->parent->target; } /* Finds the given class. Returns NULL if not found. */ struct target_class *find_target_class(const char *name) { struct target_class *target_class; list_for_each(&target_classes, target_class, class_head_link) if (!strcmp(target_class->name, name)) return target_class; return NULL; } /* Same as above but dies with an assert if the target class doesn't * exist */ struct target_class *require_target_class(const char *name) { struct target_class *target_class; target_class = find_target_class(name); if (!target_class) { PR_ERROR("Couldn't find class %s\n", name); assert(0); } return target_class; } /* Returns the existing class or allocates space for a new one */ static struct target_class *get_target_class(const char *name) { struct target_class *target_class; if ((target_class = find_target_class(name))) return target_class; /* Need to allocate a new class */ PR_DEBUG("Allocating %s target class\n", name); target_class = calloc(1, sizeof(*target_class)); assert(target_class); target_class->name = strdup(name); list_head_init(&target_class->targets); list_add(&target_classes, &target_class->class_head_link); return target_class; } extern struct hw_unit_info *__start_hw_units; extern struct hw_init_info *__stop_hw_units; struct hw_unit_info *find_compatible_target(const char *compat) { struct hw_unit_info **p; struct target *target; for (p = &__start_hw_units; p < (struct hw_unit_info **) &__stop_hw_units; p++) { target = (*p)->hw_unit + (*p)->struct_target_offset; if (!strcmp(target->compatible, compat)) return *p; } return NULL; } void targets_init(void *fdt) { struct dt_node *dn; const struct dt_property *p; struct target_class *target_class; struct hw_unit_info *hw_unit_info; void *new_hw_unit; struct target *new_target; uint32_t index; dt_root = dt_new_root(""); dt_expand(fdt); /* Now we need to walk the device-tree, assign struct targets * to each of the nodes and add them to the appropriate target * classes */ dt_for_each_node(dt_root, dn) { p = dt_require_property(dn, "compatible", -1); hw_unit_info = find_compatible_target(p->prop); if (hw_unit_info) { /* We need to allocate a new target */ new_hw_unit = malloc(hw_unit_info->size); assert(new_hw_unit); memcpy(new_hw_unit, hw_unit_info->hw_unit, hw_unit_info->size); new_target = new_hw_unit + hw_unit_info->struct_target_offset; new_target->dn = dn; dn->target = new_target; index = dt_prop_get_u32_def(dn, "index", -1); dn->target->index = index; target_class = get_target_class(new_target->class); list_add(&target_class->targets, &new_target->class_link); PR_DEBUG("Found target %s for %s\n", new_target->name, dn->name); } else PR_DEBUG("No target found for %s\n", dn->name); } } /* Disable a node and all it's children */ static void disable_node(struct dt_node *dn) { struct dt_node *next; struct dt_property *p; p = dt_find_property(dn, "status"); if (p) dt_del_property(dn, p); dt_add_property_string(dn, "status", "disabled"); dt_for_each_child(dn, next) disable_node(next); } static void _target_probe(struct dt_node *dn) { int rc; struct dt_node *next; struct dt_property *p; PR_DEBUG("Probe %s - ", dn->name); if (!dn->target) { PR_DEBUG("target not found\n"); return; } p = dt_find_property(dn, "status"); if ((p && !strcmp(p->prop, "disabled")) || (dn->target->probe && (rc = dn->target->probe(dn->target)))) { if (rc) PR_DEBUG("not found\n"); else PR_DEBUG("disabled\n"); disable_node(dn); } else { PR_DEBUG("success\n"); dt_for_each_child(dn, next) _target_probe(next); } } /* We walk the tree root down disabling targets which might/should * exist but don't */ void target_probe(void) { _target_probe(dt_first(dt_root)); } pdbg-pdbg-1.0/libpdbg/target.h000066400000000000000000000103221313304724200162370ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __TARGET_H #define __TARGET_H #include #include #include #include "compiler.h" #include "device.h" #define PR_DEBUG(x, args...) \ fprintf(stderr, x, ##args) #define PR_INFO(x, args...) \ fprintf(stderr, x, ##args) #define PR_ERROR(x, args...) \ fprintf(stderr, "%s: " x, __FUNCTION__, ##args) enum chip_type {CHIP_UNKNOWN, CHIP_P8, CHIP_P8NV, CHIP_P9}; struct target_class { char *name; struct list_head targets; struct list_node class_head_link; }; struct target { char *name; char *compatible; char *class; int (*probe)(struct target *target); int index; struct dt_node *dn; struct list_node class_link; }; struct target *require_target_parent(struct target *target); struct target_class *find_target_class(const char *name); struct target_class *require_target_class(const char *name); extern struct list_head empty_list; #define for_each_class_target(class_name, target) \ list_for_each((find_target_class(class_name) ? &require_target_class(class_name)->targets : &empty_list), target, class_link) struct hw_unit_info { void *hw_unit; size_t size; size_t struct_target_offset; }; /* We can't pack the structs themselves directly into a special * section because there doesn't seem to be any standard way of doing * that due to alignment rules. So instead we pack pointers into a * special section. */ #define DECLARE_HW_UNIT(name) \ const struct hw_unit_info __used name ##_hw_unit = \ { .hw_unit = &name, .size = sizeof(name), .struct_target_offset = container_off(typeof(name), target) }; \ const struct hw_unit_info __used __section("hw_units") *name ##_hw_unit_p = &name ##_hw_unit struct adu { struct target target; int (*getmem)(struct adu *, uint64_t, uint64_t *); int (*putmem)(struct adu *, uint64_t, uint64_t, int); }; #define target_to_adu(x) container_of(x, struct adu, target) struct pib { struct target target; int (*read)(struct pib *, uint64_t, uint64_t *); int (*write)(struct pib *, uint64_t, uint64_t); void *priv; }; #define target_to_pib(x) container_of(x, struct pib, target) struct opb { struct target target; int (*read)(struct opb *, uint32_t, uint32_t *); int (*write)(struct opb *, uint32_t, uint32_t); }; #define target_to_opb(x) container_of(x, struct opb, target) struct fsi { struct target target; int (*read)(struct fsi *, uint32_t, uint32_t *); int (*write)(struct fsi *, uint32_t, uint32_t); enum chip_type chip_type; }; #define target_to_fsi(x) container_of(x, struct fsi, target) struct chiplet { struct target target; }; #define target_to_chiplet(x) container_of(x, struct chiplet, target) struct thread { struct target target; uint64_t status; int id; int (*step)(struct thread *, int); int (*start)(struct thread *); int (*stop)(struct thread *); /* ram_setup() should be called prior to using ram_instruction() to * actually ram the instruction and return the result. ram_destroy() * should be called at completion to clean-up. */ int (*ram_setup)(struct thread *); int (*ram_instruction)(struct thread *, uint64_t opcode, uint64_t *scratch); int (*ram_destroy)(struct thread *); }; #define target_to_thread(x) container_of(x, struct thread, target) void targets_init(void *fdt); void target_probe(void); int pib_read(struct target *pib_dt, uint64_t addr, uint64_t *data); int pib_write(struct target *pib_dt, uint64_t addr, uint64_t data); int opb_read(struct target *opb_dt, uint32_t addr, uint32_t *data); int opb_write(struct target *opb_dt, uint32_t addr, uint32_t data); int fsi_read(struct target *fsi_dt, uint32_t addr, uint32_t *data); int fsi_write(struct target *fsi_dt, uint32_t addr, uint32_t data); #endif pdbg-pdbg-1.0/p8-fsi.dts.m4000066400000000000000000000017171313304724200153460ustar00rootroot00000000000000/dts-v1/; / { #address-cells = <0x1>; #size-cells = <0x0>; fsi@0 { #address-cells = <0x2>; #size-cells = <0x1>; compatible = "ibm,bmcfsi"; reg = <0x0 0x0 0x0>; /* GPIO pin definitions */ fsi_clk = <0x0 0x4>; /* A4 */ fsi_dat = <0x0 0x5>; /* A5 */ fsi_dat_en = <0x20 0x1e>; /* H6 */ fsi_enable = <0x0 0x18>; /* D0 */ cronus_sel = <0x0 0x6>; /* A6 */ clock_delay = <0x14>; index = <0x0>; status = "hidden"; pib@1000 { #address-cells = <0x2>; #size-cells = <0x1>; reg = <0x0 0x1000 0x7>; compatible = "ibm,fsi-pib", "ibm,power8-fsi-pib"; index = <0x0>; include(p8-pib.dts.m4)dnl }; hmfsi@100000 { compatible = "ibm,fsi-hmfsi"; reg = <0x0 0x100000 0x8000>; port = <0x1>; index = <0x1>; pib@1000 { #address-cells = <0x2>; #size-cells = <0x1>; reg = <0x0 0x1000 0x7>; compatible = "ibm,fsi-pib", "ibm,power8-fsi-pib"; index = <0x1>; include(p8-pib.dts.m4)dnl }; }; }; }; pdbg-pdbg-1.0/p8-i2c.dts.m4000066400000000000000000000014061313304724200152350ustar00rootroot00000000000000/dts-v1/; / { #address-cells = <0x1>; #size-cells = <0x0>; /* I2C attached pib */ pib@50 { #address-cells = <0x2>; #size-cells = <0x1>; compatible = "ibm,power8-i2c-slave"; bus = "/dev/i2c4"; reg = <0x50>; index = <0x0>; status = "hidden"; include(p8-pib.dts.m4)dnl opb@20010 { #address-cells = <0x1>; #size-cells = <0x1>; reg = <0x0 0x20010 0xa>; compatible = "ibm,power8-opb"; hmfsi@100000 { compatible = "ibm,power8-opb-hmfsi"; reg = <0x100000 0x80000>; port = <0x1>; index = <0x1>; pib@1000 { #address-cells = <0x2>; #size-cells = <0x1>; reg = <0x0 0x1000 0x7>; compatible = "ibm,fsi-pib", "ibm,power8-fsi-pib"; index = <0x1>; include(p8-pib.dts.m4)dnl }; }; }; }; }; pdbg-pdbg-1.0/p8-pib.dts.m4000066400000000000000000000015731313304724200153370ustar00rootroot00000000000000define(`CONCAT', `$1$2')dnl define(`HEX', `CONCAT(0x, $1)')dnl define(`CORE_BASE', `eval(0x10000000 + $1 * 0x1000000, 16)')dnl define(`CORE', `core@CORE_BASE($1) { #address-cells = <0x2>; #size-cells = <0x1>; compatible = "ibm,power8-core"; reg = <0x0 HEX(CORE_BASE($1)) 0xfffff>; index = <0x$2>; THREAD(0); THREAD(1); THREAD(2); THREAD(3); THREAD(4); THREAD(5); THREAD(6); THREAD(7); }')dnl define(`THREAD_BASE', `eval(0x13000 + $1 * 0x10, 16)')dnl define(`THREAD',`thread@THREAD_BASE($1) { reg = <0x0 HEX(THREAD_BASE($1)) 0x10>; compatible = "ibm,power8-thread"; index = ; }')dnl dnl define(`PROC_CORES', `CORE(1, 0); CORE(2, 1); CORE(3, 2); CORE(4, 3); CORE(5, 4); CORE(6, 5); CORE(9, 6); CORE(10, 7); CORE(11, 8); CORE(12, 9); CORE(13, 10); CORE(14, 11)')dnl adu@2020000 { compatible = "ibm,power8-adu"; reg = <0x0 0x2020000 0x4>; }; PROC_CORES; pdbg-pdbg-1.0/p9-fsi.dtsi.m4000066400000000000000000000042501313304724200155130ustar00rootroot00000000000000define(`CONCAT', `$1$2')dnl define(`HEX', `CONCAT(0x, $1)')dnl define(`CORE_BASE', `eval(0x20000000 + $1 * 0x1000000, 16)')dnl define(`CORE', `core@CORE_BASE($1) { #address-cells = <0x1>; #size-cells = <0x0>; compatible = "ibm,power9-core"; reg = <0x0 HEX(CORE_BASE($1)) 0xfffff>; index = ; THREAD(0); THREAD(1); THREAD(2); THREAD(3); }')dnl define(`THREAD_BASE', `eval($1, 16)')dnl define(`THREAD',`thread@THREAD_BASE($1) { compatible = "ibm,power9-thread"; reg = <0x0>; tid = ; index = ; }')dnl / { #address-cells = <0x1>; #size-cells = <0x0>; fsi0: fsi@0 { #address-cells = <0x2>; #size-cells = <0x1>; compatible = "ibm,bmcfsi"; reg = <0x0 0x0 0x0>; index = <0x0>; status = "hidden"; pib@1000 { #address-cells = <0x2>; #size-cells = <0x1>; reg = <0x0 0x1000 0x7>; compatible = "ibm,fsi-pib", "ibm,power9-fsi-pib"; index = <0x0>; adu@90000 { compatible = "ibm,power9-adu"; reg = <0x0 0x90000 0x5>; }; CORE(0, 0); CORE(1, 1); CORE(2, 2); CORE(3, 3); CORE(4, 4); CORE(5, 5); CORE(6, 6); CORE(7, 7); CORE(8, 8); CORE(9, 9); CORE(10, 10); CORE(11, 11); CORE(12, 12); CORE(13, 13); CORE(14, 14); CORE(15, 15); CORE(16, 16); CORE(17, 17); CORE(18, 18); CORE(19, 19); CORE(20, 20); CORE(21, 21); CORE(22, 22); CORE(23, 23); }; hmfsi@100000 { compatible = "ibm,fsi-hmfsi"; reg = <0x0 0x100000 0x8000>; port = <0x1>; index = <0x1>; pib@1000 { #address-cells = <0x2>; #size-cells = <0x1>; reg = <0x0 0x1000 0x7>; compatible = "ibm,fsi-pib", "ibm,power9-fsi-pib"; index = <0x1>; adu@90000 { compatible = "ibm,power9-adu"; reg = <0x0 0x90000 0x5>; }; CORE(0, 0); CORE(1, 1); CORE(2, 2); CORE(3, 3); CORE(4, 4); CORE(5, 5); CORE(6, 6); CORE(7, 7); CORE(8, 8); CORE(9, 9); CORE(10, 10); CORE(11, 11); CORE(12, 12); CORE(13, 13); CORE(14, 14); CORE(15, 15); CORE(16, 16); CORE(17, 17); CORE(18, 18); CORE(19, 19); CORE(20, 20); CORE(21, 21); CORE(22, 22); CORE(23, 23); }; }; }; }; pdbg-pdbg-1.0/p9-kernel.dts000066400000000000000000000015551313304724200155270ustar00rootroot00000000000000/dts-v1/; / { #address-cells = <0x1>; #size-cells = <0x0>; fsi0: kernelfsi@0 { #address-cells = <0x2>; #size-cells = <0x1>; compatible = "ibm,kernel-fsi"; reg = <0x0 0x0 0x0>; index = <0x0>; status = "hidden"; pib@1000 { #address-cells = <0x2>; #size-cells = <0x1>; reg = <0x0 0x1000 0x7>; compatible = "ibm,fsi-pib", "ibm,power9-fsi-pib"; index = <0x0>; adu@90000 { compatible = "ibm,power9-adu"; reg = <0x0 0x90000 0x5>; }; }; hmfsi@100000 { compatible = "ibm,fsi-hmfsi"; reg = <0x0 0x100000 0x8000>; port = <0x1>; index = <0x1>; pib@1000 { #address-cells = <0x2>; #size-cells = <0x1>; reg = <0x0 0x1000 0x7>; compatible = "ibm,fsi-pib", "ibm,power9-fsi-pib"; index = <0x1>; adu@90000 { compatible = "ibm,power9-adu"; reg = <0x0 0x90000 0x5>; }; }; }; }; }; pdbg-pdbg-1.0/p9r-fsi.dts000066400000000000000000000004331313304724200152040ustar00rootroot00000000000000/dts-v1/; /include/ "p9-fsi.dtsi" / { }; &fsi0 { /* GPIO pin definitions */ fsi_clk = <0x1e0 0x10>; /* AA0 */ fsi_dat = <0x1e0 0x12>; /* AA2 */ fsi_dat_en = <0x80 0xa>; /* R2 */ fsi_enable = <0x0 0x18>; /* D0 */ cronus_sel = <0x0 0x6>; /* A6 */ clock_delay = <0x14>; }; pdbg-pdbg-1.0/p9w-fsi.dts000066400000000000000000000004311313304724200152070ustar00rootroot00000000000000/dts-v1/; /include/ "p9-fsi.dtsi" / { }; &fsi0 { /* GPIO pin definitions */ fsi_clk = <0x1e0 0x10>; /* AA0 */ fsi_dat = <0x20 0x0>; /* E0 */ fsi_dat_en = <0x80 0xa>; /* R2 */ fsi_enable = <0x0 0x18>; /* D0 */ cronus_sel = <0x0 0x6>; /* A6 */ clock_delay = <0x14>; }; pdbg-pdbg-1.0/p9z-fsi.dts000066400000000000000000000004301313304724200152110ustar00rootroot00000000000000/dts-v1/; /include/ "p9-fsi.dtsi" / { }; &fsi0 { /* GPIO pin definitions */ fsi_clk = <0x0 0x13>; /* C3 */ fsi_dat = <0x0 0x12>; /* C2 */ fsi_dat_en = <0x78 0x16>; /* O6 */ fsi_enable = <0x0 0x18>; /* D0 */ cronus_sel = <0x78 0x1e>; /* P6 */ clock_delay = <0x14>; }; pdbg-pdbg-1.0/src/000077500000000000000000000000001313304724200137665ustar00rootroot00000000000000pdbg-pdbg-1.0/src/main.c000066400000000000000000000542711313304724200150670ustar00rootroot00000000000000/* Copyright 2016 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bitutils.h" #undef PR_DEBUG #define PR_DEBUG(...) enum command { GETCFAM = 1, PUTCFAM, GETSCOM, PUTSCOM, \ GETMEM, PUTMEM, GETGPR, GETNIA, GETSPR, \ GETMSR, PUTGPR, PUTNIA, PUTSPR, PUTMSR, \ STOP, START, THREADSTATUS, STEP, PROBE, \ GETVMEM }; #define MAX_CMD_ARGS 3 enum command cmd = 0; static int cmd_arg_count = 0; static int cmd_min_arg_count = 0; static int cmd_max_arg_count = 0; /* At the moment all commands only take some kind of number */ static uint64_t cmd_args[MAX_CMD_ARGS]; enum backend { FSI, I2C, KERNEL, FAKE }; static enum backend backend = KERNEL; static char const *device_node; static int i2c_addr = 0x50; #define MAX_PROCESSORS 16 #define MAX_CHIPS 24 #define MAX_THREADS THREADS_PER_CORE static int **processorsel[MAX_PROCESSORS]; static int *chipsel[MAX_PROCESSORS][MAX_CHIPS]; static int threadsel[MAX_PROCESSORS][MAX_CHIPS][MAX_THREADS]; /* Convenience functions */ #define for_each_thread(x) while(0) #define for_each_chiplet(x) while(0) #define for_each_processor(x) while(0) #define for_each_cfam(x) while(0) static void print_usage(char *pname) { printf("Usage: %s [options] command ...\n\n", pname); printf(" Options:\n"); printf("\t-p, --processor=processor-id\n"); printf("\t-c, --chip=chiplet-id\n"); printf("\t-t, --thread=thread\n"); printf("\t-a, --all\n"); printf("\t\tRun command on all possible processors/chips/threads (default)\n"); printf("\t-b, --backend=backend\n"); printf("\t\tfsi:\tAn experimental backend that uses\n"); printf("\t\t\tbit-banging to access the host processor\n"); printf("\t\t\tvia the FSI bus.\n"); printf("\t\ti2c:\tThe P8 only backend which goes via I2C.\n"); printf("\t\tkernel:\tThe default backend which goes the kernel FSI driver.\n"); printf("\t-d, --device=backend device\n"); printf("\t\tFor I2C the device node used by the backend to access the bus.\n"); printf("\t\tFor FSI the system board type, one of p8 or p9w\n"); printf("\t\tDefaults to /dev/i2c4 for I2C\n"); printf("\t-s, --slave-address=backend device address\n"); printf("\t\tDevice slave address to use for the backend. Not used by FSI\n"); printf("\t\tand defaults to 0x50 for I2C\n"); printf("\t-V, --version\n"); printf("\t-h, --help\n"); printf("\n"); printf(" Commands:\n"); printf("\tgetcfam
\n"); printf("\tputcfam
[]\n"); printf("\tgetscom
\n"); printf("\tputscom
[]\n"); printf("\tgetmem
\n"); printf("\tputmem
\n"); printf("\tgetvmem \n"); printf("\tgetgpr \n"); printf("\tputgpr \n"); printf("\tgetnia\n"); printf("\tputnia \n"); printf("\tgetspr \n"); printf("\tputspr \n"); printf("\tstart\n"); printf("\tstep \n"); printf("\tstop\n"); printf("\tthreadstatus\n"); printf("\tprobe\n"); } enum command parse_cmd(char *optarg) { cmd_max_arg_count = 0; if (strcmp(optarg, "getcfam") == 0) { cmd = GETCFAM; cmd_min_arg_count = 1; } else if (strcmp(optarg, "getscom") == 0) { cmd = GETSCOM; cmd_min_arg_count = 1; } else if (strcmp(optarg, "putcfam") == 0) { cmd = PUTCFAM; cmd_min_arg_count = 2; cmd_max_arg_count = 3; /* No mask by default */ cmd_args[2] = -1ULL; } else if (strcmp(optarg, "putscom") == 0) { cmd = PUTSCOM; cmd_min_arg_count = 2; cmd_max_arg_count = 3; /* No mask by default */ cmd_args[2] = -1ULL; } else if (strcmp(optarg, "getmem") == 0) { cmd = GETMEM; cmd_min_arg_count = 2; } else if (strcmp(optarg, "putmem") == 0) { cmd = PUTMEM; cmd_min_arg_count = 1; } else if (strcmp(optarg, "getgpr") == 0) { cmd = GETGPR; cmd_min_arg_count = 1; } else if (strcmp(optarg, "putgpr") == 0) { cmd = PUTGPR; cmd_min_arg_count = 2; } else if (strcmp(optarg, "getnia") == 0) { cmd = GETNIA; cmd_min_arg_count = 0; } else if (strcmp(optarg, "putnia") == 0) { cmd = PUTNIA; cmd_min_arg_count = 1; } else if (strcmp(optarg, "getspr") == 0) { cmd = GETSPR; cmd_min_arg_count = 1; } else if (strcmp(optarg, "putspr") == 0) { cmd = PUTSPR; cmd_min_arg_count = 2; } else if (strcmp(optarg, "getmsr") == 0) { cmd = GETMSR; cmd_min_arg_count = 0; } else if (strcmp(optarg, "putmsr") == 0) { cmd = PUTMSR; cmd_min_arg_count = 1; } else if (strcmp(optarg, "getvmem") == 0) { cmd = GETVMEM; cmd_min_arg_count = 1; } else if (strcmp(optarg, "start") == 0) { cmd = START; cmd_min_arg_count = 0; } else if (strcmp(optarg, "step") == 0) { cmd = STEP; cmd_min_arg_count = 1; } else if (strcmp(optarg, "stop") == 0) { cmd = STOP; cmd_min_arg_count = 0; } else if (strcmp(optarg, "threadstatus") == 0) { cmd = THREADSTATUS; cmd_min_arg_count = 0; } else if (strcmp(optarg, "probe") == 0) { cmd = PROBE; cmd_min_arg_count = 0; } if (cmd_min_arg_count && !cmd_max_arg_count) cmd_max_arg_count = cmd_min_arg_count; return cmd; } static bool parse_options(int argc, char *argv[]) { int c, oidx = 0, cmd_arg_idx = 0; bool opt_error = true; static int current_processor = INT_MAX, current_chip = INT_MAX, current_thread = INT_MAX; struct option long_opts[] = { {"all", no_argument, NULL, 'a'}, {"processor", required_argument, NULL, 'p'}, {"chip", required_argument, NULL, 'c'}, {"thread", required_argument, NULL, 't'}, {"backend", required_argument, NULL, 'b'}, {"device", required_argument, NULL, 'd'}, {"slave-address", required_argument, NULL, 's'}, {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, }; do { c = getopt_long(argc, argv, "-p:c:t:b:d:s:haV", long_opts, &oidx); switch(c) { case 1: /* Positional argument */ if (!cmd) opt_error = !parse_cmd(optarg); else if (cmd_arg_idx >= MAX_CMD_ARGS || (cmd && cmd_arg_idx >= cmd_max_arg_count)) opt_error = true; else { errno = 0; cmd_args[cmd_arg_idx++] = strtoull(optarg, NULL, 0); opt_error = errno; } break; case 'a': opt_error = false; for (current_processor = 0; current_processor < MAX_PROCESSORS; current_processor++) { processorsel[current_processor] = &chipsel[current_processor][0]; for (current_chip = 0; current_chip < MAX_CHIPS; current_chip++) { chipsel[current_processor][current_chip] = &threadsel[current_processor][current_chip][0]; for (current_thread = 0; current_thread < MAX_THREADS; current_thread++) threadsel[current_processor][current_chip][current_thread] = 1; } } break; case 'p': errno = 0; current_processor = strtoul(optarg, NULL, 0); if (current_processor >= MAX_PROCESSORS) errno = -1; else processorsel[current_processor] = &chipsel[current_processor][0]; opt_error = errno; break; case 'c': errno = 0; current_chip = strtoul(optarg, NULL, 0); if (current_chip >= MAX_CHIPS) errno = -1; else chipsel[current_processor][current_chip] = &threadsel[current_processor][current_chip][0]; opt_error = errno; break; case 't': errno = 0; current_thread = strtoul(optarg, NULL, 0); if (current_thread >= MAX_THREADS) errno = -1; else threadsel[current_processor][current_chip][current_thread] = 1; opt_error = errno; break; case 'b': opt_error = false; if (strcmp(optarg, "fsi") == 0) { backend = FSI; device_node = "p9w"; } else if (strcmp(optarg, "i2c") == 0) { backend = I2C; device_node = "/dev/i2c4"; } else if (strcmp(optarg, "kernel") == 0) { backend = KERNEL; /* TODO: use device node to point at a slave * other than the first? */ } else if (strcmp(optarg, "fake") == 0) { backend = FAKE; } else opt_error = true; break; case 'd': opt_error = false; device_node = optarg; break; case 's': errno = 0; i2c_addr = strtoull(optarg, NULL, 0); opt_error = errno; break; case 'V': errno = 0; printf("%s (commit %s)\n", PACKAGE_STRING, GIT_SHA1); exit(1); break; case 'h': opt_error = true; break; } } while (c != EOF && !opt_error); opt_error |= cmd_arg_idx < cmd_min_arg_count; if (opt_error) print_usage(argv[0]); cmd_arg_count = cmd_arg_idx; return opt_error; } /* Returns the sum of return codes. This can be used to count how many targets the callback was run on. */ static int for_each_child_target(char *class, struct target *parent, int (*cb)(struct target *, uint32_t, uint64_t *, uint64_t *), uint64_t *arg1, uint64_t *arg2) { int rc = 0; struct target *target; uint32_t index; struct dt_node *dn; for_each_class_target(class, target) { struct dt_property *p; dn = target->dn; if (parent && dn->parent != parent->dn) continue; /* Search up the tree for an index */ for (index = dn->target->index; index == -1; dn = dn->parent); assert(index != -1); p = dt_find_property(dn, "status"); if (p && (!strcmp(p->prop, "disabled") || !strcmp(p->prop, "hidden"))) continue; rc += cb(target, index, arg1, arg2); } return rc; } static int for_each_target(char *class, int (*cb)(struct target *, uint32_t, uint64_t *, uint64_t *), uint64_t *arg1, uint64_t *arg2) { return for_each_child_target(class, NULL, cb, arg1, arg2); } static int getcfam(struct target *target, uint32_t index, uint64_t *addr, uint64_t *unused) { uint32_t value; if (fsi_read(target, *addr, &value)) return 0; printf("p%d:0x%x = 0x%08x\n", index, (uint32_t) *addr, value); return 1; } static int putcfam(struct target *target, uint32_t index, uint64_t *addr, uint64_t *data) { if (fsi_write(target, *addr, *data)) return 0; return 1; } static int getscom(struct target *target, uint32_t index, uint64_t *addr, uint64_t *unused) { uint64_t value; if (pib_read(target, *addr, &value)) return 0; printf("p%d:0x%" PRIx64 " = 0x%016" PRIx64 "\n", index, *addr, value); return 1; } static int putscom(struct target *target, uint32_t index, uint64_t *addr, uint64_t *data) { if (pib_write(target, *addr, *data)) return 0; return 1; } static int print_thread_status(struct target *thread_target, uint32_t index, uint64_t *status, uint64_t *unused1) { struct thread *thread = target_to_thread(thread_target); *status = SETFIELD(0xf << (index * 4), *status, thread_status(thread) & 0xf); return 1; } static int print_chiplet_thread_status(struct target *chiplet_target, uint32_t index, uint64_t *unused, uint64_t *unused1) { uint64_t status = -1UL; int i, rc; printf("c%02d:", index); rc = for_each_child_target("thread", chiplet_target, print_thread_status, &status, NULL); for (i = 0; i < 8; i++) switch ((status >> (i * 4)) & 0xf) { case THREAD_STATUS_ACTIVE: printf(" A"); break; case THREAD_STATUS_DOZE: case THREAD_STATUS_QUIESCE | THREAD_STATUS_DOZE: printf(" D"); break; case THREAD_STATUS_NAP: case THREAD_STATUS_QUIESCE | THREAD_STATUS_NAP: printf(" N"); break; case THREAD_STATUS_SLEEP: case THREAD_STATUS_QUIESCE | THREAD_STATUS_SLEEP: printf(" S"); break; case THREAD_STATUS_ACTIVE | THREAD_STATUS_QUIESCE: printf(" Q"); break; case 0xf: printf(" "); break; default: printf(" U"); break; } printf("\n"); return rc; } static int print_proc_thread_status(struct target *pib_target, uint32_t index, uint64_t *unused, uint64_t *unused1) { printf("\np%01dt: 0 1 2 3 4 5 6 7\n", index); return for_each_child_target("chiplet", pib_target, print_chiplet_thread_status, NULL, NULL); }; #define REG_MEM -3 #define REG_MSR -2 #define REG_NIA -1 #define REG_R31 31 static void print_proc_reg(struct thread *thread, uint64_t reg, uint64_t value, int rc) { int proc_index, chip_index, thread_index; thread_index = thread->target.index; chip_index = thread->target.dn->parent->target->index; proc_index = thread->target.dn->parent->parent->target->index; printf("p%d:c%d:t%d:", proc_index, chip_index, thread_index); if (reg == REG_MSR) printf("msr: "); else if (reg == REG_NIA) printf("nia: "); else if (reg > REG_R31) printf("spr%03" PRIu64 ": ", reg - REG_R31); else if (reg >= 0 && reg <= 31) printf("gpr%02" PRIu64 ": ", reg); if (rc == 1) { printf("Check threadstatus - not all threads on this chiplet are quiesced\n"); } else if (rc == 2) printf("Thread in incorrect state\n"); else printf("0x%016" PRIx64 "\n", value); } static int putprocreg(struct target *thread_target, uint32_t index, uint64_t *reg, uint64_t *value) { struct thread *thread = target_to_thread(thread_target); int rc; if (*reg == REG_MSR) rc = ram_putmsr(thread, *value); else if (*reg == REG_NIA) rc = ram_putnia(thread, *value); else if (*reg > REG_R31) rc = ram_putspr(thread, *reg - REG_R31, *value); else if (*reg >= 0 && *reg <= 31) rc = ram_putgpr(thread, *reg, *value); print_proc_reg(thread, *reg, *value, rc); return 0; } static int getprocreg(struct target *thread_target, uint32_t index, uint64_t *reg, uint64_t *unused) { struct thread *thread = target_to_thread(thread_target); int rc; uint64_t value; if (*reg == REG_MSR) rc = ram_getmsr(thread, &value); else if (*reg == REG_NIA) rc = ram_getnia(thread, &value); else if (*reg > REG_R31) rc = ram_getspr(thread, *reg - REG_R31, &value); else if (*reg >= 0 && *reg <= 31) rc = ram_getgpr(thread, *reg, &value); print_proc_reg(thread, *reg, value, rc); return !rc; } #define PUTMEM_BUF_SIZE 1024 static int putmem(uint64_t addr) { uint8_t *buf; int read_size, rc = 0; struct target *adu_target; for_each_class_target("adu", adu_target) break; buf = malloc(PUTMEM_BUF_SIZE); assert(buf); do { read_size = read(STDIN_FILENO, buf, PUTMEM_BUF_SIZE); if (adu_putmem(adu_target, addr, buf, read_size)) { rc = 0; PR_ERROR("Unable to write memory.\n"); break; } rc += read_size; } while (read_size > 0); free(buf); return rc; } static int start_thread(struct target *thread_target, uint32_t index, uint64_t *unused, uint64_t *unused1) { return ram_start_thread(thread_target) ? 0 : 1; } static int step_thread(struct target *thread_target, uint32_t index, uint64_t *count, uint64_t *unused1) { return ram_step_thread(thread_target, *count) ? 0 : 1; } static int stop_thread(struct target *thread_target, uint32_t index, uint64_t *unused, uint64_t *unused1) { return ram_stop_thread(thread_target) ? 0 : 1; } static void enable_dn(struct dt_node *dn) { struct dt_property *p; PR_DEBUG("Enabling %s\n", dn->name); p = dt_find_property(dn, "status"); if (!p) /* Default assumption enabled */ return; /* We only override a status of "hidden" */ if (strcmp(p->prop, "hidden")) return; dt_del_property(dn, p); } static void disable_dn(struct dt_node *dn) { struct dt_property *p; PR_DEBUG("Disabling %s\n", dn->name); p = dt_find_property(dn, "status"); if (p) /* We don't override hard-coded device tree * status. This is needed to avoid disabling that * backend. */ return; dt_add_property_string(dn, "status", "disabled"); } /* TODO: It would be nice to have a more dynamic way of doing this */ extern unsigned char _binary_p8_i2c_dtb_o_start; extern unsigned char _binary_p8_i2c_dtb_o_end; extern unsigned char _binary_p8_fsi_dtb_o_start; extern unsigned char _binary_p8_fsi_dtb_o_end; extern unsigned char _binary_p9w_fsi_dtb_o_start; extern unsigned char _binary_p9w_fsi_dtb_o_end; extern unsigned char _binary_p9r_fsi_dtb_o_start; extern unsigned char _binary_p9r_fsi_dtb_o_end; extern unsigned char _binary_p9z_fsi_dtb_o_start; extern unsigned char _binary_p9z_fsi_dtb_o_end; extern unsigned char _binary_p9_kernel_dtb_o_start; extern unsigned char _binary_p9_kernel_dtb_o_end; extern unsigned char _binary_fake_dtb_o_start; extern unsigned char _binary_fake_dtb_o_end; static int target_select(void) { struct target *fsi, *pib, *chip, *thread; switch (backend) { case I2C: targets_init(&_binary_p8_i2c_dtb_o_start); break; case FSI: if (!strcmp(device_node, "p8")) targets_init(&_binary_p8_fsi_dtb_o_start); else if (!strcmp(device_node, "p9w") || !strcmp(device_node, "witherspoon")) targets_init(&_binary_p9w_fsi_dtb_o_start); else if (!strcmp(device_node, "p9r") || !strcmp(device_node, "romulus")) targets_init(&_binary_p9r_fsi_dtb_o_start); else if (!strcmp(device_node, "p9z") || !strcmp(device_node, "zaius")) targets_init(&_binary_p9z_fsi_dtb_o_start); else { PR_ERROR("Invalid device type specified\n"); return -1; } break; case KERNEL: targets_init(&_binary_p9_kernel_dtb_o_start); break; case FAKE: targets_init(&_binary_fake_dtb_o_start); break; default: PR_ERROR("Invalid backend specified\n"); return -1; } /* At this point we should have a device-tree loaded. We want * to walk the tree and disabled nodes we don't care about * prior to probing. */ for_each_class_target("pib", pib) { int proc_index = pib->index; if (processorsel[proc_index]) { enable_dn(pib->dn); if (!find_target_class("chiplet")) continue; for_each_class_target("chiplet", chip) { if (chip->dn->parent != pib->dn) continue; int chip_index = chip->index; if (chipsel[proc_index][chip_index]) { enable_dn(chip->dn); if (!find_target_class("thread")) continue; for_each_class_target("thread", thread) { if (thread->dn->parent != chip->dn) continue; int thread_index = thread->index; if (threadsel[proc_index][chip_index][thread_index]) enable_dn(thread->dn); else disable_dn(thread->dn); } } else disable_dn(chip->dn); } } else disable_dn(pib->dn); } for_each_class_target("fsi", fsi) { int index = fsi->index; if (processorsel[index]) enable_dn(fsi->dn); else disable_dn(fsi->dn); } return 0; } void print_target(struct dt_node *dn, int level) { int i; struct dt_node *next; struct dt_property *p; char *status = ""; p = dt_find_property(dn, "status"); if (p) status = p->prop; if (!strcmp(status, "disabled")) return; if (strcmp(status, "hidden")) { struct target *target; for (i = 0; i < level; i++) printf(" "); target = dn->target; if (target) { char c = 0; if (!strcmp(target->class, "pib")) c = 'p'; else if (!strcmp(target->class, "chiplet")) c = 'c'; else if (!strcmp(target->class, "thread")) c = 't'; if (c) printf("%c%d: %s\n", c, target->index, target->name); else printf("%s\n", target->name); } } list_for_each(&dn->children, next, list) print_target(next, level + 1); } int main(int argc, char *argv[]) { int rc = 0; uint8_t *buf; struct target *target; if (parse_options(argc, argv)) return 1; /* Disable unselected targets */ if (target_select()) return 1; target_probe(); switch(cmd) { case GETCFAM: rc = for_each_target("fsi", getcfam, &cmd_args[0], NULL); break; case PUTCFAM: rc = for_each_target("fsi", putcfam, &cmd_args[0], &cmd_args[1]); break; case GETSCOM: rc = for_each_target("pib", getscom, &cmd_args[0], NULL); break; case PUTSCOM: rc = for_each_target("pib", putscom, &cmd_args[0], &cmd_args[1]); break; case GETMEM: buf = malloc(cmd_args[1]); assert(buf); for_each_class_target("adu", target) { if (!adu_getmem(target, cmd_args[0], buf, cmd_args[1])) { if (write(STDOUT_FILENO, buf, cmd_args[1]) < 0) PR_ERROR("Unable to write stdout.\n"); else rc++; } else PR_ERROR("Unable to read memory.\n"); /* We only ever care about getting memory from a single processor */ break; } free(buf); break; case PUTMEM: rc = putmem(cmd_args[0]); printf("Wrote %d bytes starting at 0x%016" PRIx64 "\n", rc, cmd_args[0]); break; case GETGPR: rc = for_each_target("thread", getprocreg, &cmd_args[0], NULL); break; case PUTGPR: rc = for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]); break; case GETNIA: cmd_args[0] = REG_NIA; rc = for_each_target("thread", getprocreg, &cmd_args[0], NULL); break; case PUTNIA: cmd_args[1] = cmd_args[0]; cmd_args[0] = REG_NIA; rc = for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]); break; case GETSPR: cmd_args[0] += REG_R31; rc = for_each_target("thread", getprocreg, &cmd_args[0], NULL); break; case PUTSPR: cmd_args[0] += REG_R31; rc = for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]); break; case GETMSR: cmd_args[0] = REG_MSR; rc = for_each_target("thread", getprocreg, &cmd_args[0], NULL); break; case PUTMSR: cmd_args[1] = cmd_args[0]; cmd_args[0] = REG_MSR; rc = for_each_target("thread", putprocreg, &cmd_args[0], &cmd_args[1]); break; case THREADSTATUS: rc = for_each_target("pib", print_proc_thread_status, NULL, NULL); break; case START: rc = for_each_target("thread", start_thread, NULL, NULL); break; case STEP: rc = for_each_target("thread", step_thread, &cmd_args[0], NULL); break; case STOP: rc = for_each_target("thread", stop_thread, NULL, NULL); break; case PROBE: rc = 1; print_target(dt_root, 0); printf("\nNote that only selected targets will be shown above. If none are shown\n" "try adding '-a' to select all targets\n"); break; default: PR_ERROR("Unsupported command\n"); break; } if (rc <= 0) { printf("No valid targets found or specified. Try adding -p/-c/-t options to specify a target.\n"); printf("Alternatively run %s -a probe to get a list of all valid targets\n", argv[0]); rc = 1; } else rc = 0; if (backend == FSI) fsi_destroy(NULL); return rc; }