OpenSBI 中 misa_xlen() 返回 -1 是什么意思

OpenSBI 中 misa_xlen() 返回 -1 是什么意思

在平头哥的C910平台进行OpenSBI调试的时候,发现misa_xlen()这个函数返回值是-1?为何会如此呢,按照理解,这个函数只能返回1,2,3,返回-1标识出一种异常,那究竟是什么意思呢?下面通过源码进行问题的定位和解释。

首先明确一下,这个函数在哪里:
lib -> risc_main_asm.c -> misa_xlen()

从源码入手。

int misa_xlen(void)
{
	long r;

	if (csr_read(CSR_MISA) == 0) 
		return sbi_platform_misa_xlen(sbi_platform_thishart_ptr());

	__asm__ __volatile__(
		"csrr   t0, misa\n\t"
		"slti   t1, t0, 0\n\t"
		"slli   t1, t1, 1\n\t"
		"slli   t0, t0, 1\n\t"
		"slti   t0, t0, 0\n\t"
		"add    %0, t0, t1"
		: "=r"(r)
		:
		: "t0", "t1");

	return r ? r : -1;
}

从代码上看,返回-1有两个可能,第一个return,还有就是汇编代码的return.
要看懂第一个return,需要看懂第一个函数:

#define csr_read(csr)                                           \
	({                                                      \
		register unsigned long __v;                     \
		__asm__ __volatile__("csrr %0, " __ASM_STR(csr) /* 将csr的值赋值给__V */ \
				     : "=r"(__v)      /* 输出列表 */          \
				     :                /* 输入列表,这里为空*/           \
				     : "memory");     /* 影响的内存,寄存器 */           \
		__v;                                            \
	})


这种 __ asm __ 开头的写法,叫做内嵌汇编。
里面的%0 和%1,是占位符。
冒号的3个部分分别是 输入列表,输出列表,改变的register(常见的是memory)

有关于这个部分,参考下面的几个链接:

链接: 内联汇编 - 从头开始.

__asm__ __volatile__(assembly template
        : output operand list 
        : input operand list
        : clobber list
                            );

链接: A guide to inline assembly for C and C++.

链接: 内嵌汇编 %0,%1 是什么.

__asm__ __violate__
("movl %1,%0" : "=r" (result) : "m" (input));

//“movl %1,%0”是指令模板;“%0”和“%1”代表指令的操作数,称为占位符,内嵌汇编靠它们将C语言表达式与指令操作数相对应。

//指令模板后面用小括号括起来的是C语言表达式,本例中只有两个:“result”和“input”,他们按照出现的顺序分别与指令操作数“%0”,“%1,”对应;注意对应顺序:第一个C表达式对应“%0”;第二个表达式对应“%1”,依次类推,操作数至多有10个,分别用“%0”,“%1”….“%9,”表示。

//“result”前面的限制字符串是“=r”,其中“=”表示“result”是输出操作数,“r”表示需要将“result”与某个通用寄存器相关联,先将操作数的值读入寄存器,然后在指令中使用相应寄存器,而不是“result”本身,当然指令执行完后需要将寄存器中的值存入变量“result”,从表面上看好像是指令直接对“result”进行操作,实际上GCC做了隐式处理,这样我们可以少写一些指令。

链接: csr_read() 函数在Kernel的一个修改记录 commit info.

链接: GCC-Inline-Assembly-HOWTO.

这个简书的文章,把Sandeep.S的GCC-Inline-Assembly-HOWTO给翻译并勘误了,推荐配套阅读。
链接: GCC内联汇编基础.

链接: 总结CSRs寄存器的读写指令.

链接: c语言之#和##.

链接: C语言宏定义##连接符和#符的使用.

链接: GCC内联汇编教程.

从riscV网站可以得知这个register的可能值是0,1,2,3.

链接: 3.1.1 Machine ISA Register misa.

MXLXLEN
132
264
3128

The misa CSR is a WARL read-write register reporting the ISA supported by the hart. This register must be readable in any implementation, but a value of zero can be returned to indicate the misa register has not been implemented, requiring that CPU capabilities be determined through a separate non-standard mechanism.
在这里插入图片描述

The MXL (Machine XLEN) field encodes the native base integer ISA width as shown in Table [misabase]. The MXL field may be writable in implementations that support multiple base ISA widths. The effective XLEN in M-mode, MXLEN, is given by the setting of MXL, or has a fixed value if misa is zero. The MXL field is always set to the widest supported ISA variant at reset.
这个值为零的情况,指的是misa还没被实现。
但是我们的工程中,显然不是这种情况,从同时提供的打印信息,并不是第一个return导致的-1.

所以只能从后面的函数入手分析。

int misa_xlen(void)
{
	long r;

	__asm__ __volatile__(
		"csrr   t0, misa\n\t"
		"slti   t1, t0, 0\n\t"
		"slli   t1, t1, 1\n\t"
		"slli   t0, t0, 1\n\t"
		"slti   t0, t0, 0\n\t"
		"add    %0, t0, t1"
		: "=r"(r)
		:
		: "t0", "t1");

	return r ? r : -1;
}

既然是关于汇编的,那么就需要解析每一行的汇编指令。
关于汇编命令的解析,可以参考这个文档
链接: 《RISC-V-Reader-Chinese-v2p1.pdf》.

先解释几个缩写的意思:
CSR :Control and Status Register 控制和状态寄存器
MISA:Machine-Level CSRs
xlen:x length, 指的是你的register位数是多长,支持32或者64。
Risc-V的基础指令集是整数指令集,在任何架构方案中,必须完整实现基础的整数指令集。在整数指令集中,用补码表示有符号整数。
主要有四个基础指令集,它们主要通过整数寄存器的长度来区分,比如RV32I,在该指令集方案中,整数寄存器的长度为32位,在RV64I指令集方案中,整数寄存器的长度为64位。对于RV32I,由于整数寄存器是32位,所以可以提供232=4GB的地址访问空间,对于RV64I,整数寄存器是64位,所以可以提供264=4194304TB的地址访问空间,这是一个非常大的地址空间。我们通常用xlen表示整数寄存器位数或者说地址空间位数,所以对于RV32I, xlen=32, 对于RV64I, xlen=64。

下面我将每一行使用伪代码来进行注释。

    __asm__ __volatile__(
        "csrr   t0, misa\n\t"   /* 将misa的状态读到t0. [t0] = misa*/
        "slti   t1, t0, 0\n\t"  /* 如果t0的值 < 0,那么t1写1,否则写0   if [t0] < 0; [t1] = 1; else [t1] = 0;*/
        "slli   t1, t1, 1\n\t"  /* 将t1的值,左移1bit。 [t1] << 1 */
        "slli   t0, t0, 1\n\t"  /* 将t0的值,左移1bit。 [t0] << 1 */
        "slti   t0, t0, 0\n\t"  /* if [t0] < 0; [t0] = 1; else [t0] = 0; */
        "add    %0, t0, t1"     /* %0 是占位符,意思是 将 [r] = [t0] + [t1] */
        : "=r"(r)               /* 返回值是 r的值,格式是0xff */
        :
        : "t0", "t1");          /* 影响寄存器的范围是t0和t1 */

链接: GCC-Inline-Assembly-HOWTO.html.

这里面有关于返回限定的意思,rK就是返回一个0xff类型的值。
“r” : Register operand constraint, look table given above.
“q” : Registers a, b, c or d.
“I” : Constant in range 0 to 31 (for 32-bit shifts).
“J” : Constant in range 0 to 63 (for 64-bit shifts).
“K” : 0xff.
“L” : 0xffff.
“M” : 0, 1, 2, or 3 (shifts for lea instruction).
“N” : Constant in range 0 to 255 (for out instruction).
“f” : Floating point register
“t” : First (top of stack) floating point register
“u” : Second floating point register
“A” : Specifies the a’ ord’ registers. This is primarily useful for 64-bit integer values intended to be returned with the d’ register holding the most significant bits and thea’ register holding the least significant bits.

从risc-v-asm-manual.pdf 的第一个Table 1.1 RISC-V Base Integer Registers Of Size XLEN的图可以看出,t0,t1是临时使用的register.

Register NameABI NameDescription
x0zeroHard-Wired Zero
x1raReturn Address
x2spStack Pointer
x3gpGlobal Pointer
x4tpThread Pointer
x5t0Temporary/Alternate Link Register
x6-7t1-t2Temporary Register
x8s0/fpSaved Register (Frame Pointer)
x9s1Saved Register
x10-11a0-a1Function Argument/Return Value Registers
x12-17a2-a7Function Argument Registers
x18-27s2-s11Saved Registers
x28-31t3-t6Temporary Registers

最后回到这个函数

int misa_xlen(void)
{
	long r;

	__asm__ __volatile__(
		"csrr   t0, misa\n\t"
		"slti   t1, t0, 0\n\t"
		"slli   t1, t1, 1\n\t"
		"slli   t0, t0, 1\n\t"
		"slti   t0, t0, 0\n\t"
		"add    %0, t0, t1"
		: "=r"(r)
		:
		: "t0", "t1");

	return r ? r : -1;
}

也就是说,只有r读到非0值,才返回r,否则都返回-1.
因为r的正常值只能是1,2,3,所以如果是-1的话,从misa读取的值是0.

所以我认为最可能的原因是:系统此时还未初始化完毕,misa的值还未正确的填充,所以读出来的才是0值。
当然了这只是基于现有信息的分析,具体的原因仍需进一步的确定。

这一个小小的问题。不仅牵扯了riscV的misa寄存器,asm内嵌汇编,多个asm汇编指令的解析,真是举步维艰,为了求是,必不能放过任何一个疑点,共勉之。

如有错误,请指出,别喷就行,我也不指望你给我捐赠,能帮到大家是最好,我又不是真理转世,出错在所难免。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔尊moon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值