對ARM的認知大致上都是從課堂跟GCC的md檔來的
但是對於這些OS底層實作相關的知識還真是薄弱
說正確一點是弱到不行
SimpleScalar 的 system call實作上大致上是在
target-arm/syscall.c裡面
有時候遇到
warning: invalid/unimplemented syscall xxx, PC=0x0001c454, winging it
的時候可以直接略過沒關係,但是...事情總不會那麼順利
而且SimpleScalar早就沒在更新了,也大概不用期待下一版會解決這種事發生
以rename來當例子好了,忘記是哪個benchmark需要用到,少了就不能正常運作
rename 的 system call 編號是 38
所以其實要補system call的第一步是先查出缺什麼,並且它是不是必要的,
(必要的定義在於沒補齊就會跑不出數據...
接著把編號拿去syscall.c裡面查查看是啥
以38為例
#define ARM_SYS_rename 38
由此可知編號38是rename,接著丟到Google大神去查一下各參數的功能是啥
int rename ( const char * oldname, const char * newname );
rename就如他名字一般,就是拿來改檔案的
所以我們其實只要把參數在丟到對應的system call就好
第一個參數會放在R0
第二個則在R1
所以直覺上我們這樣寫
regs->regs_R[MD_REG_R0] =
rename(regs->regs_R[MD_REG_R0], regs->regs_R[MD_REG_R1]);
不過會發現一件事,regs->regs_R[MD_REG_R0]所存的指標不是host所用的address
直接傳進去可能會segment fault,或是發生其他不可預期的事
參考一下其他system call的實作可以發現有一個函數可以用
char buf[MAXBUFSIZE];
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R0], buf);
從simulator 所用的記憶體中搬出東西來,第二個參數也照做就行了
接著補上頭跟尾
case ARM_SYS_rename:
{
char buf[MAXBUFSIZE];
char buf2[MAXBUFSIZE];
/* copy filename to host memory */
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R0], buf);
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R1], buf2);
/* chmod the file */
/*result*/
regs->regs_R[MD_REG_R0] =
rename(buf, buf2);
break;
}
然後補上錯誤處理部份
case ARM_SYS_rename:
{
char buf[MAXBUFSIZE];
char buf2[MAXBUFSIZE];
/* copy filename to host memory */
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R0], buf);
mem_strcpy(mem_fn, mem, Read, /*fname*/regs->regs_R[MD_REG_R1], buf2);
/* chmod the file */
/*result*/
regs->regs_R[MD_REG_R0] =
rename(buf, buf2);
/* check for an error condition */
if (regs->regs_R[MD_REG_R0] == (qword_t)-1)
/* got an error, return details */
regs->regs_R[MD_REG_R0] = -errno;
break;
}
會用qword_t則是有一些歷史原因,simplescalar最原本是porting到alpha上用的,大概是因此沿用下來的慣例
俗話說的好要入境隨俗,所以留著吧
然後再把這段code插入sys_syscall的那個超大switch中的某個適合的地方就可以了
後記:
其實最讓我驚訝的還是在
system call的時候
第五個參數竟然就直接放在r4,這跟原本認知第五個參數以後要丟stack不一樣
至於第六個或更多參數呢...目前還沒看到,遇到再補完這邊文章