Find the physical address of exception vector table from kernel module

I have an android device - Samsung galaxy s2 with kernel version 2.6.35.14 (arm cortex a9)

I tried to find the physical address of the exception vector table. I Know that it is at 0xffff0000 virtual address. (i can print its value via kernel module)

I also know that the translation of most of the kernel virtual address (to physical) is done by substation of the value 0x8000000.

I have a device that can read data directly from devices memory and i want to get the exception vector table.

when i built a kernel module and tried to use the macro virt_to_phys(0xffff0000) i have got some address but the table is not there. i succeed to find in this way the system call table but here the macro gave me wrong address.

Does anyone know why this happens? does the address of the exception vector table resides in a special physical address? Does the kernel translates its address in some special way?

thank you!!


The exception vector table has remained fairly constant in Linux, from 2.6.35 to the most recent mainline. It is allocated very early in the boot phase and involves the memblock boot allocator. The files involved are entry-armv.S, traps.c, and vmlinux.lds.S (the linker script) in the kernel directory with init.c and mmu.c in the mm (or memory management ARM directory). Also, the vector table must be mapped all the time and it is readable by a user process. This is used by the kernel user helpers; the helper routines are also mapped to this page.

An explaination

From vmlinux.lds.S,

The vectors and stubs are relocatable code, and the only thing that matters is their relative offsets

__vectors_start represents the code in the vector page and is found in entry-armv.S. However, the function is relocated in traps.c. The boot allocator reserves a page for the virtual 0xffff000 address (if high vectors are configured). In your 2.6.35 kernel, the memblock allocator is used in init.c. Here mmu.c's devicemaps_init() allocates a page by calling early_alloc(). This page doesn't follow the normal kernel address space rules and virt_to_phys may not be used as the virtual address is forced.

However, a kernel address does exist with the original memblock_alloc() return address. This is the pointer vector in devicemaps_init(); this address does work with virt_to_phys and phys_to_virt.

The physical address of __vectors_start, etc in entry-armv.S can be easily found and a physical address calculated; however, it is discarded at the end of the init phase and I think you aren't interested in this.

An answer

You can call, memblock_dump_all(void) and look at dmesg and use these pointers to try and locate the vector page. It will be 4k size. You could alter the devicemaps_init() to export the vector value. The only way with an unmodified kernel is to do a walk of the ARM mmu tables; that is another story.


It is also possible to use the MMU directly (registers ATS1Cxx and PAR) to perform V=>P translation. See section B4.2.4 of the ARM ARM for the gory details.

If you use the MMU registers this way, you might need to protect against races with other uses of the registers.

This maybe accessed from any kernel driver with the following code,

 unsigned int pa;
 asm("\t mcr p15, 0, %0, c7, c8, 2\n"
     "\t isb\n"
     "\t mrc p15, 0, %0, c7, c4, 0\n" : "=r" (pa) : "0" (0xffff0000));
 printk("Vector is %x\n", pa & 0xfffff000);

The constants are correct.

  • 0xffff0000 is the high vector virtual address.
  • 0xfffff000 is the mask for 4k pages.

This works only on later series ARM processors such as the Cortex series.