commit 72132b63edb25a63073636e379749ee395666ed5
parent 22433ef0cf2fddc3e88733e6bb1e1d4693f7aa92
Author: Joel Hutton <Joel.Hutton@Arm.com>
Date: Fri, 26 Oct 2018 17:42:56 +0100
Add hosted language interface
A program to manipulate the trapframe, do RMC calls and inspect the
result.
commands are:
read [register name] [optional base 10 or 16, default 10]
Returns the register, in the base format specified.
set [register name] [value] [optional base >1, base<16, default 10]
Sets the register to value in the base specified. Implicit hex in format
0x... is supported.
dump
Prints out all the register values
trap
Calls trap(&tf)
rmc [rmc command name]
rmc [class] [func]
Populates the esr with RMC error cause, class value and func value then
calls trap.
Change-Id: I45b89ac168bb17f3ed85a52e7025a0b12423ba2f
Signed-off-by: Joel Hutton <Joel.Hutton@Arm.com>
Diffstat:
| A | arch/amd64/hosted.c | | | 324 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | scripts/genhosted.sh | | | 99 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 423 insertions(+), 0 deletions(-)
diff --git a/arch/amd64/hosted.c b/arch/amd64/hosted.c
@@ -0,0 +1,324 @@
+#include <errno.h>
+#include <rcode.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <hosted.h>
+
+void
+print_tf(struct trapframe *tfp)
+{
+ printf("x0=0x%llx\tx1=0x%llx\tx2=0x%llx\tx3=0x%llx\n"
+ "x4=0x%llx\tx5=0x%llx\tx6=0x%llx\tx7=0x%llx\n"
+ "x8=0x%llx\tx9=0x%llx\tx10=0x%llx\tx11=0x%llx\n"
+ "x12=0x%llx\tx13=0x%llx\tx14=0x%llx\tx15=0x%llx\n"
+ "x16=0x%llx\tx17=0x%llx\tx18=0x%llx\tx19=0x%llx\n"
+ "x20=0x%llx\tx21=0x%llx\tx22=0x%llx\tx23=0x%llx\n"
+ "x24=0x%llx\tx25=0x%llx\tx26=0x%llx\tx27=0x%llx\n"
+ "x28=0x%llx\tx29=0x%llx\tx30=0x%llx\telr=%p\n"
+ "spsr=0x%llx\tesr=0x%llx\tfar=0x%llx\n"
+ "sp=0x%p\n",
+ tfp->x0, tfp->x1, tfp->x2, tfp->x3,
+ tfp->x4, tfp->x5, tfp->x6, tfp->x7,
+ tfp->x8, tfp->x9, tfp->x10, tfp->x11,
+ tfp->x12, tfp->x13, tfp->x14, tfp->x15,
+ tfp->x16, tfp->x17, tfp->x18, tfp->x19,
+ tfp->x20, tfp->x21, tfp->x22, tfp->x23,
+ tfp->x24, tfp->x25, tfp->x26, tfp->x27,
+ tfp->x28, tfp->x29, tfp->x30, tfp->elr,
+ tfp->spsr, tfp->esr, tfp->far, tfp->sp);
+}
+
+/* Read a value in a given base between 2 and 16 0 means default base;
+ * 10, unless the string begins with "0x" or "0b"
+ */
+unsigned long long
+base_read(char* str, int base, int *err)
+{
+ unsigned long long val;
+ char *endptr;
+
+ endptr = NULL;
+ errno = 0;
+ val = strtoull(str, &endptr, base);
+ if (str == endptr || errno != 0){
+ ERROR("strtoull error with '%s' in base %d\n", str, base);
+ if(err != NULL)
+ *err = 1;
+ }
+ return val;
+}
+
+/* Get reg struct for named reg */
+unsigned long long*
+get_named_reg(char* name, struct trapframe* tfp)
+{
+ size_t i;
+ char *regptr;
+
+ regptr=NULL;
+ for(i=0;i<NUM_NAMED_REGS;i++){
+ if(strcmp(name,named_regs[i].name)==0){
+ regptr = (char*) tfp;
+ regptr += named_regs[i].offset;
+ }
+ }
+ return (unsigned long long*) regptr;
+}
+
+/* Get rmc_command struct for named rmc command */
+const struct rmc_command*
+get_rmc_cmd(char* name)
+{
+ size_t i;
+
+ for(i=0;i<NUM_RMC_COMMANDS;i++){
+ if(strcmp(name,rmc_commands[i].name)==0){
+ return &rmc_commands[i];
+ }
+ }
+ return NULL;
+}
+
+/* Get command struct for named command */
+const struct command*
+get_command(char* name)
+{
+ size_t i;
+
+ for(i=0;i<NUM_COMMANDS;i++){
+ if(strcmp(name,commands[i].name)==0){
+ return &commands[i];
+ }
+ }
+ return NULL;
+}
+
+int
+do_set(char** argv,int argc, struct trapframe* tfp)
+{
+ unsigned long long *reg=NULL;
+ unsigned long long setval=0;
+ unsigned int base;
+ int err;
+
+ err = 0;
+
+ reg = get_named_reg(argv[1],tfp);
+ if( reg == NULL){
+ ERROR("Register '%s' not found\n",argv[1]);
+ return 1;
+ }
+
+ base = 0;
+
+ switch(argc){
+ case 4:
+ base = base_read(argv[3], 10, &err);
+ if(err)
+ return 1;
+ /* fallthrough */
+ case 3:
+ setval = base_read(argv[2], base, &err);
+ if(err)
+ return 1;
+ break;
+ default:
+ ERROR("Invalid number of parameters for set\n");
+ return 1;
+ }
+ INFO("set:0x%llx\n",setval);
+ *reg=setval;
+ return 0;
+}
+
+int
+do_read(char** argv,int argc, struct trapframe* tfp)
+{
+ unsigned long long* reg=NULL;
+ char* format_string;
+
+ reg = get_named_reg(argv[1],tfp);
+ if(reg == NULL){
+ ERROR("Register '%s' not found\n",argv[1]);
+ return 1;
+ }
+
+ switch(argc){
+ case 3:
+ switch(atoi(argv[2])){
+ case 10:
+ format_string="%llu\n";
+ break;
+ case 16:
+ format_string="%llx\n";
+ break;
+ default:
+ ERROR("Unsupported base for read:%s\nsupported: 10,16\n",
+ argv[2]);
+ return 1;
+ }
+ break;
+ case 2:
+ format_string="%llu\n";
+ break;
+ default:
+ ERROR("Invalid number of arguments for read\n");
+ return 1;
+ }
+ printf(format_string,*reg);
+ return 0;
+}
+
+int
+do_dump(char** argv,int argc, struct trapframe* tfp)
+{
+ print_tf(tfp);
+ return 0;
+}
+
+int
+do_trap(char** argv,int argc, struct trapframe* tfp)
+{
+ trap(tfp);
+ return 0;
+}
+
+int
+do_rmc(char** argv,int argc, struct trapframe* tfp)
+{
+ unsigned char class;
+ unsigned char func;
+ unsigned int base;
+ const struct rmc_command *rmc_cmd;
+ int err;
+
+ err = 0;
+
+ base = 0;
+ switch(argc){
+ case 4:
+ base = base_read(argv[3], 10, &err);
+ if(err)
+ return 1;
+ /* fallthrough */
+ case 3:
+ class = base_read(argv[1], base, &err);
+ func = base_read(argv[2], base, &err);
+ if(err)
+ return 1;
+ break;
+ case 2:
+ rmc_cmd = get_rmc_cmd(argv[1]);
+ if (rmc_cmd == NULL){
+ ERROR("rmc '%s' not found\n",argv[1]);
+ return 1;
+ }
+ class = rmc_cmd->class;
+ func = rmc_cmd->func;
+ break;
+ default:
+ ERROR("Invalid number of parameters for rmc\n");
+ return 1;
+ }
+ INFO("class:%d,func:%d\n",class,func);
+ tfp->esr=(unsigned long long) RMC<<26;
+ tfp->esr |= class;
+ tfp->esr |= (func<<8);
+ trap(tfp);
+ return 0;
+}
+
+/* Separate buffer whitespace */
+void
+tokenise(char* buff, char** argv, unsigned int* argc, char* sep)
+{
+ char* token;
+
+ *argc=0;
+ token=strtok(buff,sep);
+ while(token!=NULL){
+ argv[*argc]=token;
+ (*argc)++;
+ token=strtok(NULL,sep);
+ }
+ return;
+}
+
+char*
+trim(char* buff)
+{
+ int bufflen,i;
+ char* newbuff;
+
+ newbuff = buff;
+ bufflen=strlen(buff);
+
+ /* Trailing whitespace */
+ for(i = bufflen-1; i>0; i--){
+ if(buff[i]==' ' || buff[i]=='\t' || buff[i] == '\n'){
+ buff[i]='\0';;
+ }
+ else{
+ break;
+ }
+ }
+ /* Leading whitespace */
+ for(i = 0; i<bufflen; i++){
+ if(buff[i]==' ' || buff[i]=='\t' || buff[i] == '\n'){
+ newbuff+=1;
+ }
+ else{
+ break;
+ }
+ }
+ return newbuff;
+}
+
+int
+parse_cmd(char * cmd, struct trapframe* tfp)
+{
+ char* argv[MAX_PARTS];
+ unsigned int argc;
+ const struct command* com;
+
+ cmd = trim(cmd);
+
+ /* Get array of strings by separating on whitespace */
+ tokenise(cmd,argv,&argc," ");
+
+ if(argc != 0){
+ com = get_command(argv[0]);
+ }
+
+ if(com == NULL){
+ ERROR("Command '%s' not found\n",argv[0]);
+ return 1;
+ }
+
+ /* Call eval function for specific command */
+ com->eval(argv,argc, tfp);
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char buffer[BUFFER_SIZE];
+ struct trapframe tf;
+ char* end;
+
+ memset(&tf, 0, sizeof(struct trapframe));
+ end=0;
+ do{
+ printf("$ ");
+ fflush(stdout);
+ end = fgets(buffer,BUFFER_SIZE,stdin);
+ if(strlen(buffer)>1){
+ parse_cmd(buffer,&tf);
+ }
+ fflush(stdout);
+ }
+ while(end != NULL);
+ return 0;
+}
diff --git a/scripts/genhosted.sh b/scripts/genhosted.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+echo "
+#define BUFFER_SIZE 256
+#define MAX_PARTS 50
+
+#define DEBUG(...) do{fprintf(stderr,\"DEBUG:\"); fprintf(stderr,__VA_ARGS__);}while(0)
+#define INFO(...) do{fprintf(stderr,\"INFO:\"); fprintf(stderr,__VA_ARGS__);}while(0)
+#define WARN(...) do{fprintf(stderr,\"WARN:\"); fprintf(stderr,__VA_ARGS__);}while(0)
+#define ERROR(...) do{fprintf(stderr,\"ERROR:\"); fprintf(stderr,__VA_ARGS__);}while(0)
+
+extern int do_set( char** parts, int num_parts, struct trapframe* tf);
+extern int do_read( char** parts, int num_parts, struct trapframe* tf);
+extern int do_dump( char** parts, int num_parts, struct trapframe* tf);
+extern int do_trap( char** parts, int num_parts, struct trapframe* tf);
+extern int do_rmc( char** parts, int num_parts, struct trapframe* tf);
+
+enum command_type {SET_CMD,READ_CMD,DUMP_CMD,TRAP_CMD,RMC_CMD};
+
+struct command {
+ char* name;
+ enum command_type command_type;
+ int (*eval)();
+};
+
+const struct command commands[]={
+ {\"set\", SET_CMD, do_set},
+ {\"read\", READ_CMD, do_read},
+ {\"dump\", DUMP_CMD, do_dump},
+ {\"trap\", TRAP_CMD, do_trap},
+ {\"rmc\", RMC_CMD, do_rmc}
+};
+#define NUM_COMMANDS (sizeof(commands)/sizeof(struct command))
+
+struct named_reg {
+ char* name;
+ size_t offset;
+};
+
+const struct named_reg named_regs[]={
+ {\"x0\", offsetof(struct trapframe,x0)},
+ {\"x1\", offsetof(struct trapframe,x1)},
+ {\"x2\", offsetof(struct trapframe,x2)},
+ {\"x3\", offsetof(struct trapframe,x3)},
+ {\"x4\", offsetof(struct trapframe,x4)},
+ {\"x5\", offsetof(struct trapframe,x5)},
+ {\"x6\", offsetof(struct trapframe,x6)},
+ {\"x7\", offsetof(struct trapframe,x7)},
+ {\"x8\", offsetof(struct trapframe,x8)},
+ {\"x9\", offsetof(struct trapframe,x9)},
+ {\"x10\", offsetof(struct trapframe,x10)},
+ {\"x11\", offsetof(struct trapframe,x11)},
+ {\"x12\", offsetof(struct trapframe,x12)},
+ {\"x13\", offsetof(struct trapframe,x13)},
+ {\"x14\", offsetof(struct trapframe,x14)},
+ {\"x15\", offsetof(struct trapframe,x15)},
+ {\"x16\", offsetof(struct trapframe,x16)},
+ {\"x17\", offsetof(struct trapframe,x17)},
+ {\"x18\", offsetof(struct trapframe,x18)},
+ {\"x19\", offsetof(struct trapframe,x19)},
+ {\"x20\", offsetof(struct trapframe,x20)},
+ {\"x21\", offsetof(struct trapframe,x21)},
+ {\"x22\", offsetof(struct trapframe,x22)},
+ {\"x23\", offsetof(struct trapframe,x23)},
+ {\"x24\", offsetof(struct trapframe,x24)},
+ {\"x25\", offsetof(struct trapframe,x25)},
+ {\"x26\", offsetof(struct trapframe,x26)},
+ {\"x27\", offsetof(struct trapframe,x27)},
+ {\"x28\", offsetof(struct trapframe,x28)},
+ {\"x29\", offsetof(struct trapframe,x29)},
+ {\"x30\", offsetof(struct trapframe,x30)},
+ {\"sp\", offsetof(struct trapframe,sp)},
+ {\"far\", offsetof(struct trapframe,far)},
+ {\"esr\", offsetof(struct trapframe,esr)},
+ {\"spsr\", offsetof(struct trapframe,spsr)},
+ {\"elr\", offsetof(struct trapframe,elr)}
+};
+
+#define NUM_NAMED_REGS (sizeof(named_regs)/sizeof(struct named_reg))
+
+struct rmc_command {
+ unsigned char class;
+ unsigned char func;
+ char* name;
+};
+
+#define NUM_RMC_COMMANDS (sizeof(rmc_commands)/sizeof(struct rmc_command))
+
+const struct rmc_command rmc_commands[]={
+"
+
+cat $@ |\
+awk '{print tolower($0)}'|\
+sed -e 's/\./\_/'|\
+sed -e 's/\./\_/'|\
+sed -e 's/\(^[0-9]*\)\t\([0-9]*\)\t\([a-z\_\.]*\).*/\t\{\1,\2,"\3"\},/'|\
+sed -e '$ s/.$//'
+
+echo "};"