模拟uClinux系统调用

这篇文章原来放在CU上的,现在挪过来了。CU上设置不可见了。

1.  目标

          这里主要是实验一下uclinux的系统调用。

2.   环境

         OS                :vmware + redhat 9

         编译器          :arm-elf-gcc 2.95

         ARM7模拟器:skyeye

3.   源文件

      1个汇编(init.s),3个C文件(main.c, print.c, syscall.c),1个C头文件(unistd.h),1个Makefile,1个链接文件(syscall.lds),1个skyeye的配置文件(skyeye.conf),共8个文件

init.s

.equ INTCON,   0x01e00000
.equ INTMSK,   0x01e0000c
.equ LOCKTIME, 0x01d8000c
.equ PLLCON,   0x01d80000
.equ CLKCON,   0x01d80004
.equ WTCON,    0x01d30000
.equ I_ISPR,   0x01e00020
.equ I_ISPC,   0x01e00024
.equ TCFG0,    0x01d50000
.equ TCFG1,    0x01d50004
.equ TCON,     0x01d50008
.equ TCNTB5,   0X01d50048
.equ UTXH0,    0x01d00020
.equ UFCON0,   0x01d00008
.equ ULCON0,   0x01d00000
.equ UCON0,    0x01d00004
.equ UBRDIV0,  0x01d00028


.globl _start
_start:
    b reset
    b .
    b HandlerSWI
    b .
    b .
    b .
    b .
    b .


reset:
    mov r0,#0x80 | 0x40 | 0x13  @ svc, disable irq,fiq
    msr cpsr_c,r0

    ldr sp, =0x0c700000

    ldr r0,=WTCON        @ disable watch dog
    ldr r1, =0x0
    str r1, [r0]

    ldr r0, =INTCON      @ non-vector mode, disable irq, disable fiq
    ldr r1, =0x7
    str r1, [r0]

    ldr r0, =LOCKTIME
    ldrb r1, =800
    strb r1, [r0]

    ldr r0, =PLLCON
    ldr r1, =0x34031
    str r1,[r0]
    
    ldr r0, =CLKCON
    ldr r1, =0x7ff8
    str r1, [r0]

    @ UART 0
    ldr r0,=UFCON0
    mov r1,#0x0
    str r1,[r0]

    ldr r0,=ULCON0
    mov r1,#0x03
    str r1,[r0]
    
    ldr r0,=UCON0
    mov r1,#0x05
    str r1,[r0]

    ldr r0,=UBRDIV0
    mov r1,#32
    str r1,[r0]

    ldr r0,=UTXH0        @ print 'C'
    mov r1,#'S'
    str r1,[r0]
    
    @ sp_svc
    ldr sp,=0x0c700000
    
    ldr r0, =INTMSK
    ldr r1, =0x03ffffff  @ disable all irq.
    str r1, [r0]
    
    @ move to user mode

    mov r0, #0x80 | 0x40 | 0x10  @ svc, disable irq,fiq
    msr cpsr_c,r0

    ldr sp, =0x0c600000    


    mov r0,#'\n'
    ldr r1,=UTXH0       @ print 'A'
    str r0,[r1]

    b Main      


HandlerSWI:       
    stmfd sp!,{r0-r12,lr}
 
    stmfd sp!,{r0-r2}       @ in this example, we use only three paramters at most

    ldr r0,[lr,#-4]         @ lr is "swi #x" address, get swi instruction code
    bic r0,r0,#0xff000000   @ get #x

    ldmfd sp!, {r1-r3}
    
    bl swi_c_handler                  @ c function use r0,r1 as parameter, and return result with r0

@    ldr r1,=UTXH0           @ print 'B'
@    str r0,[r1]

    str r0,[sp]             @ change r0 to true result

    ldmfd sp!, {r0-r12,pc}^               @ ^,不能在用户模式使用 作用: 1.如果寄存器列表有pc, 还要把spsr复制到cpsr, 2.如果没有pc, 那么这些寄存器指的是用户寄存器,而不是当前模式的寄存器

 

main.c

#include "unistd.h"

static inline __syscall0(void,hello);
static inline __syscall2(int,add,int,a,int,b);
static inline __syscall2(int,sub,int,a,int,b);
static inline __syscall2(int,sum,int *,p,int,count);
static inline __syscall3(int,sub3,int,a,int,b,int,c);

int swi_c_handler(int sys_call_num,int param1,int param2,int param3){
    int result=0;

    switch(sys_call_num){

        case __NR_hello:
            sys_hello();
            break;
        
        case __NR_add:
            result = sys_add(param1,param2);
            break;

        case __NR_sub:
            result = sys_sub(param1,param2);
            break;

        case __NR_sub3:
            result = sys_sub3(param1,param2,param3);
            break;
        
        case __NR_sum:
            result = sys_sum((int *)param1,param2);
            break;
        
        default:
            print("no such call number: %d\n",sys_call_num);
            result = -1;
    }

    return result;
}



void Main(){
    char *s="hello,world";
    int num[5]={4,7,10,3,8};  //32

    print("%s\n",s);
    
    hello();
    print("5+8=%d\n",add(5,8));
    print("28-13=%d\n",sub(28,13));
    print("39-13-2=%d\n",sub3(39,13,2));
    print("4+7+10+3+8=%d\n",sum(num,5));
    
    while(1);
}

 

print.c

#include

void print_char(char c){
    __asm__ __volatile__ (
    "mov r0,%0 \n\t"
    "ldr r1,=0x01d00020 \n\t"
    "str r0,[r1] \n\t"
    :
    :"r"((long)(c))
    :"r0","r1");
}

int itoa(char * buf,int num){
    int i=0,a=num,b;

    while(1){
        b = a % 10;
        a = a / 10;
        buf[i++]=b+'0';
        if(a==0) break;
    }

    return i;
}

void print(char * fmt, ...){
    char out_buf[128],itoa_buf[10],*s;
    int n,i,index=0,itoa_len;

    va_list args;
    va_start(args,fmt);

    for(;*fmt;++fmt){
        if(*fmt!='%'){
            out_buf[index++]=*fmt;
            continue;
        }
        fmt++;
        switch(*fmt){
            case 'd':
                n = (int)va_arg(args,int);
                itoa_len = itoa(itoa_buf,n);
                for(i=itoa_len-1;i>=0;i--){
                    out_buf[index++]=itoa_buf[i];
                }
                break;
            case 's':
                s = (char *)va_arg(args,char *);
                for(;*s;s++){
                    out_buf[index++]=*s;
                }
                break;
            default:
                out_buf[index++]=' ';
        }
    }

    out_buf[index]=0; // NULL

    for(s=out_buf;*s;s++){
        print_char(*s);
    }

    va_end(args);
}

 

syscall.c

void sys_hello(){
    print("hello, S3C44B0X!\n");
}


int sys_add(int a,int b){
    return a+b;
}


int sys_sub(int a,int b){
    return a-b;
}


int sys_sub3(int a,int b,int c){
    return a-b-c;
}

int sys_sum(int * pnum, int count){
    int sum=0,i;
    for(i=0;i         sum+=pnum[i];
    }
    return sum;
}

 

unistd.h

#ifndef __UNISTD_H_
#define __UNISTD_H_

#define __NR_SYSCALL_BASE 0X900000

#define __NR_hello  (__NR_SYSCALL_BASE + 1)
#define __NR_add    (__NR_SYSCALL_BASE + 2)
#define __NR_sub    (__NR_SYSCALL_BASE + 3)
#define __NR_sub3   (__NR_SYSCALL_BASE + 4)
#define __NR_sum    (__NR_SYSCALL_BASE + 5)

#define __sys1(x) #x
#define __sys2(x) __sys1(x)

#define __syscall(name) "swi " __sys2(__NR_##name) "\n\t"

#define __syscall0(type,name) \
type name(){  \
    long __res; \
    __asm__ __volatile__ ( \
    __syscall(name)        \
    "mov %0, r0 \n\t"      \
    :"=r"(__res)           \
    :                      \
    :"r0","lr");           \
    return (type)(__res);  \
}


#define __syscall1(type,name,type1,arg1){ \
type name(type1 arg1){   \
    long __res;      \
    __asm__ __volatile ( \
    "mov r0,%1 \n\t"   \
    __syscall(name)    \
    "mov %0,r0 \n\t"   \
    :"=r"((long)__res)       \
    :"r"((long)(arg1))        \
    :"r0","lr");       \
}


#define __syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2){ \
    long __res;      \
    __asm__ __volatile ( \
    "mov r0,%1 \n\t"   \
    "mov r1,%2 \n\t"   \
    __syscall(name)    \
    "mov %0,r0 \n\t"   \
    :"=r"((long)__res)       \
    :"r"((long)(arg1)),"r"((long)(arg2))        \
    :"r0","r1","lr");       \
}

#define __syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3){ \
    long __res;      \
    __asm__ __volatile ( \
    "mov r0,%1 \n\t"   \
    "mov r1,%2 \n\t"   \
    "mov r2,%3 \n\t"   \
    __syscall(name)    \
    "mov %0,r0 \n\t"   \
    :"=r"((long)__res)       \
    :"r"((long)(arg1)),"r"((long)(arg2)),"r"((long)(arg3))       \
    :"r0","r1","r2","lr");       \
}


#endif

 

 

syscall.lds

OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
    . = 0x00000000;

    .text :
    {
        init.o    (.text)
    main.o    (.text)
    print.o   (.text)
    syscall.o (.text)
    }
    
    . = ALIGN(32);

    .data :
    {
       *(.data)
    }

    . = ALIGN(32);

    .bss :
    {
    *(.bss)
    *(.rodata)
    }

}

 

Makefile

all: syscall

syscall: init.o main.o print.o syscall.o
    arm-elf-ld -T syscall.lds -o syscall init.o main.o print.o syscall.o
    arm-elf-objcopy -O binary syscall syscall.bin

init.o: init.s
    arm-elf-as --gstabs -o init.o init.s

main.o: main.c unistd.h
    arm-elf-gcc -gstabs -c main.c

print.o: print.c
    arm-elf-gcc -gstabs -c print.c

syscall.o: syscall.c
    arm-elf-gcc -gstabs -c syscall.c

.PHONY: clean
clean:
    rm -f *.o syscall syscall.bin

 

skyeye.conf

#skyeye config file for S3C44B0X
cpu: arm7tdmi
mach: s3c44b0x

# physical memory
mem_bank: map=M, type=RW, addr=0x00000000, size=0x00200000, file=syscall.bin
mem_bank: map=M, type=RW, addr=0x0c000000, size=0x00800000

# peripherals I/O mapping area
mem_bank: map=I, type=RW, addr=0x01c00000, size=0x00400000

# uart 0
uart: mod=stdio

4. 运行

        # skyeye -e syscall

 

posted @ 2018-01-04 22:12  北极熊129  阅读(342)  评论(0)    收藏  举报