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.

16.3.2. Board Information Structure

Many bootloaders are used for PowerPC platforms, but there is still no unified way to pass in board- specific data such as serial port baud rate, memory size, and other low-level hardware parameters that the bootloader has configured. The platform-initialization file from Listing 16-8 supports two different methods, data stored as struct bi_record and data stored as struct bd_info.[113] Both methods provide similar results: hardware-specific data is passed from the bootloader to the kernel in these structures.

From Listing 16-8, here is the code snippet that saves the bootloader-supplied hardware configuration:

struct bi_record *bootinfo = find_bootinfo();

if (bootinfo) parse_bootinfo(bootinfo);

else {

 /* Load the bd_t board info structure */

 if (r3) memcpy((void*)&__res,(void*)(r3+KERNELBASE), sizeof(bd_t));

First, we search for a special tag that identifies the data structure as a struct bi_record. If that is found, the bootinfo pointer is set to the address of the start of the bootinfo records. From there, the records are parsed and the hardware related data is gathered. This can be seen by inspecting .../arch/ppc/kernel/setup.c. Currently, bi_records can contain the kernel command line, the start and end address of the initrd image, the machine type, and the size of the memory. Of course, you can extend this for your own requirements.

If no bi_record data is found, the PowerPC architecture expects this data in the form of U-Boot board information structure, or bd_info. It is the bootloader's responsibility to construct this data structure and pass the address in register r3. Currently, many bits of hardware information are available in the bd_info structure, including information on DRAM, FLASH, SRAM, processor clock rates, bus frequencies, serial port baud rate setting, and more.

The bi_record structure can be examined in .../include/asm-ppc/bootinfo.h, and the bd_info structure can be found in .../include/asm-ppc/ppcboot.h.

It is the responsibility of the platform-initialization routines to make use of any of the data that might be necessary to complete the hardware setup, or to communicate it to the kernel. For example, platform_init() sets up a pointer to a function whose name reveals its purpose. The code from Listing 16-8 is reproduced here:

ppc_md.find_end_of_memory = mpc52xx_find_end_of_memory;

Looking at the function mpc52xx_find_end_of_memory(), which is found in .../arch/ppc/syslib/mpc52xx_setup.c, we find the following:

u32 ramsize = __res.bi_memsize;

if (ramsize == 0) {

 ... /* Find it another way */

}

return ramsize;

The __res data structure above is the board information structure, whose address was passed to us from the bootloader in register r3 above. As you can see, the generic setup code stored the residual data (as it is often called) passed in by the bootloader, but it's up to the machine or platform-specific code to make use of it.

16.3.3. Machine-Dependent Calls

Many common routines that the kernel needs either for initialization or for operation are architecture and machine (CPU) dependent. From the platform_init() function reproduced in Listing 16-8, we saw the following:

...

/* Setup the ppc_md struct */

ppc_md.setup_arch = lite5200_setup_arch;

ppc_md.show_cpuinfo = lite5200_show_cpuinfo;

ppc_md.show_percpuinfo = NULL;

ppc_md.init_IRQ = mpc52xx_init_irq;

ppc_md.get_irq = mpc52xx_get_irq;

#ifdef CONFIG_PCI

ppc_md.pci_map_irq = lite5200_map_irq;

#endif

ppc_md.find_end_of_memory = mpc52xx_find_end_of_memory;

ppc_md.setup_io_mappings = mpc52xx_map_io;

ppc_md.restart = mpc52xx_restart;

ppc_md.power_off = mpc52xx_power_off;

ppc_md.halt = mpc52xx_halt;

...

Lines similar to these make up the rest of the platform_init() function. Here the bulk of the platform-

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату