Presentation is loading. Please wait.

Presentation is loading. Please wait.

Computer System Laboratory

Similar presentations


Presentation on theme: "Computer System Laboratory"— Presentation transcript:

1 Computer System Laboratory
Lab11 - Bare Metal Programming / 18

2 Experimental Goal Understand the process of OS development
Write a minimal kernel for RPi 2 / 18

3 Environment Host Machine Target Machine Build Machine OS: Windows
Raspberry Pi 2 Build Machine A computer with a SD card slot OS: Ubuntu (or above) 64-bit / 18

4 Software Required Host Machine Target Machine Build Machine
PL2303 Driver PuTTY Target Machine Raspberry Pi Firmware Build Machine GCC Cross-Compiler Targeting arm-none-eabi Sample Bare Metal Program You may find all software on the CSL Course Software. / 18

5 Hardware Checklist Raspberry Pi 2 Power supply
Micro SD card and card reader USB-TTL cable / 18

6 Bare Metal Programming
The term “bare metal” means a computer without OSes on it. Bare metal programming means writing programs (usually bootloaders or kernels) running on bare metal. user space program bare metal program who prepares the runtime environment OS firmware or bootloader what services can call OS services almost none, perhaps some firmware services / 18

7 Hosted vs. Freestanding
The C standard defines two different kinds of executing environments: “freestanding” and “hosted”. A kernel is freestanding, and any user space program is hosted. A freestanding environment only provides a subset of the C library: float.h, iso646.h, limits.h, stdalign.h, stdarg.h, stdbool.h, stddef.h, stdint.h, and stdnoreturn.h. All of these consist of typedef and #define only. In other words, when you write a kernel, there is no library such as stdio.h and stdlib.h. You have to implement all operations you need by yourself. / 18

8 Preparing the Compiler
In the GNU build system, a compiler must know what target platform (architecture and OS) it generates code for. For example, you can ask an arbitrary GCC compiler what target platform it is currently using by the command below. You will get something like “x86_64-linux-gnu” or “arm-linux-gnueabihf” in the output. gcc -dumpmachine If you develop your own OS, and perhaps one day it becomes self-hosted (i.e. it can be developed under itself), usually you will modify GCC to support your own OS, and then the name of your own platform should be like “x86_64-your_OS”. In the early OS development, however, it is more suitable to use the generic targets, which tells GCC not to assume any specific OS. We will use “arm-none-eabi” as the target platform of our kernel. Run the command below in the build machine to get this cross compiler. % sudo apt-get install gcc-arm-none-eabi / 18

9 Minimal Source Code Organization
Download and extract the sample code. boot.S - This file contains the program entry point written in assembly and performs some processor-dependent initialization. In the end the control flow will jump to code in kernel.c. kernel.c - For your convenience and higher portability, it is better to write your main program in a higher level rather than architecture level. This file contains the C part of your program. linker.ld - To generate the final executable, the linker needs to know where the program entry point is and how to organize all sections in the given object files. This linker script tells the linker these information. / 18

10 Adding Code to Print Text
The RPi 2 firmware maps some addresses for memory mapped I/O. To print text, you have to read and write those addresses for UART according to the specification in the related datasheet (or, just copy-and-paste other people’s work). You are given the source code of uCOSII for RPi 2. Your goal is to find the part which prints text via UART, and then ship the files you need. Finally, in your kernel_main(), call the UART function to print text. Hint 1: You can trace the source code in the following order to understand the usage of the UART functions. _start in init/startup.s main() in usrApp/main.c userApp1() or userApp2() in usrApp/userApp.c Hint 2: You will have to ship the following files into your workspace. h/uart.h bsp/uart.c h/regs.h h/bcm2836.h / 18

11 A Little Modification Hint 3: Make sure that regs.h includes bcm2836.h instead of bcm2835.h. Hint 4: In uart.c, there are 3 extern functions referenced. These 3 functions are implemented in startup.s. So the following two solutions are both fine. If you don’t want to touch any assembly, just replace the 3 extern declarations with the following functionally equivalent C code. Alternatively, you can copy the 3 assembly functions in startup.s to your boot.S, and leave uart.c unchanged. static void PUT32 ( unsigned int addr, unsigned int value ) { *(unsigned int *)addr = value; } static unsigned int GET32 ( unsigned int addr ) return *(unsigned int *)addr; static void dummy ( unsigned int value ) (void)value; return; / 18

12 Build Instructions Compile a .c file. Assemble a .S file.
% arm-none-eabi-gcc -mcpu=cortex-a7 -fpic -ffreestanding -std=gnu99 -O0 -Wall -Wextra -c –o <output_file> <input_file> Assemble a .S file. % arm-none-eabi-gcc -mcpu=cortex-a7 -fpic -ffreestanding -c –o <output_file> <input_file> Link all .o files together to produce the ELF executable. % arm-none-eabi-gcc -ffreestanding -O0 –nostdlib -T <linker_script> –o <output_file> <input_files> / 18

13 Some Notes for Build Instructions
We don’t run the assembler arm-none-eabi-as and the linker arm-none- eabi-ld directly. arm-none-eabi-gcc will call them. -mcpu=cortex-a7 tells GCC to generate code for ARMv7-A, and tune for Cortex-A7. -ffreestanding tells GCC the executing environment is “freestanding”. -T in the linking command tells GCC to use the given linker script rather than the default one (the latter is usually used for producing user space programs). / 18

14 Boot Protocol Either firmware or an additional bootloader (loaded by firmware) can boot a kernel. Each of them has its own boot protocol the kernel should follow. Loaded by firmware Pros: Need not set up an additional bootloader. Cons: Boot protocol is not friendly to kernels. In other words, firmware usually performs very simple loading, and hence more works are left for the loaded kernel to do first. (Think about how BIOS loads a kernel on x86 PC…) Loaded by bootloader Bootloaders usually do some initialization for kernels. Bootloaders usually support loading some formats of executable. E.g. The x86 Multiboot Specification can load ELF executable. Linux even defines its own boot protocol (zImage and bzImage) and let all bootloaders support it. We will use the former way. / 18

15 Loaded by Firmware On RPi 2, the firmware is powerful enough to load a raw binary file from the boot partition file system. The content of the raw binary file is then copied to memory address 0x8000 directly. To follow this boot protocol, we have to do the follows. Tell the linker to calculate the addresses of symbols from 0x8000. This is done in the linker script. Your kernel image should use raw binary format rather than ELF format. This can be done by the command below. % arm-none-eabi-objcopy <ELF_file> -O binary <raw_binary_file> Place your raw binary file at /boot. In the firmware configuration file config.txt, modify the value of “kernel” variable to the filename of your raw binary. Now you’re ready to boot your kernel. / 18

16 Boot Successfully / 18

17 Lab Requirement Let your program print text on RPi 2. / 18

18 Reference Target Triplet - OSDev Wiki GCC Cross-Compiler - OSDev Wiki
Raspberry Pi Bare Bones - OSDev Wiki GitHub - mopplayer/uCOSII_RPi / 18


Download ppt "Computer System Laboratory"

Similar presentations


Ads by Google