在看jailhouse代码的时候,看到了hvc特权指令,这里详细研究一下
cstatic inline __jh_arg jailhouse_call_arg2(__jh_arg num, __jh_arg arg1,
__jh_arg arg2)
{
register __jh_arg num_result asm(JAILHOUSE_CALL_NUM_RESULT) = num;
register __jh_arg __arg1 asm(JAILHOUSE_CALL_ARG1) = arg1;
register __jh_arg __arg2 asm(JAILHOUSE_CALL_ARG2) = arg2;
asm volatile(
JAILHOUSE_CALL_INS
: "+r" (num_result), "+r" (__arg1), "+r" (__arg2)
: : "memory", JAILHOUSE_CALL_CLOBBERED);
return num_result;
}
#define JAILHOUSE_CALL_INS "hvc #0x4a48"
#define JAILHOUSE_CALL_NUM_RESULT "x0"
#define JAILHOUSE_CALL_ARG1 "x1"
#define JAILHOUSE_CALL_ARG2 "x2"
#define JAILHOUSE_CALL_CLOBBERED "x3"
asm asm-qualifiers ( AssemblerTemplate : OutputOperands : InputOperands : Clobbers : GotoLabels)
对于上文中的内联汇编,宏扩展后伪代码如下
asm volatile( hvc #0x4a48 : "+r" (x0), "+r" (x1), "+r" (x2) : : "memory", x3);
冒号作为操作数参数的分隔符
Extended asm syntax uses colons (‘:’) to delimit the operand parameters after the assembler template:
禁用gcc的优化(move code out of loops
)
GCC’s optimizers sometimes discard asm statements if they determine there is no need for the output variables. Also, the optimizers may move code out of loops if they believe that the code will always return the same result (i.e. none of its input values change between calls). Using the volatile qualifier disables these optimizations. asm statements that have no output operands and asm goto statements, are implicitly volatile.
对于'+',代表操作数是可读可写的
Means that this operand is both read and written by the instruction.
对于'r',代表寄存器是一个通用寄存器
A register operand is allowed provided that it is in a general register.
对于'memory',代表告诉编译器这个内存可能被读写,不要被优化。等于内存屏障
The "memory" clobber tells the compiler that the assembly code performs memory reads or writes to items other than those listed in the input and output operands (for example, accessing the memory pointed to by one of the input parameters). To ensure memory contains correct values, GCC may need to flush specific register values to memory before executing the asm. Further, the compiler does not assume that any values read from memory before an asm remain unchanged after that asm; it reloads them as needed. Using the "memory" clobber effectively forms a read/write memory barrier for the compiler.
x1和x2是通用寄存器用于传递参数,x0作为函数的返回值。
hvc指令会进入hyp模式,cpsr的值会保存到hyp模式的spsr中并执行hvc向量(指向hypervisor call的异常处理程序的入口地址) 但是imm立即数会被处理器忽略,但是在入口函数可以检索到imm的值,从而确定是什么服务
HVC #imm imm is an expression evaluating to an integer in the range 0-65535. In a processor that implements the Virtualization Extensions, the HVC instruction causes a Hypervisor Call exception. This means that the processor enters Hyp mode, the CPSR value is saved to the Hyp mode SPSR, and execution branches to the HVC vector. imm is ignored by the processor. However, it can be retrieved by the exception handler to determine what service is being requested.
Instruction: hvc #0x4a48 Hypercall code: x0 1. argument: x1 2. argument: x2 Return code: x0
这里使用虚拟化指令hvc调用立即数#0x4a48,立即数0x4a48只是用作指明是什么服务(jailhouse),参数为x1,x2返回值为x0.如x1,x2不存在则缺省.这里x0先是hypervisor调用的code,然后作为返回值提供返回出去,x1,x2是传入参数,用作根据根据x0的code入口函数的传参,最后的'memory, JAILHOUSE_CALL_CLOBBERED'用作缺省,如入口函数不需要多个参数,这里声明x1,x2,x3带有memory作为暂存寄存器.
While the compiler is aware of changes to entries listed in the output operands, the inline asm code may modify more than just the outputs. For example, calculations may require additional registers, or the processor may overwrite a register as a side effect of a particular assembler instruction. In order to inform the compiler of these changes, list them in the clobber list. Clobber list items are either register names or the special clobbers (listed below). Each clobber list item is a string constant enclosed in double quotes and separated by commas
上面意思是计算可能需要额外寄存器,或者处理器对特殊汇编指令可能会覆写这些寄存器,为了让编译器知道这种情况,可以把这些寄存器放在clobber列表作为暂存寄存器。
#define JAILHOUSE_HC_DISABLE 0 #define JAILHOUSE_HC_CELL_CREATE 1 #define JAILHOUSE_HC_CELL_START 2 #define JAILHOUSE_HC_CELL_SET_LOADABLE 3 #define JAILHOUSE_HC_CELL_DESTROY 4 #define JAILHOUSE_HC_HYPERVISOR_GET_INFO 5 #define JAILHOUSE_HC_CELL_GET_STATE 6 #define JAILHOUSE_HC_CPU_GET_INFO 7 #define JAILHOUSE_HC_DEBUG_CONSOLE_PUTC 8 /* Hypervisor information type */ #define JAILHOUSE_INFO_MEM_POOL_SIZE 0 #define JAILHOUSE_INFO_MEM_POOL_USED 1 #define JAILHOUSE_INFO_REMAP_POOL_SIZE 2 #define JAILHOUSE_INFO_REMAP_POOL_USED 3 #define JAILHOUSE_INFO_NUM_CELLS 4 /* Hypervisor information type */ #define JAILHOUSE_CPU_INFO_STATE 0 #define JAILHOUSE_CPU_INFO_STAT_BASE 1000 /* CPU state */ #define JAILHOUSE_CPU_RUNNING 0 #define JAILHOUSE_CPU_FAILED 2 /* terminal state */ /* CPU statistics */ #define JAILHOUSE_CPU_STAT_VMEXITS_TOTAL 0 #define JAILHOUSE_CPU_STAT_VMEXITS_MMIO 1 #define JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT 2 #define JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL 3 #define JAILHOUSE_GENERIC_CPU_STATS 4
上面调用作为x0传入hypervisor call,从而发送hyc #0x4a48来管理虚拟机。 举个例子如下
Cerr = jailhouse_call(JAILHOUSE_HC_DISABLE);
static inline __jh_arg jailhouse_call(__jh_arg num)
{
register __jh_arg num_result asm(JAILHOUSE_CALL_NUM_RESULT) = num;
asm volatile(
JAILHOUSE_CALL_INS
: "+r" (num_result)
: : "memory", JAILHOUSE_CALL_ARG1, JAILHOUSE_CALL_ARG2,
JAILHOUSE_CALL_CLOBBERED);
return num_result;
}
至此,关于hyc的汇编理解清楚了,接下来继续跟踪jailhouse驱动源码