• 0
toastedcpu

led_blink segmentation fault in instructables Embedded Linux Tutorial Zybo

Question

Posted (edited)

Hello,

I am still working on  Embedded Linux Tutorial Zybo http://www.instructables.com/id/Embedded-Linux-Tutorial-Zybo/, and I get a segmentation fault on the C blink code where puts  is writing to the /proc/myled

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(){
	FILE *fp;
	while(1){
                 printf("open /proc/myled 1\n");
		fp = fopen("/proc/myled", "w");
		if (fp=NULL){
                   printf("cannot open /proc/myled for write\b");
                   return -1;
                }
                printf("fputs 0x0F\n");
                fputs("0x0F\n", fp);  //SEGMENTATION FAULT HAPPENS HERE
                printf("fclose 1\n");
                fclose(fp);
                sleep(1);  

In the myled driver I put some printk to see which functions get called. When using the blink.c, the proc_myled_write never even runs. 

 

When I interact with the driver without the C code using  echo "0x05\n" >> /proc/myled in the terminal, the proc_myled_write runsthere is no segmentation fault and the LEDs change state.

 zynq> echo "0x05\n" >> /proc/myled
proc_myled_open
proc_myled_open single_open
proc_myled_open end
proc_myled_write:
5

 

Here is the myled.c file:

#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>    /* Needed for copy_from_user */
#include <asm/io.h>         /* Needed for IO Read/Write Functions */
#include <linux/proc_fs.h>  /* Needed for Proc File System Functions */
#include <linux/seq_file.h> /* Needed for Sequence File Operations */
#include <linux/platform_device.h>  /* Needed for Platform Driver Functions */

#include<linux/slab.h>
/* Define Driver Name */
#define DRIVER_NAME "myled"
 

unsigned long *base_addr;   /* Vitual Base Address */
struct resource *res;       /* Device Resource Structure */
unsigned long remap_size;   /* Device Memory Size */
 
/* Write operation for /proc/myled
 * -----------------------------------
 *  When user cat a string to /proc/myled file, the string will be stored in
 *  const char __user *buf. This function will copy the string from user
 *  space into kernel space, and change it to an unsigned long value.
 *  It will then write the value to the register of myled controller,
 *  and turn on the corresponding LEDs eventually.
 */
 static ssize_t proc_myled_write(struct file *file, const char __user * buf,
                  size_t count, loff_t * ppos)
  {
      char myled_phrase[16];
      u32 myled_value;

      printk(KERN_INFO "proc_myled_write:");
 
      if (count < 11) {
          if (copy_from_user(myled_phrase, buf, count))
              return -EFAULT;
 
         myled_phrase[count] = '\0';
     }
 
     myled_value = simple_strtoul(myled_phrase, NULL, 0);

     printk(KERN_INFO "%i\n", myled_value);
     wmb();
     iowrite32(myled_value, base_addr);
     return count;
 }
 
 /* Callback function when opening file /proc/myled
  * ------------------------------------------------------
  *  Read the register value of myled controller, print the value to
  *  the sequence file struct seq_file *p. In file open operation for /proc/myled
  *  this callback function will be called first to fill up the seq_file,
  *  and seq_read function will print whatever in seq_file to the terminal.
  */
 static int proc_myled_show(struct seq_file *p, void *v)
 {
     printk(KERN_INFO "proc_myled_show\n");
     u32 myled_value;
     printk(KERN_INFO "proc_myled_show ioread32\n");
     myled_value = ioread32(base_addr);
     printk(KERN_INFO "proc_myled_show seq_printf\n");
     seq_printf(p, "0x%x", myled_value);
     return 0;
 }
 
 /* Open function for /proc/myled
   * ------------------------------------
   *  When user want to read /proc/myled (i.e. cat /proc/myled), the open function 
   *  will be called first. In the open function, a seq_file will be prepared and the 
   *  status of myled will be filled into the seq_file by proc_myled_show function.
   */
 static int proc_myled_open(struct inode *inode, struct file *file)
  {
      unsigned int size = 16;
      char *buf;
      struct seq_file *m;
      int res;

       printk(KERN_INFO "proc_myled_open\n");
      buf = (char *)kmalloc(size * sizeof(char), GFP_KERNEL);
      if (!buf)
          return -ENOMEM;

      printk(KERN_INFO "proc_myled_open single_open\n");
      res = single_open(file, proc_myled_show, NULL);
  
      if (!res) {
          m = file->private_data;
          m->buf = buf;
          m->size = size;
      } else {
          kfree(buf);
      }

      printk(KERN_INFO "proc_myled_open end\n");
      return res;
  }
  
  /* File Operations for /proc/myled */
  static const struct file_operations proc_myled_operations = {
      .open = proc_myled_open,
      .read = seq_read,
      .write = proc_myled_write,
      .llseek = seq_lseek,
      .release = single_release
  };
  
  /* Shutdown function for myled
   * -----------------------------------
   *  Before myled shutdown, turn-off all the leds
  */
 static void myled_shutdown(struct platform_device *pdev)
 {
    printk(KERN_INFO "myled_shutdown");
    iowrite32(0, base_addr);
 }
 
 /* Remove function for myled
  * ----------------------------------
  *  When myled module is removed, turn off all the leds first,
  *  release virtual address and the memory region requested.
  */
 static int myled_remove(struct platform_device *pdev)
 {
       printk(KERN_INFO "myled_remove");
     myled_shutdown(pdev);
 
     /* Remove /proc/myled entry */
     remove_proc_entry(DRIVER_NAME, NULL);
 
     /* Release mapped virtual address */
     iounmap(base_addr);
 
     /* Release the region */
     release_mem_region(res->start, remap_size);
 
     return 0;
 }
 
 /* Device Probe function for myled
  * ------------------------------------
  *  Get the resource structure from the information in device tree.
  *  request the memory regioon needed for the controller, and map it into
  *  kernel virtual memory space. Create an entry under /proc file system
  *  and register file operations for that entry.
  */
 static int myled_probe(struct platform_device *pdev)
 {
  printk(KERN_INFO "myled_probe\n");
     struct proc_dir_entry *myled_proc_entry;
     int ret = 0;
 
     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     if (!res) {
         dev_err(&pdev->dev, "No memory resource\n");
         return -ENODEV;
     }

 printk(KERN_INFO "myled_probe res->star 0x%08lxt\n", res->start );
     remap_size = res->end - res->start + 1;
     if (!request_mem_region(res->start, remap_size, pdev->name)) {
         dev_err(&pdev->dev, "Cannot request IO\n");
         return -ENXIO;
     }
 
     base_addr = ioremap(res->start, remap_size);
     if (base_addr == NULL) {
         dev_err(&pdev->dev, "Couldn't ioremap memory at 0x%08lx\n",
             (unsigned long)res->start);
         ret = -ENOMEM;
         goto err_release_region;
     }

     myled_proc_entry = proc_create(DRIVER_NAME, 0, NULL,
                        &proc_myled_operations);
     if (myled_proc_entry == NULL) {
         dev_err(&pdev->dev, "Couldn't create proc entry\n");
         ret = -ENOMEM;
         goto err_create_proc_entry;
     }
 
     printk(KERN_INFO DRIVER_NAME " probed at VA 0x%08lx\n",
            (unsigned long) base_addr);
 
     return 0;
 
  err_create_proc_entry:
     iounmap(base_addr);
  err_release_region:
     release_mem_region(res->start, remap_size);
 
     return ret;
 }
 
 /* device match table to match with device node in device tree */
 static const struct of_device_id myled_of_match[] = {
     {.compatible = "dglnt_myled-1.00.a"},
     {},
 };
 
 MODULE_DEVICE_TABLE(of, myled_of_match);
 
 /* platform driver structure for myled driver */
 static struct platform_driver myled_driver = {
     .driver = {
            .name = DRIVER_NAME,
            .owner = THIS_MODULE,
            .of_match_table = myled_of_match},
     .probe = myled_probe,
     .remove = myled_remove,
     .shutdown = myled_shutdown
};

 /* Register myled platform driver */
 module_platform_driver(myled_driver);

 /* Module Informations */
 MODULE_AUTHOR("Digilent, Inc.");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRIVER_NAME ": MYLED driver (Simple Version)");
 MODULE_ALIAS(DRIVER_NAME);

Any ideas?

Thanks,

Frank

Edited by toastedcpu
updated code

Share this post


Link to post
Share on other sites

5 answers to this question

Recommended Posts

  • 0

Hi @toastedcpu,

We have reached out to a more experienced embedded linux engineer about your thread. They should hopefully respond in the next few days.

thank you,

Jon

Share this post


Link to post
Share on other sites
  • 0

Hello @jpeyron,

Thanks. I will put together a comprehensive post covering my notes of little changes I needed in all the previous the steps of the tutorial to make work. These are due to packages that were not inside my Ubuntu distro, or changes on where to get certain files.

Frank

Share this post


Link to post
Share on other sites
  • 0
On 5/6/2018 at 9:03 AM, toastedcpu said:

if (fp=NULL)

whoopsies... :) 

You are assigning the handle to be NULL instead of checking if it is NULL.

Share this post


Link to post
Share on other sites
  • 0

Thanks!!! I made a terrible simplistic mistake. I searched too much in the wrong places. I should have just retyped the whole thing.

Frank

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

hello @toastedcpu,

Can you tell me which tool version you are using for this tutorial? I completed it long time ago and wanted to review it recently. However, it seems like I do no longer have that cross-compile part :( I am working on Vivado/SDK 2017.4. Back then it might have been 2017.2, I think.

It seems like arm-xilinx-linux-gnueabi is not installed on my machine:

console output:

PetaLinux environment set to '/opt/pkg/petalinux'
INFO: Checking free disk space
INFO: Checking installed tools
INFO: Checking installed development libraries
INFO: Checking network and other services
user@machine:~$ arm-
arm-linux-gnueabihf-addr2line   arm-none-eabi-addr2line
arm-linux-gnueabihf-ar          arm-none-eabi-ar
arm-linux-gnueabihf-as          arm-none-eabi-as
arm-linux-gnueabihf-c++         arm-none-eabi-c++
arm-linux-gnueabihf-c++filt     arm-none-eabi-c++filt
arm-linux-gnueabihf-cpp         arm-none-eabi-cpp
arm-linux-gnueabihf-elfedit     arm-none-eabi-elfedit
arm-linux-gnueabihf-g++         arm-none-eabi-g++
arm-linux-gnueabihf-gcc         arm-none-eabi-gcc
arm-linux-gnueabihf-gcc-6.2.1   arm-none-eabi-gcc-6.2.1
arm-linux-gnueabihf-gcc-ar      arm-none-eabi-gcc-ar
arm-linux-gnueabihf-gcc-nm      arm-none-eabi-gcc-nm
arm-linux-gnueabihf-gcc-ranlib  arm-none-eabi-gcc-ranlib
arm-linux-gnueabihf-gcov        arm-none-eabi-gcov
arm-linux-gnueabihf-gcov-tool   arm-none-eabi-gcov-tool
arm-linux-gnueabihf-gdb         arm-none-eabi-gdb
arm-linux-gnueabihf-gprof       arm-none-eabi-gprof
arm-linux-gnueabihf-ld          arm-none-eabi-ld
arm-linux-gnueabihf-ld.bfd      arm-none-eabi-ld.bfd
arm-linux-gnueabihf-nm          arm-none-eabi-nm
arm-linux-gnueabihf-objcopy     arm-none-eabi-objcopy
arm-linux-gnueabihf-objdump     arm-none-eabi-objdump
arm-linux-gnueabihf-ranlib      arm-none-eabi-ranlib
arm-linux-gnueabihf-readelf     arm-none-eabi-readelf
arm-linux-gnueabihf-size        arm-none-eabi-size
arm-linux-gnueabihf-strings     arm-none-eabi-strings
arm-linux-gnueabihf-strip       arm-none-eabi-strip

 

Also, please mark this thread as 'solved'.

Edited by theUltimateSource

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now