16.2.1. Prerequisites and Assumptions

The Linux kernel makes some fundamental assumptions when it is passed control from a bootloader. Most important among them is that the bootloader must have initialized the DRAM controller. Linux does not participate in chip-level SDRAM controller setup. Linux assumes that system RAM is present and fully functional. The PowerDNA Controller we are targeting contains the U-Boot bootloader, which has initialized the CPU, DRAM, and other related hardware required for minimal system operation.

The bootloader should also initialize the system memory map. This is usually done via a set of processor registers that define what chip select signals are active within a given memory address range. Chapter 3 in the Freescale MPC5200 User's Guide describes the registers used for this task.

The bootloader might have additional hardware-related initialization tasks. On some boards, the kernel assumes that the serial port is configured. This makes it possible to display early kernel boot messages to the serial port, long before the kernel's own serial driver has been installed. Some architectures and hardware platforms contain functions such as *_serial_putc(), which can send strings to a serial port that has been preconfigured by the bootloader or by some simple early kernel setup code. You can find examples of this in the PowerPC architecture branch using grep and searching for CONFIG_SERIAL_TEXT_DEBUG.

In summary, the fundamental prerequisite for porting Linux to our new board is that a bootloader has been ported and installed on our board, and any board-specific low-level hardware initialization has been completed. It is not necessary to initialize devices for which Linux has direct device driver support, such as Ethernet controllers or I2C controllers; the kernel handles these.

It is a good idea to configure and build your Linux kernel for the board closest to your own. This provides you with a known good starting pointa Linux kernel source tree configured for your board that compiles without error. Recall from Chapter 5, 'Kernel Initialization,' the command to compile a Linux 2.6 kernel:

$ make ARCH=ppc CROSS_COMPILE=ppc_82xx- uImage

This command line results in a Linux bootable image compatible with the U-Boot bootloader. The uImage target specifies this.

16.2.2. Customizing Kernel Initialization

Now that we have a baseline kernel source tree from which to start, let's determine where to begin customizing for our particular board. We discovered that for the PowerPC architecture, the board-specific files reside in a directory called .../arch/ppc/platforms. Of course, this is not strictly necessary, but if you ever intend to submit your patches to the Linux kernel development community for consideration, proper form and consistency matter!

We find in the platforms directory a file called lite5200.c. It's a fairly simple file, containing two data structures and five functions. Listing 16-3 presents the functions from this file.

Listing 16-3. Functions from 5200 Platform File

lite5200_show_cpuinfo()  /* Prints user specified text string */

lite5200_map_irq()       /* Sets h/w specific INT logic routing */

lite5200_setup_cpu()     /* CPU specific initialization */

lite5200_setup_arch()    /* Arch. specific initialization */

platform_init()          /* Machine or board specific init */

Let's look at how these functions are used. We briefly examined the low-level kernel initialization in Chapter 5. Here we look at the details for a particular architecture. Details differ between architectures, but when you can navigate one, the others will be easier to learn.

From Chapter 5, we saw the early flow of control on power-up. The bootloader passed control to the kernel's bootstrap loader, which then passed control to the Linux kernel via the kernel's head.o module. Here the platform-specific initialization begins. Listing 16-4 reproduces the pertinent lines from .../arch/ppc/kernel/head.S.

Listing 16-4. Calling Early Machine Initialization

      ...

/*

* Do early bootinfo parsing, platform-specific initialization,

* and set up the MMU.

*/

      mr    r3,r31

      mr    r4,r30

      mr    r5,r29

      mr    r6,r28

      mr    r7,r27

      bl    machine_init

      bl    MMU_init

      ...

Here you can see the assembly language call to machine_init. Of particular significance is the setup of the registers r3 through r7. These registers are expected to contain well-known values, which you will see momentarily. They were stored away very early in the boot sequence to the PowerPC general-purpose registers r27 through r31. Here they are reloaded from these stored values.

The machine_init() function is defined in a C file called setup.c, in the same architecture-specific kernel directory: .../arch/ppc/kernel/setup.c. The start of this routine is reproduced here in Listing 16-5.

Listing 16-5. Function machine_init() in setup.c

void __init machine_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) {

#ifdef CONFIG_CMDLINE

 strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));

#endif /* CONFIG_CMDLINE */

#ifdef CONFIG_6xx

 ppc_md.power_save = ppc6xx_idle;

#endif

#ifdef CONFIG_POWER4

 ppc_md.power_save = power4_idle;

#endif

 platform_init(r3, r4, r5, r6, r7);

 if (ppc_md.progress)

 ppc_md.progress('id mach(): done', 0x200);

}

There is some very useful knowledge in this simple function. First, notice that the parameters to machine_init() represent the PowerPC general-purpose registers r3 through r7.

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

0

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

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