Книга: Embedded Linux Primer: A Practical, Real-World Approach

16.3.1. Early Variable Access

16.3.1. Early Variable Access

Let's assume that a code segment very early in the boot process needs to access the variable cmd_line so early that we're executing in 1:1 real to physical mapping. As pointed out earlier, this variable is defined in head.S and will end up in the .data section when the kernel is linked. From the Linux kernel's System.map file, you can find the linked addresses for cmd_line :

$ cat System.map | grep cmd_line
   c0115000 D cmd_line

If we were running in real = physical mode (MMU disabled) and accessed this variable using its symbol, we would be trying to read or write to an address greater than 3GB. Most smaller embedded systems don't have any RAM in this region, and the results would be undefined or would result in a crash. Even if we had physical RAM at that address, it is unlikely that it would be mapped and accessible this early in the boot process. So we have to adjust our reference to this variable to access it.

Listing 16-9 reproduces a code snippet from head.S that does just that.

Listing 16-9. Variable Reference Fixup

relocate_kernel:
      addis r9,r26,klimit@ha /* fetch klimit */
      lwz   r25,klimit@l(r9)
      addis r25,r25,-KERNELBASE@h

This code snippet from the PowerPC head.S is a good example of the issue we are describing. The variable klimit represents the end of the kernel image. It is defined elsewhere as char *klimit. Therefore, it is a pointerit is an address that contains an address. In Listing 16-9, we fetch the address of klimit, sum it with a previously calculated offset that is passed in r26, and deposit the resulting value in register r9. Register r9 now contains the high-order 16 bits of the adjusted address of klimit, with the low-order bits zeroed.[112] It was adjusted by the offset value previously calculated and passed in register r26.

In the next line, the lwz instruction uses register r9 together with the offset of klimit (the lower 16 bits of the klimit address) as an effective address from which to load register r25. (Remember, klimit is a pointer, and we are interested in the value that klimit points to.) Register r25 now holds the pointer that was stored in the variable klimit. In the final line of Listing 16-9, we subtract the kernel's linked base address (KERNELBASE) from r25 to adjust the pointer to our actual physical address. In C, it would look like this:

unsigned int *tmp; /* represents r25 */
tmp = *klimit;
tmp -= KERNELBASE;

In summary, we referenced a pointer stored in klimit and adjusted its value to our real (physical) address so we can use its contents. When the kernel enables the MMU and virtual addressing, we no longer have to worry about thisthe kernel will be running at the address where it was linked, regardless of where in physical memory it is actually located.

Оглавление книги


Генерация: 1.052. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз