Skip to content

Commit e759374

Browse files
committed
fix typo
1 parent 3b3fc8d commit e759374

File tree

23 files changed

+83
-83
lines changed

23 files changed

+83
-83
lines changed

docs/lesson01/exercises.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## 1.5: Exercises.
22

3-
Exercises are optional, though I strongly recommend you to experiment with the source code a little bit. If you were able to complete any of the exercises - please share your source code with others. For details see the [contribution guide](../Contributions.md)
3+
Exercises are optional, though I strongly recommend you to experiment with the source code a little bit. If you were able to complete any of the exercises - please share your source code with others. For details see the [contribution guide](../Contributions.md).
44

55
1. Introduce a constant `baud_rate`, calculate necessary Mini UART register values using this constant. Make sure that the program can work using baud rates other than 115200.
66
1. Change the OS code to use UART device instead of Mini UART. Use `BCM2837 ARM Peripherals` manual to figure out how to access UART registers and how to configure GPIO pins.

docs/lesson01/linux/build-system.md

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 1.3: Kernel build system.
1+
## 1.3: Kernel build system
22

33
After we examined Linux kernel structure, it worth spending some time investigating how we can build and run it. Linux also uses `make` utility to build the kernel, though Linux makefile is much more complicated. Before we will take a look at the makefile, let's learn some important concepts about Linux build system, which is called "kbuild".
44

@@ -18,7 +18,7 @@ After we examined Linux kernel structure, it worth spending some time investigat
1818
obj-y += some_file.o
1919
```
2020

21-
An example of the nested Makefile can be found [here](https://github.com/torvalds/linux/tree/v4.14/kernel/Makefile)
21+
An example of the nested Makefile can be found [here](https://github.com/torvalds/linux/tree/v4.14/kernel/Makefile).
2222

2323
* Before we move forward, you need to understand the structure of a basic make rule and be comfortable with make terminology. Common rule structure is illustrated in the following diagram.
2424

@@ -30,8 +30,8 @@ After we examined Linux kernel structure, it worth spending some time investigat
3030
* `targets` are file names, separated by spaces. Targets are generated after the rule is executed. Usually, there is only one target per rule.
3131
* `prerequisites` are files that `make` trackes to see whether it needs to update the targets.
3232
* `recipe` is a bash script. Make calls it when some of the prerequisites have been updated. The recipe is responsible for generating the targets.
33-
* Both targets and prerequisites can include wildcards (`%`) When wildcards are used the recipe is executed for each of the mached prerequisites separately. In this case, you can use `$<` and `$@` variables to refer to the prerequisite and the target inside the recipe. We already did it in the [RPi OS makefile](https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile#L14)
34-
For additional information about make rules, please refer to the [official documentation](https://www.gnu.org/software/make/manual/html_node/Rule-Syntax.html#Rule-Syntax)
33+
* Both targets and prerequisites can include wildcards (`%`). When wildcards are used the recipe is executed for each of the mached prerequisites separately. In this case, you can use `$<` and `$@` variables to refer to the prerequisite and the target inside the recipe. We already did it in the [RPi OS makefile](https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/Makefile#L14).
34+
For additional information about make rules, please refer to the [official documentation](https://www.gnu.org/software/make/manual/html_node/Rule-Syntax.html#Rule-Syntax).
3535

3636
* `make` is very good in detecting whether any of the prerequisites have been changed and updating only targets that need to be rebuilt. However, if a recipe is dynamically updated, `make` is unable to detect this change. How can this happen? Very easily. One good example is when you change some configuration variable, which results in appending an additional option to the recipe. By default, in this case, `make` will not recompile previously generated object files, because their prerequisites haven't been changed, only the recipe have been updated. To overcome this behavior Linux introduces [if_changed](https://github.com/torvalds/linux/blob/v4.14/scripts/Kbuild.include#L264) function. To see how it works let's consider the following example.
3737

@@ -42,7 +42,7 @@ After we examined Linux kernel structure, it worth spending some time investigat
4242
$(call if_changed,compile)
4343
```
4444

45-
Here for each `.c` file we build corresponding `.o` file by calling `if_changed` function with the argument `compile`. `if_changed` then looks for `cmd_compile` variable (it adds `cmd_` prefix to the first argument) and checks whether this variable has been updated since the last execution, or any of the prerequisites has been changed. If yes - `cmd_compile` command is executed and object file is regenerated. Our sample rule has 2 prerequisites: source `.c` file and `FORCE`. `FORCE` is a special prerequisite that forces the recipe to be called each time when `make` command is called. Without it, the recipe would be called only if `.c` file was changed. You can read more about `FORCE` target [here](https://www.gnu.org/software/make/manual/html_node/Force-Targets.html)
45+
Here for each `.c` file we build corresponding `.o` file by calling `if_changed` function with the argument `compile`. `if_changed` then looks for `cmd_compile` variable (it adds `cmd_` prefix to the first argument) and checks whether this variable has been updated since the last execution, or any of the prerequisites has been changed. If yes - `cmd_compile` command is executed and object file is regenerated. Our sample rule has 2 prerequisites: source `.c` file and `FORCE`. `FORCE` is a special prerequisite that forces the recipe to be called each time when `make` command is called. Without it, the recipe would be called only if `.c` file was changed. You can read more about `FORCE` target [here](https://www.gnu.org/software/make/manual/html_node/Force-Targets.html).
4646

4747
### Building the kernel
4848

@@ -55,7 +55,7 @@ We are going to tackle the second question first.
5555

5656
#### Link stage
5757

58-
* As you might see from the output of `make help` command, the default target, which is responsible for building the kernel, is called `vmlinux`
58+
* As you might see from the output of `make help` command, the default target, which is responsible for building the kernel, is called `vmlinux`.
5959

6060
* `vmlinux` target definition can be found [here](https://github.com/torvalds/linux/blob/v4.14/Makefile#L1004) and it looks like this.
6161

@@ -74,11 +74,11 @@ We are going to tackle the second question first.
7474

7575
* `link-vmlinux.sh` script first creates `thin archive` from all available object files. `thin archive` is a special object that contains references to a set of object files as well as their combined symbol table. This is done inside [archive_builtin](https://github.com/torvalds/linux/blob/v4.14/scripts/link-vmlinux.sh#L56) function. In order to create `thin archive` this function uses [ar](https://sourceware.org/binutils/docs/binutils/ar.html) utility. Generated `thin archive` is stored as `built-in.o` file and has the format that is understandable by the linker, so it can be used as any other normal object file.
7676

77-
* Next [modpost_link](https://github.com/torvalds/linux/blob/v4.14/scripts/link-vmlinux.sh#L69) is called. This function calls linker and generates `vmlinux.o` object file. We need this object file to perform [Section mismatch analysis](https://github.com/torvalds/linux/blob/v4.14/lib/Kconfig.debug#L308) This analysis is performed by the [modpost](https://github.com/torvalds/linux/tree/v4.14/scripts/mod) program and is triggered at [this](https://github.com/torvalds/linux/blob/v4.14/scripts/link-vmlinux.sh#L260) line.
77+
* Next [modpost_link](https://github.com/torvalds/linux/blob/v4.14/scripts/link-vmlinux.sh#L69) is called. This function calls linker and generates `vmlinux.o` object file. We need this object file to perform [Section mismatch analysis](https://github.com/torvalds/linux/blob/v4.14/lib/Kconfig.debug#L308). This analysis is performed by the [modpost](https://github.com/torvalds/linux/tree/v4.14/scripts/mod) program and is triggered at [this](https://github.com/torvalds/linux/blob/v4.14/scripts/link-vmlinux.sh#L260) line.
7878

7979
* Next kernel symbol table is generated. It contains information about all functions and global variables as well as their location in the `vmlinux` binary. The main work is done inside [kallsyms](https://github.com/torvalds/linux/blob/v4.14/scripts/link-vmlinux.sh#L146) function. This function first uses [nm](https://sourceware.org/binutils/docs/binutils/nm.html) to extract all symbols from `vmlinux` binary. Then it uses [scripts/kallsyms](https://github.com/torvalds/linux/blob/v4.14/scripts/kallsyms.c) utility to generate a special assembler file containing all symbols in a special format, understandable by the Linux kernel. Next, this assembler file is compiled and linked together with the original binary. This process is repeated several times because after the final link addresses of some symbols can be changed. Information from the kernel symbol table is used to generate '/proc/kallsyms' file at runtime.
8080

81-
* Finally `vmlinux` binary is ready and `System.map` is build. `System.map` contains the same information as `/proc/kallsyms` but this is static file and unlike `/proc/kallsyms` it is not generated at runtime. `System.map` is mostly used to resolve addresses to symbol names during [kernel oops](https://en.wikipedia.org/wiki/Linux_kernel_oops). The same `nm` utility is used to build `System.map`. This is done [here](https://github.com/torvalds/linux/blob/v4.14/scripts/mksysmap#L44)
81+
* Finally `vmlinux` binary is ready and `System.map` is build. `System.map` contains the same information as `/proc/kallsyms` but this is static file and unlike `/proc/kallsyms` it is not generated at runtime. `System.map` is mostly used to resolve addresses to symbol names during [kernel oops](https://en.wikipedia.org/wiki/Linux_kernel_oops). The same `nm` utility is used to build `System.map`. This is done [here](https://github.com/torvalds/linux/blob/v4.14/scripts/mksysmap#L44).
8282

8383
#### Build stage
8484

@@ -132,7 +132,7 @@ We are going to tackle the second question first.
132132

133133
This line just calls another makefile ([scripts/Makefile.build](https://github.com/torvalds/linux/blob/v4.14/scripts/Makefile.build)) and passes `obj` variable, which contains a folder to be compiled.
134134

135-
* Next logical step is to take a look at [scripts/Makefile.build](https://github.com/torvalds/linux/blob/v4.14/scripts/Makefile.build). The first important thing that happens after it is executed is that all variables from `Makefile` or `Kbuild` files, defined in the current directory, are included. By current directory I mean the directory referenced by the `obj` variable. The inclusion is done in the [following 3 lines](https://github.com/torvalds/linux/blob/v4.14/scripts/Makefile.build#L43-L45)
135+
* Next logical step is to take a look at [scripts/Makefile.build](https://github.com/torvalds/linux/blob/v4.14/scripts/Makefile.build). The first important thing that happens after it is executed is that all variables from `Makefile` or `Kbuild` files, defined in the current directory, are included. By current directory I mean the directory referenced by the `obj` variable. The inclusion is done in the [following 3 lines](https://github.com/torvalds/linux/blob/v4.14/scripts/Makefile.build#L43-L45).
136136

137137
```
138138
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))

docs/lesson01/linux/kernel-startup.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The first thing we are going to do is to take a look at [arm64 linker script](ht
88

99
It should be mentioned that the file we are going to examine is not an actual linker script - it is a template, from which the actual linker script is built by substituting some macros with their actual values. But precisely because this file consists mostly of macros it becomes much easier to read and to port between different architectures.
1010

11-
The first section that we can find in the linker script is called [.head.text](https://github.com/torvalds/linux/blob/v4.14/arch/arm64/kernel/vmlinux.lds.S#L96) This is very important for us because the entry point should be defined in this section. If you think a little about it, it makes a perfect sense: after the kernel is loaded, the content of the binary image is copied into some memory area and execution is started from the beginning of that area. This means that just by searching who is using `.head.text` section we should be able to find the entry point. And indeed, `arm64` architecture has a single file that uses [__HEAD](https://github.com/torvalds/linux/blob/v4.14/include/linux/init.h#L90) macro, which is expanded to `.section ".head.text","ax"` - this file is [head.S](https://github.com/torvalds/linux/blob/v4.14/arch/arm64/kernel/head.S)
11+
The first section that we can find in the linker script is called [.head.text](https://github.com/torvalds/linux/blob/v4.14/arch/arm64/kernel/vmlinux.lds.S#L96). This is very important for us because the entry point should be defined in this section. If you think a little about it, it makes a perfect sense: after the kernel is loaded, the content of the binary image is copied into some memory area and execution is started from the beginning of that area. This means that just by searching who is using `.head.text` section we should be able to find the entry point. And indeed, `arm64` architecture has a single file that uses [__HEAD](https://github.com/torvalds/linux/blob/v4.14/include/linux/init.h#L90) macro, which is expanded to `.section ".head.text","ax"` - this file is [head.S](https://github.com/torvalds/linux/blob/v4.14/arch/arm64/kernel/head.S).
1212

1313
The first executable line, that we can find in `head.S` file is [this one](https://github.com/torvalds/linux/blob/v4.14/arch/arm64/kernel/head.S#L85). Here we use arm assembler `b` of `branch` instruction to jump to the [stext](https://github.com/torvalds/linux/blob/v4.14/arch/arm64/kernel/head.S#L116) function. And this is the first function that is executed after you boot the kernel.
1414

@@ -32,7 +32,7 @@ When I started to examine the startup code of the Linux kernel, I found a lot of
3232

3333
When we were working on `Raspberry PI OS` kernel, we used [BCM2837 ARM Peripherals manual](https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf) to figure out what is the exact offset at which a particular memory mapped register is located. This information obviously is different for each board, and we are lucky that we have to support only one of them. But what if we need to support hundreds of different boards? It would be a total mess if we try to hardcode information about each board in the kernel code. And even if we manage to do so, how would we figure out what board we are using right now? `BCM2837`, for example, doesn't provide any means of communicating such information to the running kernel.
3434

35-
Device tree provides us with the solution to the problem, mentioned above. It is a special format that can be used to describe computer hardware. Device tree specification can be found [here](https://www.devicetree.org/). Before the kernel is executed, bootloader selects proper device tree file and passes it as an argument to the kernel. If you take a look at the files in the boot partition on a Raspberry PI SD card, you can find a lot of `.dtb` files here. `.dtb` are compiled device tree files. You can select some of them in the `config.txt` to enable or disable some Raspberry PI hardware. This process is described in more details in the [Raspberry PI official documentation](https://www.raspberrypi.org/documentation/configuration/device-tree.md)
35+
Device tree provides us with the solution to the problem, mentioned above. It is a special format that can be used to describe computer hardware. Device tree specification can be found [here](https://www.devicetree.org/). Before the kernel is executed, bootloader selects proper device tree file and passes it as an argument to the kernel. If you take a look at the files in the boot partition on a Raspberry PI SD card, you can find a lot of `.dtb` files here. `.dtb` are compiled device tree files. You can select some of them in the `config.txt` to enable or disable some Raspberry PI hardware. This process is described in more details in the [Raspberry PI official documentation](https://www.raspberrypi.org/documentation/configuration/device-tree.md).
3636

3737
Ok, now it is time to take a look at how an actual device tree looks like. As a quick exercise, let's try to find a device tree for [Raspberry PI 3 Model B](https://www.raspberrypi.org/products/raspberry-pi-3-model-b/). From the [documentation](https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837/README.md) we can figure out that `Raspberry PI 3 Model B` uses a chip that is called `BCM2837`. If you search for this name you can find [/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts](https://github.com/torvalds/linux/blob/v4.14/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dts) file. As you might see it just includes the same file from `arm` architecture. This makes a perfect sense because `ARM.v8` processor supports 32-bit mode as well.
3838

docs/lesson01/linux/project-structure.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This is the first time we are going to talk about Linux. The idea is first to co
66

77
Whenever you start investigating any large software project, it worth taking a quick look at the project structure. This is very important because it allows you to understand what modules compose the project and what is the high-level architecture. Let's try to explore project structure of the Linux kernel.
88

9-
First of all, you need to clone the Linux repository
9+
First of all, you need to clone the Linux repository.
1010

1111
```
1212
git clone https://github.com/torvalds/linux.git

docs/lesson01/rpi-os.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ void uart_init ( void )
293293
put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high
294294
put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200
295295
296-
put32(AUX_MU_CNTL_REG,3); //Finaly, enable transmitter and receiver
296+
put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver
297297
}
298298
```
299299

@@ -369,7 +369,7 @@ Now our Mini UART is connected to the GPIO pins, and the pins are configured. Th
369369
put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200
370370
put32(AUX_MU_IIR_REG,6); //Clear FIFO
371371
372-
put32(AUX_MU_CNTL_REG,3); //Finaly, enable transmitter and receiver
372+
put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver
373373
```
374374
Let's examine this code snippet line by line.
375375

@@ -408,7 +408,7 @@ baudrate = system_clock_freq / (8 * ( baudrate_reg + 1 ))
408408
The `system_clock_freq` is 250 MHz, so we can easily calculate the value of `baudrate_reg` as 270.
409409

410410
```
411-
put32(AUX_MU_CNTL_REG,3); //Finaly, enable transmitter and receiver
411+
put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver
412412
```
413413
After this line is executed, the Mini UART is ready for work!
414414

0 commit comments

Comments
 (0)