Fedoraでもarm

何を調べていたか思い出せないんだけど、気が付いたら 計測ミュージアムなんてのが表示されてた。これも ご縁と思って、4~20mA物語なんてのを 読んでみたよ。

オイラーも、この方面はちょいと首を突っ込んだ前歴があるんで、うなづける点が多々ある。 ゼロ付近の信号を扱うの難しいから、シフトしちゃえ。そうすれば、断線した結果として ゼロになってるのか、本当にゼロなのかの判定が容易って嬉しいおまけがある。交流より 直流ってのも、現場主義の賜物。

20mAで思い出すのは、TTYの駆動が20mAのカレント(電流)ループだったな。これも、ノイズ避けに 最適。RS232Cなんかだと、マーク・スペース信号に、プラス・マイナス5V以上は出力される 事。入力の判定レベルはプラス・マイナス3Vで行われる事。これでノイズマージンが2Vは 保障されますってのが決まってたな。

電流の流れる向きを、デジタル信号の1と0に対応させましょってのが最近再注目を浴びて いる。ノイズで電流の向きを反転させる、なんて事は、雷様でも難しかろうってのが、その 理由。

なんてのは、半分嘘で半分当たっている。電圧の変化で1と0を判定しようとすると、遷移 時間が問題になって、高速で信号を遅れないんだ。その点、電流モードだと、そういう事に 気を使わなくても良い。HDDと本体間の信号のやり取りがシリアル信号になってるね。

ああ、TTYと言うと、その後継でも思い出があるな。PDPに繋がっていたVT100って名前のVKT。 ビデオ・キーボード・ターミナルの略称。TTYのガタガタ言いながら印字されるのから、 輝点で文字が表示されるのを見て、ぶったまげたものだ。

今でも、そのVKTが形を変えて使われているね。

RaspberryPiクラスタ製作記 第4回「BareMetal並列計算」 が、面白いぞ。

fedoraでもarm

したいな。そんなの前回やったように、ウブで実現出来てるじゃん。そんなのは承知ですが、 ウブにだけ頼るのはどうかと思いまして。。。ウブがこけたら皆こけたはイヤですから。

で、探してみると、 arm for Fedora とか piでベアメタルプログラミング なんてのが引っかかってきた。

どうも、Fedoraではユーザーランドなアプリは作成出来ないようだ。膨大なライブラリー どうすんのってのが最大も問題なんだろうな。

で、裸の石で、自前で何とかしてよって言う、組み込み技術者養成環境なんですな。よし、 ウブみたいに生温い環境を飛び出して、何とかしたるわい。

armのクロス開発用ツールを入れる。次に貧乏人はラズパイを買えないので、qemu-system-armで 我慢するって寸法です。便利な世の中になり過ぎているな。昔なら、gccをコンパイルする だけで丸半日は優にかかってたもんなあ。それが、dnf install gcc-arm-linux-gnu 一発だからね。

そして、qemu-system-armが仮想のVKTの役目をしてくれる。わざわざ、LCDディスプレーを 用意する必要が無いばかりかUSB接続のキーボードも不要。でもマウスは必要でしょ。 昔は、マウスなんて無かったよ。それでやってこれたんだから、オイラーには必要無し。

そして、資料も買う必要無し。 組込み技術者向け「初めてのC言語」 も参考に。

英国の大学 とか、 Bare Metal Programming in C Pt1 も、参考になる。

arm開発用のbusybox

最初はMakefile。俺様の開発用busyboxです。変にGUIに凝るなんて、クリック猿のやる事です。 使い難い所が有ったら、どんどん改変しましょう。なお、途中で出て来る、arm-gdbは、Fedoraの コンパイル環境チェックの目的で入れてみた、gdb-7.9.1です。本当は、sim/runが欲しかったってのは、 秘密ですよ。

[sakae@fedora arm]$ cat Makefile
CC = arm-linux-gnu-gcc
CFLAGS= -mcpu=arm926ej-s -marm -nostdlib --no-builtin -Wall -g

LD = arm-linux-gnu-ld
LDFLAGS = -T smpl.ld

kernel = app.img
objs = main.o bio.o head.o

all: $(objs)
        $(LD) $(LDFLAGS) $(objs) -o $(kernel)

.c.o:
        $(CC) -c $(CFLAGS) $< -c

.S.o:
        $(CC) $(CFLAGS) $< -c

clean:
        rm -f *.o  $(kernel)

run:
        qemu-system-arm -M versatilepb -nographic -kernel $(kernel)
#         stop qemu for CTL-a c quit or kill qemu-system-arm

debug:
        qemu-system-arm -s -M versatilepb -nographic -kernel $(kernel)
gdb:
        arm-gdb -q $(kernel)
#         need  target remote localhost:1234 in .gdbinit

.PHONY: clean all

リンカーへ伝えるプログラム内のデータブロック配置情報。ENTRYって所に宣言されてるのが、 プログラムの実行開始番地になる。後は、.textでいわゆる実行コード部分を配置。続いて、.dataで、 初期値がある変数部分、.bssで初期値の無い変数部分(エリアだけ確保)、最後は、スタックエリアの 割り当てだな。

[sakae@fedora arm]$ cat smpl.ld
ENTRY(_start)

SECTIONS
{
        . = 0x10000;
        .text : { *(.entry); *(.text, rodata); }
        .data : { *(.data); }
        .bss : { *(.bss); }
        .stack : {
                . = . + 0x1000;
                . = ALIGN(4);
                stack_top = .;
                . = . + 0x1000;
                . = ALIGN(4);
                irq_stack_top = .;
        }
}

プログラムが起動した時に、真っ先に動き出す部分。俗にCRTと呼ばれる部分だ。 スタックを設定して、mymainをサブルーチンコール してる。本当はmainとしたかったんだけど、そうすると警告が出てきて鬱陶しいので、 独自な関数名にしてる。

[sakae@fedora arm]$ cat head.S
.text
.code 32

.globl  _start

_start:
        ldr sp, =stack_top
        bl mymain
halt:
        b halt

UARTを使った基本入出力です。manによると、getsはバッファー溢れの恐れがあるんで使うなと、 強く警告してます。そこでちと仕様を変えて、最大受付文字数を与えるようにした亜流に なってます。

石の内部に存在するUART(シリアル入出力)を使って、1文字の入出力関数を組み立て、それを 応用して、1行の入出力ルーチンを実現してます。1文字入力時にはechoしません。

UARTは、FIFO(馴染みな言い方だとパイプだな)が2本内蔵。それぞれの端に、パラレルーシリアル変換器が 接続されてて、RS232Cラインを駆動するようになっている。2本のFIFOのもう一方の端は、 共通なレジスタ(UART0)に接続されてる。このレジスタに書き込むと、データが出力(表示)され、 読み出すと、キーボードからの入力が得られる。

読み書き出来るタイミングは、FIFOの充填具合によるので(FIFOが満杯の時は書き込めない等)、 その状態を得るフラグレジスタが用意されてる。他にも制御用のレジスタが多数有る。 フラグレジスタは、基点になるUART0から6バイト変位した所にあるので、それをUARTFRで 宣言してる。

このUARTによるシリアルラインは3本用意されるようで、そのうちの一番最初のやつを利用 してる。説明書を見ると、赤外線によるコントロールとかも出来るようになってて、そんなの 今じゃ青歯だろうにと思うけど、基本はお大事にって事で、内蔵してるんだろうね。

[sakae@fedora arm]$ cat bio.c
// Basic I/O using UART

#define UART0 ((volatile unsigned int *) 0x101f1000)  // data reg. (address)
#define UARTFR 0x06                                   // flag reg. (offset)
#define UARTFR_TXFF 0x20                              // tx FIFO full
#define UARTFR_RXFF 0x10                              // rx FIFO empty

void putc(const char c) {
        while (*(UART0 + UARTFR) & UARTFR_TXFF) ;
        *UART0 = c;
}

void puts(const char *s) {
        while (*s) {
                while (*(UART0 + UARTFR) & UARTFR_TXFF) ;
                *UART0 = *s;
                s++;
        }
}

int getc(void) {
    while (*(UART0 + UARTFR) & UARTFR_RXFF) ;
    return *UART0;
}

char *gets(char * const buf, const int size) {
    int ch;
    int n = 0;
    while (n < size - 1) {
        ch = getc();
        if (ch == '\r') {
            puts("\r\n");
            break;
        }
        putc(ch);
        buf[n++] = ch;
    }
    buf[n] = 0;
    return buf;
}

ヘッダーファイルです。普通は引数の型だけ宣言しますが、それだと警告が出てきたので、 引数名も含めています。どうやるのが正解なんでしょうかね?

[sakae@fedora arm]$ cat bio.h
// Basic IO
void putc(const char c);
void puts(const char *s);
int getc(void);
char *gets(char * const buf, const int size);

最後は、お待ちかねのメインです。mainじゃなくてmymainってのがちとあれっぽいな。(謎)

[sakae@fedora arm]$ cat main.c
#include "bio.h"

void mymain(void) {
        char buff[128];

        puts("hello, ARM on Fedora\n");
        gets(buff, 128);
        puts(buff);
        puts("\n");
}

動作試験

まずは、コンパイルして、app.imgと言う偽物カーネルを作ります。

[sakae@fedora arm]$ make
arm-linux-gnu-gcc  -c -mcpu=arm926ej-s -marm -nostdlib --no-builtin -Wall -g main.c -c
arm-linux-gnu-gcc  -c -mcpu=arm926ej-s -marm -nostdlib --no-builtin -Wall -g bio.c -c
arm-linux-gnu-gcc  -mcpu=arm926ej-s -marm -nostdlib --no-builtin -Wall -g head.S -c
arm-linux-gnu-ld -T smpl.ld main.o bio.o head.o -o app.img

ちゃんと出来上がったか確認。

[sakae@fedora arm]$ file app.img
app.img: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, not stripped
[sakae@fedora arm]$ arm-linux-gnu-size app.img
   text    data     bss     dec     hex filename
    556       0    8192    8748    222c app.img

bssがやけに大きいな。何故? そうか、MMUの制御の関係かな? textエリアは、読み出しと実行が 可能領域に設定。bssは、読み書き可能で割り付けるから、ページが(勿論)別になり、管理の 都合で、切りの良い値にした。でも、bssなら初期値は無いはずだから、容量喰うのはおかしい。 あれ? それ以前に、bssに配置されるような変数を設定した覚え無いんだけどな。 静的ファイルって特殊性が反映された結果だろうね。そういう事にしておこう。

そんじゃ、実行。

[sakae@fedora arm]$ make run
qemu-system-arm -M versatilepb -nographic -kernel app.img
xcb_connection_has_error() returned true
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
hello, ARM on Fedora
ABCDEFG
ABCDEFG
QEMU 2.3.0 monitor - type 'help' for more information
(qemu) quit

helloの前に見苦しいのが出てるけど、これを消そうと思ったら、自前でqemuをコンパイル しないと駄目かな。

キーボード入力も出来てる。終了は、qemuを強制的にkillするか、ソフトに、CTL-a c して、 qemuのモニターモードに落ちてからquitだ。

オラクル提供のvboxで動かしてる時は、ゲストOSの終了で、qemuも自動終了するけど、何か 特殊なパッチでも当たっているの? それとも、インテルの石と言うかウィンテル陣営得意の、 パワーマネジメントで、ゲストOS終了を検出して、qemuを終了させてるの?

次は、qemu内蔵の通信機能を使ってリモートデバッグ。

[sakae@fedora arm]$ make debug
qemu-system-arm -s -M versatilepb -nographic -kernel app.img
xcb_connection_has_error() returned true
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
hello, ARM on Fedora

キー入力待ちになった時、別端末から

[sakae@fedora arm]$ make gdb
arm-gdb -q app.img
Reading symbols from app.img...done.
warning: Can not parse XML target description; XML support was disabled at compile time
0x00010118 in getc () at bio.c:22
22          while (*(UART0 + UARTFR) & UARTFR_RXFF) ;
(gdb) bt
#0  0x00010118 in getc () at bio.c:22
#1  0x00010170 in gets (buf=0x111a4 "", size=128) at bio.c:30
#2  0x00010024 in mymain () at main.c:7
#3  0x00010204 in _start () at head.S:8
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)

btした時、全部のフレームが見られるって、初めての体験ですよ。超気持ちイイーーー! この気持ちを手軽に味わうには、.gdbinitを用意しておいてね。

(gdb) up 2
#2  0x00010024 in mymain () at main.c:7
7               gets(buff, 128);
(gdb) b 8
Breakpoint 1 at 0x10024: file main.c, line 8.
(gdb) c
Continuing.

Breakpoint 1, mymain () at main.c:8
8               puts(buff);
(gdb) p buff
$1 = "1234\177\177\177", '\000' <repeats 120 times>

クライアント側で、1234に続いて数回バックスペースした後RET。で、buffを見ると、 バックスペースが0xFFになってる。これって、qemuさんの仕業? 0xFFって表示時には 無視された。ちゃんとクックモードを導入しろよ。

何故に太ってる

上で気になったbss領域の肥大化、どうなってるの?こういう時は、取り合えず

[sakae@fedora arm]$ arm-linux-gnu-nm app.img
000101fc T _start
0001010c T getc
0001014c T gets
00010204 t halt
0001222c B irq_stack_top
00010000 T mymain
0001004c T putc
0001009c T puts
0001122c B stack_top

うーむ、スタック領域がbssエリアに喰いこんでいるな。2本のスタックに、それぞれ4kづつ 割り当てているから、合計で8kになってるけど、そんなものなんですか? >偉い人。

今度は、objdumpを使って

[sakae@fedora arm]$ arm-linux-gnu-objdump -x app.img
app.img:     ファイル形式 elf32-littlearm
app.img
アーキテクチャ: arm, フラグ 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
開始アドレス 0x000101fc

プログラムヘッダ:
    LOAD off    0x00010000 vaddr 0x00010000 paddr 0x00010000 align 2**16
         filesz 0x0000022c memsz 0x0000222c flags rwx
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
         filesz 0x00000000 memsz 0x00000000 flags rwx
private フラグ = 5000202: [バージョン 5 EABI] [soft-float ABI] [エントリポイントを持っています]

セクション:
索引名          サイズ      VMA       LMA       File off  Algn
  0 .stack        00002000  0001022c  0001022c  0001022c  2**0
                  ALLOC
  1 .text         0000020c  00010000  00010000  00010000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .rodata       00000020  0001020c  0001020c  0001020c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
   :

スタックアリアは確かに8k割り当ててあるな。objdump --help したら、面白いスイッチが 見つかったぞ。

[sakae@fedora arm]$ arm-linux-gnu-objdump -S app.img
app.img:     ファイル形式 elf32-littlearm


セクション .text の逆アセンブル:

00010000 <mymain>:
#include "bio.h"

void mymain(void) {
   10000:       e92d4800        push    {fp, lr}
   10004:       e28db004        add     fp, sp, #4
   10008:       e24dd080        sub     sp, sp, #128    ; 0x80
        char buff[128];

        puts("hello, ARM on Fedora\n");
   1000c:       e59f0030        ldr     r0, [pc, #48]   ; 10044 <mymain+0x44>
   10010:       eb000021        bl      1009c <puts>
        gets(buff, 128);
   10014:       e24b3084        sub     r3, fp, #132    ; 0x84
   10018:       e3a01080        mov     r1, #128        ; 0x80
   1001c:       e1a00003        mov     r0, r3
   10020:       eb000049        bl      1014c <gets>
        puts(buff);
   10024:       e24b3084        sub     r3, fp, #132    ; 0x84
   10028:       e1a00003        mov     r0, r3
   1002c:       eb00001a        bl      1009c <puts>
        puts("\n");
   10030:       e59f0010        ldr     r0, [pc, #16]   ; 10048 <mymain+0x48>
   10034:       eb000018        bl      1009c <puts>
}
   10038:       e1a00000        nop                     ; (mov r0, r0)
   1003c:       e24bd004        sub     sp, fp, #4
   10040:       e8bd8800        pop     {fp, pc}
   10044:       0001020c        .word   0x0001020c
   10048:       00010224        .word   0x00010224

これが、mymainの正体とな。アセンブラーの勉強にはうってつけ。って、はるか昔にやった ような記憶が蘇ってきた。我ながら進歩が無いな。

折角、実験用コードが有るんで、インテルの石用に移植して太り具合が一緒か、確認してみる。 変更すべき所は、Makefileとhead.Sだ。head.Sだけを載せておく。

sakae@uB:~/src/i386$ cat head.S
.text
// .code 32

.globl  _start

_start:
        mov $stack_top, %esp
        call   mymain
halt:
        jmp halt

.codeってアセンブラの偽命令は無いのね。近頃は、64Bitマシンも当たり前のように有るけど、 インテル得意の32Bit仮想マシンは利用出来ないの? armは32Bitと16Bitの切り替えが、一 命令で出来るんだから、天下のインテルさんだってやればいいのに。

sakae@uB:~/src/i386$ size app.img
   text    data     bss     dec     hex filename
    533       0    8192    8725    2215 app.img
sakae@uB:~/src/i386$ nm app.img
000100b0 T getc
000100cb T gets
00010140 t halt
00012218 B irq_stack_top
00010000 T mymain
00010054 T putc
0001007c T puts
00011218 B stack_top
00010136 T _start

無謀にも走らせてみる。

sakae@uB:~/src/i386$ gdb -q app.img
(gdb) b mymain
Breakpoint 1 at 0x10009: file main.c, line 6.
(gdb) run
Starting program: /home/sakae/src/i386/app.img

Breakpoint 1, mymain () at main.c:6
6               puts("hello, ARM on Fedora\n");
(gdb) c
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00010087 in puts (s=0x10142 "hello, ARM on Fedora\n") at bio.c:15
15                      while (*(UART0 + UARTFR) & UARTFR_TXFF) ;
(gdb) bt
#0  0x00010087 in puts (s=0x10142 "hello, ARM on Fedora\n") at bio.c:15
#1  0x00010016 in mymain () at main.c:6
#2  0x00010140 in _start () at head.S:8

コードは適当な所に置いて実行出来るようだけど、変な所にアクセスするとSEGVになるのね。 だから、管理されたエリアに、UART0を移してしまえば、文句を言われないだろう。 どうするか? smpl.ldの.stackの前に、そのアドレスを書いておけば良い。

        .bss : { *(.bss); }
        . = 0x101f1000;
        .stack : {

これでstackの端っこがUART0のレジスタにかかってくる。

[sakae@fedora i386]$ nm app.img
00010139 T _start
000100b3 T getc
000100ce T gets
00010143 t halt
101f3000 B irq_stack_top
00010000 T mymain
00010055 T putc
0001007e T puts
101f2000 B stack_top

gdbから実行してみると

Breakpoint 1, mymain () at main.c:6
6               puts("hello, ARM on Fedora\n");
(gdb) c
Continuing.
1234
^C
Program received signal SIGINT, Interrupt.
halt () at head.S:10
10              jmp halt

今度はSEGVに落ちる事なく、mymainを無事に走り終えた。勿論、プログラム中のputsからの 表示は無いけどね。

objdump -xの結果も

プログラムヘッダ:
    LOAD off    0x00001000 vaddr 0x00010000 paddr 0x00010000 align 2**12
         filesz 0x00000218 memsz 0x00000218 flags r-x
    LOAD off    0x00002000 vaddr 0x101f1000 paddr 0x101f1000 align 2**12
         filesz 0x00000000 memsz 0x00002000 flags rw-
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
         filesz 0x00000000 memsz 0x00000000 flags rwx

エリアが飛んで配置されている。あれ? 今気が付いたんだけど、stackエリアの属性が 読み書き実行になってるぞ。OpenBSDの親分さんのTeoが、顔を真っ赤ににして怒りそうな 設定だな。何でも、大型コンピュータでは、スタック上でプログラムを実行可能なんて もってのほかだそうですよ。

qemuのsource探検

日頃からお世話になってるqemuのsourceがどうなってるか、探検してみたい。何ってたって、 こいつはCPUの博物館ですから、効率よく見て回る事が出来るでしょう。

なんてのは嘘です。昔、台湾にある故宮博物館を訪れた事があるけど、ツアーに組み込まれた 数時間ではとても回れるものではない。目的を持って回らないと、何を見てきたの?って事に なりきれませんから。あの時は、ツアーと言っても、おいら夫婦だけのツアーで、親日の ガイドさんが案内してくれたから、融通も利いたし、見所を的確に回ってくれた。もう一度、 行ってみたいな。

そんな訳なんで、今回はARMに絞ります。目に付くtarget-armの方じゃなくて、hw/armの 下が目的な展示室。ここには、各種ボード(-M ? で列挙されるやつ)が陳列されてる。 冒頭に、ボードの主が書いてあるんで、まずそれを確かめよう。

キヤノンさん有り、シャープさんあり、TIさんあり、サムスンさんあり、色々な派生品が置いてある。 それから、カーネルのローダーなんてのもね。上でやった -kernel app.img で、読み込みが 行われるのは、このコードが使われているんだな。納得。

ああ、先に展示を眺めちゃったけど、sourceは下記のようにして取得する。

git clone git://git.qemu-project.org/qemu.git

142Mぐらいな、大量ソースでした。

更に絞り込んで、UART系のソースを探してみた。

[sakae@fedora hw]$ grep Arm `find . -type f -print`
./gpio/pl061.c: * Arm PrimeCell PL061 General Purpose IO with additional
./dma/pl080.c: * Arm PrimeCell PL080/PL081 DMA controller
./ssi/pl022.c: * Arm PrimeCell PL022 Synchronous Serial Port
./sd/pl181.c: * Arm PrimeCell PL181 MultiMedia Card Interface
./intc/pl190.c: * Arm PrimeCell PL190 Vector Interrupt Controller
./i386/smbios.c: *  Markus Armbruster <armbru@redhat.com>
./usb/quirks-ftdi-ids.h: * Armin Laeuger originally sent the PID for the UM 100 module.
./misc/mst_fpga.c: * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
./audio/pl041.c: * Arm PrimeCell PL041 Advanced Audio Codec Interface
./audio/pl041.hx: * Arm PrimeCell PL041 Advanced Audio Codec Interface
./audio/pl041.h: * Arm PrimeCell PL041 Advanced Audio Codec Interface
./input/pl050.c: * Arm PrimeCell PL050 Keyboard / Mouse Interface
./input/pxa2xx_keypad.c: * Written by Armin Kuster <akuster@kama-aina.net>
./display/pl110.c: * Arm PrimeCell PL110 Color LCD Controller
./display/pl110_template.h: * Arm PrimeCell PL110 Color LCD Controller
./display/xenfb.c: *       Markus Armbruster <armbru@redhat.com>,
./char/pl011.c: * Arm PrimeCell PL011 UART
./arm/mainstone.c: * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or

ARMな石は英国の設計会社が、各メーカーに設計図を売って儲けている。その時に、オプションで、 音関係は必要ですか? キーボードやマウスコントロールは必要ですか? シリアルコントロールは は必要ですかってな具合に、追加出来るようになってるんだな。で、その追加部品が、PLxxxxって 具合になってる。PLってのはプロダクトの略だろう。多分。PrimeCellって事は、叩き台で、 メーカーは、コピペした後、更に改造可能だったり思想。

UART系は、PL1011なんだな。char/ の下に置いてあるんで、unix流の分類だと、キャラクターデバイスって事 になるな。

折角なので、ちょいとchar/p1011.cを観賞

static void pl011_write(void *opaque, hwaddr offset,
                        uint64_t value, unsigned size)
{
    PL011State *s = (PL011State *)opaque;
    unsigned char ch;

    switch (offset >> 2) {
    case 0: /* UARTDR */
        /* ??? Check if transmitter is enabled.  */
        ch = value;
        if (s->chr)
            qemu_chr_fe_write(s->chr, &ch, 1);
        s->int_level |= PL011_INT_TX;
        pl011_update(s);
        break;
     :

ベースアドレスと、レジスタのオフセット、送出データ、サイズ(使ってないぞ)を 受け取って、データを送出してる。色々なケースがこのルーチンで処理されてて、UARTの くせにDMA転送までやってる。一体、最大ボーレートはどのぐらいなの? そんなの、説明書を 調べろよ。色々分かって面白いな。