aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvetch <vetch97@gmail.com>2020-01-19 01:02:40 +0100
committervetch <vetch97@gmail.com>2020-01-19 01:02:40 +0100
commitd058fa9124a734b4e9cc88450495b53a1cccb62c (patch)
tree17fac3d9e13f87218a04f9f331d728247c16c311
parentb36da2f9047f493d1112ef9671b09861b5c780b0 (diff)
downloadrpi-MMU-example-d058fa9124a734b4e9cc88450495b53a1cccb62c.tar.gz
rpi-MMU-example-d058fa9124a734b4e9cc88450495b53a1cccb62c.zip
Add linker, I will add sources etc once i get good sleep
-rw-r--r--Linker-scripts-explained.txt14
-rw-r--r--document.md81
-rwxr-xr-xmakeDoc.sh4
3 files changed, 53 insertions, 46 deletions
diff --git a/Linker-scripts-explained.txt b/Linker-scripts-explained.txt
index 428cf52..130eb0c 100644
--- a/Linker-scripts-explained.txt
+++ b/Linker-scripts-explained.txt
@@ -1,4 +1,6 @@
-Linking is a process of creating an executable, library or another object file out of object files. <link wikipedia>
+## Linking
+
+Linking is a process of creating an executable, library or another object file out of object files. [wikipedia](https://en.wikipedia.org/wiki/Linker_%28computing%29)
During linking, values previously unknown to the compiler (i.e. what will be the addresses of external functions/variables, from what address will the code be executing) might be injected into the code.
Linker script is, among others, used to tell the linker, where in memory the specific parts of the executable should lie.
@@ -6,19 +8,25 @@ Linker script is, among others, used to tell the linker, where in memory the spe
In a hosted environment (when building a program to run under an full-featured operting system, like GNU/Linux), a linker script is usually provided by the toolchain and used if no other script is provided. In a bare-metal project, the developer usually has to write their own linker script, in which they specify the binary image's **load address** and section layout.
Contents of an object code file or executable (our .o or .elf) are grouped into sections. Sections have names. Common named are .text (usually contains code), .data (usually contains statically-allocated variables initialized to non-zero values), .bss (usually used to reserve memory for statically allocated variables initialized to zero), .rodata (usually contains statically-allocated variables, that are not going to be modified).
+
In a hosted environment, when an executable (say, of elf format) is executed, contents of it's sections are usually placed in different memory segments with different access privileges, so that, for example, code is not writable and variable contents are not executable. This helps reduce the risk of buffer overflow exploits.
+
In a bare-environment like ours, we don't execute an elf file directly (except in qemu, which is the unpreferred approach anyway), but rather a raw binary image created from an elf file. Still, the notion of section is used along the way.
During link, one or more object code files are combined into one file (in our case an executable). Section contents of input files land in some sections of the output file, in a way defined in the linker script. In a hosted environment, a linker script would likely put contents of input .text sections in a .text section, contents of input .data sections in a .data section, etc. The developer can, however, use sections with different names (although weird behaviour of some linkers might occur) and assign their contents in their preferred way using a linker script.
In linker script it is possible to specify a section as NOLOAD (usually used for .bss), which, in our case, causes that section not to be included in the binary image later created with objcopy.
+
It is also possible to treat same-named input sections differently depending on what file they came from and even use wildcards when specifying file names.
+
Variables can be created, as well as new symbols, which can then be references from C code.
+
Defining alignment of specific parts of future image is also easily achievable.
+
We made use of all those possibilities in our scripts.
In src/arm/PL1/kernel/kernel_stage2.ld the physical memory layout of thkernel is defined. Symbols defined there, such as _stack_end, are referenced in C header src/arm/PL1/kernel/memory.h.
-While src/arm/PL1/kernel/kernel.ld and src/arm/PL1/loader/loader.ld define the starting address, it is irrelevant, as the assembly-written position-independent code for first stages of loader and kernel <link to Boot explained> does not depend on that address.
+While src/arm/PL1/kernel/kernel.ld and src/arm/PL1/loader/loader.ld define the starting address, it is irrelevant, as the assembly-written position-independent code for [first stages of loader and kernel](./Boot_explained.txt) does not depend on that address.
-At the beginning of this project, we had very little understanding of linker scripts' syntax. <linkt to redhat resource (listed in TODOs)> proved useful and allowed us to learn the required parts in a short time. As discussing the entire syntax of linker scripts is beyond the scope of this documentation, we refer the reader to that resource.
+At the beginning of this project, we had very little understanding of linker scripts' syntax. [This article](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/sections.html#OUTPUT-SECTION-DESCRIPTION) proved useful and allowed us to learn the required parts in a short time. As discussing the entire syntax of linker scripts is beyond the scope of this documentation, we refer the reader to that resource.
diff --git a/document.md b/document.md
index ccc9aca..e6faca2 100644
--- a/document.md
+++ b/document.md
@@ -1,37 +1,6 @@
# Raspberry PI MMU project
-
-- [Raspberry PI MMU project](#raspberry-pi-mmu-project)
- * [Building and running](#building-and-running)
- + [Building the project](#building-the-project)
- + [Running in Qemu](#running-in-qemu)
- + [Running on real hardware.](#running-on-real-hardware)
- * [Makefile](#makefile)
- + [Targets](#targets)
- + [Aliased Rules](#aliased-rules)
- * [Project structure](#project-structure)
- + [Most Significant Directories](#most-significant-directories)
- * [Boot Process](#boot-process)
- + [Loader](#loader)
- + [Kernel](#kernel)
- - [Stage 1](#stage-1)
- - [Stage 2](#stage-2)
- + [Some more notes](#some-more-notes)
- * [MMU](#mmu)
- + [Coprocessor 15](#coprocessor-15)
- + [Translation table](#translation-table)
- + [Page Table](#page-table)
- + [Project specific info](#project-specific-info)
- + [Setting up MMU and FlatMap](#setting-up-mmu-and-flatmap)
- * [Program Status Register](#program-status-register)
- * [Specification](#specification)
- * [Implementations](#implementations)
- * [Exceptions](#exceptions)
- * [IRQ](#irq)
-- [Processor modes](#processor-modes)
- * [Scheduler](#scheduler)
- + [Functions](#functions)
-
-## Building and running
+//TODO insert [TOC] here
+# Building and running
Dependencies:
@@ -47,7 +16,7 @@ For building rpi-open-firmware You will need more tools (not listed here).
The project has been tested only in Qemu emulating Pi 2 and on real Pi 3. Running on Pis other than Pi 2 and Pi 3 is sure to require changing the definition in global.h (because peripheral base addresses differ between Pi versions) and might also require other modifications, not known at this time.
-### Building the project
+## Building the project
Assuming make, gcc, arm-none-eabi-gcc and its binutils are in the PATH, the kernel can be built with:
@@ -61,7 +30,7 @@ The bootloader can be built with:
Both loader and kernel can then be found in build/
-### Running in Qemu
+## Running in Qemu
To run the kernel (passed as elf file) in qemu, run:
@@ -78,15 +47,14 @@ Note, that with qemu-loader the kernel will run, but will be unable to receive a
The timer used by this project is the ARM timer ("based on an ARM AP804", with registers mapped at 0x7E00B000 in the GPU address space). It's absent in emulated environment, so no timer interrupts can be witnessed in qemu, as it would require to us to use simulated qemu clock.
-### Running on real hardware.
+## Running on real hardware.
First, build and test rpi-open-firmware. Now, copy either kernel.img or loader.img to the SD card (next to bootcode.bin) and rename it to zImage. Also copy .dtb file corresponding to your Pi (actually, any .dtb will do, it is not used right now) from stock firmware files to the SD card and name it rpi.dtb. Finally, create a cmdline.txt on the SD card (content doesn't matter).
Now, connect RaspberryPi via UART to Your machine. GPIO on the Pi works with 3.3V, so You should make sure, that UART device on the other end is also working wih 3.3V. This is the pinout of the RaspberyPi 3 model B that has been used for testing so far:
-Top left of the board is here:
-|
-v
+Top left of the board is here
+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 2| 4| 6| 8|10|12|14|16|18|20|22|24|26|28|30|32|34|36|38|40|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
@@ -114,7 +82,6 @@ If You copied the loader, You can send it the kernel image and start communicati
To run again, replug USB to UART adapter and Pi's power supply (order matters!) and re-enter the command. Replugging power supply and running the command again should also work unless screen dies.
Running under stock firmware has not been performed. In particular, the default configuration on RaspberryPi 3 seems to map other UART than used by the kernel (so-called miniUART) to pins 6, 8 and 10. This is supposed to be configurable through the use of overlays.
-
## Makefile
To maintain order, all files created with the use of make, that is binaries, object files, natively executed helper programs, etc. get placed in build/.
@@ -496,7 +463,7 @@ Some peripheral devices can be configured (through their memory-mapped registers
IRQs and FIQs can be configured as vectored - the processor then, upon interrupt, jumps to different location depending on which interrupt occured, instead of jumping to the standard [IRQ/FIQ vector](./Exception-vector-explained.txt). This can be used to speed up interrupt handling. Our simple project does not, however, use this feature.
Currently, IRQs from 2 sources are used: [ARM timer IRQ](https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf) and UART IRQs. The kernel makes sure, that timer IRQ only occurs when processor is in user mode. IRQ handler does not return in this case - it calls scheduler. The kernel makes sure, that UART IRQ only occurs, when a process is blocked and is waiting for UART IO operation. The interrupt handler, when called, checks what type of UART action happened and tries (through calling of appropriate function from scheduler.c) to handle that action and, possibly, to unblock the waiting process. UART IRQ might occur when another process is executing (not possible now, with only one process, but shall be possible when more processes are added to the project), in which case it the handler returns, or when kernel is explicitly waiting for interrupts (because all processes are blocked), in which case it calls schedule() instead of returning.
-## Processor modes
+# Processor modes
ARMv7-A core can be executing in one of several modes (not to be confused with instruction set states or endianness execution state). Those are:
@@ -574,3 +541,35 @@ The following are assured in our design:
4. If an interrupt from UART occurs during execution of user mode code (not possible here, as we only have one process, but shall become possible when proper processes are implemented), the handler shall return. If that interrupt occurs during execution of PL1 code, it means it occured in scheduler, that was implicitly waiting for it and the handler calls scheduler() again instead of returning.
5. Interrupt from timer is unmasked and set to come whenever a process gets scheduled to run. Timer interrupt is disabled when in PL1 (when scheduler is waiting for interrupt, only UART one can come).
6. A supervisor call requesting an UART operation, that can not be completed immediately, causes the process to block.
+## Linking
+
+Linking is a process of creating an executable, library or another object file out of object files. [wikipedia](https://en.wikipedia.org/wiki/Linker_%28computing%29)
+During linking, values previously unknown to the compiler (i.e. what will be the addresses of external functions/variables, from what address will the code be executing) might be injected into the code.
+
+Linker script is, among others, used to tell the linker, where in memory the specific parts of the executable should lie.
+
+In a hosted environment (when building a program to run under an full-featured operting system, like GNU/Linux), a linker script is usually provided by the toolchain and used if no other script is provided. In a bare-metal project, the developer usually has to write their own linker script, in which they specify the binary image's **load address** and section layout.
+
+Contents of an object code file or executable (our .o or .elf) are grouped into sections. Sections have names. Common named are .text (usually contains code), .data (usually contains statically-allocated variables initialized to non-zero values), .bss (usually used to reserve memory for statically allocated variables initialized to zero), .rodata (usually contains statically-allocated variables, that are not going to be modified).
+
+In a hosted environment, when an executable (say, of elf format) is executed, contents of it's sections are usually placed in different memory segments with different access privileges, so that, for example, code is not writable and variable contents are not executable. This helps reduce the risk of buffer overflow exploits.
+
+In a bare-environment like ours, we don't execute an elf file directly (except in qemu, which is the unpreferred approach anyway), but rather a raw binary image created from an elf file. Still, the notion of section is used along the way.
+
+During link, one or more object code files are combined into one file (in our case an executable). Section contents of input files land in some sections of the output file, in a way defined in the linker script. In a hosted environment, a linker script would likely put contents of input .text sections in a .text section, contents of input .data sections in a .data section, etc. The developer can, however, use sections with different names (although weird behaviour of some linkers might occur) and assign their contents in their preferred way using a linker script.
+
+In linker script it is possible to specify a section as NOLOAD (usually used for .bss), which, in our case, causes that section not to be included in the binary image later created with objcopy.
+
+It is also possible to treat same-named input sections differently depending on what file they came from and even use wildcards when specifying file names.
+
+Variables can be created, as well as new symbols, which can then be references from C code.
+
+Defining alignment of specific parts of future image is also easily achievable.
+
+We made use of all those possibilities in our scripts.
+
+In src/arm/PL1/kernel/kernel_stage2.ld the physical memory layout of thkernel is defined. Symbols defined there, such as _stack_end, are referenced in C header src/arm/PL1/kernel/memory.h.
+
+While src/arm/PL1/kernel/kernel.ld and src/arm/PL1/loader/loader.ld define the starting address, it is irrelevant, as the assembly-written position-independent code for [first stages of loader and kernel](./Boot_explained.txt) does not depend on that address.
+
+At the beginning of this project, we had very little understanding of linker scripts' syntax. [This article](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/sections.html#OUTPUT-SECTION-DESCRIPTION) proved useful and allowed us to learn the required parts in a short time. As discussing the entire syntax of linker scripts is beyond the scope of this documentation, we refer the reader to that resource.
diff --git a/makeDoc.sh b/makeDoc.sh
index 5094b8f..556969f 100755
--- a/makeDoc.sh
+++ b/makeDoc.sh
@@ -1,7 +1,7 @@
rm -f document.md
- array=("Building-and-running-explained.txt" "Makefile-explained.txt" "Project-structure-explained.txt" "Boot-explained.txt" "MMU-explained.txt" "PSRs-explained.txt" "Ramfs-explained.txt" "Exception-vector-explained.txt" "IRQ-explained.txt" "processor-modes-explained.txt" "Scheduler-explained.txt")
+ array=("Building-and-running-explained.txt" "Makefile-explained.txt" "Project-structure-explained.txt" "Boot-explained.txt" "MMU-explained.txt" "PSRs-explained.txt" "Ramfs-explained.txt" "Exception-vector-explained.txt" "IRQ-explained.txt" "processor-modes-explained.txt" "Scheduler-explained.txt" "Linker-scripts-explained.txt")
echo "# Raspberry PI MMU project" >> document.md
- echo "[TOC]" >> document.md
+ echo "//TODO insert [TOC] here" >> document.md
for file in "${array[@]}"
do
cat $file >> document.md