Good afternoon / evening / night / morning! There is one experimental course on operating systems. There he is at Stanford University. But some materials are available to everyone. In addition to the slides, full descriptions of practical exercises are available.
How does this course differ from others? Most of the code is written independently and runs on a very real modern hardware. The target platform is Raspberry Pi 3 model B. Those. sufficiently current architecture AArch64. ARMv8 Cortex-A53, four cores, 64-bit and that's it. Rust is selected as the main programming language. Which is safe, fast, without GC and so on. He, Rust, is supposed to be studied during the course.
There are about disks, file systems, input-output operations, threads / processes, scheduling, virtual memory, protection and security, interrupts, concurrency and synchronization. As in any other self-respecting course. The difference in the relevance of the material and the amount of practice. Coddit will have a lot .
If you wanted to see a literal translation, then it will not be. Instead, I will try to make the text useful and understandable. For example, in places that are relevant only to Stanford students, I will put the information useful to others. There may be a little slang, a little unrelated to the original illustrations and a small number of additional comments. For the sake of readability, there will be no obvious Translator Notes ™. The text can be considered a literary translation or an article based on. I'm not a welder - I will not be offended.
Where did I learn about this course? Someone posted a reference on Hacker News . I accidentally saw and penetrated. A little he poked the course materials and eventually decided to translate this matter.
In this part we will customize the raspberry and necessary tools. As a result, we will have a raspberry flashing LED. There are four main stages. First of all, we need to make sure that the connection between Pi and the computer works for itself. Run the pre-prepared program. In the second stage, let's figure out how to connect LEDs. Pro breadboard and wiring. At the third stage we will collect nyashny call code and run it on Pi. Install the aarch64-none-elf
and try it out. And at the fourth stage we will rewrite this whole thing on Rust.
A couple of useful links:
Before completing the course, you should get yourself a unix-like operating system for your immediate use. It can be Linux, BSD or macOS with git
, wget
, tar
, screen
and make
installed. Theoretically, it can work in Windows 10 with the linux subsystem, but no one has verified for sure. At least this configuration is not supported. Those. There are no ready-made recipes for Windows and it is recommended to install Ubuntu LST or Fedora .
From iron we will need:
In the discussion on reddit there are references on amazon with what may be required. However, all this can be bought in any other store. Including offline. In addition, all you can buy more any components to your taste.
Caution : Malinka is electrostatically sensitive. Try not to touch the contacts with your bare hands. You will not be killed by a current or even scratched, but Malinka itself may be completely incapacitated. Ground yourself.
When all this is available, you can tighten the job code:
git clone https://web.stanford.edu/class/cs140e/assignments/0-blinky/skeleton.git 0-blinky cd assignment0 make fetch
Feel free to explore the content yourself.
The first thing we need to do is configure the CP2102 adapter. It is needed for communication between a computer and Pi. In addition to this, the raspberry gets through it the vital 5 volts. On the one hand there is USB, on the other there are five pins, in the middle of the handkerchief.
On Linux, everything should work right out of the box. You need to install a driver on Macs. Download this archive and unpack. We start SiLabsUSBDriverDisk.dmg
and agree with the points on the sale of the soul under a license. After that, on the mounted volume, launch Silicon Labs VPC Driver.pkg
. Install and reboot.
Try inserting the CP2102 into a free USB slot. If everything works, the corresponding files should appear in /dev
. In the case of poppy /dev/tty.SLAB_USBtoUART
. In the case of Linux, something like /dev/ttyUSB0
. Write it down - useful. Take out the adapter.
Now connect the Raspberry Pi to the CP2102. Here is the connector mapping table:
CP2102 connectors | Raspberry Pi connectors |
---|---|
+ 5v | four |
GND | 6 |
Rxd | eight |
Txd | ten |
Numbering of pins on the raspberry (still there is an interactive version):
All together it will look like this (the colors of the wires can be chosen arbitrarily):
Important : check and recheck the connections before connecting all this to the computer. We need fresh raspberry, not burnt jam.
If there is confidence in the correctness of pairing the raspberry and adapter - you can still connect the CP2102 to the computer.
Raspberry Pi loads programs from a microSD card during power up. Right now we will figure out how to cook it.
First of all, we need to drop files from the cloned repository onto the microSD box. Namely, those that are in the files/firmware
folder. Those. bootcode.bin
, config.txt
and start.elf
. Copy them to the root of the flash card. If suddenly there are no these files in the repository repository - you forgot about make fetch
.
Why do we needbootcode.bin
,config.txt
andstart.elf
?
This is all a bootloader for the raspberry.bootcode.bin
is the first boot loader. His task is to loadstart.elf
. Which configures the processor in accordance with the contents of theconfig.txt
file. After that, it loadskernel8.img
and passes control to it. By the way where is he?
Now copy the files/activity-led-blink.bin
from the repo to the root of the flash card and give this file the name kernel8.img
. Unmount the card and pull out. Make sure that the raspberry is disabled. Then we insert the card into the raspberry and connect the raspberry to the power supply. We should see a flashing LED on the raspberry and on the CP2102 adapter. Blinking of the latter means that some data is being transferred there.
Data? What data? In order to see them, we need to connect a serial terminal emulator to the CP2102 and read what is happening there. We will use the screen for it is installed on both Linux and macOS. Remember the device path from the /dev
folder and run
screen /dev/<> 115200
On Linux, you may need to use sudo
to run this command. However, you can add your user to the dialout
group and not constantly write to this sudo
command:
sudo gpasswd --add <-> dialout
One way or another, but we should see greetings from the raspberry. To exit the screen
, press <ctrl-a> k
, and then answer y
to the exit prompt.
At this stage we will connect the 16th pin of the GPIO (physical contact No. 36) of the raspberry to the LED on the breadboard. Check out his work using a pre-prepared binary with firmware. Make sure the raspberry is disabled.
As the name implies, GPIO is a common mechanism for transferring data / signals between any two devices through electrical contacts.
The GPIO pins on the malinka can work as inputs or as outputs . When a contact is a holiday , it can be turned on or off. The inclusion of a contact means that you can take 3.3 volts from it. By turning off, it means that there is no current through this contact. When the GPIO-contact is input , the Malinka checks whether there are 3.3 volts on it, or not.
These contacts are incredibly, breathtakingly versatile and can be used to implement a huge range of different functions. Details can be found in the documentation . Documentation is not just attached. It is possible, and sometimes necessary, to read along the course.
Let's start with the construction of such a scheme:
If you have never used a breadboard, then it is recommended to read (or at least see the pictures) here in this guide . In our scheme, we connect the LED to the contact 3.3 volts (pin number 1) and to the contact with zero potential (number 14). Pay attention to the correct connection of the LED. His shorter leg must be connected through a resistor to pin 14 (zero potential, or ground differently). After that, you can connect the malinka to the power. The LED will be on (if everything is connected correctly). If you turn the LED, it simply will not light up. He is finally the same diode as any of his friends.
If everything worked with a uniformly lit LED, then you can try to blink it. Cut off the raspberry from food. Now we reconnect the LED from pin 1 to pin 36 (GPIO 16) like this:
Again, remove the memory card. Copy files/gpio16-blink.bin
with the name kernel8.img
instead of the old one with the same name. Put the card back and connect the malinka to the power supply. Now the LED should blink uncontrollably.
This time we will be writing a prog, which will do the same as gpio16-blink.bin
. In order to be able to compile the nude sishechka under the raspberry we need a cross-compiler under aarch64-none-elf
.
We need to install a GNU toolchain for the aarch64-none-elf
architecture (the gcc compiler and its company are like objcopy).
First you need to install the homebrew package manager. If already installed, then this part can be skipped.
xcode-select --install
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Now install the aarch64-none-elf toolchain using homebrew.
brew tap SergioBenitez/osxct brew install aarch64-none-elf
Check whether everything is correctly installed:
$ aarch64-none-elf-gcc --version aarch64-none-elf-gcc (GCC) 7.2.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
arch64-none-elf
to /usr/local/bin
: wget https://web.stanford.edu/class/cs140e/files/aarch64-none-elf-linux-x64.tar.gz tar -xzvf aarch64-none-elf-linux-x64.tar.gz sudo mv aarch64-none-elf /usr/local/bin
/usr/local/bin/aarch64-none-elf/bin
to the PATH environment variable. How exactly - it depends on your particular Linux distribution. In most cases, you should add the following to ~/.profile
: PATH="/usr/local/bin/aarch64-none-elf/bin:$PATH"
aarch64-none-elf-gcc --version
You can build yourself from the source if such a desire arises. Read more here .
The interaction of the vast majority of modern hardware devices with software is carried out through its mapping into memory Memory-mapped I / O. The bottom line is this: you can communicate with devices as if it were just some part of the memory. This provides a specification of what will happen when you write or read certain addresses in memory. Addresses are usually divided into pieces of 32 or 64 bits, which are called registers. Registers can only be read from, written to, or both.
How do we know which registers and what to use, and where are they in memory? Manufacturers of various devices write documentation for these devices. Usually they are called datasheets (data sheet), manuals (device manual), well, or just documentation. There is no common widespread format for documenting devices. Sometimes the documentation may be insufficient or it may not be at all. The ability to read and understand the hardware documentation is quite a useful skill, and in some ways even art.
Documentation for many of the peripherals that the Rasbperry Pi has can be found in BCM2837 ARM Peripherals Manual . About GPIO can be read on page 89.
Pajazhi, in the same place about BCM2835, and we have BCM2837. Is that normal?
If you open the manual, then there can be seen in many places mentioning BCM2835. We just took a guide to it and corrected some errors. Well, the title was changed to BCM2837. BCM2837 and BCM2835 have the same peripheral devices with the same relative addresses in memory. The main difference in the overall configuration of physical memory. The base physical address of the peripherals on the BCM2837 is0x3F000000
, as opposed to0x20000000
in the BCM2835. However, both chips display these addresses at0x7E000000
. Briefly on the BCM2837, the "peripheral" address0x7EXXXXXX
will be located at the physical address0x3FXXXXXX
. This documentation has been modified to reflect this.
For our task, the following registers are enough for us:
name | address | description | the size | read / write |
---|---|---|---|---|
GPFSEL1 | 0x7E200004 | GPIO Function Select 1 | 32 bits | both |
GPSET0 | 0x7E20001C | GPIO Pin Output Set 0 | 32 bits | only record |
GPCLR0 | 0x7E200028 | GPIO Pin Output Clear 0 | 32 bits | only record |
This is directly copied directly from the documentation on page 90.
Now read the documentation for the GPFSELn
register on pages 91 and 92. We write to this register to configure the pins as output or input. What should be the value in each field of the register GPFSEL1
to configure the output number 16 GPIO, so that it becomes an output?
Now, again, read the documentation on page 95. About the registers GPSET0
and GPCLR0
. We write to the GPSET0
register to enable the contact. And in GPCLR0
for shutdown. What value do we need to write to these registers to enable / disable pin 16?
In the phase3/
turnips directory there is a procurement code for building a binary file for Malinka. For now, we can do without explaining why we need crt0.S
, layout.ld
and Makefile
. Instead, focus on blinky.c
. In it you will find that the addresses of all three registers we need at the top are already indicated. In addition, there are a couple of functions that can create a time delay. The task is to supplement the main
function so that pin 16 of the GPIO is configured as an output, and then it turns on and then turns off to flash with a LED.
When the code is ready - it should be tested. First, compile it by running make
, being in the phase3/
directory. If everything is good and there are no errors, then the blinky.bin blinky.bin
will be blinky.bin
. Rename it to kernel8.img
, copy it to a microSD card and run it all on a raspberry. If you already have a working kernel8.img
, you can proceed to the next phase.
Tips:
Setting / on / off pins can be implemented in a single line of code.
')
Here operators<<
,|
,&
and~
.
Hex and binary forms can be used in sishechke. For the number three, something like0x03
and0b011
respectively.
This time we will be writing a program like gpio16-blink.bin
, but already in Rust. The code is written in phase4/src/lib.rs
In order to compile programs on Rust, we should install this compiler. In addition, we will install xargo
, which is a wrapper associated with the package manager cargo
. Xargo allows us to compile our code for Rasbperry Pi and all that.
rustup
. Verify that Rust was installed correctly by running rustc --version
.rustup
and cargo
(which was installed with rustc in the last step) to install the Rust night assembly. At the same time and install the source code of the standard library. And xargo
course. rustup default nightly-2018-01-09 rustup component add rust-src cargo install xargo
$ rustc --version rustc 1.25.0-nightly (b5392f545 2018-01-08) $ xargo --version xargo 0.3.10 cargo 0.25.0-nightly (a88fbace4 2017-12-29)
Now we have quite a working compiler Rust.
To write code in the file phase4/src/lib.rs
you need to know at least the following constructs:
1) You can read from and write to what is behind the bare pointers ( *mut T
) using the read_volatile()
and write_volatile()
methods. For example, we have declared this:
const A: *mut u32 = 0x12 as *mut u32; const B: *mut u32 = 0x34 as *mut u32;
We can write a 32-bit unsigned integer with the address 0x12
into the cell with the address 0x34
like this:
B.write_volatile(A.read_volatile());
2) Local variables are declared using the let _ = _;
.
You can read A
from the previous example (i.e. the value located at address 0x12
) into a variable like this:
let value = A.read_volatile();
3) Call the function fn f(param: usize);
can be like this: f(123);
.
4) The loop
block can be used to repeat infinitely something:
loop { do_this_again_and_again(); }
5) Rust has the following bitwise operators:
!
- inversion<<
- left shift>>
- right shift|
- bit OR&
- bit I.Now you are ready to flash the LED from the code on Rust. The code is written in phase4/src/lib.rs
Translate the code into a similar rust code (in the kmain
function). There are already announced the necessary registers and the function of "sleep", which creates a delay for some time. Use it all.
When you are ready to test your program, compile it by running make
in the phase4
directory. If everything is fine, then the file build/blinky.bin
will be created, which we rename to kernel8.img
and put it on the microSD card, which we then insert into the raspberry. When the LED flashes again, we can assume that this part of the tutorial is complete.
UPD Next series
Source: https://habr.com/ru/post/349248/
All Articles