[ARM] kernel先頭から。その1

2013/07/17Linux::ARMimport

ARMv7 ARCHのARMから...

MPcoreから追加されている話も新規として扱います. 脳内はARM928EJ-Sあたりで停止していましたので..
メモリ空間の属性は、
  • ストロングリオーダ(Strongly ordered)
  • ノーマル()\メモリ属性は以下がある。
    • (Outer Shareable)
    • (Inner Shareable)
    • (Non shareable)
  • デバイス
    • (shareable)
    • (Non shareable)
ここでいうshareは、プロセッサ間で共有アクセスの有無を示す。
Outer/Inter sharebleの差異は、Outerが実装定義でレベルをつけたアクセス制御が入るらしい???
A3-27あたりからatomic accessに関する記載がある。

mm初期化処理を追う... ために, kernel起動先頭から少し追ってみる.

vmlinuxをdisasすると entry pointが "stext"なのがわかる.*1
entry pointには、以下のコメントがあり、展開される位置、状態、レジスタ値について記載がある。

・・・どのみちすぐにldscript読まなあかんかった。
FILE:arch/arm/kernel/vmlinux.lds
 .init.pv_table : {
  __pv_table_begin = .;
  *(.pv_table)
  __pv_table_end = .;
 }

 Kernel startup entry point.
 ---------------------------

 This is normally called from the decompressor code.  The requirements
 are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
 r1 = machine nr, r2 = atags or dtb pointer.

 This code is mostly position independent, so if you link the kernel at
 0xc0008000, you call this at __pa(0xc0008000).

 See linux/arch/arm/tools/mach-types for the complete list of machine
 numbers for r1.

 We're trying to keep crap to a minimum; DO NOT add any machine specific
 crap here - that's what the boot loader (or in extreme, well justified
 circumstances, zImage) is for.
	/*
	 * r1 = machine no, r2 = atags or dtb,
	 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
	 */
	bl	__vet_atags			// ゴミデータなら r2=NULL と修正される。
#ifdef CONFIG_SMP_ON_UP
	bl	__fixup_smp
#endif
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT //enable
	bl	__fixup_pv_table	//
#endif
	bl	__create_page_tables
kernel imageがロードされた物理アドレス と kernel空間を設置しようとしている論理アドレス、との
アドレス値の差分を r8に計算、保持する。
__fixup_pv_tableを呼び出して、"arch/arm/include/asm/memory.h"で定義した関数・マクロの
論理ー物理変換関数が参照する変数を書き換える。
ロード位置が固定されていればいらないのかもしれないけれど,headの記述からするとそうもいかんような.
このheadは展開後のkernel start位置なので、compressed kernelの先頭は別のところ。*2

*1 : 本当は順序建てて ldscriptから..のほうがいいけれど, この手順でやってもうたので、こう記しておく。

*2 : たぶん、これだけど、未検証:arch/arm/boot/compressed/head.S

LInux開発入門

2013/06/09linux::入門編import
冒頭から逃げを書いておきますが・・・
手探り状態、読者対象が具体的に見えない状況下で記載を始めます。
昨今、マトモな出版物も増えてきているので、需要がないかもしれませんが、少しでも道標になれば幸いです。

Linux OSを用いた開発

以前までは、組み込みといえばuITRON系のRTOSが幅をきかせていましたが、
プロセッサ能力向上・メモリ単価の減少、要求要件の拡大などの要因により、
見直されてきているように思います。
最も影響があるのはNetwork Protocol Stackや、複数プラットフォームで共通的に使えるソフトでしょう。

もちろん、ITRON系のリソースも現役です。少ないROM/RAM、軽量なマイコンでも動くので、住み分けができるでしょう。
より低機能であればOSレスもありますし、畑は広大です。

さておき、ひとことでLinux OS開発といっても、OSはもよとり、コンパイラ・アセンブラ・リンカその他ツール類すべてがOpen Source Softwareを使用します。自らソースコードを元に開発環境や実行環境を用意することができます。MicrosoftのVisual Cのように、コンパイラに対価を支払うのとは対照的ですが、何か問題が起きたとき、起きそうなとき、それを知るための方法を、どのように確保するのか、が課題となります。これを商売にしている会社もありますね。

構成

以下に、クロス開発環境を前提としたソフトの構成例を記します。
開発ツールを買えば、裏ではこれらのソフトを準備してくれたりします。
MSDOSやWindows、商用UNIXでやってきた方には、高い金でコンパイラや統合開発環境を買った記憶があることでしょう。

Linux_SW_001.png


黄色い部分が、ターゲットに載せるべきものです。
右下にある、libraryを除く開発ツールは、必須ではありません。必要に応じてセルフ開発環境やデバッグツールを取り込むのがよいでしょう。

ubuntoやdebianの各arch向けディストリを使う場合は、セルフ環境も必要になりそうな気はします。いや、基本はバイナリインストールになっているしょうか。

ベンダ提供

あえてドライバ・アプリのところへ、ベンダ提供〜を記載しました。
実務で使っていると、必ずしもすべてをopenにしているのでは無いですから、ね。各社の製造ソフトに関しても、GPL伝播していないものは公開義務を負いませんから公開されることは無いです。GPLv2までの場合は、その再配布責任を追うことから、なんらかの手段で製品で使用したtarballなどの提供を受けることができます。
液晶テレビ・レコーダ・STB・そのほかそれっぽい家電の説明書を眺めてみれば、Open Source使用の旨と、その製品で使用したものの入手方法が記載されているでしょう。
尤も、オンラインでさくっと手に入るところもあれば、電話問い合わせ・郵送による配送もあります。
エンドユーザから公開の依頼が頻繁にはないのでしょう、かねぇ?

ライセンスの話が出てきましたが、これだけで深いネタになります。
僕も把握しきれておらず、法的な問題になる場合は判例を調べた上で判断したほうが良いでしょう。
個人で楽しむ分にも、価値が認められ、公開義務を追うような作りをした場合は、開示を迫る人がでてくるかもしれません。

toolchain

いわゆるコンパイル環境、です。ソースコードをターゲットで動くバイナリに変換します。
最近は LLVMというのが注目を集めているようです?

汎用性を考慮されたソフトの配布では、Makefileを利用していることでしょう。
また、autoconfや独自のconfigrationツールを用意して、buildするホスト環境差分を自動的に検出・適切に変更するような手段を提供しています。

しばらくしてわかったこと

何事も過去の経緯を知ることが理解への早道に繋がることがあります。同じようなものがなぜ複数存在するのか、ディストリビューションのそれぞれの目的、本当に全てが無料なのか。製品に搭載するために必要なことは?などなど。いまだにわからない事だらけですが、所詮個人がわかる範囲なんてのはしれてるわけで。

必要なとき、必要なところで、短時間でほしい情報に辿りつけるハナ・直感力を持てるようにしておくのが、対策となろうかと思います。もしくは大まかに畑を分割して、担当範囲を分けておくか、です。ですよね・・・?
後半は妄想でしかないので...

sched_switchの出力フォーマットに関するメモ

2013/03/10Linux::kernelimport

sched_switchの出力フォーマットに関するメモ

ステータス表示

"RMSDTtZXxKW"
char status
Rrunning
Mrunning-mutex
Ssleeping
Ddisk sleep
Tstopped
ttracing stop
Zzombie
Xdead
xdead
Kwakekill
Wwaking

FILE: linux-2.6/kernel/trace/trace_output.c
/* TRACE_CTX an TRACE_WAKE */
static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
                         char *delim)

    T = task_state_char(field->next_state);
    S = task_state_char(field->prev_state);
    trace_find_cmdline(field->next_pid, comm);
    if (!trace_seq_printf(&iter->seq,
                  " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
                  field->prev_pid,
                  field->prev_prio,
                  S, delim,
                  field->next_cpu,
                  field->next_pid,
                  field->next_prio,
                  T, comm))
        return TRACE_TYPE_PARTIAL_LINE;


static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags)
{
    return trace_ctxwake_print(iter, "==>");
}

static enum print_line_t trace_wake_print(struct trace_iterator *iter,
                      int flags)
{
    return trace_ctxwake_print(iter, "  +");
}

[powerpc]oprofileの実装を追う

2012/07/25Linux::powerpcimport
oprofileがなぜ存在するのか。
ftraceとは何が異なるのかを確認するため、実装を追いかけた。
アーキテクチャ依存する部位も含むため、大枠はこれで理解するといいかもしれない。
QorIQをターゲットとして捜査したので、ほかのpower architectureは各自で追いかけていただきたい。

参考:
http://ssvb.github.com/2011/08/23/yet-another-oprofile-tutorial.html

参照したファイル類

linux-2.6/drivers/oprofile/oprof.c
linux-2.6/drivers/oprofile/oprofile_stats.c
linux-2.6/drivers/oprofile/oprofile_files.c
linux-2.6/drivers/oprofile/oprofile_stats.c
linux-2.6/drivers/oprofile/event_buffer.c
linux-2.6/drivers/oprofile/buffer_sync.c
linux-2.6/drivers/oprofile/cpu_buffer.c
linux-2.6/include/linux/ring_buffer.h
linux-2.6/kernel/trace/ring_buffer_benchmark.c
linux-2.6/kernel/trace/ring_buffer.c
linux-2.6/arch/powerpc/oprofile/common.c
linux-2.6/arch/powerpc/kernel/head_booke.h
linux-2.6/arch/powerpc/kernel/head_fsl_booke.S
linux-2.6/arch/powerpc/kernel/cpu_setup_fsl_booke.S
linux-2.6/arch/powerpc/kernel/traps.c
linux-2.6/arch/powerpc/kernel/pmc.c

platform initialization

linux-2.6/arch/powerpc/kernel/cpu_setup_fsl_booke.S

_GLOBAL(__setup_cpu_e500v1)
_GLOBAL(__setup_cpu_e500v2)
	mflr	r4
	bl	__e500_icache_setup
	bl	__e500_dcache_setup
	bl	__setup_e500_ivors
	mtlr	r4
	blr

FILE: linux-2.6/arch/powerpc/kernel/cpu_setup_fsl_booke.S

"PerformanceMonitor"へ飛ぶようにセットしてる。
/* Adjust or setup IVORs for e500v1/v2 */
_GLOBAL(__setup_e500_ivors)
	li	r3,DebugCrit@l
	mtspr	SPRN_IVOR15,r3
	li	r3,SPEUnavailable@l
	mtspr	SPRN_IVOR32,r3
	li	r3,SPEFloatingPointData@l
	mtspr	SPRN_IVOR33,r3
	li	r3,SPEFloatingPointRound@l
	mtspr	SPRN_IVOR34,r3
	li	r3,PerformanceMonitor@l
	mtspr	SPRN_IVOR35,r3
	sync
	blr
	/* Performance Monitor */
	EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD)

linux-2.6/arch/powerpc/kernel/traps.c

PerformanceMonitor()を用意、
void performance_monitor_exception(struct pt_regs *regs)
{
	perf_irq(regs);
}

linux-2.6/arch/powerpc/kernel/pmc.c

perf_irq() が定義されている。以下の関数で、ユーザ定義?の関数に差し替えることができる。
oprofile driverで差し替えとる。
int reserve_pmc_hardware(perf_irq_t new_perf_irq)

linux-2.6/arch/powerpc/oprofile/common.c

static void op_handle_interrupt(struct pt_regs *regs)
{
	model->handle_interrupt(regs, ctr);
}
初期化処理で、ハンドルを奪う。
static int op_powerpc_setup(void)
{
	/* Grab the hardware */
	err = reserve_pmc_hardware(op_handle_interrupt);
driver登録時点で、以下の初期化が行われている。
int __init oprofile_arch_init(struct oprofile_operations *ops)

		case PPC_OPROFILE_FSL_EMB:
			model = &op_model_fsl_emb;


linux-2.6/arch/powerpc/oprofile/op_model_fsl_emb.c

static void fsl_emb_handle_interrupt(struct pt_regs *regs,
				    struct op_counter_config *ctr)
oprofile_add_ext_sample()でイベント登録。
イベントがなければぬける。
うっひょ-

linux-2.6/drivers/oprofile/cpu_buffer.c

カウントはこちらで行う。
static inline void
__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
			  unsigned long event, int is_kernel)
{
	struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
	unsigned long backtrace = oprofile_backtrace_depth;

	/*
	 * if log_sample() fail we can't backtrace since we lost the
	 * source of this event
	 */
	if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event))
		/* failed */
		return;

	if (!backtrace)
		return;

	oprofile_begin_trace(cpu_buf);
	oprofile_ops.backtrace(regs, backtrace);
	oprofile_end_trace(cpu_buf);
}

void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
			     unsigned long event, int is_kernel)
{
	__oprofile_add_ext_sample(pc, regs, event, is_kernel);
}

集計は?

ユーザ空間でoprofiledとかctrlが間接的に呼び出す。
上記kernel空間で取得したPC/backtraceデータを用いて、どの区間を何ステップ走行したか、で
実行時間を推定している。
集計結果だけを見ているようでは、厳密な測定結果とはいえないだろう。
ざっくりとみる分には、それでもいいかもしれないですね。
profile取得のオーバヘッドと、サンプリング周期と測定対象の解像度とを十分に考慮してくださいね。

CodeSourcery G++ LITEのsource compile

2012/07/24build_systemimport

cross compile環境の構築

昔は h8のcross環境をへろへろ~っと作っていたけれど、久しぶり。
野良よりも、toolchainを公開されているものを流用してくることにします。
CodeSourcery G++ LITEですが、mentorの組み込みソフト部門として買収されたようです。

Host OSは Virtual machine上のCentOS5.7だったと思う.. 小数点部分が怪しい.
$ uname -a
Linux localhost.localdomain 2.6.18-274.el5 #1 SMP Fri Jul 22 04:49:12 EDT 2011 i686 i686 i386 GNU/Linux

$ gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52)
Copyright (C) 2006 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.

targetとか準備

ざっと作業メモを貼っておく。将来の自分用メモ的な意味で...
$ mkdir -p /tmp/csl_scratch/local_tools/bin
 ln -sf /usr/bin/gcc i686-pc-linux-gnu-gcc
 ln -sf /usr/bin/g++ i686-pc-linux-gnu-g++
 ln -sf /usr/bin/ar i686-pc-linux-gnu-ar
 ln -sf /usr/bin/ranlib i686-pc-linux-gnu-ranlib
 ln -sf /usr/bin/strip i686-pc-linux-gnu-strip

$ export OSS_DIR=/path/to/OSS
 ※ここは各自sourceを拾ってきたpathを設定。環境変わっても流用できるように.. 少しくらいは.

$ mkdir -p /tmp/csl_scratch/
$ cd /tmp/csl_scratch/
$ tar xf $OSS_DIR/CodeSourcery/freescale-2010.09-55-powerpc-linux-gnu.src.tar.bz2 

$ mkdir -p /tmp/csl_scratch/gnu-lite-release/src
$ cd /tmp/csl_scratch/gnu-lite-release/src
$ for f in $(ls /tmp/csl_scratch/freescale-2010.09-55-powerpc-linux-gnu/*.bz2); do tar xf $f; done

HOST環境を用意.

付属のshell scriptを見ると、GCC 4.3.3が無難そう.
置換で済む変更は sedでざっくり書き換え. テキトウに手動補正.
$ cp -a freescale-2010.09-55-powerpc-linux-gnu/freescale-2010.09-55-powerpc-linux-gnu.sh build.sh

$ sed -e 's,/scratch/froydnj,/tmp/csl_scratch,g' \
   -e 's,pushenvvar PATH /usr/local/tools/gcc-4.3.3/bin,pushenvvar PATH /tmp/csl_scratch/local_tools/bin:\$PATH,' \
   -e 's,pushenvvar LD_LIBRARY_PATH,#pushenvvar LD_LIBRARY_PATH,' \
   -e 's,rmdir ./lib/rh73,# rmdir ./lib/rh73,' \
   -e 's,/rh73/,/,' \
   -e 's/ -j4/ -j8/g' \
   -e 's,-mrh73,,' \
   -e 's,/usr/local/tools/gcc-4.3.3/bin/,/tmp/csl_scratch/local_tools/bin/,' \
   -i build.sh

CSFLを見ながら構築していこうと思ったけれど頓挫した.
ので, そのタイミングで拾っておいた m4,texinfoをHostに入れてしまう.
既存環境を壊さないように、これも/tmpに放り込んでみた.
永続して使うなら, 適当なuser directoryにでも入れておくと良いだろう.
ここに書いてないけれど, hostのgcc, binutils, kernel headers, flex, bisonくらいは必要.
厳密にどれだけ必要なのかは... 調べきる元気が無かったので, 既存環境に無いものをだましだまし追加.
tar xf $OSS_DIR/CLFS_PKG/m4-1.4.16.tar.bz2 

./configure --prefix=/tmp/csl_scratch/local_tools
make
make install
tar xf $OSS_DIR//CLFS_PKG/texinfo-4.13a.tar.gz 

./configure --prefix=/tmp/csl_scratch/local_tools
make
make install


カットアンドトライ

以下は残す. 2~35はコメントアウト*1
# task [001/258] 
# task [036/258] /i686-pc-linux-gnu/host_cleanup

ここでこける.
task [068/258] /i686-pc-linux-gnu/toolchain/binutils/postinstall
gnu-lte-release/obj/binutil... powerpc-linux-gnu-i686-pc-linux-gnu/libiberty/functions.texi
500行目あたり, 関数定義のマクロ部分に余計な改行が入っているので、改行をとってリトライ.
[148/258] /i686-pc-linux-gnu/toolchain/gdb/0/build
 /tmp/csl_scratch/gnu-lite-release/obj/gdb-src-2010.09-55-powerpc-linux-gnu-i686-pc-linux-gnu/libiberty/functions.texi

task [147/258] /i686-pc-linux-gnu/toolchain/gdb/0/configure
ここからやり直すとよい.

以下のtaskで参照している, getting started guideのソースが無い..?
task [158/258] /i686-pc-linux-gnu/getting_started/copy
task [159/258] /i686-pc-linux-gnu/getting_started/configure
task [160/258] /i686-pc-linux-gnu/getting_started/build
task [161/258] /i686-pc-linux-gnu/getting_started/install
task [162/258] /i686-pc-linux-gnu/csl_docbook
以下は 置換漏れ. まさかフルパスで書いていたとはな...
task [172/258] /i686-pc-linux-gnu/strip_host_objects
./build.sh: line 57432: /usr/local/tools/gcc-4.3.3/bin/i686-pc-linux-gnu-strip: No such file or directory

targetのlibcにデバッグシンボルを残したいときは, 次のタスクをスキップすると良い.
 task [173/258] /i686-pc-linux-gnu/strip_target_objects

installer?これも無かったと思う.
このディレクトリ"gnu-lite-release/src/scripts-trunk/"が無い.
パッケージを作るためのスクリプトが入っているようだけれど、source archiveには入ってなさそう.
task [175/258] /i686-pc-linux-gnu/package_installanywhere/unpack
task [176/258] /i686-pc-linux-gnu/package_installanywhere/merge_modules
task [177/258] /i686-pc-linux-gnu/package_installanywhere/installer
task [178/258] /i686-pc-linux-gnu/package_rpm

*1 : if false; then .... fi で切ってしまう

まとめ

たぶん host側も CSLのtoolchainを持っていれば良かったのだろう.
これに限らず host環境の依存性も重要であると再認識できた.