1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CFEでHello world!

Last updated at Posted at 2018-11-26

BCM/mipsのBCM4712などの古いターゲットではFreeBSDで動くようにならなさそうで、捨てるのも忍びないのでBare Metalで使えないか試してみる事にしました。

CFEとはBroadcomがmips SOC用に提供しているブートローダーで、Common Firmware Environmentが正式名称です。Broadcomのmips SOCはSiByteを2000年に買収して始まりCFEはSiByte時代からのもののようです。SiByteはハイエンドのmips SOCを作っていたようなのですが、Broadcomになってからのmips SOCは小規模なものに変わっています。またCFEはもともとx86やppcなどのサポートなどもある大規模なブートローダーでした。

以下のページを参考にしました。

いつものように環境はFreeBSDですが、gccはpkgでgcc-mipsを入れました。いつものようにLinuxのtoolchainを使わなかったのはBroadcomが配っていたtoolchainはgcc-3だったからです。

% mips-unknown-freebsd11.2-gcc -v
Using built-in specs.
COLLECT_GCC=mips-unknown-freebsd11.2-gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/mips-unknown-freebsd11.2/6.4.0/lto-wr
apper
Target: mips-unknown-freebsd11.2
Configured with: /wrkdirs/usr/ports/devel/mips-gcc/work/gcc-6.4.0/configure --ta
rget=mips-unknown-freebsd11.2 --disable-nls --enable-languages=c,c++ --enable-gn
u-indirect-function --without-headers --with-gmp=/usr/local --with-pkgversion='F
reeBSD Ports Collection for mips' --with-system-zlib --with-gxx-include-dir=/usr
/include/c++/v1/ --with-sysroot=/ --with-as=/usr/local/bin/mips-unknown-freebsd1
1.2-as --with-ld=/usr/local/bin/mips-unknown-freebsd11.2-ld --enable-initfini-ar
ray --prefix=/usr/local --localstatedir=/var --mandir=/usr/local/man --infodir=/
usr/local/info/ --build=x86_64-unknown-freebsd11.2
Thread model: posix
gcc version 6.4.0 (FreeBSD Ports Collection for mips) 

Entry.Sはそのままです。

Main.cは以下のように修正しました。

void putchar(char c)
{
        volatile char* lsr = (volatile char*)0xb8000305; // Line status register.
        volatile char* thr = (volatile char*)0xb8000300; // Transmitter holding register.
 
        while(((*lsr) & 0x20) == 0) ; // Wait until THR is empty.
 
        *thr = c;
}
 
void printk(const char* s)
{
        while(*s)
        {
                putchar(*s);
                s++;
        }
}
 
int main(void)
{
        printk("Hello world!¥n");
        return 0;
}

シリアルのアドレスはLinuxのブートログなどで確認できます。LSRのアドレスは5か倍数(0x0aか0x14)になりますが、このチップは5でした。

ldscriptはFreeBSDのsys/conf/ldscript.mips.cfeを使います。修正点は_startをstartにしてKERNLOADADDRを0x80001000にしました。

Makefileは以下のようにしました。

CROSS=mips-unknown-freebsd11.2

Kernel.elf : Entry.o Main.o
        $(CROSS)-ld -EL -T ldscript.mips.cfe -o Kernel.elf Entry.o Main.o

Entry.o : Entry.S
        $(CROSS)-as -EL -msoft-float -march=mips32 -o Entry.o Entry.S

Main.o : Main.c
        $(CROSS)-gcc -EL -o Main.o -c Main.c -Wall -Wextra  -Werror ¥
                -march=mips32 -mno-abicalls -nostdlib -fno-builtin ¥
                -nostartfiles  -nodefaultlibs -O2 

clean:
        rm Kernel.elf Entry.o Main.o

ちょっとはまったのはpkgのgccがなぜかデフォルトがBigEndianでビルドされていたことと、元のldscriptではうまく動かなかった事です。

% file Kernel.elf 
Kernel.elf: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (FreeBSD), statica
lly linked, interpreter *empty*, not stripped
% readelf -h Kernel.elf 
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 09 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            FreeBSD
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           MIPS R3000 Big-Endian only
  Version:                           0x1
  Entry point address:               0x80001000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          5028 (bytes into file)
  Flags:                             0x50001001, mips32, o32, noreorder
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         7
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 11

ターゲットにシリアル接続して、電源投入後に^Cでブートローダーを止めて、ネットワーク接続して実行してみます。サーバ側でtftpdを使えるようにして、指定したディレクトリにKernel.elfをコピーしておきます。

CFE> ifconfig eth0 -addr=10.10.10.200
CFE> boot -elf 10.10.10.3:Kernel.elf
Loader:elf Filesys:tftp Dev:eth0 File:10.10.10.3:Kernel.elf Options:(null)
Loading: 0x80001000/256 0x80003100/4096 Entry at 0x80001000
Closing network.
et0: link down (interface down)
Starting program at 0x80001000
Hello world!

できました。

CFEはAPIがあり、もしAPIを使いたい場合には、メモリに張り付いているCFEの領域を壊してしまわないようにします。APIを使ってシリアル出力をすることも可能です。

Total memory used by CFE:  0x80400000 - 0x804A39B0 (670128)
Initialized Data:          0x80439670 - 0x8043C210 (11168)
BSS Area:                  0x8043C210 - 0x8043D9B0 (6048)
Local Heap:                0x8043D9B0 - 0x804A19B0 (409600)
Stack Area:                0x804A19B0 - 0x804A39B0 (8192)
Text (code) segment:       0x80400000 - 0x80439670 (235120)
Boot area (physical):      0x004A4000 - 0x004E4000
Relocation Factor:         I:00000000 - D:00000000

CFE> show memory
Range Start  Range End    Range Size     Description
------------ ------------ -------------- --------------------
000000000000-0000003FFFFF (000000400000) DRAM (available)
0000004A4000-000000FFFFFF (000000B5C000) DRAM (available)
*** command status = 0

MMUを使う場合は、この領域を別扱いにすれば良いのかもしれませんが、BareMetalで連続したメモリー空間で使う場合には、この領域を保護するのはちょっと面倒です。アプリケーション起動直後の壊す可能性の低いうちにAPIを叩いてその後は壊しても良いようにAPIを叩かないって方法がいいのかもしれません。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?