コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2020年12月10日 >>> 2020年11月27日
link もっと後

2020年12月10日

QEMU RISC-Vエミュレーションで例外が起きるときの仕組み

目次: RISC-V

RISC-VではCPUが単精度浮動小数点F拡張や、倍精度浮動小数点D拡張の命令(flw, fldなど)に対応していても、mstatusのFSビットでFPUを有効にしていないと、命令実行時にIllegal Instruction例外が発生します。

QEMUはこのチェックをどこで行っているのかメモしておきます。

QEMU RISC-V例外発生部分

// qemu/target/riscv/translate.c

static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
{
    /* check for compressed insn */
    if (extract16(opcode, 0, 2) != 3) {
        if (!has_ext(ctx, RVC)) {
            gen_exception_illegal(ctx);
        } else {
            ctx->pc_succ_insn = ctx->base.pc_next + 2;
            if (!decode_insn16(ctx, opcode)) {
                /* fall back to old decoder */
                decode_RV32_64C(ctx, opcode);
            }
        }
    } else {
        uint32_t opcode32 = opcode;
        opcode32 = deposit32(opcode32, 16, 16,
                             translator_lduw(env, ctx->base.pc_next + 2));
        ctx->pc_succ_insn = ctx->base.pc_next + 4;
        if (!decode_insn32(ctx, opcode32)) {    //★この関数がfalseを返す★
            gen_exception_illegal(ctx);
        }
    }
}

static void gen_exception_illegal(DisasContext *ctx)
{
    generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);    //★Illegal Instruction例外★
}

関数decode_insn32() で命令をデコードしfalseが返ってきたら、例外を発生させます。このdecode_insn32() という関数は自動生成されており、ビルドディレクトリの下にあります。RV64向けなら下記のようなパスです。

QEMU RISC-V命令デコード部分

// (build_dir)/libqemu-riscv64-softmmu.fa.p/decode-insn32.c.inc

static bool decode_insn32(DisasContext *ctx, uint32_t insn)
{
    switch (insn & 0x0000007f) {

    ...

    case 0x00000007:
        /* ........ ........ ........ .0000111 */
        switch ((insn >> 12) & 0x7) {

        ...

        case 0x3:
            /* ........ ........ .011.... .0000111 */
            /* ../target/riscv/insn32.decode:199 */
            decode_insn32_extract_i(ctx, &u.f_i, insn);
            if (trans_fld(ctx, &u.f_i)) return true;    //★このifが成立「しない」★
            break;

...


static void decode_insn32_extract_i(DisasContext *ctx, arg_i *a, uint32_t insn)
{
    a->imm = sextract32(insn, 20, 12);
    a->rs1 = extract32(insn, 15, 5);
    a->rd = extract32(insn, 7, 5);
}


// qemu/target/riscv/insn_trans/trans_rvd.c.inc

static bool trans_fld(DisasContext *ctx, arg_fld *a)
{
    REQUIRE_FPU;    //★このマクロ内でreturn false★
    REQUIRE_EXT(ctx, RVD);
    TCGv t0 = tcg_temp_new();
    gen_get_gpr(t0, a->rs1);
    tcg_gen_addi_tl(t0, t0, a->imm);

    tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEQ);

    mark_fs_dirty(ctx);
    tcg_temp_free(t0);
    return true;
}


// qemu/target/riscv/insn_trans/trans_rvf.c.inc

#define REQUIRE_FPU do {\
    if (ctx->mstatus_fs == 0) \
        return false;                       \
} while (0)

大体の仕組みは把握できましたので、実際にこの部分を通るかどうか見ましょう。

実行して確かめる

Illegal Instruction例外は実行中に何度も発生する例外ではありません。カーネル内で1度でも発生するとZephyrはログを出して止まります。すなわちQEMUも例外を発生させるのは1度だけです。

何度も通る処理だとブレーク条件が必要でややこしいですが、1度しか通らない処理なら単純にREQUIRE_FPUの行でブレークすれば良いです。条件ctx->mstatus_fs == 0が成立するかどうか簡単に確認できます。

GDBでmstatus_fsの値を確認する
$ gdb qemu/build/qemu-system-riscv64

(gdb) b trans_rvd.c.inc:23

Breakpoint 1 at 0x555555a858b8: file ../target/riscv/insn_trans/trans_rvd.c.inc, line 23.

(gdb) r

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff440c700 (LWP 1675592)]
[New Thread 0x7ffff3a89700 (LWP 1675593)]
*** Booting Zephyr OS build zephyr-v2.4.0-2328-g4f33cf942643  ***
Running test suite test_sprintf
===================================================================
START - test_sprintf_double
[Switching to Thread 0x7ffff3a89700 (LWP 1675593)]

Thread 3 "qemu-system-ris" hit Breakpoint 1, trans_fld (ctx=0x7ffff3a883d0,
    a=0x7ffff3a88290) at ../target/riscv/insn_trans/trans_rvd.c.inc:23
23          REQUIRE_FPU;

(gdb) l

18       * this program.  If not, see <http://www.gnu.org/licenses/>.
19       */
20
21      static bool trans_fld(DisasContext *ctx, arg_fld *a)
22      {
23          REQUIRE_FPU;        //★ここで止めた★
24          REQUIRE_EXT(ctx, RVD);
25          TCGv t0 = tcg_temp_new();
26          gen_get_gpr(t0, a->rs1);
27          tcg_gen_addi_tl(t0, t0, a->imm);

(gdb) p ctx->mstatus_fs

$1 = 0

ちょっとしたメモのつもりが長くなってしまいました。まあいいや。

編集者:すずき(2021/09/21 22:59)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2020年12月9日

Zephyrと浮動小数点数命令のサポート その2 - 実行

目次: Zephyr

ひとまずF拡張とD拡張の双方を有効にしRV64IMAFDC(省略形だとRV64GCともいう)でビルドして、実行します。使用するのはtests/lib/sprintfで、その名の通りsprintf() のテストです。しかし実行するやいなや、エラーで吹き飛んでしまいます。

D拡張を有効にしてsprintfのテストを実行するとクラッシュする
$ cmake -G Ninja -DBOARD=qemu_rv64_virt ../tests/lib/sprintf/
$ ninja
$ ninja run

[0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: riscv64
*** Booting Zephyr OS build zephyr-v2.4.0-2328-g4f33cf942643  ***
Running test suite test_sprintf
===================================================================
START - test_sprintf_double
E: Exception cause Illegal instruction (2)
E: Faulting instruction address = 0x80000cba
E:   ra: 0x80003836  gp: 0x00000000  tp: 0x00000000  t0: 0x00000000
E:   t1: 0x00000000  t2: 0x00000000  t3: 0x00000000  t4: 0x00000000
E:   t5: 0x00000000  t6: 0x00000000  a0: 0x8000bdb0  a1: 0x00000000
E:   a2: 0x00000000  a3: 0x00000000  a4: 0x00000000  a5: 0x80006cb6
E:   a6: 0x00000000  a7: 0x00000000

E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
E: Current thread: 0x80009820 (unknown)
E: Halting system

ログには非常に役立つ情報が出ています。エラーの理由はIllegal Instruction例外、アドレスは0x80000cbaだと言っています。なるほど。この付近を逆アセンブルします。

例外が発生した命令を特定する
$ riscv64-zephyr-elf-objdump -drS build32/zephyr/zephyr.elf

0000000080000cb2 <test_sprintf_double>:
{
    80000cb2:   7121                    addi    sp,sp,-448
    80000cb4:   af22                    fsd     fs0,408(sp)
        sprintf(buffer, "%e", var.d);
    80000cb6:   00006797                auipc   a5,0x6
    ★fld命令でIllegal Instruction例外★
    80000cba:   ad27b407                fld     fs0,-1326(a5) # 80006788 <__font_entry_end>
    80000cbe:   e2040653                fmv.x.d a2,fs0
    80000cc2:   00007597                auipc   a1,0x7
    80000cc6:   ad658593                addi    a1,a1,-1322 # 80007798 <__clz_tab+0xf78>

...

QEMUのrv64 CPU指定は倍精度浮動小数D拡張命令に対応しているのに、なぜエラーになるのか?原因はztestというZephyrのテストフレームワークの仕組みによるものです。次回以降、エラーの原因を追います。

編集者:すずき(2023/09/24 11:59)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2020年12月8日

Zephyrと浮動小数点数命令のサポート その1 - ボードの設定とビルド

目次: Zephyr

RISC-V向けZephyrには、既存のボード設定がいくつか含まれていますが、私が持っているボード(SiFive HiFive1 Rev.B)やQEMU用の設定では、浮動小数点数命令(単精度浮動小数点数命令 = F拡張、倍精度浮動小数点数命令 = D拡張)は未サポートです。

実はQEMUは浮動小数点数命令をサポートしているCPUタイプもあります(-cpu rv32もしくは -cpu rv64)。せっかくサポートしているのに使わないのは勿体無いですよね?

浮動小数点数命令のサポートを追加、ビルド

新たにqemu_rv64_virtボードを追加し、ハードウェア浮動小数点数命令をサポートします。Zephyrには既に仕組みがあるので、特に難しくはありません。CPU_HAS_FPUとCPU_HAS_FPU_DOUBLE_PRECISIONをselectするだけです。

D拡張を有効にしてsprintfのテストを実行するとクラッシュする

config BOARD_QEMU_RV64_VIRT
	bool "QEMU RV64 virt target"
	depends on SOC_QEMU_RV64_VIRT
	select QEMU_TARGET
	select 64BIT
	select CPU_HAS_FPU                     #★F拡張に対応★
	select CPU_HAS_FPU_DOUBLE_PRECISION    #★D拡張に対応★

この場合RV64IMAFDCの意味になりますが、select CPU_HAS_FPUだけ指定して、D拡張だけ外したRV64IMAFCにすることもできます。しかしZephyr SDKのツールチェーンが対応していないため、下記のようにリンク時に猛烈にエラーが出て怒られます。

F拡張だけ有効にしてビルドすると大量のエラー
[105/110] Linking C executable zephyr/zephyr_prebuilt.elf
FAILED: zephyr/zephyr_prebuilt.elf
: && ccache zephyr-sdk/riscv64-zephyr-elf/bin/riscv64-zephyr-elf-gcc   zephyr/CMakeFiles/zephyr_prebuilt.dir/misc/empty_file.c.obj -o zephyr/zephyr_prebuilt.elf  -Wl,-T  zephyr/linker.cmd  -Wl,-Map=zephyr/build32/zephyr/zephyr_prebuilt.map  -Wl,--whole-archive  app/libapp.a  zephyr/libzephyr.a  zephyr/arch/common/libarch__common.a  zephyr/arch/arch/riscv/core/libarch__riscv__core.a  zephyr/lib/libc/minimal/liblib__libc__minimal.a  zephyr/lib/posix/liblib__posix.a  zephyr/subsys/testsuite/ztest/libsubsys__testsuite__ztest.a  zephyr/drivers/serial/libdrivers__serial.a  -Wl,--no-whole-archive  zephyr/kernel/libkernel.a  zephyr/CMakeFiles/offsets.dir/./arch/riscv/core/offsets/offsets.c.obj  -L"zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0"  -Lzephyr/build32/zephyr  -lgcc  -Wl,--print-memory-usage  zephyr/arch/common/libisr_tables.a  -mabi=lp64f  -march=rv64imafc  -Wl,--gc-sections  -Wl,--build-id=none  -Wl,--sort-common=descending  -Wl,--sort-section=alignment  -Wl,-u,_OffsetAbsSyms  -Wl,-u,_ConfigAbsSyms  -nostdlib  -static  -no-pie  -Wl,-X  -Wl,-N  -Wl,--orphan-handling=warn && :
zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/../../../../riscv64-zephyr-elf/bin/ld: zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/libgcc.a(_clzdi2.o): ABI is incompatible with that of the selected emulation:
  target emulation `elf32-littleriscv' does not match `elf64-littleriscv'
zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/../../../../riscv64-zephyr-elf/bin/ld: failed to merge target specific data of file zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/libgcc.a(_clzdi2.o)
zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/../../../../riscv64-zephyr-elf/bin/ld: zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/libgcc.a(_ctzdi2.o): ABI is incompatible with that of the selected emulation:
  target emulation `elf32-littleriscv' does not match `elf64-littleriscv'
zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/../../../../riscv64-zephyr-elf/bin/ld: failed to merge target specific data of file zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/libgcc.a(_ctzdi2.o)
zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/../../../../riscv64-zephyr-elf/bin/ld: zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/libgcc.a(_clz.o): ABI is incompatible with that of the selected emulation:
  target emulation `elf32-littleriscv' does not match `elf64-littleriscv'
zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/../../../../riscv64-zephyr-elf/bin/ld: failed to merge target specific data of file zephyr-sdk/riscv64-zephyr-elf/bin/../lib/gcc/riscv64-zephyr-elf/10.2.0/libgcc.a(_clz.o)
Memory region         Used Size  Region Size  %age Used
             RAM:       49220 B       256 KB     18.78%
        IDT_LIST:          57 B         2 KB      2.78%
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

上記のエラーについてZephyr SDKを作っている人に聞いてみたところ「RV64IMAFCは本当に必要?」と逆に聞かれてしまいました。うーん、現状そんな変なCPUはこの世にないし、対応する理由も思いつきません。要らないですね。

編集者:すずき(2023/09/24 11:59)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2020年12月5日

東京オリンピックと祝日とカレンダー

日本政府は未だに東京オリンピックやる気満々らしく、内閣府の発表(国民の祝日について - 内閣府)によると、2020年に引き続いて来年2021年も、海の日、スポーツの日、山の日が本来と異なる日付に移動されるようです。

  • 海の日: 7月 第3月曜7/19 → 7/22
  • スポーツの日: 10月 第2月曜10/11 → 7/23
  • 山の日: 8/11 → 8/8(日曜日なので8/9が振替休日になる)

混乱しそうなのでこのサイトのカレンダー機能にも反映しておきました。カレンダー機能は便利で実装して良かったと思っている機能の一つですが、まさかこんなに東京オリンピック関係で祝日が蹂躙されるとは思っていませんでしたね。

編集者:すずき(2020/12/05 22:51)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2020年12月3日

Zephyrのcollaboratorその2

目次: Zephyr

ZephyrのWatchdogのCollaboratorになりました。先日(2020年11月17日の日記参照)CollaboratorになったRISC-VもWatchdogも、元々メンテナーが不在の領域です。

発端はSiFive HiFive1を買った記念にWatchdogドライバを書いたら、割とあっさり動いたので、PRを送ったことです。送ったまでは良かったのですが、メンテナーが不在でした。またこのパターン……。

Zephyrは周辺ドライバが充実しているのが売りですが、メンテナーは不足気味です。今ならサブシステムのCollaboratorくらいなら、何の実績もなくても気前良く追加してくれます。

RTOS興味ある人はいかがですか?

編集者:すずき(2023/09/24 12:00)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2020年12月10日 >>> 2020年11月27日
link もっと後

管理用メニュー

link 記事を新規作成

<2020>
<<<12>>>
--12345
6789101112
13141516171819
20212223242526
2728293031--

最近のコメント20件

  • link 21年9月20日
    すずきさん (11/19 01:04)
    「It was my pleasure.」
  • link 21年9月20日
    whtさん (11/17 23:41)
    「This blog solves my ...」
  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」
  • link 24年10月1日
    hdkさん (10/03 08:30)
    「おー、面白いですね。xrdpはすでに立ち...」
  • link 14年6月13日
    2048player...さん (09/26 01:04)
    「最後に、この式を出すのに紙4枚(A4)も...」
  • link 14年6月13日
    2048playerさん (09/26 01:00)
    「今のところ最も簡略化した式です。\n--...」
  • link 14年6月13日
    2048playerさん (09/16 01:00)
    「返信ありがとうございます。\nコメントが...」
  • link 14年6月13日
    すずきさん (09/12 21:19)
    「コメントありがとうございます。同じ結果に...」
  • link 14年6月13日
    2048playerさん (09/08 17:30)
    「私も2048の最高スコアを求めたのですが...」
  • link 14年6月13日
    2048さん (09/08 17:16)
    「私も2048の最高スコアを求めたのですが...」
  • link 14年6月13日
    2048playerさん (09/08 16:10)
    「私も2048の最高スコアを求めたのですが...」
  • link 02年8月4日
    lxbfYeaaさん (07/12 10:11)
    「555」
  • link 24年6月17日
    すずきさん (06/23 00:12)
    「ありがとうございます。バルコニーではない...」
  • link 24年6月17日
    hdkさん (06/22 22:08)
    「GPSの最初の同期を取る時は見晴らしのい...」
  • link 24年5月16日
    すずきさん (05/21 11:41)
    「あー、確かにdpkg-reconfigu...」
  • link 24年5月16日
    hdkさん (05/21 08:55)
    「システム全体のlocale設定はDebi...」
  • link 24年5月17日
    すずきさん (05/20 13:16)
    「そうですねえ、普通はStandardなの...」
  • link 24年5月17日
    hdkさん (05/19 07:45)
    「なるほど、そういうことなんですね。Exc...」

最近の記事3件

  • link 24年11月18日
    すずき (12/04 02:08)
    「[nvJPEGとNVJPGとJetson APIその1 - nvJPEG decoupled API] 目次: Linux半年...」
  • link 23年4月10日
    すずき (12/04 01:40)
    「[Linux - まとめリンク] 目次: Linux関係の深いまとめリンク。目次: RISC-V目次: ROCK64/ROCK...」
  • link 24年11月28日
    すずき (12/01 00:53)
    「[BIOS/UEFI画面に入る方法] PCは起動時にあるキーを押すとBIOS/UEFIの設定画面に遷移します。良く見るパターン...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 12/04 02:08