【问题标题】:Map size and mmap Invalid argument error地图大小和 mmap 无效参数错误
【发布时间】:2017-11-03 15:57:32
【问题描述】:

我正在尝试使用 mmap 访问我的 ARM (https://4donline.ihs.com/images/VipMasterIC/IC/ATML/ATML-S-A0001248554/ATML-S-A0001248554-1.pdf) 上的物理地址寄存器,但我不知道要放置多长。
例如,如果我有一个地址为 0xFFFFFCE8 的寄存器我可以在其中访问 32 位。
我应该在 mmap size_t 中输入什么?

谢谢你的帮助 !

编辑:
Herehere 我们可以看到他们输入了 4096,第一个是 SAM9,与我的几乎相同。
那么,他们为什么放 4096 呢?
也许是因为如果我放了:

#include <unistd.h>
long sz = sysconf(_SC_PAGESIZE);
printf("%ld",sz);

答案是 4096...

编辑 2:
基于 this post 我可以这样写:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>

#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define PIOD_START_ADDR                     0xFFFFFA00
#define PIOD_STOP_ADDR                      0xFFFFFC00
#define PIOD_SIZE                           (PIOD_STOP_ADDR-PIOD_START_ADDR)

#define PIO_WPMR_OFFSET                     0xE4    // PIO Write Protection Mode Register Bank D

#define PIO_PUER_OFFSET                     0x64    // PIO Pull-Up Enable Register Bank D
#define PIO_PUSR_OFFSET                     0x68    // PIO Pull-Up Status Register Bank D

#define LED7_ON                             0xFFDFFFFF  // LED7 Mask ON
#define LED7_OFF                            0xFFFFFFFF  // LED7 Mask OFF
#define DESABLE_WRITE_PROTECTION_BANK_D     0x50494F00  // Desable write protection

int main(void) {
    volatile void *gpio_D_addr;
    volatile unsigned int *gpio_pullup_enable_addr;
    volatile unsigned int *gpio_pullup_status_addr;
    volatile unsigned int *gpio_enable_write_addr;

    int fd = open("/dev/mem", O_RDWR|O_SYNC);
    if (fd < 0){
        fprintf(stderr, "Unable to open port\n\r");
        exit(fd);
    }

    gpio_D_addr = mmap(0, PIOD_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PIOD_START_ADDR);
    gpio_addr =  mmap(0, GPIO1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1_START_ADDR);

    if(gpio_D_addr == MAP_FAILED){
        handle_error("mmap");
    }

    gpio_enable_write_addr = gpio_D_addr + PIO_WPMR_OFFSET;
    gpio_pullup_enable_addr = gpio_D_addr + PIO_PUER_OFFSET;
    gpio_pullup_status_addr = gpio_D_addr + PIO_PUSR_OFFSET;

    *gpio_enable_write_addr = DESABLE_WRITE_PROTECTION_BANK_D;

    *gpio_pullup_enable_addr = *gpio_pullup_status_addr & LED7_ON;

    return 0;
}

但我有一个mmap: Invalid argument 错误。 --> 但是通过像这样更改 mmap(感谢thread):mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PIOD_START_ADDR &amp; ~MAP_MASK); 和:

#define MAP_SIZE                            4096UL
#define MAP_MASK                            (MAP_SIZE - 1)

我不再有错误但什么也没发生...

有什么想法吗?

【问题讨论】:

    标签: c linux arm memory-address cpu-registers


    【解决方案1】:

    阅读您作为链接提供的数据表的第 5 章。它描述了该设备的各种内存和内存映射。您提供的地址是 32 位的,但您需要确定它的映射。这就是 p 上的图表。如果您真的想在低级别对这些 SAM 器件进行编程,请熟悉整个 1200 页的数据表。

    您提供的地址似乎也是 PMC(电源管理控制器)内存空间的地址(根据地图),所以我会查看该部分,第 21 章。

    【讨论】:

    • 感谢您的帮助。我已经看过这一章,但请参阅上面我的帖子的编辑。
    • 我不知道 4096 的值.. 需要更多的研究才能理解这一点。但是现在,工作电话:(
    • 通过这样做#include &lt;unistd.h&gt; long sz = sysconf(_SC_PAGESIZE); printf("%ld",sz); 我们有4096。所以页面大小是4096。
    【解决方案2】:

    感谢@vlk 和他在 python 中的library 我可以让它工作!这是一个切换 LED 的小例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    
    
    #define handle_error(msg) \
               do { perror(msg); exit(EXIT_FAILURE); } while (0)
    
    #define _PIOD_BANK_D                            0xA00
    
    #define _PIO_OFFSET                             0xFFFFF000
    
    /* When executing this on the board :
        long sz = sysconf(_SC_PAGESIZE);
        printf("%ld\n\r",sz);
       We have 4096.
    */
    #define _MAP_SIZE                           0x1000  // 4096 
    
    #define _WPMR_OFFSET                        0x0E4   // PIO Write Protection Mode Register Bank D
    
    #define _PIO_ENABLE                         0x000
    #define _PIO_DISABLE                        0x004
    #define _PIO_STATUS                         0x008
    #define _OUTPUT_ENABLE                      0x010
    #define _OUTPUT_DISABLE                     0x014
    #define _OUTPUT_STATUS                      0x018
    #define _FILTER_ENABLE                      0x020
    #define _FILTER_DISABLE                     0x024
    #define _FILTER_STATUS                      0x028
    #define _OUTPUT_DATA_SET                    0x030
    #define _OUTPUT_DATA_CLEAR                  0x034
    #define _OUTPUT_DATA_STATUS                 0x038
    #define _PIN_DATA_STATUS                    0x03c
    #define _MULTI_DRIVER_ENABLE                0x050
    #define _MULTI_DRIVER_DISABLE               0x054
    #define _MULTI_DRIVER_STATUS                0x058
    #define _PULL_UP_DISABLE                    0x060
    #define _PULL_UP_ENABLE                     0x064
    #define _PULL_UP_STATUS                     0x068
    #define _PULL_DOWN_DISABLE                  0x090
    #define _PULL_DOWN_ENABLE                   0x094
    #define _PULL_DOWN_STATUS                   0x098
    
    #define _DISABLE_WRITE_PROTECTION           0x50494F00  // Desable write protection
    
    #define LED_PIN                                 21
    
    int main(void) {
    
        volatile void *gpio_addr;
        volatile unsigned int *gpio_enable_addr;
        volatile unsigned int *gpio_output_mode_addr;
        volatile unsigned int *gpio_output_set_addr;
        volatile unsigned int *gpio_output_clear_addr;
        volatile unsigned int *gpio_data_status_addr;
        volatile unsigned int *gpio_write_protection_addr;
    
        int fd = open("/dev/mem", O_RDWR|O_SYNC);
        if (fd < 0){
            fprintf(stderr, "Unable to open port\n\r");
            exit(fd);
        }
    
    
        gpio_addr = mmap(NULL, _MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PIO_OFFSET);
    
    
        if(gpio_addr == MAP_FAILED){
            handle_error("mmap");
        }
    
    
        gpio_write_protection_addr = gpio_addr + _PIOD_BANK_D + _WPMR_OFFSET;
    
        gpio_enable_addr = gpio_addr + _PIOD_BANK_D + _PIO_ENABLE;
    
        gpio_output_mode_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_ENABLE;
    
        gpio_output_set_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_SET;
    
        gpio_output_clear_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_CLEAR;
    
        gpio_data_status_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_STATUS;
    
    
        *gpio_write_protection_addr = _DISABLE_WRITE_PROTECTION;
    
        *gpio_enable_addr = 1 << LED_PIN;
        *gpio_output_mode_addr = 1 << LED_PIN; // Output
    
    
        // If LED
        if((*gpio_data_status_addr & (1<<LED_PIN)) > 0){
            *gpio_output_clear_addr = 1 << LED_PIN;
        }else{
            *gpio_output_set_addr = 1 << LED_PIN;
        }
    
        return 0;
    }
    

    我不得不将_PIO_OFFSET 放入0xFFFFF000,并将D Bank 的值(0xA00)添加到地址,而不是0xFFFFFA00,因为它导致mmap: Invalid argument。不知道为什么..

    编辑:
    通过mmap example 找到解决方案:

    #define _PIO_OFFSET                         0xFFFFFA00 // Instead of 0xFFFFF000
    #define _MAP_SIZE                           0x1000  // 4096 
    #define _MAP_MASK                           (_MAP_SIZE - 1)
    #define _PA_OFFSET                          _PIO_OFFSET & ~_MAP_MASK
    

    还有mmap:

    gpio_addr = mmap(NULL, _MAP_SIZE + _PIO_OFFSET - _PA_OFFSET, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PA_OFFSET);
    

    对于分配:

    gpio_enable_addr = gpio_addr + _PIO_OFFSET - (_PA_OFFSET) + _PIO_ENABLE;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多