Showing posts with label MIPS. Show all posts
Showing posts with label MIPS. Show all posts

Sunday, April 21, 2013

MIPS Bootstrapping


Bootstrapping is the process of taking a CPU just out of reset, fetching and executing instructions serially, to a more complex running environment. The program that does that is called a "Boot loader" or "Boot strap code" or simply "Boot code".

First Instruction Fetch

When power is applied to a processor and it comes out of reset, it fetches its first instruction from an address that is hardwired. This address is known as the "Boot Vector" or the "Reset Vector". The MIPS processors' boot vector is located at physical address 0x1FC00000. The MIPS processors have MMU enabled as soon as they are powered on. The MIPS core thus presents a virtual address of 0xBFC00000. The MMU translates this address to physical address of 0x1FC00000, the boot vector. This translation again is hardwired. Typically, a boot device is present at this address and responds to the read request of the processor2. See Firgure 1.  The offset 0 of bootstrap code in Figure 1 may not always be true. This may be changed by your hardware designer by pulling the physical address lines high, there by changing the final physical address.

A boot device is a permanent storage device which gives random access on reads, just like RAM. NOR flash, NVRAM etc. are a few boot devices.

U-Boot: The Boot Loader

U-Boot is a boot loader from Denx Software Engineering. This boot loader supports multiple architecture including MIPS. We can draw a general outline on what U-Boot does as part of bootstrapping MIPS. Board specific and other details will be left out.

U-Boot can be divided in two stages: Stage 1 and Stage 2. 

Stage 1 Loader

Stage 1 is completely or partially written in assembly language. A program written in C language requires memory to be up and stack to set in stack register. When the CPU is executing the stage 1 code, usually at that time the RAM is not available and thus the C code cannot run. For this reason, first few instructions are coded in assembly language.

How soon can the assembly code can jump to C, depends on what features does CPU provide. Some of the MIPS implementations give a way to lock the cache lines and use them as stack. Some have seperate SRAM which can be used as temporary stack. In these cases, assembly can quickly use setup these temporary stacks and jump to C code. Otherwise, all code to initialize RAM has to be written in assembly, which can be quite a pain. Whatever the case is, all this time CPU is running by fetching instructions directly from boot device. The accesses to boot device are not fast as RAM and thus CPU cannot continue doing so. Thus the next step for stage 1 loader is to copy the rest of the code from the boot device to RAM. Before processor can start executing from RAM, the recently copied code in RAM is relocated. What now runs in RAM can be called as the stage 2 loader.

Stage 2 Loader

The stage 2 loader is responsible for doing the following:

  1. Prepare and initialize the other subsystems like other storage devices, USB, Networks etc.
  2. The evironment variables are initialized.
  3. Give the user prompt for further commands or autoboot a predefined operating system.

Loading Linux Kernel

U-Boot usually loads Linux as any other ELF binary. The ELF header is parsed and the entry point is taken from the ELF header. The kernel entry function pointer declaration below, shows how U-Boot passes the control over to Linux and what information is provided along with.

void (*theKernel)(int, char **, char **, int *);

U-Boot passes 4 arguments when it calls the Linux kernel. The following are the arguments passed:
  1. Number of arguments.
  2. Linux arguments.
  3. Linux environment variables.
  4. Nothing (0).

As part of environment variables, information like memsize, initrd start, flash start, etc is passed over. The Linux arguments contains whatever is defined in bootargs environtment variable of U-Boot. The 4 arguments are passed via a0, a1, a2 and a3 registers.


Friday, April 20, 2012

What is X-Visor?

X-Visor aims towards providing an open source virtualization solution, which is light-weight, portable, and flexible. It tries to ensure small memory foot print and less virtualization overhead in every functionality. Open source projects such as: Linux, NetBSD, FreeBSD, and QEMU have made a great impact in Xvisor design & development. X-Visor has most of the features expected from a modern full-fledged hypervisor, such as:

  • Tree based Configuration (Device Tree)
  • CPU virtualization (Guest, Virtual CPUs, Virtual IRQs)
  • MMU virtualization (Virtual MMU, Virtual Guest Address Space)
  • IO virtualization (Device Emulation Framework, Emulators)
  • Device Driver Framework (Host Address Space, Host IRQs, Drivers)
  • Threading Framework (Hypervisor Threads)
  • Managment Terminal (Mterm)
  • Serial Port Virtualization (Virtual Serial)

Xvisor is a highly portable source code. In fact, its development was initiated in 3 different architectures (ARM, MIPS and Intel 64) simultaneously, to ensure flexiblity and portablity from the begining itself. It is easily portable to most general-purpose 32- or 64-bit architectures as long as they have a paged memory management unit (PMMU) and a port of the GNU C compiler (gcc) (part of The GNU Compiler Collection, GCC).

MIPS port has been abandoned because of lack of interest from MIPS designers. Intel has virtualization support, ARM is adding it but there is no plans for MIPS. I don't want to waste time on something for which people don't care. Hence I took up Intel 64. Why Intel 64? I think 32-bit days will be over soon. 64-bit architecture is future. I don't want to get in that 32-bit clutter. If somebody wants to take 32-bit support, be my guest.