セキュリティミニキャンプ北陸2016で利用した講義資料です。
Copyright Toshifumi NISHINAGA License: CC-BY-SA-NC 4.0
BareMetal で遊ぶ Raspberry Piミニキャンプ北陸 verToshifumi NISHINAGA2016/12/04この作品はクリエイティブ・コモンズ・表示 - 非営利 - 継承 4.0 国際・ライセンスで提供されています。このライセンスのコピーを閲覧するには、 http://creativecommons.org/licenses/by-nc-sa/4.0/ を訪問して下さい。
View Slide
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0BareMetal 開発ってなに?• BareMetal とは?• (組み込みの分野では) OS などの入っていないコンピュータのこと• BareMetal 開発とは?• BereMetal なコンピュータの上で動くプログラムを作っていくこと22016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0導入〜 L チカは簡単?〜• L チカ( LED Blink )とは• LED を点滅させるだけの”簡単“なプログラム• 低レイヤー版 Hello World• Linux の起動した Raspberry Pi では,シェルを叩くだけで”簡単”に L チカができる• $ sudo echo 47 > /sys/class/gpio/export• $ sudo echo out > /sys/class/gpio/gpio47/direction• $ sudo sh –c ‘echo 1 > /sys/class/gpio/gpio47/value’• $ sudo sh –c ‘echo 0 > /sys/class/gpio/gpio47/value’32016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0導入〜 L チカは本当に簡単?〜• 本当に簡単ですか?• ドライバがなかったら?• GPIO1 の初期化,設定,出力のための処理を全て書く必要がある• Linux が起動していなかったら?• CPU の初期化, C 言語が動くための初期化,その他いろいろ行う必要がある• 以上の状況でも,同じように L チカは簡単といえますか?4補足 1: デジタル信号の入出力を行う外部装置(ペリフェラル)2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0これからも L チカを簡単にするために• 何故 L チカが”簡単に“できるか• Raspberry Pi に Linux を移植した人がいる• ドライバを書き,簡単に GPIO を使えるようにした人がいる• これからも L チカを”簡単”に行っていくためには• Linux の移植やドライバ実装を自分たちで行う必要がある• 使う側から作る側になるために• まずは低レイヤーの学び方を学ぶところから始めよう!52016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0この講義の目的と得られるもの• 低レイヤー知識とその学び方を身につける• 電源投入からプログラムが動くまで• クロスコンパイル環境の作り方(簡略版)• Makefile を使ったプログラムのビルド方法• データシートの探し方,読み方• ペリフェラルの使い方62016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0目次1. コンピュータ基礎知識2. 低レイヤー資料の読み方探し方3. クロス開発環境の構築4. C 言語を動かそう5. LED Blink(L チカ )2016/12/04 7
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0コンピュータ基礎知識2016/12/04 8
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0コンピュータ基礎知識• コンピュータを構成する要素は以下の 2 つに分類される• ハードウエア• ソフトウエア2016/12/04 9
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0ハードウェア• コンピュータの目に見える物理的な機械の部分• 一般的に,以下の装置によって構成される• 中央演算処理装置• CPU (大切なので次頁で解説)• 主記憶装置• メインメモリ (RAM)• 補助記憶装置• HDD, SSD など• 入力装置• キーボード,マウスなど• 出力装置• ディスプレイ,スピーカーなどCPU主記憶入力 出力補助記憶: データの流れ2016/12/04 10
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0中央演算装置 ( 以降, CPU)• 演算や制御の中心となる装置• 次のような機能が存在する• Register• 計算に必要な数値を一時的に格納する機能.• 計算は基本レジスタに対し行われ,結果もレジスタに入る.• レジスタが扱える値は限り 1 がある• PC( プログラムカウンタ )• 次に実行する命令の場所 ( メモリアドレス 2) を示すカウンタ• その他,説明を省略2016/12/04 11補足 1 : 64-bit マシン (x86_64) なら 64-bit まで.計算結果が 64-bit 以上になる時,溢れた分は ( 基本 ) 消える補足 2 : CPU は一般的にメインメモリに置かれたプログラムを逐次実行するようになっている .CPU は PC の示す場所から命令を取り出し,実行する.
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0例 : ARM のレジスタ• 汎用レジスタ (R0-R12)• 計算など自由に使えるレジスタ• R0 ~ R12 の 13 本ある• スタックポインタ (SP=R13)• スタックの先頭メモリアドレスを指すレジスタ• リンクレジスタ (LR=R14)• 関数の戻りメモリアドレスを指すレジスタ• プログラムカウンタ (PC)• 次に実行する命令のメモリアドレスを指すレジスタ2016/12/04 12
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0ソフトウェア• ハードウェアを制御するプログラムのこと• 以下のようなものは全てソフトウエアに分類される• ファームウェア• BIOS や UEFI など• OS• Windows , Mac , Linux , *BSD など• アプリケーション• Word や Excel など2016/12/04 13
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0実行可能なプログラムの作り方1. コンピュータにしてほしいことを書いたソースコードを作る2. ソースコード以下の手順で実行可能なプログラムに変換する 11. プリプロセス : ソースコードの文法チェックなどを行う2. コンパイル : ソースコードをオブジェクトコードに変換する3. リンク : 実行に必要な複数のオブジェクトを結合する2016/12/04 14補足 1: この一連の工程をビルド (build) や make という
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0ソースコードとオブジェクトコード• ソースコード ( 略 : ソース )• 人間がコンピュータにやってほしいことを記述したコード• 中身はテキスト ( 人間が読める )• コンピュータでは直接実行することができない• オブジェクトコード ( 略 : オブジェクト )• コンピュータで直接実行できる形式のコード• 中身は 0 または 1 で構成されたバイナリ ( 普通の人間は読めない )• ソースコードはコンパイラを使ってこの形式に変換される• この変換することをコンパイルという2016/12/04 15
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0コンパイル• コンパイラ (compiler) を使ってソースコードをオブジェクトコードの形式に変換すること2016/12/04 16#includeint main(void){print(“hello\n”);return 0;}コンパイラ01010100001011101011101010101010010101010101101010101010101010101010101010100010111010101101011010ソースコード オブジェクトコード
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0リンク• リンカ (linker) を使ってプログラムの実行に必要な複数のオブジェクトを結合すること• プログラムをメモリのどこに置けばよいかなどの設定も行う2016/12/04 17リンカ010101000010オブジェクトコードオブジェクトコード01010100001001010100001001010100001011101011101010101010010101010101101010101010101010101010101010100010111010101101011010
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Tips: コンパイルとビルド• Q.• gcc でコンパイルするとそのまま実行可能ファイルができるのはなぜ?• 「ビルド」 と 「コンパイル」 は同じ意味ってこと?• A.• Linux 等で特にオプションを付けずに実行すると,コンパイルとリンクが自動で行われ, a.out という実行可能ファイルが得られます• 例 : gcc hogehoge.c• -c オプションを付けるとコンパイルだけ行えます• gcc –c hogehoge.c• 「ビルド」 と 「コンパイル」 は厳密には別ですが,同じ意味で使っている人も多いのであまり気にしなくて良いと思います.2016/12/04 18
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0低レイヤー資料の読み方探し方2016/12/04 19
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0低レイヤー資料の読み方探し方• 今回使用する Raspberry Pi は ARM アーキテクチャの SoC(System on Chip) を使用しているので,それに関連する資料を集める• しかし……• ARM の SoC は資料が各所にばらけていて集めづらい• 理由• CPU コアやアーキテクチャを設計している所( ARM )とSoC を製造している所( Broadcom など)が違うため• 資料を探す前に SoC , CPU コア, CPU アーキテクチャの違いを学ぶ2016/12/04 20
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0SoC, CPU, CPU アーキテクチャの違い• SoC(System on Chip)• 必要なシステム全てを1つのチップに集積する半導体の設計手法• 本資料では CPU やペリフェラル(外部装置)を集積したものを SoCと呼ぶ• CPU コア(プロセッサ)• SoC の中で計算等を行う部分• CPU アーキテクチャ• CPU コアの基礎設計• ここが同じ CPU は命令セットなどの基礎設計部が共通.• ペリフェラル• UART (シリアル通信)等を行うための外部装置.• CPU と一緒に SoC へ搭載される.• ARM 社またはチップベンダ (Broadcom 社など ) が設計している21SoCCPU コアUART Timer USB SPI2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0RasPi の SoC , CPU ,アーキテクチャ• SoC(System on Chip)• Broadcom 社の BCM2835• CPU コア(プロセッサ)• ARM1176JZF-S• 補足 : ARM11 はプロセッサファミリ名• CPU アーキテクチャ• ARMv6KZ アーキテクチャ2016/12/04 22SoC(BCM2835)CPU コア(ARM1176JZF-S)UART Timer USB SPI
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0各資料の場所• SoC• 基本は SoC を製造しているメーカー(チップベンダ)のサイトにある• 例外: BCM2835 の資料は RasPi の公式サイトにある• https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf• CPU コア ( プロセッサ ) , CPU アーキテクチャ• ARM 社のサイトにある.アーキテクチャは要登録.• http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf• https://silver.arm.com/download/download.tm?pv=1057882• ペリフェラル• 基本的には SoC の資料に書かれている• ARM 社の作ったペリフェラルについては ARM 社のサイトにも資料がある• こちらの方がわかりやすい場合もある232016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0資料の読み方1. 目次を見て知りたい機能について書かれたページ番号を見つける2. 初めに特徴 (feature) や概要 (outline, summary) ,簡単な使い方(How to use 的なもの ) が書かれているので,大まかな機能や使い方を把握する• 図がある場合は図を先に見て,頭のなかにイメージを作る3. 手順 1. と 2. を繰り返し,目的の機能を見つけ,読んでいく• それでもわからない時• Google などで検索して,解説している記事や,その機能を使って実装されたコードを読んで理解する2016/12/04 24
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0クロス開発環境の構築2016/12/04 25
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0セルフコンパイルとクロスコンパイル• セルフコンパイル• プログラムをコンパイルするコンピュータ ( ホスト ) の CPU アーキテクチャと,プログラムを実行するコンピュータ(ターゲット)の CPU アーキテクチャが同じコンパイルのことをセルフコンパイル,開発のことをセルフ開発という.• クロスコンパイル• ホストとターゲットが異なるコンパイルをクロスコンパイル,開発のことをクロス開発という.• ToolChain( 開発環境 )• 開発に必要なもの (binutils, gcc 等 ) をまとめて toolchain という• クロス開発環境のことは cross toolchain という• 「ターゲットアーキテクチャ名 cross toolchain 」等で検索すると情報が見つかる2016/12/04 26
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0なぜクロス開発環境が必要か• パッケージ管理ソフトで入れられるのは基本セルフ開発環境のみ• ホストのパソコンは x86_64 アーキテクチャ,ターゲットの Raspberry Pi は ARM アーキテクチャなので,クロス開発環境が必要272016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : クロス開発環境構築• ミニキャンプではこの節の残りの説明・演習を省略します.• クロス開発環境は予めビルドを行い,パスも通してあります.• 興味のある方は,後日試してみてください.2016/12/04 28
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0クロス開発環境の作り方• ビルド済み環境 (Prebuild toolchain) を持ってくる• メリット :ダウンロードして展開するだけで利用できてお手軽• デメリット :特定環境用のものがない場合がある• 自分でビルドする(今回行ったのはこちら)• メリット : 特定環境に特化した toolchain が作れる.• デメリット : ビルドのための学習コストや時間がかかる.292016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Tips: ARM のビルド済みクロス開発環境• CodeSourcery• Lite edition は無料.• Linaro Toolchain• https://wiki.linaro.org/WorkingGroups/ToolChain• Raspberry Pi 公式• https://github.com/raspberrypi/tools/tree/master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x6430詳細は http://elinux.org/Toolchains 参照2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0クロス開発環境を自分で作る• 普通のやり方• 以下の手順で作る1. binutils (アセンブラ等)をビルドする2. お互いに依存する gcc と libc1 を交互にビルドする• 便利なツールを使って作るやり方• Crosstool-NG( ← 今回つかったのはこちら )• Yocto2• Buildroot231補足 1: C 言語の基本的な関数 (printf など ) を提供するライブラリ補足 2: どちらも組み込み Linux イメージを作るためのプロジェクト,ツール2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Crosstool-NG• クロス開発環境を作るためのツール• TUI でアーキテクチャ等を設定すれば,後は自動でクロス開発環境ができる322016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : クロス開発環境構築• 作業用ディレクトリを作る• $ mkdir ~/ctng && cd ~/ctng• テンプレートを取得• $ ct-ng arm-unknown-eabi• 細かい設定に入る• $ ct-ng menuconfig• 細かい設定• MMU を無効化• Target options -> Use the MMU のチェックを外す• アーキテクチャを設定• Target options -> Emit assembly for CPU に arm1176jzf-s をセット• システムコール実装の無効化• C-library -> Disable the syscalls supplied with newlibがチェックされていることを確認(理由は BareMetal で遊ぶ Raspberry Pi, 6 章参照)332016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : クロス開発環境構築• ビルド• $ ct-ng build.4• Tips: 4 は並列ビルド数• パスを通す• 1 時間ほど待つと $HOME/x-tools/arm-unknown-eabi/ 以下にクロス開発環境ができるので,以下のコマンドでパスを通す• $ echo ’export PATH=$PATH:$HOME/x-tools/arm-unknown-eabi/bin’ >> $HOME/.bashrc• $ source $HOME/.bashrc342016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0C 言語を動かそう2016/12/04 35
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0開発用ディレクトリ• ホームディレクトリ以下に「 ledblink 」という開発用ディレクトリがあります.• 以降,ソースコード等はこの ledblink ディレクトリ以下に置いて作業してください362016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0BareMetal で C 言語を動かすためには1. 電源 ON からプログラムが動くまでの動作を知る2. リンカスクリプトを作る3. スタートアップコードの作成1. スタックポインタの設定2. BSS のクリア3. main を呼ぶ4. Makefile を作る5. make する2016/12/04 37
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0電源 ON からプログラムが動くまで• Raspberry Pi の場合1. 電源 ON2. GPU が SD カードからファームウェアを読み込んで実行を開始する3. GPU がメインメモリの有効化などを行う4. GPU が SD カードから kernel.img(config.txt で書き換え可 ) をメインメモリの 0x8000 番地にロードする5. CPU のプログラムカウンタ (PC) を 0x8000 に設定して CPU に処理を渡す6. kernel.img が 0x8000 番地から実行を開始する2016/12/04 38参考 URL: https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=6685
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0リンカスクリプトを作る• リンカスクリプトとは?• リンカに対しプログラムをメモリのどこに置くかなど指示するためのスクリプト• 以下の様なことを指示することができる.• セクション(後述)の配置• エントリポイントとなるシンボル名(関数名)• 何故リンカスクリプトが必要なの?• 基本的にマイコン等のメモリ配置はターゲットごとばらばらなので,リンカはプログラムをメモリのどこに置けばよいかわからない.• なので,リンカスクリプトを書いて各ターゲットのメモリ配置を教える必要がある392016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0リンカスクリプトの役者紹介• OUTPUT_ARCH( arch )• アーキテクチャの指定を行う.今回は arm を指定• ENTRY( entry point )• プログラムの実行開始地点となるシンボルを指定する.今回は _start を指定.• MEMORY• メモリ空間及びその空間の属性(読み書き可など)を定義する.• ROM と RAM が分かれているような環境(マイコン等)では必須.• RAM のみ用いる今回は書かなくても動いているが,本当は書いたほうが良い• SECTION { ... }• プログラムの各セクション配置を定義する.最低限 以下を書けば動く ( 動いた ) .• .text : 実行可能プログラムのあるセクション• .data: 初期値を持つ変数の値が格納されるセクション• .rodata: 定数が格納される.書かなければ .data に統合される.• .bss: 初期値を持たない変数等が格納されるセクション.402016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0リンカスクリプトの役者紹介• ALIGN(4096)• メモリの区切り (Align) を 4096byte に設定する.• . = 0x00008000;• 現在地点のアドレスを設定する.上記の次の行に書かれたセクションは,設定されたアドレスから開始される.• __hoge__ = . ;• 現在地点のアドレスにシンボルをつける.• シンボルをつけたアドレスは,アセンブリや C 言語等から利用できる.• C 言語で利用する例: extern void *__hoge__;• BSS 領域(後述)のクリア等のために使用する.• その他について• 実際に書かれたリンカスクリプトを読んで覚える• 坂井さんの「リンカ・ローダー実践開発テクニック * 」などを読む41* 坂井 弘亮 , 「リンカ・ローダー実践開発テクニック」 ,CQ 出版社2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : リンカスクリプトを読むOUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{. = 0x8000;.text : { *(.text*) }. = ALIGN(4096);__rodata_start = .;.rodata : { *(.rodata*) }. = ALIGN(4096);__rodata_end = .;__data_start = . ;.data : { *(.data*) }. = ALIGN(4096);__data_end = . ;__bss_start = . ;.bss : { *(.bss*) }. = ALIGN(4096);__bss_end = . ;}422016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0リンカスクリプトで作ったメモリ配置430x000000000xffff.text0x00008000.rodataメモリアドレス シンボル名.data.bss__rodata_start__rodata_end__data_start__data_end__bss_start__bss_end2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0スタートアップコードの作成• C 言語を動かせるようにするために,以下を行うスタートアップコード (start.S) を書く• CPU モードの設定(今回は省略)• ベクタテーブルの設定(今回は省略)• スタックポインタの設定• BSS のクリア• main へ飛ぶ• 以降,各設定の説明及び記述例を示します.• 最初にアセンブリコードの書き方もちょこっと示します.442016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Tips: アセンブリコードの用語説明• ラベル• ラベルが宣言された場所のメモリアドレスを値として持たせることができる.• 関数名やループのジャンプ先の指定のために利用する• 書き方 (_start 関数の定義 )• _start:• グローバル宣言• ラベルを別のソースからも参照できるようにする• 書き方 (_start 関数をグローバル宣言する )• .global _start• アライメント• コードのアライメントを byte 単位で設定する .ARM 命令の命令長は 32-bit(4-byte) なので 4 を設定する.• 書き方• .align 4452016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0start.S のテンプレート.align 4.global _start_start:// ここに初期化のコードを書く// main を呼ぶ// 無限ループb .462016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0スタックポインタ (sp) の設定• C 言語は自動変数をメインメモリ上のスタック (Stack) 呼ばれる場所に置く• スタックはスタックポインタの初期メモリアドレスから,スタックポインタの示すメモリアドレスまでを利用する• スタックポインタの初期メモリアドレスを正しく設定しないと,メモリアクセス違反でプログラムが動かなくなる2016/12/04 47プログラムスタック成長方向0x000000000xffffスタックの初期アドレススタックポインタのアドレス
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0参考 : ヒープメモリとスタックメモリ• ヒープ (Heap)• プログラムが動的に獲得するメモリ• malloc 関数等で確保して使う• 成長方向は(基本)下位アドレスから上位アドレス.• スタック (Stack)• 自動変数,引数,戻りアドレスなどを格納するためのメモリ• 成長方向は(基本)上位アドレスから下位アドレス.48プログラムヒープスタック成長方向0x000000000xffff
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0スタックポインタ (sp) の設定• Raspberry Pi(512MB モデル ) のメモリは0x00000000 – 0x20000000までを自由に利用可能• ただし一部は GPU が利用する• デフォルトでは 64MiB* , 最大 448MiB .• よって, sp には 0x1c000000 をセットする• ldr sp, =0x1c00000049GPU(64MiB)0x000000000xffffStack0x1c000000.text.rodata.data.bss*: https://www.raspberrypi.org/documentation/confguration/confg-txt.md参考 URL に書かれた単位は MB ですが, MiB のほうが正しい……はず.0x200000002016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0start.S(SP 設定後 ).align 4.global _start_start:// ここに初期化のコードを書くldr sp, =0x1c000000// main を呼ぶ// 無限ループb .502016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0BSS のクリア• BSS• 初期値を持たない変数(グローバル変数)等が格納されるセクション• 0 で初期化する必要がある.• BSS クリアの方法• リンカスクリプトで付けたシンボル名を用いて,__bss_start から __bss_end までを 0 で初期化する512016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0BSS 領域をクリアするアセンブリコード• アセンブリコードmov r0, #0 // r0 <- 0ldr r1, =__bss_start // r1 <- __bss_startldr r2, =__bss_end // r2 <- __bss_endloop:cmp r1, r2 // r1 - r2 を行い,フラグをセットするbeq loop_end // r1 == r2 なら loop_end に飛ぶstr r0, [r1] // r1 の指すアドレスのメモリに r0 の値をストアadd r1, r1, #4 // アドレスを増加b loop // loop へ無条件ジャンプloop_end:// その後の処理を書く52※ 「 // 」以降はコメント2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0start.S(BSS 初期化後 ).align 4.global _start_start:// ここに初期化のコードを書くldr sp, =0x1c000000mov r0, #0ldr r1, =__bss_startldr r2, =__bss_endloop:cmp r1, r2beq loop_endstr r0, [r1]add r1, r1, #4b looploop_end:// mainを呼ぶb . // 無限ループ532016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0main 関数に飛ぶ• 初期設定完了後は main 関数に飛ぶ• BL(Branch with Link) 命令を使う• 例 : bl main• 補足 : BL 命令について• BL 命令は分岐後に戻ってきたい場合に用いる ( 関数呼び出しなど)• BL 命令は次の命令のアドレス (pc+4) を lr に保存した後,ジャンプする• ジャンプ後, BX 命令を用いて bx lr のようにすると,分岐した場所の次の命令に戻れる54_startmainbl main bx lr2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0start.S(BSS 初期化後 ).align 4.global _start_start:// ここに初期化のコードを書くldr sp, =0x1c000000mov r0, #0ldr r1, =__bss_startldr r2, =__bss_endloop:cmp r1, r2beq loop_endstr r0, [r1]add r1, r1, #4b looploop_end:bl main // mainを呼ぶb . // 無限ループ552016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Tips: 引数の渡し方と戻り値の返し方 (ARM編 )• 関数呼び出しの引数の渡し方• 引数が4つ以下なら,第1引数から順に R0 から R3 レジスタに入れて渡す.• 引数が5つ以上の場合は,第5引数からはスタックに積んで送る.• 戻り値の返し方• 返り値が 32-bit 以下で表せるなら, R0 レジスタに入れて返す.56参考 (5.4, 5.5 節 ): http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Tips: Caller/Callee saved registers• Caller saved registers• 引数渡しに使われるレジスタ (R0-R3) など,関数を呼び出す側が内容を保存するレジスタのこと.• つまり,関数呼び出し後は値の同一性が保証されないレジスタ• Callee saved registers• 呼び出された関数側で値を保証しなければならないレジスタの事.• Caller saved registers 以外のレジスタ (R4-R12) のうち,関数内で上書き使用するレジスタを必要に応じて保存する.• Caller saved registers は関数の初めにスタックに保存してから使い,最後にスタックから復元する.572016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Tips: Caller/Callee saved registers• 関数呼び出し及び戻り時のレジスタ保護イメージ58関数 A関数 BR0-R3 をスタックに退避処理の流れスタックから R0-R3 を復元関数 B 呼び出しR4-R12 の中で使用するレジスタをスタックに退避退避したレジスタを復元処理2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Makefile を書く• Makefile とは?• プログラムをビルドするためのルール等を記すファイル• このファイルを make コマンドに読み込ませると,書かれたルールに従ってビルドを行ってくれる.• Makefile のいいところ• 依存関係を調べ,更新のあるファイルだけをビルドしてくれる• 複数に別れたコードも一括でビルドできる• 長く使われているので資料が多い(←大切)592016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : Makefile を書く• ミニキャンプではこの節の残りの説明・演習を省略します.• 興味のある方は,後日試してみてください.2016/12/04 60
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Makefile の基本的な書き方• ビルドルールの基本形• ターゲット : 依存関係 ( 複数可 )コマンドコマンド...61参考 URL: https://www.gnu.org/software/make/manual/html_node/Pattern-Intro.html#Pattern-Intro2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0• ビルドルールの例• ldscript.lds, source.c から target を作る2016/12/04 62target を作るビルドルールsource.cldsctipt.lds01010100001011101011101010101010010101010101101010101010101010101010101010100010111010101101011010targettarget: ldscript.lds source.carm-unknown-eabi-gcc -c -o source.o source.carm-unknown-eabi-ld -T ldscript.lds source.o -o target
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Makefile の基本的な書き方• ルールを分けることも可能2016/12/04 63target: ldscript.lds source.carm-unknown-eabi-gcc -c -o source.o source.carm-unknown-eabi-ld -T ldscript.lds source.o -o targettarget: ldscript.lds source.oarm-unknown-eabi-ld -T ldscript.lds source.o -o targetsource.o: source.carm-unknown-eabi-gcc -c -o source.o source.c分離
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0自動変数• 自動変数とは• ターゲットや依存ファイルの名前を省略して書くためのもの• 以下の3つはよく使うので覚えておくと便利• $@ : ターゲットファイル名• $< : 依存ファイル名 ( 一番最初のみ )• $^ : 依存ファイル名 ( 全部 )642016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0source.o: source.carm-unknown-eabi-gcc -c -o source.o source.cMakefile の基本的な書き方• 自動変数使用例2016/12/04 65source.o: source.carm-unknown-eabi-gcc –c -o $@ $^自動変数を使って書き直し• source.c は $^ に置換• source.o は $@ に置換
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0変数• 変数• コンパイラ名やコンパイルオプション等を入れた変数を定義できる• メリット• ルールを短く書ける• 共通の設定を一度に変更できる ( 最適化レベル変更などの際便利 )• 文法• CFLAGS= -Os # 変数を定義• CFLAGS+= -g # 変数に追加• CPPFLAGS= $(CFLAGS) # 変数を呼び出して変数を定義662016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0source.o: source.carm-unknown-eabi-gcc –c -o $@ $^Makefile の基本的な書き方• 変数使用例2016/12/04 67CC=arm-unknown-eabi-gccsource.o: source.c$(CC) –c -o $@ $^変数 CC でコンパイラを指定
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0暗黙のルール (implicit rule)• 暗黙のルール• よく使うルールを暗黙のルールとして定義しておくと,詳細を指定しなくても暗黙のルールで処理できる.68参考 URL: https://www.gnu.org/software/make/manual/make.html#Implicit-Rules2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0target: ldscript.lds source.o$(LD) -T $^ -o $@source.o: source.c$(CC) –c -o $@ $^Makefile の基本的な書き方• 暗黙のルール使用例2016/12/04 69.c.o:$(CC) –c $< –o $@target: ldscript.lds source.o$(LD) -T $^ -o $@.c から .o の変換は暗黙のルールで処理
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0サフィックスルール• サフィックスルール (.SUFFIXES)• 「 .o は .c から作られる」など,あるターゲットを得るためには何をビルドすべきかの関係を示すためのルール• 例 : .bin が .elf からビルドされることを示す• .SUFFIXES: .elf .bin702016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0その他• all ルール• make コマンドを引数無しで実行したときに,処理したいルールを列挙するために用いられることの多いルール名• Makefile に書かれたルールの先頭に定義する必要がある• 引数無しで make コマンドを実行すると,先頭にあるルールが実行される• 例 : (make を叩くと target を作って欲しい場合 )• all: target• clean ルール• ビルドしたファイル等を削除するためによく用いられるルール名• 例 :• clean:rm target source.o712016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Makefile を書くときの注意• 改行コードに CR+LF を使うとエラーになる• Linux では改行コードが LF なので多分注意する必要はない• Windows の場合は CR+LF の場合が多いので,注意すること• コマンドの前のインデントはスペースでなくタブを使う• タブの中にスペースがあったりすると,エラーとなる.722016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : Makefile を読む• 次スライドの Makefile を読み,以下の質問に答えてください1. 変数 $(CC) にはどんな値が入っていますか?2. .c.o のルールは何をコンパイルして,何を作りますか?3. myprog.bin を作るにはどのソースコードが必要ですか?2016/12/04 73
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : Makefile を読むCROSS= arm-unknown-eabi-CC= $(CROSS)gccLD= $(CROSS)ldOBJCOPY= $(CROSS)objcopyOBJS=start.o main.oCFLAGS = -mfloat-abi=soft -mlittle-endian -fno-builtin –nostartfiles -std=c11LDFLAGS = -static –nostdlib.SUFFIXES: .elf .binall: myprog.binmyprog.elf: $(OBJS)$(LD) $(LDFLAGS) -T ldscript.lds $^ `$(CC) -print-libgcc-file-name` -o $@.elf.bin:$(OBJCOPY) -O binary $< $@.c.o:$(CC) $(CFLAGS) -c $< -o $@.S.o:$(CC) $(CFLAGS) -c $< -o $@clean:$(RM) *.o *.bin *.elf742016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Tips: libgcc をリンクする理由• libgcc とは• C 言語を動かすために必要な基本関数群をもつライブラリ• gcc でコンパイルしたプログラムには必ずリンクする必要がある• なぜリンクする必要があるの?• ソースコードのコンパイル時に演算をそのまま命令に変換することが出来ない場合がある• ARM は最近まで除算命令 (div) などを持っていなかった• libgcc にはこのような演算をソフトウェアでシミュレーションするプログラムなどが含まれており,必ずリンクする必要がある.752016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : main.c を作る• 以下の様な何もしないコードを main.c として保存してください.#include int main(void) {return 0;}762016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : ビルドしてみる• ビルド• make コマンドを実行して myprog.bin ができていることを確認してください• 逆アセンブリ結果を見る• 以下のコマンドで .elf を逆アセンブルしてコードを読んでみてください• arm-unknown-eabi-objdump -D myprog.elf772016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0逆アセンブル結果782016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0逆アセンブル結果79.text が 0x8000 から開始している0x1c000000 がsp に設定されているBSS 初期化が完了したらmain に飛ぶ2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : ビルドしたコードを動かしてみる1. ( 済 )FAT でフォーマットした SD カードにブートのためのファイルを入れる• 取得元 : https://github.com/raspberrypi/firmware/tree/master/boot• 必要なファイル ( 予め $HOME/sdcard 以下にダウンロード済み ):• start*.elf• fixup*.dat• bootcode.bin• LICENCE.broadcom• config.txt: 以下を記述 *• kernel=myprog.bin2. myprog.bin を SD カードに入れる3. SD カードを Raspberry Pi に刺して,電源を入れる• ただし,無限ループするだけなので,現在はまだ何も起こらない80* 参考 : https://www.raspberrypi.org/documentation/confguration/confg-txt.md2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0LED Blink(L チカ )2016/12/04 81
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0LED Blink• L チカ( LED Blink )とは ( 再掲 )• LED を点滅させるだけの”簡単“なプログラム• 低レイヤー版 Hello World• BareMetal 環境では GPIO のペリフェラルを直接制御して行う• そのために ...• メモリマップド I/O について知る• GPIO レジスタの使い方を知る822016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Raspberry Pi の LED• Raspberry Pi Type B+ はACT LED が GPIO47 に繋がれているので, L チカに使える• Tips: Type-B では GPIO16 に ACT LED が繋がれていた• GPIO47 を Low にすると点灯,High にすると消灯する832016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0Memory Mapped I/O(MMIO)• Memory Mapped I/O(MMIO)• ペリフェラルの制御レジスタが主記憶と同じメモリアドレス上に割り当てられている方式.• 制御レジスタが割り当てられたメモリアドレスに値を書き込むと,値が制御レジスタにセットされる• Raspberry Pi はアドレス 0x20000000※ からペリフェラルがマップされている• BCM2835-ARM-Peripherals.pdf, pp.5 の図 , ARM Physical Address を参照• ※ 注意• マニュアルに書かれている各ペリフェラルのアドレスはARM Bus Address のアドレス (0x7E000000 開始 ) となっている• Raspberry Pi 起動時のアドレスは ARM Physical Address に変換されているので, 0x7E...... は 0x20...... に読み替えて使用する.84Tips: MMIO の他に I/O マップド I/O という方式もある2016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0GPIO• General Purpose I/O(GPIO)• 汎用的に使える信号の入出力を行うための I/O ペリフェラル• LED を接続して出力にしたり,スイッチを接続して入力にしたり• High(RasPi では 3.3V) や Low(0V) の信号を出力できる• Alternative mode で SPI や I2C ペリフェラルの入出力にも使用できる• 資料の場所• Raspberry Pi のペリフェラルドキュメント (pp.89-105)• BCM2835-ARM-Peripherals.pdf• https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf852016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0ペリフェラルマニュアルの読み方1. Index (目次)から,希望のペリフェラルのページを見つける• GPIO については pp.89-1052. 最初の 1 ページ目 (pp.89) に概要が書かれているので,そこから大まかな内容を把握する.3. 節の最初か最後に簡単な使い方 (How to use 的なもの ) が書かれていることがあるので,それを探す• 残念ながら GPIO については無い……4. 各レジスタの説明を読む5. それでもわからないことは, Web で調べる• 公式 Forum や StackOverflow 等に書いてあることがある• Linux や U-Boot 等の既存コードを読むとわかることもある862016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0調べること• GPIO ペリフェラルのベースアドレス• よくある書き方• オフセットのみ書かれているもの.ベースアドレス + オフセット で計算する.• 一覧表に書かれている• 各種 GPIO 制御レジスタのメモリアドレス• よくある書き方• ベースアドレスと同じ• 各種 GPIO 制御レジスタの役割と使い方• よくある書き方• 各種レジスタ説明の一番最初に書かれていることが多い872016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0BCM2835 の GPIO 概要• 標準的な I/O は以下のレジスタを用いて行う• GPFSEL• GPIO の入出力モードを設定するレジスタ• GPSET• GPIO の出力を High に設定するレジスタ• GPCLR• GPIO の出力を Low に設定するレジスタ• GPLEV• GPIO の入力レベルを取得するレジスタ( 詳細説明は省略 )882016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0GPFSEL[0-5]• GPFSEL(GPio Function SELect)• GPIO の入出力モードを設定する 32-bit レジスタたち• アドレスは 0x20200000 から 24-byte(32-bit(4-byte) x 6)• 1 つのレジスタあたり 10 ポートの設定を担当する• 1 つの GPIO のモードを 3-bit で設定する• 000: Input• 001: Output• 以下省略( BCM2835-ARM-Peripherals.pdf , pp.92, Table 6-3 等を参照)• 例: GPIO47(GPFSEL4) を Output にする• *((uint32_t *)(0x20200010) &= ~(uint32_t)(0x07 << (7 * 3)); // GPIO47 に対応する 3bit をクリア• *((uint32_t *)(0x20200010) |= (uint32_t)(0x01 << (7 * 3)); // GPIO47 に対応する 3bit を 001 にセット892016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0GPSET[0-1]• GPSET[0-1]• GPIO を High にするレジスタ• アドレスは 0x2020001C から 8-byte• GPSET1 は GPIO53-32, GPSET0 は GPIO31-0 を担当• GPSET0 から右詰めで 1-bit ずつが各 GPIO に対応する• 例 : GPIO47 を High にする• *(uint32_t *)0x20200020 = 1 << (47 - 32);902016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0GPCLR[0-1]• GPCLR[0-1]• GPIO を Low にするレジスタ• アドレスは 0x20200028 から 8-byte• GPCLR1 は GPIO53-32, GPCLR0 は GPIO31-0 を担当• GPCLR0 から右詰めで 1-bit ずつが各 GPIO に対応する• 例 : GPIO47 を Low にする• *(uint32_t *)0x2020002C = 1 << (47 - 32);912016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0LED Blink の手順1. GPIO47 のモードを,GPFSEL レジスタで Output(0x01) にセットする2. GPSET レジスタの GPIO47 に対応するビットに 1 をセットして,GPIO47 の出力を High にする3. for 文を空回しして 500ms 程度待つ4. GPCLR レジスタの GPIO47 に対応するビットに 1 をセットして,GPIO47 の出力を Low にする5. for 文を空回しして 500ms 程度待つ6. 手順 2. に戻る922016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : LED Blink してみる• main.c に LED Blink を行うコードを書いてみましょう• 書けたら以下の手順で動かしてみましょう1. make する2. ( エラーが出た場合 ) プログラムを直して手順 1. に戻る3. myprog.bin を Raspberry Pi の SD カードに入れる4. Raspberry Pi の電源を抜き差しして再起動する5. LED 点滅してなかったらプログラムを直して手順 1. に戻る932016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : LED Blink してみる• GPIO47 のモードを Output にする2016/12/04 94#include int main(void) {*((uint32_t *)(0x20200010)) &= ~(uint32_t)(0x07 << (7 * 3));*((uint32_t *)(0x20200010)) |= (uint32_t)(0x01 << (7 * 3));return 0;}
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : LED Blink してみる• 無限ループを作る2016/12/04 95#include int main(void) {*((uint32_t *)(0x20200010)) &= ~(uint32_t)(0x07 << (7 * 3));*((uint32_t *)(0x20200010)) |= (uint32_t)(0x01 << (7 * 3));while (1) {}return 0;}
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : LED Blink してみる• GPIO47 を High にする2016/12/04 96#include int main(void) {*((uint32_t *)(0x20200010)) &= ~(uint32_t)(0x07 << (7 * 3));*((uint32_t *)(0x20200010)) |= (uint32_t)(0x01 << (7 * 3));while (1) {*(uint32_t *)0x20200020 = 1 << (47 - 32);}return 0;}
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : LED Blink してみる• 適当に待つ2016/12/04 97#include int main(void) {*((uint32_t *)(0x20200010)) &= ~(uint32_t)(0x07 << (7 * 3));*((uint32_t *)(0x20200010)) |= (uint32_t)(0x01 << (7 * 3));while (1) {*(uint32_t *)0x20200020 = 1 << (47 - 32);for (int i = 0; i < 1000000; i++);}return 0;}配布資料では 100000000となっていますが,0 を 2 つ減らして1000000 にしてください
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : LED Blink してみる• GPIO47 を Low にする2016/12/04 98#include int main(void) {*((uint32_t *)(0x20200010)) &= ~(uint32_t)(0x07 << (7 * 3));*((uint32_t *)(0x20200010)) |= (uint32_t)(0x01 << (7 * 3));while (1) {*(uint32_t *)0x20200020 = 1 << (47 - 32);for (int i = 0; i < 1000000; i++);*(uint32_t *)0x2020002C = 1 << (47 - 32);}return 0;}
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0演習 : LED Blink してみる• 適当に待つ2016/12/04 99#include int main(void) {*((uint32_t *)(0x20200010)) &= ~(uint32_t)(0x07 << (7 * 3));*((uint32_t *)(0x20200010)) |= (uint32_t)(0x01 << (7 * 3));while (1) {*(uint32_t *)0x20200020 = 1 << (47 - 32);for (int i = 0; i < 1000000; i++);*(uint32_t *)0x2020002C = 1 << (47 - 32);for (int i = 0; i < 1000000; i++);}return 0;}
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0発展課題• Systick Timer 等を用いて正確に 500ms 待ってみる• スイッチを繋げて,スイッチを押した時だけ LED が点灯するようにしてみる• GPIO をもっと簡単に制御するための関数を作ってみる• USART を使ってパソコンに文字を出力してみる• 必要なケーブル等は講師またはチューターにもらってください1002016/12/04
(C) Toshifumi NISHINAGA CC-BY-SA-NC 4.0おわりに• 低レイヤーは楽しいです!• つらいこともたくさんあるけど,動いた時の感動は最高!• 学べばどこかで役に立ちます!• マイコンを始めとした組込み機器をより自由に使うことが出来ますよ!• プログラムの最適化やマルウェアの解析等はコンピュータアーキテクチャの知識があるとより深く考えられるようになりますよ!• 皆さん一緒に低レイヤーを学んで,一緒に遊びましょう!1012016/12/04