目次: Zephyr
SMP対応の序盤、ビルドエラー対処の続きです。
ビルドの難所です。CONFIG_SMPを有効にするとisr.Sで大量にエラーが出ます。
zephyr/arch/riscv/core/isr.S:305: Error: illegal operands `lw sp,_kernel_offset_to_irq_stack(t2)'
zephyr/arch/riscv/core/isr.S:316: Error: illegal operands `lw t3,_kernel_offset_to_nested(t2)'
zephyr/arch/riscv/core/isr.S:376: Error: illegal operands `sw t2,_kernel_offset_to_nested(t1)'
zephyr/arch/riscv/core/isr.S:463: Error: illegal operands `lw t1,(0x78+___ready_q_t_cache_OFFSET)(t0)'
zephyr/arch/riscv/core/isr.S:468: Error: illegal operands `sw t1,_kernel_offset_to_current(t0)'
原因は_kernel_offset_* 系のオフセットマクロが未定義になるためです。
// zephyr/kernel/include/offsets_short.h
#ifndef CONFIG_SMP
/* Relies on _kernel.cpu being the first member of _kernel and having 1 element
*/
#define _kernel_offset_to_nested \r (___cpu_t_nested_OFFSET)
#define _kernel_offset_to_irq_stack \r (___cpu_t_irq_stack_OFFSET)
#define _kernel_offset_to_current \r (___cpu_t_current_OFFSET)
#endif /* CONFIG_SMP */
#define _kernel_offset_to_idle \r (___kernel_t_idle_OFFSET)
#define _kernel_offset_to_current_fp \r (___kernel_t_current_fp_OFFSET)
#define _kernel_offset_to_ready_q_cache \r (___kernel_t_ready_q_OFFSET + ___ready_q_t_cache_OFFSET)
...
// zephyr/include/kernel_offsets.h
...
#ifndef CONFIG_SMP
GEN_OFFSET_SYM(_ready_q_t, cache);
#endif
当たり前ですが、この #ifdefを外すだけではSMPは動きません。対策方法を理解するには、Zephyrのカーネル構造体の内部に、少しだけ立ち入る必要があります。
カーネル構造体は_kernelという名前で何度か出ていましたが、見覚えありますか?なくても全然構わないです。下記のような定義の構造体です。細かい定義はさておき、大事なことはcpusが _kernelの先頭にある、という点です。
// zephyr/kernel/sched.c
/* the only struct z_kernel instance */
struct z_kernel _kernel;
// zephyr/include/kernel_structs.h
struct z_kernel {
struct _cpu cpus[CONFIG_MP_NUM_CPUS]; //★_kernelの先頭にcpusがある★
#ifdef CONFIG_SYS_CLOCK_EXISTS
/* queue of timeouts */
sys_dlist_t timeout_q;
#endif
#ifdef CONFIG_SYS_POWER_MANAGEMENT
int32_t idle; /* Number of ticks for kernel idling */
#endif
/*
* ready queue: can be big, keep after small fields, since some
* assembly (e.g. ARC) are limited in the encoding of the offset
*/
struct _ready_q ready_q;
...
// zephyr/include/kernel_structs.h
struct _cpu {
/* nested interrupt count */
uint32_t nested;
/* interrupt stack pointer base */
char *irq_stack;
/* currently scheduled thread */
struct k_thread *current;
/* one assigned idle thread per CPU */
struct k_thread *idle_thread;
...
CPUが1つしか存在しない場合、cpusの要素数は1であり、_kernelの先頭 = cpus[0] の先頭になります。そのため _kernel.cpus[0].currentのオフセット = cpu構造体のcurrentへのオフセット、です。offsets_short.hの定義はこの性質を利用しています。
C言語だとcpus[0] とcpus[i] の違いでしかなく、ありがたみがわかりませんが、アセンブラだと非常に単純かつ高速にオフセットを求めることができます。下記はisr.Sから持ってきた例ですが、_kernel.cpus[0].currentへのアクセスがわずか2命令で実現できます。
la t0, _kernel
RV_OP_LOADREG t0, _kernel_offset_to_current(t0)
残念ながらSMPの場合はcpusが1つではありませんから、上記の最適化は使えません。cpus[n] のオフセット、つまりHART ID * sizeof(struct _cpu) を計算する必要があります。
まずはstruct _cpuのオフセットマクロが未定義なので、追加します。ZephyrではGEN_ABSOLUTE_SYM() というマクロが用意されており、アセンブラ用のマクロを生成してくれます。便利ですね。
// zephyr/arch/riscv/core/offsets/offsets.c
#ifdef CONFIG_SMP
GEN_ABSOLUTE_SYM(__cpu_t_SIZEOF, sizeof(_cpu_t));
#endif
次にisr.Sのビルドエラーが出ている箇所を直します。
// zephyr/arch/riscv/core/isr.S
/*
* xreg0: result &_kernel.cpu[mhartid]
* xreg1: work area
*/
.macro z_riscv_get_cpu xreg0, xreg1
#ifdef CONFIG_SMP
csrr xreg0, mhartid
addi xreg1, x0, __cpu_t_SIZEOF
mul xreg1, xreg0, xreg1
la xreg0, _kernel
add xreg0, xreg0, xreg1
#else
la xreg0, _kernel
#endif
.endm
//(変更前)
/* Get reference to _kernel */
la t1, _kernel
/* Decrement _kernel.cpus[0].nested variable */
lw t2, _kernel_offset_to_nested(t1)
addi t2, t2, -1
sw t2, _kernel_offset_to_nested(t1)
//(変更後)
/* Get reference to _kernel.cpus[n] */
z_riscv_get_cpu t1, t2 //★z_riscv_get_cpuに置き換え★
/* Decrement _kernel.cpus[n].nested variable */
lw t2, ___cpu_t_nested_OFFSET(t1) //★_kernel_offset_to_* から ___cpu_t_*_OFFSETに置き換え★
addi t2, t2, -1
sw t2, ___cpu_t_nested_OFFSET(t1)
修正方針は2つあります。
ここまで直すとビルドが通るはずですが、実はビルドが通るだけでは動きません。次回は実行時のエラーを対策します。
< | 2020 | > | ||||
<< | < | 10 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.15.
using GD bundled (2.1.0 compatible)(png support.)