├── LICENSE
├── Makefile
├── README.md
└── pci_debug.c
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile
2 | #
3 | # 03/12/2021 Léo Dumez (leo.dumez@outlook.com)
4 | #
5 | # Generic makefile (Yocto Compliant)
6 | #
7 | # 5/3/2012 D. W. Hawkins (dwh@ovro.caltech.edu)
8 | #
9 | # Create the Linux pci_debug utility for accessing
10 | # BAR regions.
11 | #
12 |
13 |
14 | APP_NAME=pci_debug
15 |
16 | SRC_DIR=.
17 | OBJS_DIR=obj
18 | BIN_DIR=bin
19 |
20 | CFLAGS=
21 | LIBS=-lreadline
22 |
23 | EXEC=$(BIN_DIR)/$(APP_NAME)
24 | SRC := $(wildcard $(SRC_DIR)/*.c)
25 | OBJS=$(SRC:$(SRC_DIR)/%.c=$(OBJS_DIR)/%.o)
26 |
27 | MKDIR_P=mkdir -p
28 | RM_RF=rm -rf
29 |
30 | all: $(EXEC)
31 |
32 |
33 | $(EXEC): $(OBJS)
34 | @echo 'Building target: $@'
35 | @echo 'Invoking: Cross GCC Linker'
36 | $(MKDIR_P) $(BIN_DIR)
37 | $(CC) -o "$@" $(OBJS) $(LDFLAGS) $(LIBS)
38 | @echo 'Finished building target: $@'
39 | @echo ' '
40 |
41 | $(OBJS_DIR)/%.o: $(SRC_DIR)/%.c
42 | @echo 'Building file: $<'
43 | @echo 'Invoking: Cross GCC Compiler'
44 | $(MKDIR_P) $(OBJS_DIR)
45 | $(CC) -O0 -g3 -Wall -c -fmessage-length=0 -o "$@" "$<" $(CFLAGS)
46 | @echo 'Finished building: $<'
47 | @echo ' '
48 |
49 | clean:
50 | $(RM_RF) obj *~ core .depend .*.cmd *.ko *.mod.c
51 | $(RM_RF) Module.markers modules.order
52 | $(RM_RF) .tmp_versions
53 | $(RM_RF) Modules.symvers
54 | $(RM_RF) bin
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pcie_debug
2 | Command line tool to Read/Write to PCIe BARx memory space
3 |
4 | # Command file structure
5 |
6 | The option -f allow to provide a commands file to pci_debug. The commands file will be executed before give you the hand on the PCI> prompt (if -q option is not).
7 | first line => Must be the BAR concerned by the command file. Must be compliant with the -b option
8 | Other lines => Commands
9 |
10 | Example in a file put:
11 | ```sh
12 | bar2
13 | c32 0 A5
14 | c32 14 196E
15 | c32 8 AAB565
16 | ```
17 | The -q option allows to quit pci_debug after the execution of the command file. This option allows you to chain several command files in a bash script for example.
18 |
19 | Example:
20 |
21 | #!/bin/sh
22 |
23 | #bar 1 configure usart
24 | echo "bar1" > /tmp/cmd
25 | echo "c32 0 40" >> /tmp/cmd
26 | echo "c32 4 196E" >> /tmp/cmd
27 | echo "c32 8 196E" >> /tmp/cmd
28 | echo "c32 18 8004" >> /tmp/cmd
29 | pci_debug -s 01:00.0 -b 1 -f /tmp/cmd -q -v 1
30 |
31 | #bar 0 read conf irq
32 | echo "bar0" > /tmp/cmd
33 | echo "d32 40 1" >> /tmp/cmd
34 | echo "d32 50 1" >> /tmp/cmd
35 | echo "d32 60 1" >> /tmp/cmd
36 | pci_debug -s 01:00.0 -b 0 -f /tmp/cmd -q -v 0
37 |
38 | #bar 1 start to send words
39 | echo "bar1" > /tmp/cmd
40 | echo "c32 14 AA" >> /tmp/cmd
41 | echo "c32 14 BB" >> /tmp/cmd
42 | echo "c32 14 CC" >> /tmp/cmd
43 | echo "c32 14 DD" >> /tmp/cmd
44 | pci_debug -s 01:00.0 -b 1 -f /tmp/cmd -q -v 1
45 |
46 | #bar 1 start to read words (not very optim but it's for debug)
47 | echo "bar1" > /tmp/cmd
48 | echo "d32 14 1" >> /tmp/cmd
49 | for i in {1. .4}
50 | do
51 | pci_debug -s 01:00.0 -b 1 -f /tmp/cmd -q -v 0
52 | done
53 |
54 | #take the hand on bar 1
55 | pci_debug -s 01:00.0 -b 1
56 |
57 | output:
58 | ```sh
59 | Accessing BAR1
60 | Send: c32 0 40
61 | Send: c32 4 196E
62 | Send: c32 8 196E
63 | Send: c32 18 8004
64 |
65 | Accessing BAR0
66 |
67 | 00000040: 00000001
68 |
69 |
70 | 00000050: 0000FFFF
71 |
72 |
73 | 00000060: 00000004
74 |
75 |
76 | Accessing BAR1
77 | Send: c32 14 AA
78 | Send: c32 14 BB
79 | Send: c32 14 CC
80 | Send: c32 14 DD
81 |
82 | 00000014: 000000CC
83 |
84 |
85 | PCI debug
86 | ---------
87 |
88 | - accessing BAR1
89 | - region size is 1048576-bytes
90 | - offset into region is 0-bytes
91 |
92 | ? Help
93 | d[width] addr len Display memory starting from addr
94 | [width]
95 | 8 - 8-bit access
96 | 16 - 16-bit access
97 | 32 - 32-bit access (default)
98 | c[width] addr val Change memory at addr to val
99 | e Print the endian access mode
100 | e[mode] Change the endian access mode
101 | [mode]
102 | b - big-endian (default)
103 | l - little-endian
104 | f[width] addr val len inc Fill memory
105 | addr - start address
106 | val - start value
107 | len - length (in bytes)
108 | inc - increment (defaults to 1)
109 | q Quit
110 |
111 | Notes:
112 | 1. addr, len, and val are interpreted as hex values
113 | addresses are always byte based
114 |
115 | PCI>
116 |
117 | ```
118 |
119 | # Links
120 |
121 | This tool is derived from D. W. Hawkins (dwh@ovro.caltech.edu). The original
122 | sources can be found on [altera forum](http://www.alteraforum.com/forum/showthread.php?t=35678).
123 |
124 |
--------------------------------------------------------------------------------
/pci_debug.c:
--------------------------------------------------------------------------------
1 | /* pci_debug.c
2 | *
3 | * Update version:2025/01/24 Release v1.0
4 | * Add version option
5 | *
6 | * Update version:2021/06/21 Léo Dumez leo.dumez@outlook.com
7 | * Add commands file support.
8 | * Add verbosity level:
9 | * - 0: only error and warning
10 | * - 1: 0 + the current BAR
11 | * - 2: 1 + the sent command
12 | * - 3: Everything
13 | *
14 | * First version :2010/06/21 D. W. Hawkins
15 | *
16 | * PCI debug registers interface.
17 | *
18 | * This tool provides a debug interface for reading and writing
19 | * to PCI registers via the device base address registers (BARs).
20 | * The tool uses the PCI resource nodes automatically created
21 | * by recently Linux kernels.
22 | *
23 | * The readline library is used for the command line interface
24 | * so that up-arrow command recall works. Command-line history
25 | * is not implemented. Use -lreadline -lcurses when building.
26 | *
27 | * ----------------------------------------------------------------
28 | */
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 |
42 | /* Readline support */
43 | #include
44 | #include
45 |
46 |
47 | int quit = 0;
48 | int verbosity = 3;
49 |
50 | #define VERSION "v1.0"
51 |
52 | /* PCI device */
53 | typedef struct {
54 | /* Base address region */
55 | unsigned int bar;
56 |
57 | /* Slot info */
58 | unsigned int domain;
59 | unsigned int bus;
60 | unsigned int slot;
61 | unsigned int function;
62 |
63 | /* Resource filename */
64 | char filename[100];
65 |
66 | /* File descriptor of the resource */
67 | int fd;
68 |
69 | /* Memory mapped resource */
70 | unsigned char *maddr;
71 | unsigned int size;
72 | unsigned int offset;
73 |
74 | /* PCI physical address */
75 | unsigned int phys;
76 |
77 | /* Address to pass to read/write (includes offset) */
78 | unsigned char *addr;
79 | } device_t;
80 |
81 | void display_help(device_t *dev);
82 | void parse_command(device_t *dev, char* cmdFilePath);
83 | int process_command(device_t *dev, char *cmd);
84 | int change_mem(device_t *dev, char *cmd);
85 | void useCmdFile(device_t *dev, char* cmdFilePath);
86 | int fill_mem(device_t *dev, char *cmd);
87 | int display_mem(device_t *dev, char *cmd);
88 | int change_endian(device_t *dev, char *cmd);
89 |
90 | /* Endian read/write mode */
91 | static int big_endian = 0;
92 |
93 | /* Low-level access functions */
94 | static void
95 | write_8(
96 | device_t *dev,
97 | unsigned int addr,
98 | unsigned char data);
99 |
100 | static unsigned char
101 | read_8(
102 | device_t *dev,
103 | unsigned int addr);
104 |
105 | static void
106 | write_le16(
107 | device_t *dev,
108 | unsigned int addr,
109 | unsigned short int data);
110 |
111 | static unsigned short int
112 | read_le16(
113 | device_t *dev,
114 | unsigned int addr);
115 |
116 | static void
117 | write_be16(
118 | device_t *dev,
119 | unsigned int addr,
120 | unsigned short int data);
121 |
122 | static unsigned short int
123 | read_be16(
124 | device_t *dev,
125 | unsigned int addr);
126 |
127 | static void
128 | write_le32(
129 | device_t *dev,
130 | unsigned int addr,
131 | unsigned int data);
132 |
133 | static unsigned int
134 | read_le32(
135 | device_t *dev,
136 | unsigned int addr);
137 |
138 | static void
139 | write_be32(
140 | device_t *dev,
141 | unsigned int addr,
142 | unsigned int data);
143 |
144 | static unsigned int
145 | read_be32(
146 | device_t *dev,
147 | unsigned int addr);
148 |
149 | /* Usage */
150 | static void show_usage()
151 | {
152 | printf("\nUsage: pci_debug -s \n"\
153 | " -h Help (this message)\n"\
154 | " -V display version\n"\
155 | " -s Slot/device (as per lspci)\n" \
156 | " -b Base address region (BAR) to access, eg. 0 for BAR0\n" \
157 | " -q Quit after send a command file\n" \
158 | " -v Verbosity (0 to 3 - Default is 3)\n" \
159 | " -f Use commands file to play before display prompt\n\n");
160 | }
161 |
162 | int main(int argc, char *argv[])
163 | {
164 | int opt;
165 | char *slot = NULL;
166 | char *cmdFilePath = NULL;
167 | int status;
168 | struct stat statbuf;
169 | device_t device;
170 | device_t *dev = &device;
171 |
172 | /* Clear the structure fields */
173 | memset(dev, 0, sizeof(device_t));
174 |
175 | while ((opt = getopt(argc, argv, "b:hs:f:qv:V")) != -1) {
176 | switch (opt) {
177 | case 'b':
178 | /* Defaults to BAR0 if not provided */
179 | dev->bar = atoi(optarg);
180 | break;
181 | case 'V':
182 | printf("pci_debug %s\n", VERSION);
183 | return -1;
184 | case 'h':
185 | show_usage();
186 | return -1;
187 | case 'q':
188 | quit = 1;
189 | break;
190 | case 'v':
191 | verbosity = atoi(optarg);
192 | break;
193 | case 's':
194 | slot = optarg;
195 | break;
196 | case 'f':
197 | cmdFilePath = optarg;
198 | break;
199 | default:
200 | show_usage();
201 | return -1;
202 | }
203 | }
204 | if (slot == 0) {
205 | show_usage();
206 | return -1;
207 | }
208 |
209 | /* ------------------------------------------------------------
210 | * Open and map the PCI region
211 | * ------------------------------------------------------------
212 | */
213 |
214 | /* Extract the PCI parameters from the slot string */
215 | status = sscanf(slot, "%2x:%2x.%1x",
216 | &dev->bus, &dev->slot, &dev->function);
217 | if (status != 3) {
218 | printf("Error parsing slot information!\n");
219 | show_usage();
220 | return -1;
221 | }
222 |
223 | /* Convert to a sysfs resource filename and open the resource */
224 | snprintf(dev->filename, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/resource%d",
225 | dev->domain, dev->bus, dev->slot, dev->function, dev->bar);
226 | dev->fd = open(dev->filename, O_RDWR | O_SYNC);
227 | if (dev->fd < 0) {
228 | printf("Open failed for file '%s': errno %d, %s\n",
229 | dev->filename, errno, strerror(errno));
230 | return -1;
231 | }
232 |
233 | /* PCI memory size */
234 | status = fstat(dev->fd, &statbuf);
235 | if (status < 0) {
236 | printf("fstat() failed: errno %d, %s\n",
237 | errno, strerror(errno));
238 | return -1;
239 | }
240 | dev->size = statbuf.st_size;
241 |
242 | /* Map */
243 | dev->maddr = (unsigned char *)mmap(
244 | NULL,
245 | (size_t)(dev->size),
246 | PROT_READ|PROT_WRITE,
247 | MAP_SHARED,
248 | dev->fd,
249 | 0);
250 | if (dev->maddr == (unsigned char *)MAP_FAILED) {
251 | // printf("failed (mmap returned MAP_FAILED)\n");
252 | printf("BARs that are I/O ports are not supported by this tool\n");
253 | dev->maddr = 0;
254 | close(dev->fd);
255 | return -1;
256 | }
257 |
258 | /* Device regions smaller than a 4k page in size can be offset
259 | * relative to the mapped base address. The offset is
260 | * the physical address modulo 4k
261 | */
262 | {
263 | char configname[100];
264 | int fd;
265 |
266 | snprintf(configname, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/config",
267 | dev->domain, dev->bus, dev->slot, dev->function);
268 | fd = open(configname, O_RDWR | O_SYNC);
269 | if (dev->fd < 0) {
270 | printf("Open failed for file '%s': errno %d, %s\n",
271 | configname, errno, strerror(errno));
272 | return -1;
273 | }
274 |
275 | status = lseek(fd, 0x10 + 4*dev->bar, SEEK_SET);
276 | if (status < 0) {
277 | printf("Error: configuration space lseek failed\n");
278 | close(fd);
279 | return -1;
280 | }
281 | status = read(fd, &dev->phys, 4);
282 | if (status < 0) {
283 | printf("Error: configuration space read failed\n");
284 | close(fd);
285 | return -1;
286 | }
287 | dev->offset = ((dev->phys & 0xFFFFFFF0) % 0x1000);
288 | dev->addr = dev->maddr + dev->offset;
289 | close(fd);
290 | }
291 |
292 |
293 | /* ------------------------------------------------------------
294 | * Tests
295 | * ------------------------------------------------------------
296 | */
297 | if (verbosity >= 3)
298 | {
299 | printf("\n");
300 | printf("PCI debug\n");
301 | printf("---------\n\n");
302 | printf(" - accessing BAR%d\n", dev->bar);
303 | printf(" - region size is %d-bytes\n", dev->size);
304 | printf(" - offset into region is %d-bytes\n", dev->offset);
305 |
306 | /* Display help */
307 | display_help(dev);
308 | }
309 |
310 | verbosity==1?printf("\nAccessing BAR%d\n", dev->bar):0;
311 |
312 | /* Process commands */
313 | parse_command(dev, cmdFilePath);
314 |
315 | /* Cleanly shutdown */
316 | munmap(dev->maddr, dev->size);
317 | close(dev->fd);
318 | return 0;
319 | }
320 |
321 | void useCmdFile(device_t *dev, char* cmdFilePath)
322 | {
323 |
324 | FILE * fp;
325 | char * line = NULL;
326 | size_t len = 0;
327 | int status;
328 | int firstLine = 1;
329 | int bar = -1;
330 | ssize_t read;
331 |
332 | verbosity>=3?printf("Exectue a commands file\n"):0;
333 |
334 | fp = fopen(cmdFilePath, "r");
335 | if (fp == NULL)
336 | {
337 | printf("Can not open the commands file\n");
338 | exit(EXIT_FAILURE);
339 | }
340 |
341 | while ((read = getline(&line, &len, fp)) != -1) {
342 | len = strlen(line);
343 | if(len > 1)
344 | {
345 |
346 | if (firstLine == 1)
347 | {
348 | sscanf(line, "bar%d", &bar);
349 | if(dev->bar != bar)
350 | {
351 | printf("Warning: BAR is no compliant with the command file (Expected: %d - Found: %d)\n", dev->bar, bar);
352 | break;
353 | }
354 | firstLine = 0;
355 | }else{
356 | verbosity>=2?printf("Send: %s (%ld)", line, len):0;
357 | status = process_command(dev, line);
358 | if (status < 0) {
359 | printf("Warning: Command failure - %s", line);
360 | }
361 | }
362 |
363 | }
364 | }
365 |
366 | fclose(fp);
367 | if (line)
368 | free(line);
369 | }
370 |
371 |
372 |
373 | void
374 | parse_command(
375 | device_t *dev, char* cmdFilePath)
376 | {
377 | char *line;
378 | int len;
379 | int status;
380 | if (cmdFilePath != NULL)
381 | useCmdFile(dev, cmdFilePath);
382 |
383 | if(quit) return;
384 |
385 | while(1) {
386 | line = readline("PCI> ");
387 | /* Ctrl-D check */
388 | if (line == NULL) {
389 | printf("\n");
390 | continue;
391 | }
392 | /* Empty line check */
393 | len = strlen(line);
394 | if (len == 0) {
395 | continue;
396 | }
397 | /* Process the line */
398 | status = process_command(dev, line);
399 | if (status < 0) {
400 | break;
401 | }
402 |
403 | /* Add it to the history */
404 | add_history(line);
405 | free(line);
406 | }
407 | return;
408 | }
409 |
410 | /*--------------------------------------------------------------------
411 | * User interface
412 | *--------------------------------------------------------------------
413 | */
414 | void
415 | display_help(
416 | device_t *dev)
417 | {
418 | printf("\n");
419 | printf(" ? Help\n");
420 | printf(" d[width] addr len Display memory starting from addr\n");
421 | printf(" [width]\n");
422 | printf(" 8 - 8-bit access\n");
423 | printf(" 16 - 16-bit access\n");
424 | printf(" 32 - 32-bit access (default)\n");
425 | printf(" c[width] addr val Change memory at addr to val\n");
426 | printf(" e Print the endian access mode\n");
427 | printf(" e[mode] Change the endian access mode\n");
428 | printf(" [mode]\n");
429 | printf(" b - big-endian (default)\n");
430 | printf(" l - little-endian\n");
431 | printf(" f[width] addr val len inc Fill memory\n");
432 | printf(" addr - start address\n");
433 | printf(" val - start value\n");
434 | printf(" len - length (in bytes)\n");
435 | printf(" inc - increment (defaults to 1)\n");
436 | printf(" q Quit\n");
437 | printf("\n Notes:\n");
438 | printf(" 1. addr, len, and val are interpreted as hex values\n");
439 | printf(" addresses are always byte based\n");
440 | printf("\n");
441 | }
442 |
443 | int process_command(device_t *dev, char *cmd)
444 | {
445 | if (cmd[0] == '\0') {
446 | return 0;
447 | }
448 | switch (cmd[0]) {
449 | case '?':
450 | display_help(dev);
451 | break;
452 | case 'c':
453 | case 'C':
454 | return change_mem(dev, cmd);
455 | case 'd':
456 | case 'D':
457 | return display_mem(dev, cmd);
458 | case 'e':
459 | case 'E':
460 | return change_endian(dev, cmd);
461 | case 'f':
462 | case 'F':
463 | return fill_mem(dev, cmd);
464 | case 'q':
465 | case 'Q':
466 | return -1;
467 | default:
468 | break;
469 | }
470 | return 0;
471 | }
472 |
473 | int display_mem(device_t *dev, char *cmd)
474 | {
475 | int width = 32;
476 | int addr = 0;
477 | int len = 0;
478 | int status;
479 | int i;
480 | unsigned char d8;
481 | unsigned short d16;
482 | unsigned int d32;
483 |
484 | /* d, d8, d16, d32 */
485 | if (cmd[1] == ' ') {
486 | status = sscanf(cmd, "%*c %x %x", &addr, &len);
487 | if (status != 2) {
488 | printf("Syntax error (use ? for help)\n");
489 | /* Don't break out of command processing loop */
490 | return 0;
491 | }
492 | } else {
493 | status = sscanf(cmd, "%*c%d %x %x", &width, &addr, &len);
494 | if (status != 3) {
495 | printf("Syntax error (use ? for help)\n");
496 | /* Don't break out of command processing loop */
497 | return 0;
498 | }
499 | }
500 | if (addr > dev->size) {
501 | printf("Error: invalid address (maximum allowed is %.8X\n", dev->size);
502 | return 0;
503 | }
504 | /* Length is in bytes */
505 | if ((addr + len) > dev->size) {
506 | /* Truncate */
507 | len = dev->size;
508 | }
509 | switch (width) {
510 | case 8:
511 | for (i = 0; i < len; i++) {
512 | if ((i%16) == 0) {
513 | printf("\n%.8X: ", addr+i);
514 | }
515 | d8 = read_8(dev, addr+i);
516 | printf("%.2X ", d8);
517 | }
518 | printf("\n");
519 | break;
520 | case 16:
521 | for (i = 0; i < len; i+=2) {
522 | if ((i%16) == 0) {
523 | printf("\n%.8X: ", addr+i);
524 | }
525 | if (big_endian == 0) {
526 | d16 = read_le16(dev, addr+i);
527 | } else {
528 | d16 = read_be16(dev, addr+i);
529 | }
530 | printf("%.4X ", d16);
531 | }
532 | printf("\n");
533 | break;
534 | case 32:
535 | for (i = 0; i < len; i+=4) {
536 | if ((i%16) == 0) {
537 | printf("\n%.8X: ", addr+i);
538 | }
539 | if (big_endian == 0) {
540 | d32 = read_le32(dev, addr+i);
541 | } else {
542 | d32 = read_be32(dev, addr+i);
543 | }
544 | printf("%.8X ", d32);
545 | }
546 | printf("\n");
547 | break;
548 | default:
549 | printf("Syntax error (use ? for help)\n");
550 | /* Don't break out of command processing loop */
551 | break;
552 | }
553 | printf("\n");
554 | return 0;
555 | }
556 |
557 | int change_mem(device_t *dev, char *cmd)
558 | {
559 | int width = 32;
560 | int addr = 0;
561 | int status;
562 | unsigned char d8;
563 | unsigned short d16;
564 | unsigned int d32;
565 |
566 | /* c, c8, c16, c32 */
567 | if (cmd[1] == ' ') {
568 | status = sscanf(cmd, "%*c %x %x", &addr, &d32);
569 | if (status != 2) {
570 | printf("Syntax error (use ? for help)\n");
571 | /* Don't break out of command processing loop */
572 | return 0;
573 | }
574 | } else {
575 | status = sscanf(cmd, "%*c%d %x %x", &width, &addr, &d32);
576 | if (status != 3) {
577 | printf("Syntax error (use ? for help)\n");
578 | /* Don't break out of command processing loop */
579 | return 0;
580 | }
581 | }
582 | if (addr > dev->size) {
583 | printf("Error: invalid address (maximum allowed is %.8X\n", dev->size);
584 | return 0;
585 | }
586 | switch (width) {
587 | case 8:
588 | d8 = (unsigned char)d32;
589 | write_8(dev, addr, d8);
590 | break;
591 | case 16:
592 | d16 = (unsigned short)d32;
593 | if (big_endian == 0) {
594 | write_le16(dev, addr, d16);
595 | } else {
596 | write_be16(dev, addr, d16);
597 | }
598 | break;
599 | case 32:
600 | if (big_endian == 0) {
601 | write_le32(dev, addr, d32);
602 | } else {
603 | write_be32(dev, addr, d32);
604 | }
605 | break;
606 | default:
607 | printf("Syntax error (use ? for help)\n");
608 | /* Don't break out of command processing loop */
609 | break;
610 | }
611 | return 0;
612 | }
613 |
614 | int fill_mem(device_t *dev, char *cmd)
615 | {
616 | int width = 32;
617 | int addr = 0;
618 | int len = 0;
619 | int inc = 0;
620 | int status;
621 | int i;
622 | unsigned char d8;
623 | unsigned short d16;
624 | unsigned int d32;
625 |
626 | /* c, c8, c16, c32 */
627 | if (cmd[1] == ' ') {
628 | status = sscanf(cmd, "%*c %x %x %x %x", &addr, &d32, &len, &inc);
629 | if ((status != 3) && (status != 4)) {
630 | printf("Syntax error (use ? for help)\n");
631 | /* Don't break out of command processing loop */
632 | return 0;
633 | }
634 | if (status == 3) {
635 | inc = 1;
636 | }
637 | } else {
638 | status = sscanf(cmd, "%*c%d %x %x %x %x", &width, &addr, &d32, &len, &inc);
639 | if ((status != 4) && (status != 5)) {
640 | printf("Syntax error (use ? for help)\n");
641 | /* Don't break out of command processing loop */
642 | return 0;
643 | }
644 | if (status == 4) {
645 | inc = 1;
646 | }
647 | }
648 | if (addr > dev->size) {
649 | printf("Error: invalid address (maximum allowed is %.8X\n", dev->size);
650 | return 0;
651 | }
652 | /* Length is in bytes */
653 | if ((addr + len) > dev->size) {
654 | /* Truncate */
655 | len = dev->size;
656 | }
657 | switch (width) {
658 | case 8:
659 | for (i = 0; i < len; i++) {
660 | d8 = (unsigned char)(d32 + i*inc);
661 | write_8(dev, addr+i, d8);
662 | }
663 | break;
664 | case 16:
665 | for (i = 0; i < len/2; i++) {
666 | d16 = (unsigned short)(d32 + i*inc);
667 | if (big_endian == 0) {
668 | write_le16(dev, addr+2*i, d16);
669 | } else {
670 | write_be16(dev, addr+2*i, d16);
671 | }
672 | }
673 | break;
674 | case 32:
675 | for (i = 0; i < len/4; i++) {
676 | if (big_endian == 0) {
677 | write_le32(dev, addr+4*i, d32 + i*inc);
678 | } else {
679 | write_be32(dev, addr+4*i, d32 + i*inc);
680 | }
681 | }
682 | break;
683 | default:
684 | printf("Syntax error (use ? for help)\n");
685 | /* Don't break out of command processing loop */
686 | break;
687 | }
688 | return 0;
689 | }
690 |
691 | int change_endian(device_t *dev, char *cmd)
692 | {
693 | char endian = 0;
694 | int status;
695 |
696 | /* e, el, eb */
697 | status = sscanf(cmd, "%*c%c", &endian);
698 | if (status < 0) {
699 | /* Display the current setting */
700 | if (big_endian == 0) {
701 | printf("Endian mode: little-endian\n");
702 | } else {
703 | printf("Endian mode: big-endian\n");
704 | }
705 | return 0;
706 | } else if (status == 1) {
707 | switch (endian) {
708 | case 'b':
709 | big_endian = 1;
710 | break;
711 | case 'l':
712 | big_endian = 0;
713 | break;
714 | default:
715 | printf("Syntax error (use ? for help)\n");
716 | /* Don't break out of command processing loop */
717 | break;
718 | }
719 | } else {
720 | printf("Syntax error (use ? for help)\n");
721 | /* Don't break out of command processing loop */
722 | }
723 | return 0;
724 | }
725 |
726 | /* ----------------------------------------------------------------
727 | * Raw pointer read/write access
728 | * ----------------------------------------------------------------
729 | */
730 | static void
731 | write_8(
732 | device_t *dev,
733 | unsigned int addr,
734 | unsigned char data)
735 | {
736 | *(volatile unsigned char *)(dev->addr + addr) = data;
737 | msync((void *)(dev->addr + addr), 1, MS_SYNC | MS_INVALIDATE);
738 | }
739 |
740 | static unsigned char
741 | read_8(
742 | device_t *dev,
743 | unsigned int addr)
744 | {
745 | return *(volatile unsigned char *)(dev->addr + addr);
746 | }
747 |
748 | static void
749 | write_le16(
750 | device_t *dev,
751 | unsigned int addr,
752 | unsigned short int data)
753 | {
754 | if (__BYTE_ORDER != __LITTLE_ENDIAN) {
755 | data = bswap_16(data);
756 | }
757 | *(volatile unsigned short int *)(dev->addr + addr) = data;
758 | msync((void *)(dev->addr + addr), 2, MS_SYNC | MS_INVALIDATE);
759 | }
760 |
761 | static unsigned short int
762 | read_le16(
763 | device_t *dev,
764 | unsigned int addr)
765 | {
766 | unsigned int data = *(volatile unsigned short int *)(dev->addr + addr);
767 | if (__BYTE_ORDER != __LITTLE_ENDIAN) {
768 | data = bswap_16(data);
769 | }
770 | return data;
771 | }
772 |
773 | static void
774 | write_be16(
775 | device_t *dev,
776 | unsigned int addr,
777 | unsigned short int data)
778 | {
779 | if (__BYTE_ORDER == __LITTLE_ENDIAN) {
780 | data = bswap_16(data);
781 | }
782 | *(volatile unsigned short int *)(dev->addr + addr) = data;
783 | msync((void *)(dev->addr + addr), 2, MS_SYNC | MS_INVALIDATE);
784 | }
785 |
786 | static unsigned short int
787 | read_be16(
788 | device_t *dev,
789 | unsigned int addr)
790 | {
791 | unsigned int data = *(volatile unsigned short int *)(dev->addr + addr);
792 | if (__BYTE_ORDER == __LITTLE_ENDIAN) {
793 | data = bswap_16(data);
794 | }
795 | return data;
796 | }
797 |
798 | static void
799 | write_le32(
800 | device_t *dev,
801 | unsigned int addr,
802 | unsigned int data)
803 | {
804 | if (__BYTE_ORDER != __LITTLE_ENDIAN) {
805 | data = bswap_32(data);
806 | }
807 | *(volatile unsigned int *)(dev->addr + addr) = data;
808 | msync((void *)(dev->addr + addr), 4, MS_SYNC | MS_INVALIDATE);
809 | }
810 |
811 | static unsigned int
812 | read_le32(
813 | device_t *dev,
814 | unsigned int addr)
815 | {
816 | unsigned int data = *(volatile unsigned int *)(dev->addr + addr);
817 | if (__BYTE_ORDER != __LITTLE_ENDIAN) {
818 | data = bswap_32(data);
819 | }
820 | return data;
821 | }
822 |
823 | static void
824 | write_be32(
825 | device_t *dev,
826 | unsigned int addr,
827 | unsigned int data)
828 | {
829 | if (__BYTE_ORDER == __LITTLE_ENDIAN) {
830 | data = bswap_32(data);
831 | }
832 | *(volatile unsigned int *)(dev->addr + addr) = data;
833 | msync((void *)(dev->addr + addr), 4, MS_SYNC | MS_INVALIDATE);
834 | }
835 |
836 | static unsigned int
837 | read_be32(
838 | device_t *dev,
839 | unsigned int addr)
840 | {
841 | unsigned int data = *(volatile unsigned int *)(dev->addr + addr);
842 | if (__BYTE_ORDER == __LITTLE_ENDIAN) {
843 | data = bswap_32(data);
844 | }
845 | return data;
846 | }
847 |
848 |
--------------------------------------------------------------------------------