////////////////////////////////////////////////////////////////////////////////// // File : stdio.c // Date : 01/04/2010 // Author : alain greiner & Joel Porquet // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// // The stdio.c and stdio.h files are part of the GIET_VM nano-kernel. // This library contains all user-level functions that contain a system call // to access protected or shared ressources. /////////////////////////////////////////////////////////////////////////////////// #include #include #include //////////////////////////////////////////////////////////////////////////////////// ////////////////////// MIPS32 related system calls /////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// ///////////////////// TTY device related system calls ///////////////////////////// //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// void giet_tty_printf( char* format, ...) { va_list args; va_start( args, format ); int ret; // return value from the syscalls unsigned int channel = 0xFFFFFFFF; printf_text: while (*format) { unsigned int i; for (i = 0 ; format[i] && (format[i] != '%') ; i++); if (i) { ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)format, i, channel, 0); if (ret != i) goto return_error; format += i; } if (*format == '%') { format++; goto printf_arguments; } } va_end( args ); return; printf_arguments: { char buf[20]; char * pbuf; unsigned int len = 0; static const char HexaTab[] = "0123456789ABCDEF"; unsigned int i; switch (*format++) { case ('c'): /* char conversion */ { int val = va_arg( args, int ); len = 1; buf[0] = val; pbuf = &buf[0]; break; } case ('d'): /* 32 bits decimal signed integer */ { int val = va_arg( args, int ); if (val < 0) { val = -val; ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)"-", 1, channel, 0); if (ret != 1) goto return_error; } for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('u'): /* 32 bits decimal unsigned integer */ { unsigned int val = va_arg( args, unsigned int ); for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('x'): /* 32 bits hexadecimal integer */ { unsigned int val = va_arg( args, unsigned int ); ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)"0x", 2, channel, 0); if (ret != 2) goto return_error; for(i = 0; i < 8; i++) { buf[7 - i] = HexaTab[val % 16]; if (!(val /= 16)) break; } len = i + 1; pbuf = &buf[7 - i]; break; } case ('l'): /* 64 bits hexadecimal unsigned */ { unsigned long long val = va_arg( args, unsigned long long ); ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)"0x", 2, channel, 0); if (ret != 2) goto return_error; for(i = 0; i < 16; i++) { buf[15 - i] = HexaTab[val % 16]; if (!(val /= 16)) break; } len = i + 1; pbuf = &buf[15 - i]; break; } case ('s'): /* string */ { char* str = va_arg( args, char* ); while (str[len]) { len++; } pbuf = str; break; } default: goto return_error; } ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)pbuf, len, channel, 0); if (ret != len) goto return_error; goto printf_text; } return_error: va_end( args ); giet_exit("error in giet_tty_printf()"); } // end giet_tty_printf() //////////////////////////////////////// void giet_shr_printf( char* format, ...) { va_list args; va_start( args, format ); int ret; // return value from the syscalls unsigned int channel = 0; unsigned int sr_save; sys_call( SYSCALL_TTY_GET_LOCK, channel, (unsigned int)&sr_save, 0, 0 ); printf_text: while (*format) { unsigned int i; for (i = 0 ; format[i] && (format[i] != '%') ; i++); if (i) { ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)format, i, channel, 0); if (ret != i) goto return_error; format += i; } if (*format == '%') { format++; goto printf_arguments; } } sys_call( SYSCALL_TTY_RELEASE_LOCK, channel, (unsigned int)&sr_save, 0, 0 ); va_end( args ); return; printf_arguments: { char buf[20]; char * pbuf; unsigned int len = 0; static const char HexaTab[] = "0123456789ABCDEF"; unsigned int i; switch (*format++) { case ('c'): /* char conversion */ { int val = va_arg( args, int ); len = 1; buf[0] = val; pbuf = &buf[0]; break; } case ('d'): /* 32 bits decimal signed integer */ { int val = va_arg( args, int ); if (val < 0) { val = -val; ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)"-", 1, channel, 0); if (ret != 1) goto return_error; } for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('u'): /* 32 bits decimal unsigned integer */ { unsigned int val = va_arg( args, unsigned int ); for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('x'): /* 32 bits hexadecimal integer */ { unsigned int val = va_arg( args, unsigned int ); ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)"0x", 2, channel, 0); if (ret != 2) goto return_error; for(i = 0; i < 8; i++) { buf[7 - i] = HexaTab[val % 16]; if (!(val /= 16)) break; } len = i + 1; pbuf = &buf[7 - i]; break; } case ('l'): /* 64 bits hexadecimal unsigned */ { unsigned long long val = va_arg( args, unsigned long long ); ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)"0x", 2, channel, 0); if (ret != 2) goto return_error; for(i = 0; i < 16; i++) { buf[15 - i] = HexaTab[val % 16]; if (!(val /= 16)) break; } len = i + 1; pbuf = &buf[15 - i]; break; } case ('s'): /* string */ { char* str = va_arg( args, char* ); while (str[len]) { len++; } pbuf = str; break; } default: goto return_error; } ret = sys_call(SYSCALL_TTY_WRITE, (unsigned int)pbuf, len, channel, 0); if (ret != len) goto return_error; goto printf_text; } return_error: sys_call( SYSCALL_TTY_RELEASE_LOCK, channel, (unsigned int)&sr_save, 0, 0 ); va_end( args ); giet_exit("error in giet_shr_printf()"); } // end giet_shr_printf() ///////////////////////////////// void giet_tty_getc( char * byte ) { int ret; do { ret = sys_call(SYSCALL_TTY_READ, (unsigned int)byte, // buffer address 1, // number of characters 0xFFFFFFFF, // channel index from task context 0); if ( ret < 0 ) giet_exit("error in giet_tty_getc()"); } while (ret != 1); } ///////////////////////////////////// void giet_tty_gets( char* buf, unsigned int bufsize ) { int ret; unsigned char byte; unsigned int index = 0; while (index < (bufsize - 1)) { do { ret = sys_call(SYSCALL_TTY_READ, (unsigned int)(&byte), 1, 0xFFFFFFFF, 0); if ( ret < 0 ) giet_exit("error in giet_tty_gets()"); } while (ret != 1); if (byte == 0x0A) /* LF */ { break; } else if ((byte == 0x7F) && (index > 0)) /* DEL */ { index--; } else { buf[index] = byte; index++; } } buf[index] = 0; } /////////////////////////////////////// void giet_tty_getw( unsigned int* val ) { unsigned char buf[32]; unsigned int string_byte = 0x00000000; // string containing one single byte unsigned int string_cancel = 0x00082008; // string containing BS/SPACE/BS unsigned int save = 0; unsigned int dec = 0; unsigned int done = 0; unsigned int overflow = 0; unsigned int length = 0; unsigned int i; unsigned int channel = 0xFFFFFFFF; int ret; // return value from syscalls // get characters while (done == 0) { // read one character do { ret = sys_call( SYSCALL_TTY_READ, (unsigned int)(&string_byte), 1, channel, 0); if ( ret < 0 ) giet_exit("error in giet_tty_getw()"); } while (ret != 1); // analyse character if ((string_byte > 0x2F) && (string_byte < 0x3A)) /* decimal character */ { buf[length] = (unsigned char)string_byte; length++; // echo ret = sys_call( SYSCALL_TTY_WRITE, (unsigned int)(&string_byte), 1, channel, 0 ); if ( ret < 0 ) giet_exit("error in giet_tty_gets()"); } else if (string_byte == 0x0A) /* LF character */ { done = 1; } else if ( (string_byte == 0x7F) || /* DEL character */ (string_byte == 0x08) ) /* BS character */ { if ( length > 0 ) { length--; // cancel the character ret = sys_call( SYSCALL_TTY_WRITE, (unsigned int)(&string_cancel), 3, channel, 0 ); if ( ret < 0 ) giet_exit("error in giet_tty_gets()"); } } // test buffer overflow if ( length >= 32 ) { overflow = 1; done = 1; } } // end while characters // string to int conversion with overflow detection if ( overflow == 0 ) { for (i = 0; (i < length) && (overflow == 0) ; i++) { dec = dec * 10 + (buf[i] - 0x30); if (dec < save) overflow = 1; save = dec; } } // final evaluation if ( overflow == 0 ) { // return value *val = dec; } else { // cancel all echo characters for (i = 0; i < length ; i++) { ret = sys_call( SYSCALL_TTY_WRITE, (unsigned int)(&string_cancel), 3, channel, 0 ); if ( ret < 0 ) giet_exit("error in giet_tty_gets()"); } // echo character '0' string_byte = 0x30; ret = sys_call( SYSCALL_TTY_WRITE, (unsigned int)(&string_byte), 1, channel, 0 ); if ( ret < 0 ) giet_exit(); // return 0 value *val = 0; } } ////////////////////////////////////////////////////////////////////////////////// ///////////////////// TIMER related system calls //////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// /////////////////////// void giet_timer_start() { if ( sys_call( SYSCALL_TIMER_START, 0, 0, 0, 0 ) ) giet_exit("error in giet_timer_start()"); } ////////////////////// void giet_timer_stop() { if ( sys_call( SYSCALL_TIMER_STOP, 0, 0, 0, 0 ) ) giet_exit("error in giet_timer_stop()"); } ////////////////////////////////////////////////////////////////////////////////// /////////////// Frame buffer device related system calls /////////////////////// ////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////// void giet_fb_sync_write( unsigned int offset, void * buffer, unsigned int length ) { if ( sys_call( SYSCALL_FB_SYNC_WRITE, offset, (unsigned int)buffer, length, 0 ) ) giet_exit("error in giet_fb_sync_write()"); } /////////////////////////////////////////// void giet_fb_sync_read( unsigned int offset, void * buffer, unsigned int length ) { if ( sys_call( SYSCALL_FB_SYNC_READ, offset, (unsigned int)buffer, length, 0 ) ) giet_exit("error in giet_fb_sync_read()"); } ///////////////////////////////////////// void giet_fb_cma_init( void * buf0, void * buf1, unsigned int length ) { if ( sys_call( SYSCALL_FB_CMA_INIT, (unsigned int)buf0, (unsigned int)buf1, length, 0 ) ) giet_exit("error in giet_fb_cma_init()"); } /////////////////////////////////////////////// void giet_fb_cma_write( unsigned int buffer_id ) { if ( sys_call( SYSCALL_FB_CMA_WRITE, buffer_id, 0, 0, 0 ) ) giet_exit("error in giet_fb_cma_write()"); } //////////////////////// void giet_fb_cma_stop() { if ( sys_call( SYSCALL_FB_CMA_STOP, 0, 0, 0, 0 ) ) giet_exit("error in giet_fb_cma_stop()"); } ////////////////////////////////////////////////////////////////////////////////// /////////////////////// NIC related system calls ///////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// ///////////////////////// void giet_nic_cma_start() { if ( sys_call( SYSCALL_NIC_CMA_START, 0, 0, 0, 0 ) ) giet_exit("error in giet_nic_cma_start()"); } ///////////////////////// void giet_nic_cma_stop() { if ( sys_call( SYSCALL_NIC_CMA_STOP, 0, 0, 0, 0 ) ) giet_exit("error in giet_nic_cma_stop()"); } /////////////////////////////////////////////////////////////////////////////////// ///////////////////// FAT related system calls //////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////// int giet_fat_open( const char* pathname, unsigned int flags ) { return sys_call( SYSCALL_FAT_OPEN, (unsigned int)pathname, flags, 0, 0 ); } //////////////////////////////////// void giet_fat_read( unsigned int fd, void* buffer, unsigned int count, unsigned int offset ) { if ( sys_call( SYSCALL_FAT_READ, fd, (unsigned int)buffer, count, offset ) != count ) giet_exit("in giet_fat_read()"); } ///////////////////////////////////// void giet_fat_write( unsigned int fd, void* buffer, unsigned int count, unsigned int offset ) { if ( sys_call( SYSCALL_FAT_WRITE, fd, (unsigned int)buffer, count, offset ) != count ) giet_exit("in giet_fat_write()"); } /* variant implementing the UNIX spec /////////////////////////////////////////////////////////////////////////////////// // This system call writes to a file identified by the "fd" file descriptor. // - "buffer" is the source buffer virtual address (must be word aligned). // - "count" is a number of bytes (must be multiple of 4). // It uses the implicit "lseek" pointer in file descriptor. /////////////////////////////////////////////////////////////////////////////////// void giet_fat_write( unsigned int fd, void* buffer, unsigned int count ) // number of bytes { return sys_call( SYSCALL_FAT_WRITE, fd, (unsigned int)buffer, count, 0 ); } */ ///////////////////////////////////// void giet_fat_lseek( unsigned int fd, unsigned int offset, unsigned int whence ) { if ( sys_call( SYSCALL_FAT_LSEEK, fd, offset, whence, 0 ) ) giet_exit("in giet_fat_lseek()"); } ////////////////////////////////////// void giet_fat_fstat( unsigned int fd ) { if ( sys_call( SYSCALL_FAT_FSTAT, fd, 0, 0, 0 ) ) giet_exit("in giet_fat_lseek()"); } ///////////////////////////////////// void giet_fat_close( unsigned int fd ) { if ( sys_call( SYSCALL_FAT_CLOSE, fd, 0, 0, 0 ) ) giet_exit("in giet_fat_close()"); } ////////////////////////////////////////////////////////////////////////////////// ///////////////////// Miscellaneous system calls ///////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// ///////////////// int giet_procid() { return sys_call( SYSCALL_PROCID, 0, 0, 0, 0 ); } //////////////////// int giet_proctime() { return sys_call( SYSCALL_PROCTIME, 0, 0, 0, 0 ); } /////////////////////// int giet_proc_task_id() { return sys_call( SYSCALL_LOCAL_TASK_ID, 0, 0, 0, 0 ); } ///////////////////////// int giet_global_task_id() { return sys_call( SYSCALL_GLOBAL_TASK_ID, 0, 0, 0, 0 ); } //////////////////// int giet_thread_id() { return sys_call( SYSCALL_THREAD_ID, 0, 0, 0, 0 ); } /////////////// int giet_rand() { unsigned int x = sys_call(SYSCALL_PROCTIME, 0, 0, 0, 0); if ((x & 0xF) > 7) { return (x*x & 0xFFFF); } else { return (x*x*x & 0xFFFF); } } ////////////////////////////// void giet_exit( char* string ) { sys_call( SYSCALL_EXIT, (unsigned int)string, 0, 0, 0 ); } ///////////////////////////////////////// void giet_assert( unsigned int condition, char* string ) { if ( condition == 0 ) giet_exit( string ); } //////////////////////////////////////////////////// void giet_vobj_get_vbase( char* vspace_name, char* vobj_name, unsigned int* vobj_vaddr ) { if ( sys_call( SYSCALL_VOBJ_GET_VBASE, (unsigned int) vspace_name, (unsigned int) vobj_name, (unsigned int) vobj_vaddr, 0 ) ) giet_exit("in giet_vobj_get_vbase()"); } /////////////////////////////////////////////// void giet_proc_number( unsigned int cluster_id, unsigned int* buffer ) { if ( sys_call( SYSCALL_PROC_NUMBER, cluster_id, (unsigned int) buffer, 0, 0) ) giet_exit("in giet_proc_number()"); } ////////////////////////// void giet_context_switch() { sys_call( SYSCALL_CTX_SWITCH, 0, 0, 0, 0 ); } ///////////////////////////////////////// void giet_heap_info( unsigned int* vaddr, unsigned int* length ) { if ( sys_call( SYSCALL_HEAP_INFO, (unsigned int)vaddr, (unsigned int)length, 0, 0 ) ) giet_exit("in giet_heap_info()"); } // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4