LoginSignup
7
4

More than 5 years have passed since last update.

Linuxでレジスタ操作

Posted at

概要

RaspberryPiやらNanoPiやらSBC使っていると、直接レジスタ操作したくなってくる。
ので、ちょっとレジスタ操作用アプリ作ってみた。

コード

reg.c
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdint.h>

int main( int argc, char * argv[] )
{
    int             fd;
    int             num         = 4;
    int             block_size  = 16;
    void*           base_addr   = 0;
    void*           base_addr2map;
    void*           map_addr;
    void*           map_addr_target;
    unsigned int    value;
    int             mode;

    if( argc < 3 )
    {
        printf( "reg r32 <StartAddress> <num=16>\n");
        printf( "reg w32 <Address> <data>\n");
        return  -1;
    }

    sscanf( argv[2], "%p", &base_addr );

    if( 0 == strcmp( argv[1], "r32" ) )
    {
        mode        = 'R';
        num         = 16;

        if( 3 < argc )
        {
            sscanf( argv[3], "%d", &num );
        }
        block_size  = num * 4;
    }
    else if( 0 == strcmp( argv[1], "w32") )
    {
        mode        = 'W';
        block_size  = 4;

        if( argc < 4 )
        {
            printf( "reg w32 <Address> <data>\n");
            return  -1;
        }

        sscanf( argv[3], "0x%x", &value );
    }

    fd  = open( "/dev/mem", O_RDWR | O_SYNC );
    if( fd == -1 )
    {
        printf( "ERROR! Cannot open /dev/mem\n" );
        return  -1;
    }


    base_addr2map   = (void*)(((size_t)base_addr) >> 12 << 12);
    block_size      += (size_t)base_addr - (size_t)base_addr2map;

    map_addr    = mmap( NULL, block_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)base_addr2map );
    if( map_addr == MAP_FAILED )
    {
        printf("ERROR! Cannot map physical addr to virtual addr. %p\n", base_addr );
        return  -1;
    }

    map_addr_target = (void*)((size_t)map_addr + (size_t)base_addr - (size_t)base_addr2map);

    close( fd );

    switch( mode )
    {
    case 'R':
        {
            uint32_t*   addr    = (uint32_t*)map_addr_target;
            int         i;

            for( i = 0; i < num;i++ )
            {
                printf( "%p : 0x%08x\r\n", &((uint32_t*)base_addr)[i], addr[i] );
            }
        }
        break;

    case 'W':
        {
            uint32_t*   addr    = (uint32_t*)map_addr_target;
            uint32_t    org     = addr[0];

            addr[0] = value;

            msync( map_addr_target, 4, MS_SYNC );
            printf( "%p : 0x%08x --> w 0x%08x --> r 0x%08x\r\n", base_addr, org, value, addr[0] );
        }
        break;
    }

    munmap( map_addr, block_size );

    return  0;
}

使い方

ソースゲット&コンパイル

git clone https://github.com/blue777/NanoPi-NEO/
cd NanoPi-NEO
gcc reg.c -o reg

レジスタ読み込み

reg r32 [PhysicalAddress] [Num=16]

r32 は、Read で 32bit単位読み出し。
r8とかは、まだない。

PhysicalAddressにレジスタのアドレスを入れる。
Numには、表示する個数

root@NanoPi-NEO-Plus2:~/NanoPi-NEO# ./reg r32 0x1c22000

0x1c22000 : 0x00060115
0x1c22004 : 0x00001f77
0x1c22008 : 0x00000000
0x1c2200c : 0x00000044
0x1c22010 : 0x00000000
0x1c22014 : 0x000400f4
0x1c22018 : 0x003e0000
0x1c2201c : 0x00000080
0x1c22020 : 0x00000000
0x1c22024 : 0x00000111
0x1c22028 : 0x00d73c06
0x1c2202c : 0x00000000
0x1c22030 : 0x00000001
0x1c22034 : 0x00001031
0x1c22038 : 0x00000000
0x1c2203c : 0x00000000

レジスタ書き込み

reg w32 [PhysicalAddress][Value]

w32 は、32bit単位書き込み。
w8とかは、まだない。

PhysicalAddressにレジスタのアドレスを入れる。
Valueに書き込む値を設定

root@NanoPi-NEO-Plus2:~/NanoPi-NEO# ./reg w32 0x01c22004 0x00001775

0x1c22004 : 0x00001f77 --> w 0x00001775 --> r 0x00001775

書く前に一回読みだして表示し、書き込んだ後、再度読み出して表示しています。

最後に

レジスタ操作等は、危険ですので理解したうえでご利用くださいませ。
最悪、壊れます。

あと、root権限必要となります。

7
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4