最初からオペレーティングシステム。 レベル0

こんにちは/夕方/夜/朝! オペレーティングシステムに関する実験コースが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で書き換えます。







いくつかの便利なリンク:









フェーズ0:はじめに



コースを完了する前に、Unixのようなオペレーティングシステムを直接使用する必要があります。 git



wget



tar



screen



、およびmake



インストールされたLinux、BSD、またはmacOSにすることができます。 理論的には、Linuxサブシステムを備えたWindows 10で動作しますが、誰も確認していません。 少なくともこの構成はサポートされていません。 つまり ワインダー用の既製のレシピはありません。UbuntuLSTまたはFedoraをインストールすることをお勧めします。













鉄から必要なもの:









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







ブレッドボードモデルを使用したことがない場合は、このガイドを読む(または少なくとも写真を見る)ことをお勧めします。 この回路では、LEDを3.3ボルトの接点(ピン番号1)とゼロ電位の接点(番号14)に接続します。 LEDの正しい接続に注意してください。 より短いレッグは抵抗を介してピン14に接続する必要があります(ゼロ電位、または別の方法での接地)。 その後、ラズベリーを電源に接続できます。 LEDが点灯します(すべてが正しく接続されている場合)。 LEDがひっくり返ると、点灯しなくなります。 結局のところ、彼は彼の友人のいずれかと同じダイオードです。







すべてが均一に点灯しているLEDで機能する場合、点滅させることができます。 食べ物からラズベリーを切り落とします。 次のように、ピン1からピン36(GPIO 16)にLEDを再接続します。







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パッケージマネージャーをインストールします。 すでにインストールされている場合、この部分はスキップできます。







  1. コマンドライン用のXcodeツールをインストールします。 ダイアログボックスが表示されます。 表示されたら-[インストール]、[続行]、または通常そこにあるものをクリックします。

     xcode-select --install
          
          



  2. 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の下で



  1. 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
          
          



  2. /usr/local/bin/aarch64-none-elf/bin



    をPATH環境変数に追加します。 正確には-特定のLinuxディストリビューションに依存します。 ほとんどの場合、以下を~/.profile



    追加する必要があります。

     PATH="/usr/local/bin/aarch64-none-elf/bin:$PATH"
          
          



  3. すべてが正常かどうかを確認します。 その結果、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進形式を使用できます。 3 0b011



それぞれ0x03



0b011



ようなものです。


フェーズ4:錆



今回は、 gpio16-blink.bin



似たプログラムを作成しますが、すでにRustにあります。 phase4/src/lib.rs



コードを記述します。







RustとXargoをインストールする



Rustでプログラムをコンパイルするには、この同じコンパイラーをインストールする必要があります。 さらに、 cargo



パッケージマネージャーに関連付けられたラッパーであるxargo



をインストールします。 Xargoを使用すると、Rasbperry Piなどのコードをコンパイルできます。







  1. に行きましょう https://rustup.rs/そして、指示に従ってrustup



    をインストールしrustup



    rustc --version



    実行して、Rustが正しくインストールされたことを確認します。
  2. さて、 rustup



    cargo



    (最後の手順でrustcを使用してインストールされた)を使用して、Rustナイトアセンブリをインストールします。 同時に、標準ライブラリのソースをインストールします。 そしてxargo



    もちろんxargo





     rustup default nightly-2018-01-09 rustup component add rust-src cargo install xargo
          
          



  3. インストールされたコマンドをチェックし、これらすべてのバージョンがそれらに必要なものに対応していることを確認します。

     $ 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には次のビット演算子があります:









これで、RustコードのLEDを点滅させる準備ができました。 phase4/src/lib.rs



コードを記述します。 コードを同じ錆コードに変換します( kmain



関数内)。 必要なレジスタと、しばらくの間遅延を作成する「スリープ」機能をすでに発表しています。 それをすべて使用します。







プログラムをテストする準備ができたら、 phase4



ディレクトリでmake



を実行しmake



コンパイルします。 すべてが正常であれば、 build/blinky.bin



ファイルが作成されます。 build/blinky.bin



ファイルの名前をkernel8.img



に変更し、microSDカードに配置してから、ラズベリーに挿入します。 LEDが再び点滅したら-チュートリアルのこの部分が完了していると想定できます。







UPD Next Series








All Articles