From 51d4dd040a291b62c648ff6cc0d7e0058cf4056f Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 17 Aug 2018 17:51:51 +0200 Subject: starting implicit function calls cleanup --- Makefile | 37 +++---- Makefile.common | 5 +- asm/syscallasm.s | 22 +++++ fs/fs.c | 1 - kernel/config.h | 6 +- kernel/interrupts.c | 4 +- kernel/mem.c | 6 +- kernel/syscalls.c | 11 ++- kernel/syscalls.h | 7 -- kernel/timer.c | 204 +++++++++++++++++++++++++++++++++----- kernel/usermode.c | 9 +- lib/logger/log.c | 6 +- syscalls.c | 232 ++++++++++++++++++++++++++++++++++++++++++++ userspace/Makefile | 47 ++++----- userspace/crt0.S | 7 -- userspace/sys/Makefile | 28 ------ userspace/sys/crt0.S | 23 ----- userspace/sys/sgtty.h | 19 ---- userspace/sys/sys.c | 188 ----------------------------------- userspace/sys/sys/ioctl.h | 0 userspace/sys/sys/termios.h | 27 ------ userspace/sys/syscalls.c | 158 ------------------------------ xxx/sys/Makefile | 28 ++++++ xxx/sys/crt0.S | 23 +++++ xxx/sys/sgtty.h | 19 ++++ xxx/sys/sys.c | 188 +++++++++++++++++++++++++++++++++++ xxx/sys/sys/ioctl.h | 0 xxx/sys/sys/termios.h | 27 ++++++ xxx/sys/syscalls.c | 158 ++++++++++++++++++++++++++++++ 29 files changed, 940 insertions(+), 550 deletions(-) create mode 100644 asm/syscallasm.s create mode 100644 syscalls.c delete mode 100644 userspace/sys/Makefile delete mode 100644 userspace/sys/crt0.S delete mode 100644 userspace/sys/sgtty.h delete mode 100644 userspace/sys/sys.c delete mode 100644 userspace/sys/sys/ioctl.h delete mode 100644 userspace/sys/sys/termios.h delete mode 100644 userspace/sys/syscalls.c create mode 100644 xxx/sys/Makefile create mode 100644 xxx/sys/crt0.S create mode 100644 xxx/sys/sgtty.h create mode 100644 xxx/sys/sys.c create mode 100644 xxx/sys/sys/ioctl.h create mode 100644 xxx/sys/sys/termios.h create mode 100644 xxx/sys/syscalls.c diff --git a/Makefile b/Makefile index a3980d5..52f9acb 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,7 @@ - ##################### - # # - # FoolOS Build Sys. # - # # - ##################### + #################### + # FoolOS Build Sys # + #################### .PHONY: all new run newrun stick clean tags mount umount @@ -18,32 +16,29 @@ CC=i686-elf-gcc AS=i686-elf-as ############ compiler flags ############ + CFLAGS= -## CFLAGS+=-fstack-protector-all -CFLAGS+=-Wno-implicit-function-declaration -## CFLAGS+=-w -CFLAGS+=-ffreestanding -#CFLATS+=-Wall -#CFLAGS+=-Wextra -#CFLAGS+=-O3 +CFLAGS+=-ffreestanding # do we need this if using own compiler? +CFLAGS+=-nostdlib CFLAGS+=-O0 -#CFLAGS+=-nostdlib -CFLAGS+=-std=gnu11 CFLAGS+=-I. -#CFLAGS+=-I/home/miguel/temp/fool-os-stuff/newlib-2.1.0/newlib/libc/include CFLAGS+=-I/home/miguel/foolos/usr/i686-foolos//include/ CFLAGS+=-gstabs -#CFLAGS+=-lgcc + +#CFLAGS+=-fstack-protector-all #CFLAGS+=-fno-zero-initialized-in-bss -#CFLAGS+= -O4 #CFLAGS+=-fdata-sections -ffunction-sections + +#CFLAGS+= -w # disable all warnings +#CFLAGS+= -Wimplicit-function-declaration +#CFLAGS+= -Wextra +#CFLAGS+= -Wall #CFLAGS+= -Werror -CFLAGS+= -w +CFLAGS+= -Werror=implicit-function-declaration ######## linker flags #################### LDFLAGS= -LDFLAGS+=-nostdlib -LDFLAGS+=-lgcc +LDLIBS+=-lgcc ########## assembler flags ################# ASFLAGS= @@ -121,7 +116,7 @@ $(CLEANDIRS): ############ linking kernel binary ############ $(KERNEL_IMG): $(ASM_MULTIBOOT_OBJ) $(ASM_OBJECTS) $(OBJECTS) - $(CC) $(CFLAGS) $(LDFLAGS) -T linker.ld -o $@ $^ + $(CC) $(CFLAGS) $(LDFLAGS) -T linker.ld -o $@ $^ $(LDLIBS) ############ assembling of final image ############ diff --git a/Makefile.common b/Makefile.common index 32bb965..9f9f5cd 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1,4 +1,5 @@ -### implicit rules ### +### explicit rules ### + %.o: %.asm nasm -f elf $*.asm -o $@ @@ -11,5 +12,3 @@ %.o: %.c $(CC) -c $(CFLAGS) $*.c -o $*.o $(CC) -MM -MT $*.o $(CFLAGS) $*.c > $*.d - - diff --git a/asm/syscallasm.s b/asm/syscallasm.s new file mode 100644 index 0000000..8860d89 --- /dev/null +++ b/asm/syscallasm.s @@ -0,0 +1,22 @@ +.global syscall + +// call from c with 4 x 32bit params +// syscall number, p1,p2,p3,p4 + +// TODO: push stack frame? + +syscall: + + push %ebx // preserve (sysV abi convnetion) + + mov 0x8(%esp),%eax //syscall number + mov 0xC(%esp),%edx //p1 + mov 0x10(%esp),%ecx //p2 + mov 0x14(%esp),%ebx //p3 + + int $0x80 + mov %ebx, %eax // set as return value + + pop %ebx // preserve + ret + diff --git a/fs/fs.c b/fs/fs.c index bc43e22..0810735 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -5,7 +5,6 @@ #include "lib/logger/log.h" - static uint32_t root_ext2_ramimage=0; // diff --git a/kernel/config.h b/kernel/config.h index 4923a0e..6c9e3d5 100644 --- a/kernel/config.h +++ b/kernel/config.h @@ -1,11 +1,9 @@ /******************************************** - * * - * Fool OS Central Configuration File * - * * + * Fool OS Central Configuration File * ********************************************/ -#include +#include "lib/logger/log.h" #ifndef FOOLOS_CONFIG_H #define FOOLOS_CONFIG_H diff --git a/kernel/interrupts.c b/kernel/interrupts.c index f0b9bbd..e19d816 100644 --- a/kernel/interrupts.c +++ b/kernel/interrupts.c @@ -108,7 +108,7 @@ void exception_handle_18(){ panic(FOOLOS_MODULE_NAME,"Machine Check"); } void int_install_ir(int irq, uint16_t flags, uint16_t sel, void *addr) { - uint64_t base=(uint64_t)&(*addr); + uint64_t base=(uint32_t)&(*(uint32_t*)addr); idt[irq].addrLo = base & 0xffff; idt[irq].addrHi = (base >> 16) & 0xffff; @@ -184,7 +184,7 @@ void int_install() idtd.size=sizeof(struct int_desc)*INT_MAX; - uint32_t addr=&idt[0]; + uint32_t addr=(uint32_t)&idt[0]; idtd.baseHi=addr>>16; idtd.baseLo=0xffff&addr; diff --git a/kernel/mem.c b/kernel/mem.c index dfd59a7..74b3a98 100644 --- a/kernel/mem.c +++ b/kernel/mem.c @@ -129,7 +129,7 @@ void* pmmngr_alloc_block () void pmmngr_free_block (void* p) { - uint32_t addr = (uint32_t*)p; + uint32_t addr = (uint32_t)(uint32_t*)p; int frame = addr / PMMNGR_BLOCK_SIZE; if(mmap_test(frame)) @@ -171,7 +171,7 @@ uint32_t mem_init(multiboot_information *info) // iterate : print memory map, calc blocks, deinit for(uint32_t mmap_addr=memmap;mmap_addrbase_addr; uint64_t mem_end=mmap->base_addr+mmap->length; @@ -200,7 +200,7 @@ uint32_t mem_init(multiboot_information *info) // deinit modules memory if(info->flags&&1<<3) { - multiboot_mod *mod=info->mods_addr; + multiboot_mod *mod=(multiboot_mod *)info->mods_addr; for(int i=0;imods_count;i++) { log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"mod 0x%08X-0x%08X : %s", diff --git a/kernel/syscalls.c b/kernel/syscalls.c index e3db767..c507a4e 100644 --- a/kernel/syscalls.c +++ b/kernel/syscalls.c @@ -10,6 +10,9 @@ #include #include +// TODO: use includes!!! +uint64_t timer_get_ms(); + int syscall_unhandled(int nr) { log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"syscall: %d", nr); @@ -20,13 +23,15 @@ int syscall_gettimeofday(struct timeval *tv, struct timezone *tz) { if(tv!=NULL) { - uint32_t t=timer_get_ms(); - tv->tv_sec=t/1000; + uint64_t t=timer_get_ms(); + tv->tv_sec=t/1000+2*3600; // add gmt+2 tv->tv_usec=0;//t-tv->tv_sec*1000; } + + // tz struct is obsolote if(tz!=NULL) { - tz->tz_minuteswest=0; + tz->tz_minuteswest=0;// -21*60; // warsaw tz->tz_dsttime=DST_NONE; } return 0; diff --git a/kernel/syscalls.h b/kernel/syscalls.h index ff7760e..9a08cba 100644 --- a/kernel/syscalls.h +++ b/kernel/syscalls.h @@ -60,10 +60,3 @@ int syscall_wait(int *status); // int syscall_unhandled(int nr); */ - - - - - - - diff --git a/kernel/timer.c b/kernel/timer.c index 9ca748c..a339d70 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1,7 +1,8 @@ -/// PIT /// Timer stuff +/// PIT /// Timer stuff // CMOS /* http://www.brokenthorn.com/Resources/OSDevPit.html + https://wiki.osdev.org/CMOS vcc/gnd - voltage/ground @@ -26,20 +27,195 @@ mode1: mode2: rate generator (sys timer) .... - - */ #define FOOLOS_MODULE_NAME "timer" #include "timer.h" +#include "x86.h" +#include "lib/logger/log.h" -#include "lib/logger/log.h" // logger facilities - +// TODO: use mutex? do we need volatile at all!?? +// abstract atomic variable set,get,increment static volatile uint64_t task_system_clock=0; +//called by interrupt +void timer_tick() +{ + task_system_clock++; +} + +// get value +uint64_t timer_get_ticks() +{ + return task_system_clock; +} +/// + +uint64_t timer_get_ms() +{ + uint64_t t=timer_get_ticks(); + uint64_t s=t/25; + uint64_t ms=0; // TODO ms + return s*1000; +} + +// CMOS RTC + + +// read real time clock register +unsigned char get_rtc_reg(int reg) { + x86_outb(0x70, reg); //cmos at addr 0x70 + return x86_inb(0x71); //cmos data at addr 0x71 +} + +// check if cmos rtc update in progress +int get_rtc_update_flag() { + x86_outb(0x70, 0x0A); + return (x86_inb(0x71) & 0x80); +} + +// get real time clock rom cmos (seconds since jan) +uint64_t get_rtc_time() +{ + + int CURRENT_YEAR = 2018; // Change this each year! + + int century_register = 0x00; // Set by ACPI table parsing code if possible + + unsigned char second; + unsigned char minute; + unsigned char hour; + unsigned char day; + unsigned char month; + unsigned int year; + + unsigned char century; + unsigned char last_second; + unsigned char last_minute; + unsigned char last_hour; + unsigned char last_day; + unsigned char last_month; + unsigned char last_year; + unsigned char last_century; + unsigned char registerB; + + // Note: This uses the "read registers until you get the same values twice in a row" technique + // to avoid getting dodgy/inconsistent values due to RTC updates + + while (get_rtc_update_flag()); // Make sure an update isn't in progress + second = get_rtc_reg(0x00); + minute = get_rtc_reg(0x02); + hour = get_rtc_reg(0x04); + day = get_rtc_reg(0x07); + month = get_rtc_reg(0x08); + year = get_rtc_reg(0x09); + + if(century_register != 0) { + century = get_rtc_reg(century_register); + } + + do { + last_second = second; + last_minute = minute; + last_hour = hour; + last_day = day; + last_month = month; + last_year = year; + last_century = century; + + while (get_rtc_update_flag()); // Make sure an update isn't in progress + second = get_rtc_reg(0x00); + minute = get_rtc_reg(0x02); + hour = get_rtc_reg(0x04); + day = get_rtc_reg(0x07); + month = get_rtc_reg(0x08); + year = get_rtc_reg(0x09); + if(century_register != 0) { + century = get_rtc_reg(century_register); + } + } while( (last_second != second) || (last_minute != minute) || (last_hour != hour) || + (last_day != day) || (last_month != month) || (last_year != year) || + (last_century != century) ); + + registerB = get_rtc_reg(0x0B); + + // Convert BCD to binary values if necessary + if (!(registerB & 0x04)) { + second = (second & 0x0F) + ((second / 16) * 10); + minute = (minute & 0x0F) + ((minute / 16) * 10); + hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80); + day = (day & 0x0F) + ((day / 16) * 10); + month = (month & 0x0F) + ((month / 16) * 10); + year = (year & 0x0F) + ((year / 16) * 10); + if(century_register != 0) { + century = (century & 0x0F) + ((century / 16) * 10); + } + } + + // Convert 12 hour clock to 24 hour clock if necessary + if (!(registerB & 0x02) && (hour & 0x80)) { + hour = ((hour & 0x7F) + 12) % 24; + } + + // Calculate the full (4-digit) year + if(century_register != 0) { + year += century * 100; + } else { + year += (CURRENT_YEAR / 100) * 100; + if(year < CURRENT_YEAR) year += 100; + } + + // return ((((uint64_t)year-1970)*356;//+month*30+day)*24+hour*60+minute)*60+second; + + // thank you doug16k @ #osdev + // https://github.com/doug65536/dgos/blob/eab7080e69360493381669e7ce0ff27587d3127a/kernel/lib/time.cc + int days[] = { + 31, + (year-1900) % 4 ? 28 : + (year-1900) % 100 ? 29 : + (year-1900) % 400 ? 28 : + 29, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31 + }; + + int yday = 0; + for (int m = 1; m < month; ++m) + yday += days[m-1]; + yday += day - 1; + + uint64_t epoch_seconds= ((uint64_t)(second)) + + minute * 60 + + hour * 3600 + + (yday) * 86400 + + (year-1900 - 70) * 365 * 86400 + + ((year-1900 - 69) / 4) * 86400 - + ((year-1900 - 1) / 100) * 86400 + + ((year-1900 + 299) / 400) * 86400; + + log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"CMOS Hardware Clock: %u-%u-%u %u:%u:%u",day,month,year,hour,minute,second); + log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"CMOS Hardware Clock: %u seconds since Epoch",epoch_seconds); + + return epoch_seconds; +} + +// PIT +// TODO: move to asm file void timer_init() { + uint64_t epoch_time=get_rtc_time(); + epoch_time*=25; + task_system_clock=epoch_time; + // config out timer on channel 0 : mode 2 (sys timer) // http://en.wikipedia.org/wiki/Intel_8253#Control_Word_Register // http://www.brokenthorn.com/Resources/OSDevPit.html @@ -61,23 +237,5 @@ void timer_init() __asm__("popa"); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"Configured PIT Channel 0 : Mode 2 : 1/25 s."); - -} - -void timer_tick() -{ - task_system_clock++; -} - -uint64_t timer_get_ticks() -{ - return task_system_clock; } -uint32_t timer_get_ms() -{ - uint32_t t=timer_get_ticks(); - uint32_t s=t/25; - uint32_t ms=t*1000/25-1000*s; - return s*1000;//+ms; -} diff --git a/kernel/usermode.c b/kernel/usermode.c index f0618d7..eb19cdf 100644 --- a/kernel/usermode.c +++ b/kernel/usermode.c @@ -7,6 +7,7 @@ tss_struct sys_tss; //Define the TSS as a global structure // generic syscall interface! +/* int syscall(int call, int p1, int p2, int p3) { int ebx; // will hold return value; @@ -31,16 +32,20 @@ int syscall(int call, int p1, int p2, int p3) return ebx; } +*/ +/* int write(int file, char *ptr, int len) { return syscall(SYSCALL_WRITE,file,ptr,len); } - +*/ +/* int execve(char *name, char **argv, char **env) { return syscall(SYSCALL_EXECVE,name,argv,env); } +*/ void install_tss(int cpu_no){ @@ -65,6 +70,6 @@ char *env_init[]={"var1=dupa","var2=mundl",NULL}; // THIS WILL BE RUN IN RING 3! void userfunc() { - execve("/bin/init",argv_init,env_init); + syscall(SYSCALL_EXECVE,"/bin/init",argv_init,env_init); while(1); // we should never get here. } diff --git a/lib/logger/log.c b/lib/logger/log.c index dc93784..fbc0614 100644 --- a/lib/logger/log.c +++ b/lib/logger/log.c @@ -25,17 +25,19 @@ void log(char *module_name, int log_level, char *format_string, ...) #ifdef FOOLOS_LOG_OFF return; #endif + if(log_level +#include +#include +#include + +typedef struct fs_dirent_struct +{ + uint32_t inode; + uint32_t offset; + uint16_t length; + uint8_t type; + char name[256]; +}fs_dirent; + +//fool-os syscalls +#define SYSCALL_READDIR 63 +#define SYSCALL_HAS_DATA 80 +#define SYSCALL_TUNE 81 + +//syscalls required by newlib +#define SYSCALL_EXIT 60 +#define SYSCALL_WRITE 61 +#define SYSCALL_READ 62 +#define SYSCALL_EXECVE 64 +#define SYSCALL_OPEN 65 +#define SYSCALL_CLOSE 66 +#define SYSCALL_FSTAT 67 +#define SYSCALL_ISATTY 68 +#define SYSCALL_LSEEK 69 +#define SYSCALL_SBRK 70 +#define SYSCALL_STAT 74 +#define SYSCALL_LSTAT 79 + +// stubs only so far! +#define SYSCALL_GETTIMEOFDAY 71 +#define SYSCALL_FORK 72 +#define SYSCALL_KILL 73 +#define SYSCALL_LINK 73 +#define SYSCALL_TIMES 75 +#define SYSCALL_UNLINK 76 +#define SYSCALL_WAIT 77 +#define SYSCALL_GETPID 78 + +/* +int syscall_execve(char *name, char **argv, char **env); +int syscall_write(int file, char *buf, int len); + +int syscall_readdir(const char *name,struct fs_dirent *dirs,int max); + +int syscall_exit(int ret, int none1, int none2); +int syscall_open(char *name, int flags, int len); +int syscall_read(int file, char *buf, int len); +int syscall_close(int file,int none1,int none2); +int syscall_fstat(int file, struct stat *st,int none); +int syscall_isatty(int file,int none1,int none2); +int syscall_lseek(int file,int ptr,int dir); +int syscall_stat(char *file, struct stat *st); +int syscall_sbrk(int incr, int none1, int none2); +// +int syscall_gettimeofday(struct timeval *tv, struct timezone *tz); +int syscall_fork(void); +int syscall_getpid(void); +int syscall_kill(int pid, int sig); +int syscall_link(char *old, char *ne); +int syscall_times(struct tms *buf); +int syscall_unlink(char *name); +int syscall_wait(int *status); +// +int syscall_unhandled(int nr); +*/ + +extern char **environ; +//struct _reent *_impure_ptr; + +// generic syscall interface! +/*int volatile __attribute__ ((noinline)) syscall(int call, int p1, int p2, int p3) +{ + int ebx; // persist over func call( a,c,d are scratch) + int ret; // will hold return val + + asm("mov %%ebx, %0": "=b" (ebx)); + +// asm("pusha"); + + // select syscall + asm("mov %0, %%eax"::"m"(call)); + + // pass params + asm("mov %0,%%edx"::"m"(p1)); + asm("mov %0,%%ecx"::"m"(p2)); + asm("mov %0,%%ebx"::"m"(p3)); + + // interrrupt + asm("int $0x80"); + + // get return value + asm("mov %%ebx, %0": "=b" (ret)); + + // restore + asm("mov %0,%%ebx"::"m"(ebx)); + +// asm("popa"); + + return ret; +} +*/ + +// fool os custom +int readdir(const char *name,fs_dirent *dirs,int max) +{ + + return syscall(SYSCALL_READDIR,name,dirs,max); +} + +int has_data_waiting() +{ + + return syscall(SYSCALL_HAS_DATA,0,0,0); +} + +int fool_tune(int v1, int v2, int v3) +{ + + return syscall(SYSCALL_TUNE,v1,v2,v3); +} + +void _exit(int ret) +{ + _exit2(ret,environ); +} + +void _exit2(int ret,char **environ) +{ + return syscall(SYSCALL_EXIT,ret,environ,0); +} + +//required by newlibc +int _close(int file) +{ + return syscall(SYSCALL_CLOSE,file,0,0); +} + +int _isatty(int file) +{ + return syscall(SYSCALL_ISATTY,file,0,0); +} + +int _lseek(int file, int ptr, int dir) +{ + return syscall(SYSCALL_LSEEK,file,ptr,dir); +} + +int _read(int file, char *ptr, int len) +{ + + return syscall(SYSCALL_READ,file,ptr,len); +} + +int _open(const char *name, int flags, int mode) +{ + return syscall(SYSCALL_OPEN,name,flags,mode); +} + +int _write(int file, char *ptr, int len) +{ + return syscall(SYSCALL_WRITE,file,ptr,len); +} + +int _execve(char *name, char **argv, char **env) +{ + return syscall(SYSCALL_EXECVE,name,argv,env); +} + +uint32_t _sbrk(int incr) +{ + return syscall(SYSCALL_SBRK,incr,0,0); +} + +int _gettimeofday(struct timeval *tv, void *tz) +{ + return syscall(SYSCALL_GETTIMEOFDAY,tv,tz,0); +} + +int _fork(void) +{ + return syscall(SYSCALL_FORK,0,0,0); +} + +int _getpid(void) +{ + return syscall(SYSCALL_GETPID,0,0,0); +} + +int _kill(int pid, int sig) +{ + return syscall(SYSCALL_KILL,pid,sig,0); +} + +int _link(char *old, char *ne) +{ + return syscall(SYSCALL_LINK,old,ne,0); +} + +int _unlink(char *name) +{ + return syscall(SYSCALL_UNLINK,name,0,0); +} + +int _times(struct tms *buf) +{ + return syscall(SYSCALL_TIMES,buf,0,0); +} + +int _wait(int *status) +{ + return syscall(SYSCALL_WAIT,status,0,0); +} + +int _stat(const char *file, struct stat *st) +{ + return syscall(SYSCALL_STAT,file,st,0); +} + +int _lstat(const char *file, struct stat *st) +{ + return syscall(SYSCALL_LSTAT,file,st,0); +} + +int _fstat(int file, struct stat *st) +{ + return syscall(SYSCALL_FSTAT,file,st,0); +} diff --git a/userspace/Makefile b/userspace/Makefile index 2812edd..e1e5484 100644 --- a/userspace/Makefile +++ b/userspace/Makefile @@ -1,35 +1,42 @@ +IMAGESIZE=30000 #ext2.img size in Kb (30Megs) + +####################### + CC=i686-foolos-gcc CC=i686-elf-gcc CFLAGS= +CFLAGS=-w CFLAGS+=-I.. CFLAGS+=-I/home/miguel/foolos/usr/i686-foolos/include -CFLAGS+=-w -CFLAGS+=-std=gnu11 CFLAGS+=-O0 CFLAGS+=-g -#CFLAGS+=-fstack-protector-all -#LDFLAGS=-nostdlib LDFLAGS=-L/home/miguel/foolos/usr/i686-foolos/lib/ LDLIBS=-lc -lm -lg -lnosys -PROGS=foolshell ls simple brainfuck test-math checker clear task1 task2 init cat snake +PROGS_C=$(wildcard *.c) +PROGS=$(patsubst %.c,%,$(PROGS_C)) + include ../Makefile.common +all: ext2.img + ext2.img: crt0.o $(PROGS) ../mp/mp.bin - dd if=/dev/zero of=ext2.img bs=512 count=50000 + + dd if=/dev/zero of=ext2.img bs=1024 count=$(IMAGESIZE) sudo mkfs.ext2 -O none ext2.img -F mkdir mnt sudo mount ext2.img mnt sudo chown miguel mnt mkdir -p mnt/home/miguel mkdir -p mnt/boot - echo "hello one" > mnt/home/miguel/test1.txt + echo "Welcome to FoolOs\nWe hope you will enjoy your stay." > mnt/home/miguel/hello.txt mkdir -p mnt/bin - cp $^ mnt/bin + cp $(PROGS) mnt/bin echo "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." > mnt/home/miguel/hello.brain + # cp ~/temp/fool-os-stuff/binutils-build-host-foolos/binutils/readelf mnt/bin # cp ../font/binfont.bin mnt/ # cp ~/temp/fool-os-stuff/ncurses/ncurses-5.9-build/progs/* mnt/bin/ @@ -39,6 +46,7 @@ ext2.img: crt0.o $(PROGS) ../mp/mp.bin # cp ~/opt/foolos/usr/bin/view mnt/bin/ # cp ~/opt/foolos/usr/bin/ncurses mnt/bin/ # cp ~/opt/foolos/usr/bin/bs mnt/bin/ +# cp ../mp/mp.bin mnt/boot/ mkdir -p mnt/etc echo "127.0.0.1 localhost" > mnt/etc/hosts @@ -46,27 +54,8 @@ ext2.img: crt0.o $(PROGS) ../mp/mp.bin sudo umount mnt rm mnt -rf -brainfuck: brainfuck.o -snake: snake.o -foolshell: foolshell.o -simple: simple.o -test-math: test-math.o -checker: checker.o -task1: task1.o -task2: task2.o -init: init.o -cat: cat.o - clean: - -rm *.o $(PROGS) ext2.img *.d + -rm -f *.o $(PROGS) ext2.img *.d -mount: - mkdir mnt - sudo mount ext2.img mnt - sudo chown miguel mnt - -umount: - sudo umount mnt - rm mnt -rf +new: clean all -new: clean ext2.img diff --git a/userspace/crt0.S b/userspace/crt0.S index 23efec5..87f1995 100644 --- a/userspace/crt0.S +++ b/userspace/crt0.S @@ -7,13 +7,6 @@ mov %eax, environ pop %eax #mov %eax, _impure_ptr - -#mov $61, %eax # write syscall -#mov $1,%edx # stdout -#mov .hellostr,%ecx -#mov 9,%ebx # string length -#int $0x80 - call main push environ diff --git a/userspace/sys/Makefile b/userspace/sys/Makefile deleted file mode 100644 index 289da1e..0000000 --- a/userspace/sys/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -CC=i686-elf-gcc -LD=i686-elf-ld - -#CFLAGS= -#CFLAGS+=-w -#CFLAGS+=-I../.. -#CFLAGS+=-gstabs -#CFLAGS+=-I. - -#LDFLAGS=-L/home/miguel/foolos/usr/i686-foolos/lib/ -lc -lm -lg -lnosys -#CFLAGS+=-I/home/miguel/foolos/usr/i686-foolos/include - -#install: crt_install header_install - -#crt_install: crt0.o -# cp crt0.o $(SYSROOT)/usr/lib/ - -#crt0.o: crt.o sys.o #syscalls.o -# $(LD) -r $^ -o $@ - -#header_install: -# cp *.h $(SYSROOT)/usr/include/ -# cp sys/*.h $(SYSROOT)/usr/include/sys/ - -crt0.o: crt0.S - -clean: - -rm -f *.o *.a diff --git a/userspace/sys/crt0.S b/userspace/sys/crt0.S deleted file mode 100644 index 2d6cbbd..0000000 --- a/userspace/sys/crt0.S +++ /dev/null @@ -1,23 +0,0 @@ -.global _start - -_start: - -jmp . - -##pop %eax -##mov %eax, environ - -##pop %eax -#mov %eax, _impure_ptr - -##call main - - -##push environ -##push %eax -##call _exit2 - -# this should never be reached anyway! -.wait: - hlt -jmp .wait diff --git a/userspace/sys/sgtty.h b/userspace/sys/sgtty.h deleted file mode 100644 index 24d0218..0000000 --- a/userspace/sys/sgtty.h +++ /dev/null @@ -1,19 +0,0 @@ -#define TIOCFLUSH 0x01 -#define RAW 0x02 -#define CBREAK 0x04 -#define XTABS 0x08 -#define CRMOD 0x10 -#define ECHO 0x20 - -// TODO: same struct should be used for /terminal/terminal.h ? -struct sgttyb{ - - int sg_ospeed; - int sg_ispeed; - - char sg_erase; - char sg_kill; - - int sg_flags; - -}; diff --git a/userspace/sys/sys.c b/userspace/sys/sys.c deleted file mode 100644 index 4ff77f3..0000000 --- a/userspace/sys/sys.c +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include -#include -#include - -// CODE FOR Stack Smashing Protector, TODO: MOVE / and do not duplicate -// with kernel.c -// http://wiki.osdev.org/Stack_Smashing_Protector -#include -#include - -#if UINT32_MAX == UINTPTR_MAX -#define STACK_CHK_GUARD 0xe2dee396 -#else -#define STACK_CHK_GUARD 0x595e9fbd94fda766 -#endif - -uintptr_t __stack_chk_guard = STACK_CHK_GUARD; - -__attribute__((noreturn)) -void __stack_chk_fail(void) -{ - write(1,"stack smashing!\n",16); - exit(99); -} - - -/////////////////// - -// required by binutils! - -long sysconf(int name) -{ - printf("UNIMPL: sysconf\n"); - printf("SYSCONF CALLED WITH : %s\n",name); - return 0; -} - -// set file mode creation mask -mode_t umask(mode_t mask) -{ - printf("UNIMPL: umask\n"); - return mask; -} - -// chmod -int chmod(const char * path, mode_t mode) -{ - printf("UNIMPL: chmod\n"); - return -1; -} - -// manipulating file descriptor -int fcntl(int fd, int cmd, ...) -{ - printf("UNIMPL: fcntl\n"); - return -1; -} - -// working directory -char *getwd(char *buf) -{ - printf("UNIMPL: getwd\n"); - static char wd[]="/"; - buf=wd; - return buf; -} - -// check if access allowed -int access(const char *pathname, int mode) -{ - printf("UNIMPL: access\n"); - //TODO: at leas check if this file exists! - return 0; -} - -// update time -int utime(const char *filename, const int *x) -{ - printf("UNIMPL: utime\n"); - return -1; -} - -// rmdir -int rmdir (const char *pathname) -{ - printf("UNIMPL: rmdir\n"); - return -1; -} - -// chonw -int chown(const char *path, uid_t owner, gid_t group) -{ - printf("UNIMPL: chown\n"); - return -1; -} - -// termios / ncurses -int tcgetattr(int fd, struct termios *termios_p) -{ - printf("UNIMPL: tcgetattr\n"); - return 0; -} -int tcsetattr(int fd, int optional_actions, const struct termios *termios_p){ - printf("UNIMPL: tsetattr\n"); - return 0; -} -int mkdir(const char *pathname, mode_t mode) -{ - printf("UNIMPL: mkdir\n"); - return -1; -} -int chdir (const char *pathname) -{ - printf("UNIMPL: chdir\n"); - return -1; -} - -// TODO; check if this is allright for not-real serial line!? -// http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC242 -// here they write something about padding may be affected? experiment. -speed_t cfgetospeed(const struct termios *termios_p) -{ -// printf("UNIMPL: cfgetospeed\n"); - return 9600; -} - -char *ttyname(int fd) -{ - printf("UNIMPL: ttyname\n"); - return "foolterm"; -} - - -DIR *opendir(const char *name) -{ - printf("UNIMPL: opendir\n"); - return 0; -} -int closedir(DIR *dirp) -{ - printf("UNIMPL: closedir\n"); - return 0; -} - - -int tcflush(int fd, int queue_selector) -{ - printf("UNIMPL: tcflush\n"); - return -1; -} -long fpathconf(int fd, int name) -{ - printf("UNIMPL: fpathconf\n"); - return -1; -} - - -unsigned int sleep(unsigned int seconds) -{ - printf("UNIMPL: sleep\n"); - return 0; -} - -char *getlogin(void) -{ - printf("UNIMPL: getlogin\n"); - return NULL; -} - -int ioctl(int fd, unsigned long request, ...) -{ - printf("UNIMPL: ioctl\n"); - return -1; -} - -int gtty(int fd, void *buf) -{ - // printf("UNIMPL: gettty\n"); - return -1; -} - -int stty(int fd, void *buf) -{ - // printf("UNIMPL: settty\n"); - return -1; -} - diff --git a/userspace/sys/sys/ioctl.h b/userspace/sys/sys/ioctl.h deleted file mode 100644 index e69de29..0000000 diff --git a/userspace/sys/sys/termios.h b/userspace/sys/sys/termios.h deleted file mode 100644 index 9b9cdc4..0000000 --- a/userspace/sys/sys/termios.h +++ /dev/null @@ -1,27 +0,0 @@ -#include - -typedef uint32_t speed_t; -typedef uint32_t DIR; - -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 - -struct direct{ - char d_name[256]; - int d_namlen -}; - diff --git a/userspace/sys/syscalls.c b/userspace/sys/syscalls.c deleted file mode 100644 index 10e035c..0000000 --- a/userspace/sys/syscalls.c +++ /dev/null @@ -1,158 +0,0 @@ -#include "kernel/syscalls.h" - -extern char **environ; -//struct _reent *_impure_ptr; - -// generic syscall interface! - -int __attribute__ ((noinline)) syscall(int call, int p1, int p2, int p3) -{ - int ebx; // will hold return value; - - // select syscall and pass params - asm("pusha"); - - asm("mov %0, %%eax"::"m"(call)); - - asm("mov %0,%%edx"::"m"(p1)); - asm("mov %0,%%ecx"::"m"(p2)); - asm("mov %0,%%ebx"::"m"(p3)); - - // interrrupt - asm("int $0x80"); - - // get return value - asm("mov %%ebx, %0": "=b" (ebx)); - - asm("popa"); - - return ebx; -} - -// fool os custom -int readdir(const char *name,fs_dirent *dirs,int max) -{ - - return syscall(SYSCALL_READDIR,name,dirs,max); -} - -int has_data_waiting() -{ - - return syscall(SYSCALL_HAS_DATA,0,0,0); -} - -int fool_tune(int v1, int v2, int v3) -{ - - return syscall(SYSCALL_TUNE,v1,v2,v3); -} - -void _exit(int ret) -{ - _exit2(ret,environ); -} - -void _exit2(int ret,char **environ) -{ - return syscall(SYSCALL_EXIT,ret,environ,0); -} - -//required by newlibc -int close(int file) -{ - return syscall(SYSCALL_CLOSE,file,0,0); -} - -int isatty(int file) -{ - return syscall(SYSCALL_ISATTY,file,0,0); -} - -int lseek(int file, int ptr, int dir) -{ - return syscall(SYSCALL_LSEEK,file,ptr,dir); -} - -int read(int file, char *ptr, int len) -{ - - return syscall(SYSCALL_READ,file,ptr,len); -} - -int open(const char *name, int flags, int mode) -{ - return syscall(SYSCALL_OPEN,name,flags,mode); -} - -int write(int file, char *ptr, int len) -{ - return syscall(SYSCALL_WRITE,file,ptr,len); -} - -int execve(char *name, char **argv, char **env) -{ - return syscall(SYSCALL_EXECVE,name,argv,env); -} - -uint32_t sbrk(int incr) -{ - return syscall(SYSCALL_SBRK,incr,0,0); -} - -int gettimeofday(struct timeval *tv, void *tz) -{ - return syscall(SYSCALL_GETTIMEOFDAY,tv,tz,0); -} - -int fork(void) -{ - return syscall(SYSCALL_FORK,0,0,0); -} - -int getpid(void) -{ - return syscall(SYSCALL_GETPID,0,0,0); -} - -int kill(int pid, int sig) -{ - return syscall(SYSCALL_KILL,pid,sig,0); -} - -int link(char *old, char *ne) -{ - return syscall(SYSCALL_LINK,old,ne,0); -} - -int unlink(char *name) -{ - return syscall(SYSCALL_UNLINK,name,0,0); -} - -int times(struct tms *buf) -{ - return syscall(SYSCALL_TIMES,buf,0,0); -} - -int wait(int *status) -{ - return syscall(SYSCALL_WAIT,status,0,0); -} - -int stat(const char *file, struct stat *st) -{ - return syscall(SYSCALL_STAT,file,st,0); -} - -int lstat(const char *file, struct stat *st) -{ - return syscall(SYSCALL_LSTAT,file,st,0); -} - -int fstat(int file, struct stat *st) -{ - return syscall(SYSCALL_FSTAT,file,st,0); -} - - diff --git a/xxx/sys/Makefile b/xxx/sys/Makefile new file mode 100644 index 0000000..289da1e --- /dev/null +++ b/xxx/sys/Makefile @@ -0,0 +1,28 @@ +CC=i686-elf-gcc +LD=i686-elf-ld + +#CFLAGS= +#CFLAGS+=-w +#CFLAGS+=-I../.. +#CFLAGS+=-gstabs +#CFLAGS+=-I. + +#LDFLAGS=-L/home/miguel/foolos/usr/i686-foolos/lib/ -lc -lm -lg -lnosys +#CFLAGS+=-I/home/miguel/foolos/usr/i686-foolos/include + +#install: crt_install header_install + +#crt_install: crt0.o +# cp crt0.o $(SYSROOT)/usr/lib/ + +#crt0.o: crt.o sys.o #syscalls.o +# $(LD) -r $^ -o $@ + +#header_install: +# cp *.h $(SYSROOT)/usr/include/ +# cp sys/*.h $(SYSROOT)/usr/include/sys/ + +crt0.o: crt0.S + +clean: + -rm -f *.o *.a diff --git a/xxx/sys/crt0.S b/xxx/sys/crt0.S new file mode 100644 index 0000000..2d6cbbd --- /dev/null +++ b/xxx/sys/crt0.S @@ -0,0 +1,23 @@ +.global _start + +_start: + +jmp . + +##pop %eax +##mov %eax, environ + +##pop %eax +#mov %eax, _impure_ptr + +##call main + + +##push environ +##push %eax +##call _exit2 + +# this should never be reached anyway! +.wait: + hlt +jmp .wait diff --git a/xxx/sys/sgtty.h b/xxx/sys/sgtty.h new file mode 100644 index 0000000..24d0218 --- /dev/null +++ b/xxx/sys/sgtty.h @@ -0,0 +1,19 @@ +#define TIOCFLUSH 0x01 +#define RAW 0x02 +#define CBREAK 0x04 +#define XTABS 0x08 +#define CRMOD 0x10 +#define ECHO 0x20 + +// TODO: same struct should be used for /terminal/terminal.h ? +struct sgttyb{ + + int sg_ospeed; + int sg_ispeed; + + char sg_erase; + char sg_kill; + + int sg_flags; + +}; diff --git a/xxx/sys/sys.c b/xxx/sys/sys.c new file mode 100644 index 0000000..4ff77f3 --- /dev/null +++ b/xxx/sys/sys.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include + +// CODE FOR Stack Smashing Protector, TODO: MOVE / and do not duplicate +// with kernel.c +// http://wiki.osdev.org/Stack_Smashing_Protector +#include +#include + +#if UINT32_MAX == UINTPTR_MAX +#define STACK_CHK_GUARD 0xe2dee396 +#else +#define STACK_CHK_GUARD 0x595e9fbd94fda766 +#endif + +uintptr_t __stack_chk_guard = STACK_CHK_GUARD; + +__attribute__((noreturn)) +void __stack_chk_fail(void) +{ + write(1,"stack smashing!\n",16); + exit(99); +} + + +/////////////////// + +// required by binutils! + +long sysconf(int name) +{ + printf("UNIMPL: sysconf\n"); + printf("SYSCONF CALLED WITH : %s\n",name); + return 0; +} + +// set file mode creation mask +mode_t umask(mode_t mask) +{ + printf("UNIMPL: umask\n"); + return mask; +} + +// chmod +int chmod(const char * path, mode_t mode) +{ + printf("UNIMPL: chmod\n"); + return -1; +} + +// manipulating file descriptor +int fcntl(int fd, int cmd, ...) +{ + printf("UNIMPL: fcntl\n"); + return -1; +} + +// working directory +char *getwd(char *buf) +{ + printf("UNIMPL: getwd\n"); + static char wd[]="/"; + buf=wd; + return buf; +} + +// check if access allowed +int access(const char *pathname, int mode) +{ + printf("UNIMPL: access\n"); + //TODO: at leas check if this file exists! + return 0; +} + +// update time +int utime(const char *filename, const int *x) +{ + printf("UNIMPL: utime\n"); + return -1; +} + +// rmdir +int rmdir (const char *pathname) +{ + printf("UNIMPL: rmdir\n"); + return -1; +} + +// chonw +int chown(const char *path, uid_t owner, gid_t group) +{ + printf("UNIMPL: chown\n"); + return -1; +} + +// termios / ncurses +int tcgetattr(int fd, struct termios *termios_p) +{ + printf("UNIMPL: tcgetattr\n"); + return 0; +} +int tcsetattr(int fd, int optional_actions, const struct termios *termios_p){ + printf("UNIMPL: tsetattr\n"); + return 0; +} +int mkdir(const char *pathname, mode_t mode) +{ + printf("UNIMPL: mkdir\n"); + return -1; +} +int chdir (const char *pathname) +{ + printf("UNIMPL: chdir\n"); + return -1; +} + +// TODO; check if this is allright for not-real serial line!? +// http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC242 +// here they write something about padding may be affected? experiment. +speed_t cfgetospeed(const struct termios *termios_p) +{ +// printf("UNIMPL: cfgetospeed\n"); + return 9600; +} + +char *ttyname(int fd) +{ + printf("UNIMPL: ttyname\n"); + return "foolterm"; +} + + +DIR *opendir(const char *name) +{ + printf("UNIMPL: opendir\n"); + return 0; +} +int closedir(DIR *dirp) +{ + printf("UNIMPL: closedir\n"); + return 0; +} + + +int tcflush(int fd, int queue_selector) +{ + printf("UNIMPL: tcflush\n"); + return -1; +} +long fpathconf(int fd, int name) +{ + printf("UNIMPL: fpathconf\n"); + return -1; +} + + +unsigned int sleep(unsigned int seconds) +{ + printf("UNIMPL: sleep\n"); + return 0; +} + +char *getlogin(void) +{ + printf("UNIMPL: getlogin\n"); + return NULL; +} + +int ioctl(int fd, unsigned long request, ...) +{ + printf("UNIMPL: ioctl\n"); + return -1; +} + +int gtty(int fd, void *buf) +{ + // printf("UNIMPL: gettty\n"); + return -1; +} + +int stty(int fd, void *buf) +{ + // printf("UNIMPL: settty\n"); + return -1; +} + diff --git a/xxx/sys/sys/ioctl.h b/xxx/sys/sys/ioctl.h new file mode 100644 index 0000000..e69de29 diff --git a/xxx/sys/sys/termios.h b/xxx/sys/sys/termios.h new file mode 100644 index 0000000..9b9cdc4 --- /dev/null +++ b/xxx/sys/sys/termios.h @@ -0,0 +1,27 @@ +#include + +typedef uint32_t speed_t; +typedef uint32_t DIR; + +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 + +struct direct{ + char d_name[256]; + int d_namlen +}; + diff --git a/xxx/sys/syscalls.c b/xxx/sys/syscalls.c new file mode 100644 index 0000000..10e035c --- /dev/null +++ b/xxx/sys/syscalls.c @@ -0,0 +1,158 @@ +#include "kernel/syscalls.h" + +extern char **environ; +//struct _reent *_impure_ptr; + +// generic syscall interface! + +int __attribute__ ((noinline)) syscall(int call, int p1, int p2, int p3) +{ + int ebx; // will hold return value; + + // select syscall and pass params + asm("pusha"); + + asm("mov %0, %%eax"::"m"(call)); + + asm("mov %0,%%edx"::"m"(p1)); + asm("mov %0,%%ecx"::"m"(p2)); + asm("mov %0,%%ebx"::"m"(p3)); + + // interrrupt + asm("int $0x80"); + + // get return value + asm("mov %%ebx, %0": "=b" (ebx)); + + asm("popa"); + + return ebx; +} + +// fool os custom +int readdir(const char *name,fs_dirent *dirs,int max) +{ + + return syscall(SYSCALL_READDIR,name,dirs,max); +} + +int has_data_waiting() +{ + + return syscall(SYSCALL_HAS_DATA,0,0,0); +} + +int fool_tune(int v1, int v2, int v3) +{ + + return syscall(SYSCALL_TUNE,v1,v2,v3); +} + +void _exit(int ret) +{ + _exit2(ret,environ); +} + +void _exit2(int ret,char **environ) +{ + return syscall(SYSCALL_EXIT,ret,environ,0); +} + +//required by newlibc +int close(int file) +{ + return syscall(SYSCALL_CLOSE,file,0,0); +} + +int isatty(int file) +{ + return syscall(SYSCALL_ISATTY,file,0,0); +} + +int lseek(int file, int ptr, int dir) +{ + return syscall(SYSCALL_LSEEK,file,ptr,dir); +} + +int read(int file, char *ptr, int len) +{ + + return syscall(SYSCALL_READ,file,ptr,len); +} + +int open(const char *name, int flags, int mode) +{ + return syscall(SYSCALL_OPEN,name,flags,mode); +} + +int write(int file, char *ptr, int len) +{ + return syscall(SYSCALL_WRITE,file,ptr,len); +} + +int execve(char *name, char **argv, char **env) +{ + return syscall(SYSCALL_EXECVE,name,argv,env); +} + +uint32_t sbrk(int incr) +{ + return syscall(SYSCALL_SBRK,incr,0,0); +} + +int gettimeofday(struct timeval *tv, void *tz) +{ + return syscall(SYSCALL_GETTIMEOFDAY,tv,tz,0); +} + +int fork(void) +{ + return syscall(SYSCALL_FORK,0,0,0); +} + +int getpid(void) +{ + return syscall(SYSCALL_GETPID,0,0,0); +} + +int kill(int pid, int sig) +{ + return syscall(SYSCALL_KILL,pid,sig,0); +} + +int link(char *old, char *ne) +{ + return syscall(SYSCALL_LINK,old,ne,0); +} + +int unlink(char *name) +{ + return syscall(SYSCALL_UNLINK,name,0,0); +} + +int times(struct tms *buf) +{ + return syscall(SYSCALL_TIMES,buf,0,0); +} + +int wait(int *status) +{ + return syscall(SYSCALL_WAIT,status,0,0); +} + +int stat(const char *file, struct stat *st) +{ + return syscall(SYSCALL_STAT,file,st,0); +} + +int lstat(const char *file, struct stat *st) +{ + return syscall(SYSCALL_LSTAT,file,st,0); +} + +int fstat(int file, struct stat *st) +{ + return syscall(SYSCALL_FSTAT,file,st,0); +} + + -- cgit v1.2.3