diff --git a/include/errno.h b/include/errno.h index 47aeed1..4092e5c 100644 --- a/include/errno.h +++ b/include/errno.h @@ -15,6 +15,7 @@ # define ENODEV 19 # define EINVAL 22 # define ERANGE 34 +# define EAGAIN 35 # define ENOSYS 78 # define ENOTSUP 86 diff --git a/include/project.conf b/include/project.conf index 72473a8..d2e8bc6 100644 --- a/include/project.conf +++ b/include/project.conf @@ -1,2 +1,2 @@ subdirs=kernel,sys -dist=Makefile,elf.h,errno.h,fcntl.h,limits.h,stdarg.h,stdbool.h,stddef.h,stdint.h,stdio.h,stdlib.h,string.h,unistd.h +dist=Makefile,elf.h,errno.h,fcntl.h,limits.h,stdarg.h,stdbool.h,stddef.h,stdint.h,stdio.h,stdlib.h,string.h,time.h,unistd.h diff --git a/include/time.h b/include/time.h new file mode 100644 index 0000000..975b9ad --- /dev/null +++ b/include/time.h @@ -0,0 +1,21 @@ +/* $Id$ */ +/* Copyright (c) 2018 Pierre Pronchery */ +/* This file is part of DeforaOS uKernel */ + + + +#ifndef UKERNEL_TIME_H +# define UKERNEL_TIME_H + + +/* types */ +# ifndef time_t +# define time_t time_t +typedef long long time_t; +# endif + + +/* functions */ +time_t time(time_t * t); + +#endif /* !UKERNEL_TIME_H */ diff --git a/src/drivers/clock.c b/src/drivers/clock.c new file mode 100644 index 0000000..3e950ad --- /dev/null +++ b/src/drivers/clock.c @@ -0,0 +1,72 @@ +/* $Id$ */ +/* Copyright (c) 2018 Pierre Pronchery */ +/* This file is part of DeforaOS uKernel */ + + + +#include +#include +#include +#include "clock.h" + + +/* private */ +/* variables */ +static ukClock * _clock = NULL; + + +/* public */ +/* variables */ +#if defined(__amd64__) || defined(__i386__) +extern ukClock cmos_clock; +#endif + + +/* functions */ +/* clock_init */ +ukClock * clock_init(ukBus * bus, char const * name) +{ + ukClock * clock = NULL; + const ukClock * drivers[] = { +#if defined(__amd64__) || defined(__i386__) + &cmos_clock +#endif + }; + size_t i; + + for(i = 0; i < sizeof(drivers) / sizeof(*drivers); i++) + if(strncmp(drivers[i]->name, name, + strlen(drivers[i]->name)) == 0 + && drivers[i]->init != NULL) + { + fprintf(stderr, "%s clock%s%s\n", name, (bus != NULL) + ? " at " : "", + (bus != NULL) ? bus->name : ""); + clock = drivers[i]->init(bus); + } + if(clock == NULL) + errno = ENODEV; + else if(_clock == NULL) + _clock = clock; + return clock; +} + + +/* accessors */ +/* clock_get_default */ +ukClock * clock_get_default(void) +{ + if(_clock == NULL) + errno = ENODEV; + return _clock; +} + + +/* clock_get_time */ +int clock_get_time(ukClock * clock, time_t * time) +{ + if(clock == NULL + && (clock = clock_get_default()) == NULL) + return -1; + return clock->get_time(clock, time); +} diff --git a/src/drivers/clock.h b/src/drivers/clock.h new file mode 100644 index 0000000..bd546f3 --- /dev/null +++ b/src/drivers/clock.h @@ -0,0 +1,42 @@ +/* $Id$ */ +/* Copyright (c) 2018 Pierre Pronchery */ +/* This file is part of DeforaOS uKernel */ + + + +#ifndef UKERNEL_DRIVERS_CLOCK_H +# define UKERNEL_DRIVERS_CLOCK_H + +# include +# include "bus.h" + + +/* public */ +/* types */ +typedef struct _ukClock ukClock; + +typedef struct _ukClockData ukClockData; + +struct _ukClock +{ + char name[16]; + + ukClock * (*init)(ukBus * bus); + void (*destroy)(ukClock * clock); + + int (*get_time)(ukClock * clock, time_t * time); + + ukClockData * data; +}; + + +/* prototypes */ +ukClock * clock_init(ukBus * bus, char const * name); +void clock_destroy(ukClock * clock); + +/* accessors */ +ukClock * clock_get_default(void); + +int clock_get_time(ukClock * clock, time_t * time); + +#endif /* !UKERNEL_DRIVERS_CLOCK_H */ diff --git a/src/drivers/clock/cmos.c b/src/drivers/clock/cmos.c new file mode 100644 index 0000000..bbc36e4 --- /dev/null +++ b/src/drivers/clock/cmos.c @@ -0,0 +1,140 @@ +/* $Id$ */ +/* Copyright (c) 2018 Pierre Pronchery */ +/* This file is part of DeforaOS uKernel */ + + + +#include +#include +#include "drivers/clock.h" + + +/* private */ +/* types */ +typedef struct _ukClock CMOSClock; + +typedef struct _ukClockData +{ + ukBus * bus; +} CMOSClockData; + + +/* constants */ +#define CMOS_REGISTER_SECONDS 0x00 +#define CMOS_REGISTER_MINUTES 0x02 +#define CMOS_REGISTER_HOURS 0x04 +#define CMOS_REGISTER_WEEKDAY 0x06 +#define CMOS_REGISTER_DAY 0x07 +#define CMOS_REGISTER_MONTH 0x08 +#define CMOS_REGISTER_YEAR 0x09 + + +/* prototypes */ +/* console */ +static CMOSClock * _cmos_clock_init(ukBus * bus); +static void _cmos_clock_destroy(CMOSClock * clock); + +static int _cmos_clock_get_time(CMOSClock * console, time_t * time); + + +/* public */ +/* variables */ +/* console */ +CMOSClock cmos_clock = +{ + "cmos", + _cmos_clock_init, + _cmos_clock_destroy, + _cmos_clock_get_time, + NULL +}; + + +/* functions */ +/* console */ +/* cmos_clock_init */ +static CMOSClock * _cmos_clock_init(ukBus * bus) +{ + CMOSClock * clock = &cmos_clock; + CMOSClockData * data; + + if(bus == NULL) + { + errno = ENODEV; + return NULL; + } + if((data = malloc(sizeof(*data))) == NULL) + return NULL; + data->bus = bus; + clock->data = data; + return clock; +} + + +/* cmos_clock_destroy */ +static void _cmos_clock_destroy(CMOSClock * clock) +{ + free(clock->data); +} + + +/* cmos_clock_get_time */ +static int _get_time_do(ukBus * bus, unsigned char * seconds, + unsigned char * minutes, unsigned char * hours, + unsigned char * day, unsigned char * month, + unsigned char * year); +static int _cmos_clock_get_time(CMOSClock * clock, time_t * time) +{ + CMOSClockData * data = clock->data; + unsigned char seconds, s; + unsigned char minutes, m; + unsigned char hours, h; + unsigned char day, d; + unsigned char month, M; + unsigned char year, y; + size_t i; + + if(time == NULL) + { + errno = EINVAL; + return -1; + } + for(i = 0; i < 3; i++) + { + if(_get_time_do(data->bus, &seconds, &minutes, &hours, &day, + &month, &year) != 0 + || _get_time_do(data->bus, &s, &m, &h, &d, &M, + &y) != 0) + return -1; + if(seconds == s && minutes == m && hours == h + && day == d && month == M && year == y) + break; + } + if(i == 3) + { + errno = EAGAIN; + return -1; + } + /* FIXME this is not correct */ + *time = seconds + (minutes * 60) + (hours * 60 * 24) + + (day * 60 * 24 * 30) + (month * 60 * 24 * 12) + + (((year >= 70) ? (year - 1970) : (year + 30)) + * 60 * 24 * 365); + return 0; +} + +static int _get_time_do(ukBus * bus, unsigned char * seconds, + unsigned char * minutes, unsigned char * hours, + unsigned char * day, unsigned char * month, + unsigned char * year) +{ + /* FIXME check first if the data is available */ + if(bus->read8(bus, CMOS_REGISTER_SECONDS, seconds) != 0 + || bus->read8(bus, CMOS_REGISTER_MINUTES, minutes) != 0 + || bus->read8(bus, CMOS_REGISTER_HOURS, hours) != 0 + || bus->read8(bus, CMOS_REGISTER_DAY, day) != 0 + || bus->read8(bus, CMOS_REGISTER_MONTH, month) != 0 + || bus->read8(bus, CMOS_REGISTER_YEAR, year) != 0) + return -1; + return 0; +} diff --git a/src/drivers/clock/project.conf b/src/drivers/clock/project.conf new file mode 100644 index 0000000..d1f3c1d --- /dev/null +++ b/src/drivers/clock/project.conf @@ -0,0 +1,15 @@ +targets=cmos.o,sys.o +cppflags_force=-nostdinc -isystem ../../../include -I../.. +cflags_force=`../../../tools/platform.sh -V UKERNEL_CFLAGS -C "$$ARCH"` +cflags=-W -Wall -g -O2 +ldflags_force=`../../../tools/platform.sh -V UKERNEL_LDFLAGS -C "$$ARCH"` +dist=Makefile + +#targets +[cmos.o] +type=object +sources=cmos.c + +[sys.o] +type=object +sources=sys.c diff --git a/src/drivers/clock/sys.c b/src/drivers/clock/sys.c new file mode 100644 index 0000000..5c37d98 --- /dev/null +++ b/src/drivers/clock/sys.c @@ -0,0 +1,59 @@ +/* $Id$ */ +/* Copyright (c) 2018 Pierre Pronchery */ +/* This file is part of DeforaOS uKernel */ + + + +#include +#include "drivers/clock.h" + + +/* private */ +/* types */ +typedef struct _ukClock SysClock; + + +/* prototypes */ +/* console */ +static SysClock * _sys_clock_init(ukBus * bus); + +static int _sys_clock_get_time(SysClock * console, time_t * time); + +extern time_t _time(time_t * t); + + +/* public */ +/* variables */ +/* console */ +SysClock sys_clock = +{ + "sys", + _sys_clock_init, + NULL, + _sys_clock_get_time, + NULL +}; + + +/* functions */ +/* console */ +/* sys_clock_init */ +static SysClock * _sys_clock_init(ukBus * bus) +{ + (void) bus; + + return &sys_clock; +} + + +/* sys_clock_get_time */ +static int _sys_clock_get_time(SysClock * clock, time_t * time) +{ + time_t t; + + if(_time(&t) == -1) + return -1; + if(time != NULL) + *time = t; + return 0; +} diff --git a/src/drivers/project.conf b/src/drivers/project.conf index 3d9dcb6..1302e5b 100644 --- a/src/drivers/project.conf +++ b/src/drivers/project.conf @@ -1,5 +1,5 @@ -subdirs=boot,bus,console -targets=bus.o,console.o +subdirs=boot,bus,clock,console +targets=bus.o,clock.o,console.o cppflags_force=-nostdinc -isystem ../../include -I.. as=$(CC) asflags_force=$(CFLAGSF) $(CFLAGS) -c @@ -13,6 +13,10 @@ dist=Makefile,bus.h,console.h type=object sources=bus.c +[clock.o] +type=object +sources=clock.c + [console.o] type=object sources=console.c @@ -21,5 +25,8 @@ sources=console.c [bus.c] depends=bus.h,bus/ioport.c +[clock.c] +depends=bus.h,clock.h + [console.c] depends=bus.h,console/vga.h,console/vga.c diff --git a/src/kernel/project.conf b/src/kernel/project.conf index 325c15b..458448f 100644 --- a/src/kernel/project.conf +++ b/src/kernel/project.conf @@ -27,8 +27,8 @@ sources=../common/crtn.S [uKernel.bin] type=binary sources=arch.S,gdt.c,main.c,multiboot.c,start.S -ldflags=$(OBJDIR)crti.o $(OBJDIR)crtbegin.o $(OBJDIR)../drivers/boot/multiboot.o $(OBJDIR)../drivers/bus.o $(OBJDIR)../drivers/bus/cmos.o $(OBJDIR)../drivers/bus/ioport.o $(OBJDIR)../drivers/console.o $(OBJDIR)../drivers/console/uart.o $(OBJDIR)../drivers/console/vesa.o $(OBJDIR)../drivers/console/vga.o $(OBJDIR)../lib/libuKernel.a $(OBJDIR)crtend.o $(OBJDIR)crtn.o `$(CC) -print-libgcc-file-name` -depends=$(OBJDIR)crtbegin.o,$(OBJDIR)crtend.o,$(OBJDIR)crti.o,$(OBJDIR)crtn.o,$(OBJDIR)../drivers/boot/multiboot.o,$(OBJDIR)../drivers/bus.o,$(OBJDIR)../drivers/bus/cmos.o,$(OBJDIR)../drivers/bus/ioport.o,$(OBJDIR)../drivers/console.o,$(OBJDIR)../drivers/console/uart.o,$(OBJDIR)../drivers/console/vesa.o,$(OBJDIR)../drivers/console/vga.o,$(OBJDIR)../lib/libuKernel.a,../arch/amd64/uKernel.ld,../arch/i386/uKernel.ld +ldflags=$(OBJDIR)crti.o $(OBJDIR)crtbegin.o $(OBJDIR)../drivers/boot/multiboot.o $(OBJDIR)../drivers/bus.o $(OBJDIR)../drivers/bus/cmos.o $(OBJDIR)../drivers/bus/ioport.o $(OBJDIR)../drivers/clock.o $(OBJDIR)../drivers/clock/cmos.o $(OBJDIR)../drivers/console.o $(OBJDIR)../drivers/console/uart.o $(OBJDIR)../drivers/console/vesa.o $(OBJDIR)../drivers/console/vga.o $(OBJDIR)../lib/libuKernel.a $(OBJDIR)crtend.o $(OBJDIR)crtn.o `$(CC) -print-libgcc-file-name` +depends=$(OBJDIR)crtbegin.o,$(OBJDIR)crtend.o,$(OBJDIR)crti.o,$(OBJDIR)crtn.o,$(OBJDIR)../drivers/boot/multiboot.o,$(OBJDIR)../drivers/bus.o,$(OBJDIR)../drivers/bus/cmos.o,$(OBJDIR)../drivers/bus/ioport.o,$(OBJDIR)../drivers/clock.o,$(OBJDIR)../drivers/clock/cmos.o,$(OBJDIR)../drivers/console.o,$(OBJDIR)../drivers/console/uart.o,$(OBJDIR)../drivers/console/vesa.o,$(OBJDIR)../drivers/console/vga.o,$(OBJDIR)../lib/libuKernel.a,../arch/amd64/uKernel.ld,../arch/i386/uKernel.ld #sources [arch.S] diff --git a/src/lib/project.conf b/src/lib/project.conf index b224ace..8e12749 100644 --- a/src/lib/project.conf +++ b/src/lib/project.conf @@ -7,7 +7,7 @@ dist=Makefile,ssp.h [libuKernel] type=library -sources=ctype.c,errno.c,ssp.c,stdio.c,stdlib.c,string.c,sys/mman.c,unistd.c +sources=ctype.c,errno.c,ssp.c,stdio.c,stdlib.c,string.c,sys/mman.c,time.c,unistd.c [ctype.c] depends=../../include/ctype.h @@ -29,3 +29,6 @@ depends=../../include/string.h [sys/mman.c] depends=../../include/sys/mman.h + +[time.c] +depends=../../include/time.h,../drivers/clock.h diff --git a/src/lib/time.c b/src/lib/time.c new file mode 100644 index 0000000..1da13cd --- /dev/null +++ b/src/lib/time.c @@ -0,0 +1,23 @@ +/* $Id$ */ +/* Copyright (c) 2018 Pierre Pronchery */ +/* This file is part of DeforaOS uKernel */ + + + +#include +#include +#include "drivers/clock.h" + + +/* functions */ +/* time */ +time_t time(time_t * time) +{ + time_t t; + + if(clock_get_time(NULL, &t) != 0) + return -1; + if(time != NULL) + *time = t; + return t; +} diff --git a/tools/arch/i386/start.S b/tools/arch/i386/start.S index 728012b..a1ba466 100644 --- a/tools/arch/i386/start.S +++ b/tools/arch/i386/start.S @@ -35,6 +35,14 @@ _exit: jmp _syscall +/* gettimeofday */ +.global _gettimeofday +.type _gettimeofday, @function +_gettimeofday: + mov $0x1a2, %eax + jmp _syscall + + /* read */ .global _read .type _read, @function @@ -99,6 +107,23 @@ _start: hlt +/* time */ +.global _time +.type _time, @function +_time: + push $0x0 + sub $0xc, %esp + push %esp + call _gettimeofday + cmp $-1, %eax + je 1f + mov 0xc(%esp), %eax + mov 0x8(%esp), %edx +1: + add $0x14, %esp + ret + + /* write */ .global _write .type _write, @function diff --git a/tools/clock.c b/tools/clock.c new file mode 100644 index 0000000..6d856bf --- /dev/null +++ b/tools/clock.c @@ -0,0 +1,74 @@ +/* $Id$ */ +/* Copyright (c) 2018 Pierre Pronchery */ +/* This file is part of DeforaOS uKernel */ + + + +#include +#include +#include +#include "drivers/clock.h" + + +/* private */ +/* variables */ +static ukClock * _clock = NULL; + + +/* public */ +/* variables */ +extern ukClock sys_clock; + + +/* functions */ +/* clock_init */ +ukClock * clock_init(ukBus * bus, char const * name) +{ + const ukClock * drivers[] = { + &sys_clock + }; + size_t i; + ukClock * clock = NULL; + + for(i = 0; i < sizeof(drivers) / sizeof(*drivers); i++) + if(strncmp(drivers[i]->name, name, + strlen(drivers[i]->name)) == 0 + && drivers[i]->init != NULL) + { + printf("%s%s%s\n", name, (bus != NULL) ? " at " : "", + (bus != NULL) ? bus->name : ""); + clock = drivers[i]->init(bus); + } + if(clock == NULL) + { + errno = ENODEV; + return NULL; + } + else if(_clock == NULL) + _clock = clock; + return clock; +} + + +/* FIXME code duplication with src/drivers/clock.c */ +/* accessors */ +/* clock_get_default */ +ukClock * clock_get_default(void) +{ + if(_clock == NULL) + errno = ENODEV; + return _clock; +} + + +/* clock_get_time */ +int clock_get_time(ukClock * clock, time_t * time) +{ + if(clock == NULL + && (clock = clock_get_default()) == NULL) + { + errno = ENODEV; + return -1; + } + return clock->get_time(clock, time); +} diff --git a/tools/init.c b/tools/init.c index 6a394a0..b8de7b0 100644 --- a/tools/init.c +++ b/tools/init.c @@ -6,9 +6,11 @@ #include #include "drivers/bus.h" +#include "drivers/clock.h" #include "drivers/console.h" #define TOOLS_BUS "tty" +#define TOOLS_CLOCK "sys" #define TOOLS_CONSOLE "stdio" @@ -18,5 +20,6 @@ int _init(void) bus = bus_init(NULL, TOOLS_BUS); console_init(bus, TOOLS_CONSOLE); + clock_init(NULL, TOOLS_CLOCK); return 0; } diff --git a/tools/project.conf b/tools/project.conf index 3bc3f5e..7e265ed 100644 --- a/tools/project.conf +++ b/tools/project.conf @@ -14,9 +14,9 @@ sources=start.S [uKernel] type=binary -sources=bus.c,console.c,init.c,main.c -ldflags=$(OBJDIR)start.o $(OBJDIR)../src/lib/libuKernel.a $(OBJDIR)../src/drivers/console/stdio.o `$(CC) -print-libgcc-file-name` -depends=$(OBJDIR)start.o,$(OBJDIR)../src/lib/libuKernel.a,$(OBJDIR)../src/drivers/console/stdio.o +sources=bus.c,clock.c,console.c,init.c,main.c +ldflags=$(OBJDIR)start.o $(OBJDIR)../src/lib/libuKernel.a $(OBJDIR)../src/drivers/clock/sys.o $(OBJDIR)../src/drivers/console/stdio.o `$(CC) -print-libgcc-file-name` +depends=$(OBJDIR)start.o,$(OBJDIR)../src/lib/libuKernel.a,$(OBJDIR)../src/drivers/clock/sys.o,$(OBJDIR)../src/drivers/console/stdio.o #sources [bus.c]