こんにちは/夕方/夜/朝! オペレーティングシステムに関する実験コースが1つあります。 彼はスタンフォード大学にいます。 ただし、一部の資料は誰でも利用できます。 スライドに加えて、実践的な演習の完全な説明が利用可能です。
このコースは他のコースとどう違いますか? ほとんどのコードは独立して記述され、非常に現実的な最新のハードウェアで実行されます。 Raspberry Pi 3モデルBがターゲットプラットフォームとして選択されました。 つまり かなり最新のアーキテクチャAArch64。 ARMv8 Cortex-A53、4コア、64ビット、それだけです。 Rustは主要なプログラミング言語として選択されています。 GCを使用しないなど、安全で高速です。 Rustはコース中に学習することになっています。
ディスク、ファイルシステム、I / O、スレッド/プロセス、スケジューリング、仮想メモリ、保護とセキュリティ、割り込み、同時実行性と同期についてです。 他の自尊心のあるコースのように。 素材の関連性と練習の量の違い。 Codditはたくさんあるでしょう。
翻訳者のメモ
文字通りの翻訳を見たいなら、そうではないでしょう。 代わりに、テキストを有用で理解しやすいものにしようとします。 たとえば、スタンフォード大学の学生にのみ関連する場所では、他の人に役立つ情報を投稿します。 少しスラングがあり、元のイラストとは少し無関係で、少数の追加コメントがあるかもしれません。 読みやすくするために、明示的なTranslator™Notesはありません。 テキストは、芸術的な翻訳または動機に基づく記事と見なすことができます。 私は溶接機ではありません-気分を害することはありません。
このコースについてどうやって知りましたか? 誰かがHacker Newsへのリンクを投稿しました。 私は誤って見たと染み込んだ。 コース教材を自分で突いて、最終的にこの問題を翻訳することにしました。
復習
このパートでは、ラズベリーと必要なツールをセットアップします。 その結果、ラズベリーの点滅LEDができます。 4つの主要な段階があります。 まず、Piとコンピューターの接続がそれ自体で機能することを確認する必要があります。 事前に準備されたプログラムを実行します。 第2段階では、LEDの接続方法を理解します。 ブレッドボードと配線について。 第三段階で収集します きれいな コードを作成し、Piで実行します。 aarch64-none-elf
クロスコンパイラをインストールして試してください。 そして、第4段階で、このすべてをRustで書き換えます。
いくつかの便利なリンク:
- BCM2837プロセッサのドキュメント -主に周辺機器について
- ブレッドボードと配線に関するカラフルで包括的な記事
- ラズベリーでのGPIOの使用について
- すでにかなり良いプログラミングをしている人のための基本的なRust構文について簡単に説明します
- Rustの公式教科書 ( ロシア語版はまだ準備ができていません-翻訳のお手伝いができます)
- 固体安全性のための錆びたタイプ
- Rustのライフタイムチートシート
- Rustのコンテナのチートシート (青色のテキストをクリック可能)
フェーズ0:はじめに
コースを完了する前に、Unixのようなオペレーティングシステムを直接使用する必要があります。 git
、 wget
、 tar
、 screen
、およびmake
インストールされたLinux、BSD、またはmacOSにすることができます。 理論的には、Linuxサブシステムを備えたWindows 10で動作しますが、誰も確認していません。 少なくともこの構成はサポートされていません。 つまり ワインダー用の既製のレシピはありません。UbuntuLSTまたはFedoraをインストールすることをお勧めします。
鉄から必要なもの:
- Raspberry Pi 3モデルB(BCM2837に必要)
- ブレッドボード、プロトタイピングボードでもあります
- microSDカード(プラスアダプター/アダプター)
- USB-UARTアダプター(CP2102 USB TTL)
- 10個のマルチカラーLED
- 100オームと1 kOhmの抵抗、それぞれ4
- 配線
redditに関する議論では、Amazonに必要なリンクがあります 。 ただし、これらはすべて他の店舗で購入できます。 オフラインを含む。 これに加えて、好みに合わせてコンポーネントを追加購入できます。
注意 :ラズベリーは静電気に敏感です。 素手でコンタクトに触れないようにしてください。 あなたは感電で殺されることはなく、傷つけられることさえありませんが、ラズベリー自体は全く無力化することができます。 自分を接地します。
これがすべて利用可能になったら、タスクコードを実行できます。
git clone https://web.stanford.edu/class/cs140e/assignments/0-blinky/skeleton.git 0-blinky cd assignment0 make fetch
内容を自分で自由に探索してください。
フェーズ1:ラズベリーの調理
最初に行う必要があるのは、CP2102アダプターの構成です。 コンピューターとPiの間の通信に必要です。 これに加えて、ラズベリーはそれを通して重要な5ボルトを受け取ります。 USBの片側、他の5つの部分、ショールの中央。
ドライバーのセットアップ
Linuxでは、すべてがすぐに動作するはずです。 ポピーでは、ドライバーをインストールする必要があります。 このアーカイブをダウンロードして解凍します。 SiLabsUSBDriverDisk.dmg
を起動し、ライセンスに基づく魂の販売ポイントに同意します。 その後、マウントされたボリュームで、 Silicon Labs VPC Driver.pkg
実行します。 インストールして再起動します。
CP2102を空きUSBスロットに接続してみてください。 すべてが機能する場合、適切なファイルが/dev
表示されます。 ポピー/dev/tty.SLAB_USBtoUART
場合。 Linuxの場合、 /dev/ttyUSB0
ようなもの。 それを書き留めてください-便利になります。 アダプタを取り出します。
ラズベリーをつなぐ
次に、Raspberry PiをCP2102に接続します。 コネクタの一致表は次のとおりです。
CP2102コネクタ | Raspberry Piコネクタ |
---|---|
+ 5v | 4 |
GND | 6 |
Rxd | 8 |
Txd | 10 |
ラズベリーのピンの番号付け(まだインタラクティブなバージョンがあります):
一緒にすべてがこのようになります(ワイヤの色は任意に選択できます):
重要 :これをすべてコンピューターに接続する前に、接続を確認して再確認してください。 焦げたジャムではなく、新鮮なラズベリーが必要です。
ラズベリーとアダプターの正しいペアリングに自信がある場合は、CP2102をコンピューターに接続できます。
打ち上げ
Raspberry Piは、電源投入時にmicroSDカードからプログラムをロードします。 今、私たちはそれを調理する方法を見つけます。
まず、クローンリポジトリからmicroSD-shkuにファイルをドロップする必要があります。 つまり、 files/firmware
フォルダにあるもの。 つまり bootcode.bin
、 config.txt
およびstart.elf
それらをフラッシュカードのルートにコピーします。 クローンリポジトリにこれらのファイルが突然ない場合は、 make fetch
を忘れていました。
なぜbootcode.bin
、config.txt
、およびstart.elf
が必要なのですか?
これがすべてのラズベリーブートローダーです。bootcode.bin
は最初のブートローダーです。 そのタスクはstart.elf
をロードすることstart.elf
。config.txt
ファイルの内容に従ってプロセッサを構成します。 その後、kernel8.img
をロードし、制御を転送します。 ところで、彼はどこにいるの?
files/activity-led-blink.bin
をリポジトリからフラッシュカードのルートにコピーし、このファイルにkernel8.img
という名前をkernel8.img
ます。 カードをアンマウントして引き出します。 ラズベリーがオフになっていることを確認してください。 次に、カードをラズベリーに挿入し、ラズベリーを食物に接続します。 ラズベリーとCP2102アダプタのLEDが点滅しているはずです。 後者の点滅は、データがそこに転送されていることを意味します。
データ? どのようなデータですか? それらを確認するには、シリアルターミナルエミュレーターをCP2102に接続し、そこで何が起こるかを読む必要があります。 LinuxとmacOSの両方にインストールされているため、 screenを使用します 。 /dev
フォルダーのデバイスパスを覚えて実行します
screen /dev/<> 115200
Linuxでは、 sudo
を使用してこのコマンドを実行する必要がある場合があります。 ただし、ユーザーをdialout
グループに追加して、このsudo
コマンドの前に絶えず書き込むことはできません。
sudo gpasswd --add <-> dialout
いずれにしても、ラズベリーからの挨拶が表示されるはずです。 screen
を終了するには、 <ctrl-a> k
押してから、終了の提案に対してy
と答えます。
フェーズ2:LEDの点滅
この段階で、ラズベリーのGPIO(物理接点No. 36)の16番目のピンをブレッドボードのLEDに接続します。 ファームウェアで事前に準備されたバイナリを使用して、その動作を確認しましょう。 ラズベリーがオフになっていることを確認してください。
GPIO:汎用I / O
名前が示すように、GPIOは電気接点を介して任意の2つのデバイス間でデータ/信号を転送するための一般的なメカニズムです。
ラズベリー色のGPIOピンは、 入力または出力として機能します 。 接点が出力の場合、オンまたはオフにできます。 接点をオンにすると、3.3ボルトを取ることができます。 シャットダウンとは、この接点に電流が流れないことを意味します。 GPIOピンが入力の場合、Malinkaは3.3ボルトがあるかどうかを確認します。
これらの連絡先は信じられないほど息をのむほど普遍的であり、さまざまな機能を幅広く実装するために使用できます。 詳細はドキュメントに記載されています 。 ドキュメントは添付されていません。 コース中に読むことができ、時には必要です。
LED接続。
そのような図を作成することから始めましょう。
ブレッドボードモデルを使用したことがない場合は、このガイドを読む(または少なくとも写真を見る)ことをお勧めします。 この回路では、LEDを3.3ボルトの接点(ピン番号1)とゼロ電位の接点(番号14)に接続します。 LEDの正しい接続に注意してください。 より短いレッグは抵抗を介してピン14に接続する必要があります(ゼロ電位、または別の方法での接地)。 その後、ラズベリーを電源に接続できます。 LEDが点灯します(すべてが正しく接続されている場合)。 LEDがひっくり返ると、点灯しなくなります。 結局のところ、彼は彼の友人のいずれかと同じダイオードです。
すべてが均一に点灯しているLEDで機能する場合、点滅させることができます。 食べ物からラズベリーを切り落とします。 次のように、ピン1からピン36(GPIO 16)にLEDを再接続します。
メモリカードを再び取り出します。 同じ名前の古いkernel8.img
なく、 kernel8.img
という名前files/gpio16-blink.bin
をコピーしfiles/gpio16-blink.bin
。 カードを戻し、ラズベリーを電源に接続します。 これで、LEDが制御不能に点滅するはずです。
フェーズ3:かわいいC
今回は、 gpio16-blink.bin
と同じことを行うprogプログラムをgpio16-blink.bin
ます。 raspberryのちょっとしたバイトをコンパイルできるようにするには、 aarch64-none-elf
クロスコンパイラが必要です。
クロスコンパイラのインストール
aarch64-none-elf
アーキテクチャ(gccコンパイラとobjcopyのような会社)のGNUツールチェーンをインストールする必要があります。
macOSの下で
まず、 homebrewパッケージマネージャーをインストールします。 すでにインストールされている場合、この部分はスキップできます。
- コマンドライン用のXcodeツールをインストールします。 ダイアログボックスが表示されます。 表示されたら-[インストール]、[続行]、または通常そこにあるものをクリックします。
xcode-select --install
- Homebrewインストールスクリプトを実行します。 インストールプロセスの残りの手順を説明します。
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
ここで、homebrewを使用してaarch64-none-elfツールチェーンをインストールします。
brew tap SergioBenitez/osxct brew install aarch64-none-elf
すべてが正しくインストールされているかどうかを確認します。
$ 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.
Linuxの下で
- aarch64-none-elf-linux-x64.tar.gzをダウンロードして解凍します。 その後、
arch64-none-elf
を/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
をPATH環境変数に追加します。 正確には-特定のLinuxディストリビューションに依存します。 ほとんどの場合、以下を~/.profile
追加する必要があります。
PATH="/usr/local/bin/aarch64-none-elf/bin:$PATH"
- すべてが正常かどうかを確認します。 その結果、gccバージョンとその他すべてを取得する必要があります。
aarch64-none-elf-gcc --version
そのような要望が生じた場合は、ソースから自分でコンパイルできます。 詳細はこちら 。
今、鉄について少し
最新のハードウェアデバイスの大部分とソフトウェアとの相互作用は、それをメモリマップドI / Oメモリにマッピングすることによって実行されます。 要するに、まるでメモリの特定の部分であるかのようにデバイスと通信できます。 同時に、メモリ内の特定のアドレスを読み書きする際に何が起こるかについての仕様が提供されます。 アドレスは通常、レジスタと呼ばれる32ビットまたは64ビットの断片に分割されます。 レジスタは、読み取り専用、書き込み、またはその両方にすることができます。
どのレジスターを使用し、なぜ使用するのか、そしてそれらがメモリー内のどこにあるのかをどのようにして知るのですか さまざまなデバイスのメーカーが、これらの同じデバイスのドキュメントを作成しています。 通常、それらはデータシート(データシート)、マニュアル(デバイスマニュアル)、または単にドキュメントと呼ばれます。 デバイスを文書化するための一般的な一般的な形式はありません。 ドキュメントが不十分な場合や、まったくない場合があります。 ハードウェアのドキュメントを読んで理解する能力は、非常に有用なスキルであり、ある意味ではアートでもあります。
インメモリGPIO
Rasbperry Piに搭載されている多くの周辺機器のドキュメントは、 BCM2837 ARM Peripherals Manualにあります。 GPIOについては、89ページで読むことができます。
パダジ、BCM2835についての同じ場所にあり、BCM2837があります。 これは正常ですか?
マニュアルを開くと、BCM2835の言及を多くの場所で見ることができます。 ただそれをガイドして、いくつかのエラーを修正しました。 まあ、タイトルはBCM2837に変更されました。 BCM2837とBCM2835には、メモリ内に同じ相対アドレスを持つ同じ周辺機器があります。 物理メモリの全体的な構成の主な違い。0x3F000000
とは異なり、0x20000000
の周辺デバイスのベース物理アドレスは0x3F000000です。 ただし、両方のチップはこれらのアドレスを0x7E000000
マップし0x7E000000
。 簡単に言うと、BCM2837では、「周辺」アドレス0x7EXXXXXX
は物理アドレス0x3FXXXXXX
配置されます。 上記のドキュメントは、これを考慮して修正されています。
このタスクでは、次のレジスタで十分です。
名 | 住所 | 説明 | サイズ | 読み取り/書き込み |
---|---|---|---|---|
GPFSEL1 | 0x7E200004 | GPIO機能選択1 | 32ビット | 両方 |
GPSET0 | 0x7E20001C | GPIOピン出力セット0 | 32ビット | 記録のみ |
Gpclr0 | 0x7E200028 | GPIOピン出力クリア0 | 32ビット | 記録のみ |
Taschettoは、90ページのドキュメントから直接コピーされます。
次に、91ページおよび92ページのGPFSELn
レジスタのドキュメントをお読みください。このレジスタに書き込み、ピンを出力または入力として設定します。 GPIOの出力番号16が出力になるように構成するには、 GPFSEL1
レジスタの各フィールドの値は何ですか?
ここで再び95ページのドキュメントを読みますGPSET0
およびGPCLR0
について。 GPSET0
レジスタに書き込み、連絡先を有効にします。 そしてGPCLR0
オフにします。 ピン16をオン/オフするには、これらのレジスタにどの値を書き込む必要がありますか?
コード記述
phase3/
turnipディレクトリには、ラズベリーのバイナリファイルをビルドするためのコードがあります。 今のところ、 crt0.S
、 layout.ld
およびMakefile
が必要な理由を説明せずに行います。 代わりに、 blinky.c
に注目してblinky.c
。 その中に、必要な3つのレジスタすべてのアドレスがすでに上部に示されていることがわかります。 さらに、時間遅延を作成できる関数がいくつかあります。 タスクは、GPIOのピン番号16が出力として設定されるようにmain
機能を補うことです。その後、オンとオフが切り替わり、LEDが点滅します。
コードの準備ができたら、テストする必要があります。 開始make
には、 phase3/
ディレクトリでmake
を実行しmake
コンパイルします。 すべてが正常でエラーがない場合、blinky.bin blinky.bin
がblinky.bin
ます。 名前をkernel8.img
に変更し、microSDカードにコピーして、すべてラズベリーで実行します。 既に機能するkernel8.img
がある場合は、次のフェーズに進むことができます。
ヒント:
ピンの設定/有効化/無効化は、1行のコードで実装できます。
演算子<<
、|
、&
および~
。
文字列には16進形式と2進形式を使用できます。 30b011
それぞれ0x03
と0b011
ようなものです。
フェーズ4:錆
今回は、 gpio16-blink.bin
似たプログラムを作成しますが、すでにRustにあります。 phase4/src/lib.rs
コードを記述します。
RustとXargoをインストールする
Rustでプログラムをコンパイルするには、この同じコンパイラーをインストールする必要があります。 さらに、 cargo
パッケージマネージャーに関連付けられたラッパーであるxargo
をインストールします。 Xargoを使用すると、Rasbperry Piなどのコードをコンパイルできます。
- に行きましょう https://rustup.rs/そして、指示に従って
rustup
をインストールしrustup
。rustc --version
実行して、Rustが正しくインストールされたことを確認します。 - さて、
rustup
とcargo
(最後の手順でrustcを使用してインストールされた)を使用して、Rustナイトアセンブリをインストールします。 同時に、標準ライブラリのソースをインストールします。 そしてxargo
もちろんxargo
。
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)
これで、Rustコンパイラが完全に動作するようになりました。
コード記述
phase4/src/lib.rs
コードを書くには、少なくとも次の構成要素を知っている必要がありphase4/src/lib.rs
。
1) read_volatile()
およびwrite_volatile()
メソッドを使用して、ベアポインターの背後にあるもの( *mut T
)の読み取りと書き込みを行うことができます。 たとえば、これを宣言しました:
const A: *mut u32 = 0x12 as *mut u32; const B: *mut u32 = 0x34 as *mut u32;
アドレス0x12
符号なし32ビット整数を、アドレス0x34
セルに次のように書き込むことができます。
B.write_volatile(A.read_volatile());
2)ローカル変数は、構文let _ = _;
を使用して宣言let _ = _;
。
前の例のA
( 0x12
ある値)を次のような変数に読み込むことができます:
let value = A.read_volatile();
3)関数fn f(param: usize);
次のようになります: f(123);
。
4) loop
ブロックを使用して、無限に何かを繰り返すことができます。
loop { do_this_again_and_again(); }
5)Rustには次のビット演算子があります:
-
!
-反転 -
<<
-左シフト -
>>
-右にシフト -
|
-ビット単位のOR -
&
-ビットI
これで、RustコードのLEDを点滅させる準備ができました。 phase4/src/lib.rs
コードを記述します。 コードを同じ錆コードに変換します( kmain
関数内)。 必要なレジスタと、しばらくの間遅延を作成する「スリープ」機能をすでに発表しています。 それをすべて使用します。
プログラムをテストする準備ができたら、 phase4
ディレクトリでmake
を実行しmake
コンパイルします。 すべてが正常であれば、 build/blinky.bin
ファイルが作成されます。 build/blinky.bin
ファイルの名前をkernel8.img
に変更し、microSDカードに配置してから、ラズベリーに挿入します。 LEDが再び点滅したら-チュートリアルのこの部分が完了していると想定できます。
UPD Next Series