Jinwoo Bae
Jinwoo Bae

Reputation: 45

How to printk value of specific memory adrress?

I want to print 12byte from specific memory address in kernel.

Following is my hard coding.

void *Unique_Id = 0x5C000234;
for(int i=0;i<12;i++){
    printk("%02x ", *(uniqueId+i));
}

This is correct? or there are any other suggestion?

Please give me advice.

Thank you.

Upvotes: 1

Views: 3205

Answers (2)

Ian Abbott
Ian Abbott

Reputation: 17503

  1. Converting integers to pointers without a cast will produce a compiler warning, so the initialization should be:

    void *Unique_Id = (void *)0x5C000234;
    
  2. The kernel uses virtual addresses to access memory locations. The number 0x5C000234 is most likely a physical address of some registers in hardware I/O memory space. These need to be remapped into the kernel's virtual address space before their contents can be accessed. For hardware I/O memory, that is done by ioremap() or one of the ioremap_*() variants. Pointers to remapped I/O memory should be tagged with __iomem:

    void __iomem *Unique_Id = ioremap(0x5C000234, 12);
    

    (The second parameter is the length of the mapping in bytes.)

    ioremap() will return NULL if it fails to map the memory, so that should be checked:

    if (Unique_Id == NULL) {
        /* Deal with the error */
    

    When the mapping is no longer required, iounmap() can be called to unmap it:

    iounmap(Unique_Id);
    
  3. The contents of remapped I/O memory should not be accessed directly. There are specific functions for accessing 8-bit, 16-bit, 32-bit, and (on 64-bit systems) 64-bit quantities. These are readb() and writeb() (8-bit), readw() and writew() (16-bit), readl() and writel() (32-bit), and readq() and writeq() (64-bit). So the for loop to print 12 successive bytes could be written as:

    for (int i = 0; i < 12; i++) {
        printk("%02x ", readb(Unique_Id + i));
    }
    

    (Note that pointer arithmetic on a void * is a GCC extension, but is blessed by the Linux kernel developers.)

    There are also memcpy_fromio() and memcpy_toio() functions for copying between normal kernel memory and I/O memory, so the 12-byte ID could be copied into a 12-byte array using memcpy_fromio():

    u8 id[12];
    memcpy_fromio(id, Unique_Id, 12);
    for (int i = 0; i < 12; i++) {
        printk("%02x ", id[i]);
    }
    

    (u8 is an unsigned 8-bit integer type defined by #include <linux/types.h>.)

  4. The normal usage of printk() is to precede the format string with a "log-level" macro such as KERN_INFO (relying on C string literal concatenation to combine it with the format string), and to end the format string with a new-line character:

    for (int i = 0; i < 12; i++) {
        printk(KERN_INFO "%02x\n", id[i]);
    }
    

    That would split the ID over 12 lines in the kernel log. There is a special KERN_CONT macro to indicate that the message is a continuation of a previous message, so the proper way to combine the printk() calls would be something like:

    printk(KERN_INFO "%02x ", id[0]);
    for (int i = 1; i < 11; i++) {
         printk(KERN_CONT "%02x ", id[i]);
    }
    printk(KERN_CONT, "%02x\n", id[11]);
    

    (It may be preferable to use snprintf() to construct a string in a temporary array of char and use a single call to printk() to print it all in one go.)

  5. The kernel's print format string processing has special extensions where the p specifier for printing pointer values can be suffixed by various characters to change its behaviour. For example, the 12-byte ID could be printed by:

    u8 id[12];
    memcpy_fromio(id, Unique_Id, 12);
    printk(KERN_INFO "%12ph\n", id);
    

    That works for hex strings of up to 64 bytes.

    See How to get printk format specifiers right for details of printk format specifiers.

  6. The kernel has a print_hex_dump() function for printing hex dumps. The 12-byte ID could be printed as follows:

    u8 id[12];
    memcpy_fromio(id, Unique_Id, 12);
    print_hex_dump(KERN_INFO, "Unique_Id: ", DUMP_PREFIX_NONE, 12, 1, id, 12, false);
    

    (The parameters of print_hex_dump() are level (e.g. KERN_INFO), prefix_str (string prefixed to each line of output), prefix_type (one of DUMP_PREFIX_NONE, DUMP_PREFIX_ADDRESS or DUMP_PREFIX_OFFSET), rowsize (number of bytes printed per row of output), groupsize (number of bytes to print in each space-separated group), buf (pointer to data to dump), len (length of data to dump), ascii (include ASCII after the hex output if true).

Upvotes: 3

Wessam Koraim
Wessam Koraim

Reputation: 21

I think since you want to print bytes so just cast the uniqueID + i to a character/unsigned character pointer

printk("%02x ", *((char *)(uniqueId+i)));

Upvotes: 0

Related Questions