4

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!!

user1010822
  • 111
  • 2
  • 7

2 Answers2

6

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.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • That is to say the `vector` pointer in `devicemaps_init` is a virtual alias of 0xffff0000, which maps to the same physical page. The reason for the *alias* should be obvious. Most ARM CPUs need the vector at either 0 or 0xffff0000, although newer ARMs could forgo this. – artless noise Oct 09 '13 at 18:29
  • Thank you for the fast answer!. so let see if i understood correctly. memblock_alloc() return a virtual address that points the vector table (the variable - vector). In addition the kernel have to map the address 0xffff0000 to the physical address that was allotted earlier. so there are 2 virtual addresses in the kernel that are mapped to the same physical address or after the 0xffff0000 mapping the first one is not relevant? – user1010822 Oct 09 '13 at 18:50
  • `memblock_alloc()` allocates a *normal* physical/virtual pair. Then in `devicemaps_init()`, a 2nd alias is created to the 0xffff0000. The first virtual address is relevant and remains active; it is the value of the `vector` pointer in `devicemaps_init()`. It remains in the MMU tables; The MMU table is a list of **virt** to **phys**; so two entries point to the same **phys** page. The 0xffff0000 doesn't follow the normal rules as you observe. – artless noise Oct 09 '13 at 19:10
  • An important *caveat* with this aliasing. If you intend to modify one of them (not 0xffff0000), you need to *flush the cache* and *write buffer* or it is possible that the old value can remain for some time (in the 0xffff0000 value in cache). The cache makes a 2nd copy of the same data and it won't know about aliasing. – artless noise Oct 09 '13 at 19:18
2

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.

artless noise
  • 21,212
  • 6
  • 68
  • 105
scott
  • 728
  • 4
  • 8