Bar
SpaceWire UK
Specialist providers of VHDL Intellectual Property & Design Services
BarBarBarBar
Tutorial
Missing Image!
Part 17 - Create Peek & Poke CGI binaries to access Programmable Logic address space (28 November 2021)

Introduction

This tutorial details the steps required to create and install peek & poke CGI binary applications to be used with the website. The C source from the previously installed binary peek & poke applications will be used as a starting point along with extra code to make CGI possible. The end result will be a peek & poke CGI binary.

Aims

The aims of this tutorial are as follows :-
  1. Setup environment
  2. Change present working directory
  3. Create C application
  4. Copy previous peek & poke application
  5. Edit C application
  6. Modify BitBake recipe
  7. Build, package & deploy project on Zedboard
  8. Check application is working

1. Setup environment

Setup Xilinx design environment for the 2021.2 toolset.
steve@Linux-Steve:/home/steve$ source xilinx.sh
Xilinx tools available tools at /opt/Xilinx :-
1) 2021.2 - Vivado - SDK - Vitis - PetaLinux
0) Exit
Please select tools required or exit : 1

Tools are as follows :-
vivado @ /opt/Xilinx/Vivado/2021.2/bin/vivado
vitis @ /opt/Xilinx/Vitis/2021.2/bin/vitis
petalinux-build @ /opt/Xilinx/PetaLinux/2021.2/tool/tools/common/petalinux/bin/petalinux-build

2. Change present working directory

Change the present working directory to be the project directory.
steve@Linux-Steve:/home/steve$ cd /home/steve/projects/petalinux

3. Create C application

Create a new auto-enabled C application.
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-create --type apps --template c --name peekpokecgi --enable
Examine the file structure of the newly created C application.
steve@Linux-Steve:/home/steve/projects/petalinux$ tree project-spec/meta-user/recipes-apps/peekpokecgi
project-spec/meta-user/recipes-apps/peekpokecgi
├── files
│   ├── Makefile
│   └── peekpokecgi.c
├── peekpokecgi.bb
└── README

1 directory, 4 files

4. Copy previous peek & poke application

Copy the sources from the previously installed peek & poke application and remove the unrequired files.
steve@Linux-Steve:/home/steve/projects/petalinux$ cp project-spec/meta-user/recipes-apps/peekpoke/files/{Makefile,peek.c,poke.c} project-spec/meta-user/recipes-apps/peekpokecgi/files
steve@Linux-Steve:/home/steve/projects/petalinux$ cp project-spec/meta-user/recipes-apps/peekpoke/peekpoke.bb project-spec/meta-user/recipes-apps/peekpokecgi/peekpokecgi.bb
steve@Linux-Steve:/home/steve/projects/petalinux$ rm project-spec/meta-user/recipes-apps/peekpokecgi/files/peekpokecgi.c

5. Edit C application

Examine the source for peek & poke to gain an understanding of what they are doing. Edit the sources to remove unnecessary code, include CGI specific code and provide status & verbose error reporting back to the client application.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/peekpokecgi/files/{peek.c,poke.c}

peek.c

  1. //
  2. // File .......... peek.c
  3. // Author ........ Steve Haywood
  4. // Version ....... 1.0
  5. // Date .......... 26 Novemebr 2021
  6. // Description ...
  7. //   Very simple CGI peek application for single 32-bit reads. Provides
  8. // status & error reporting back to the client side application.
  9. //

  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <sys/mman.h>
  14. #include <fcntl.h>

  15. int main()
  16. {
  17.   char *querystring;
  18.   char *paddr;
  19.   char *pval;
  20.   int fd;
  21.   void *ptr;
  22.   unsigned addr, page_addr, page_offset;
  23.   unsigned page_size = sysconf(_SC_PAGESIZE);
  24.   printf("Content-Type: text/plain;charset=us-ascii\n\n");
  25.   querystring = getenv("QUERY_STRING");
  26.   if (querystring) {
  27.     pval = querystring;
  28.     if (paddr = strtok_r(pval, "&", &pval)) {
  29. //      if (pval) {
  30.         fd = open("/dev/mem", O_RDWR);
  31.         if (fd > 0) {
  32.           addr = strtoul(paddr, NULL, 0);
  33.           page_addr = (addr & ~(page_size - 1));
  34.           page_offset = addr - page_addr;
  35.           ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);
  36.           if (ptr != MAP_FAILED) {
  37.             printf("0x%08X",*((unsigned *)(ptr + page_offset)));
  38.           } else printf("Error: Failed to mmap");
  39.         } else printf("Error: Failed to open /dev/mem");
  40. //      } else printf("Error: Data not found");
  41.     } else printf("Error: Address not found");
  42.   } else printf("Error: No QUERY_STRING");
  43. }

poke.c

  1. //
  2. // File .......... poke.c
  3. // Author ........ Steve Haywood
  4. // Version ....... 1.0
  5. // Date .......... 26 Novemebr 2021
  6. // Description ...
  7. //   Very simple CGI poke application for single 32-bit writes. Provides
  8. // status & error reporting back to the client side application.
  9. //

  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <sys/mman.h>
  14. #include <fcntl.h>

  15. int main()
  16. {
  17.   char *querystring;
  18.   char *paddr;
  19.   char *pval;
  20.   int fd;
  21.   void *ptr;
  22.   unsigned val;
  23.   unsigned addr, page_addr, page_offset;
  24.   unsigned page_size = sysconf(_SC_PAGESIZE);
  25.   printf("Content-Type: text/plain;charset=us-ascii\n\n");
  26.   querystring = getenv("QUERY_STRING");
  27.   if (querystring) {
  28.     pval = querystring;
  29.     if (paddr = strtok_r(pval, "&", &pval)) {
  30.       if (pval) {
  31.         fd = open("/dev/mem", O_RDWR);
  32.         if (fd > 0) {
  33.           addr = strtoul(paddr, NULL, 0);
  34.           val = strtoul(pval, NULL, 0);
  35.           page_addr = (addr & ~(page_size - 1));
  36.           page_offset = addr - page_addr;
  37.           ptr = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr);
  38.           if (ptr != MAP_FAILED) {
  39.             *((unsigned *)(ptr + page_offset)) = val;
  40.             printf("Success");
  41.           } else printf("Error: Failed to mmap");
  42.         } else printf("Error: Failed to open /dev/mem");
  43.       } else printf("Error: Data not found");
  44.     } else printf("Error: Address not found");
  45.   } else printf("Error: No QUERY_STRING");
  46. }

6. Modify BitBake recipe

Modify the BitBake recipe to change the installation location of the peek & poke applications.
steve@Linux-Steve:/home/steve/projects/petalinux$ subl project-spec/meta-user/recipes-apps/peekpokecgi/peekpokecgi.bb

peekpokecgi.bb

  1. #
  2. # This is the peekpokecgi aplication recipe
  3. #
  4. #

  5. SUMMARY = "peekpokecgi application"
  6. SECTION = "PETALINUX/apps"
  7. LICENSE = "MIT"
  8. LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
  9. SRC_URI = "file://peek.c \
  10.            file://poke.c \
  11.            file://Makefile \
  12.           "
  13. FILES_${PN} += "/srv/www/cgi-bin"
  14. S = "${WORKDIR}"
  15. CFLAGS_prepend = "-I ${S}/include"
  16. do_compile() {
  17.         oe_runmake
  18. }
  19. do_install() {
  20.         install -d ${D}/srv/www/cgi-bin
  21.         install -m 0755 ${S}/peek ${D}/srv/www/cgi-bin
  22.         install -m 0755 ${S}/poke ${D}/srv/www/cgi-bin
  23. }


7. Build, package & deploy project on Zedboard

Rebuild the project to include the updated files, package it up ready for deployment, power cycle the Zedboard and deploy via JTAG.
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-build
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-package --prebuilt --force
steve@Linux-Steve:/home/steve/projects/petalinux$ petalinux-boot --jtag --prebuilt 3

8. Check application is working

Access the CGI application directly to test functionality by performing a write to the LED register and a read from the slide switch register.

Using the Client URL (curl) command enter the following URL to command the CGI script to write 0x0F to the LED register at 0x41200000.
steve@Linux-Steve:/home/steve/projects/petalinux$ curl -w "\nReceived %{size_download} bytes\n" "http://192.168.2.87/cgi-bin/poke?0x41200000&0x0F"
All being well LED's 0, 1, 2 & 3 should illuminate and the script should return the success message.
Success
Received 7 bytes
Again using curl enter the following URL to command the CGI script to read from the slide switch register at 0x41200008.
steve@Linux-Steve:/home/steve/projects/petalinux$ curl -w "\nReceived %{size_download} bytes\n" "http://192.168.2.87/cgi-bin/peek?0x41200008"
All being well the script should successfully return something akin to the following indicating which of the slide switches are in their on position, in this case switches 0 & 1.
0x00000003
Received 10 bytes