diff --git a/repos/os/run/rtc.run b/repos/os/run/rtc.run new file mode 100644 index 000000000..a03bacbcf --- /dev/null +++ b/repos/os/run/rtc.run @@ -0,0 +1,44 @@ +# RTC test + +build { core init drivers/rtc drivers/timer test/rtc } + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +build_boot_image { core init timer rtc_drv test-rtc } + +append qemu_args " -nographic -m 128 " + +run_genode_until ".*--- RTC test finished ---.*\n" 20 + +puts "Test succeeded" diff --git a/repos/os/src/drivers/rtc/x86/linux.cc b/repos/os/src/drivers/rtc/x86/linux.cc new file mode 100644 index 000000000..512943bc3 --- /dev/null +++ b/repos/os/src/drivers/rtc/x86/linux.cc @@ -0,0 +1,27 @@ +/* + * \brief Linux RTC pseudo driver + * \author Christian Helmuth + * \date 2015-01-06 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Linux includes */ +#include + +#include "rtc.h" + + +Genode::uint64_t Rtc::get_time(void) +{ + struct timeval now { }; + + gettimeofday(&now, nullptr); + + return now.tv_sec * 1000000ULL + now.tv_usec; +} diff --git a/repos/os/src/drivers/rtc/x86/main.cc b/repos/os/src/drivers/rtc/x86/main.cc index 0418c8f61..c43ff32ab 100644 --- a/repos/os/src/drivers/rtc/x86/main.cc +++ b/repos/os/src/drivers/rtc/x86/main.cc @@ -1,13 +1,11 @@ /* - * \brief Simple real-time-clock driver + * \brief RTC server * \author Christian Helmuth - * \author Markus Partheymueller - * \date 2007-04-18 + * \date 2015-01-06 */ /* - * Copyright (C) 2007-2013 Genode Labs GmbH - * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -15,229 +13,73 @@ /* Genode */ #include -#include -#include +#include #include -#include #include -#include -#include -using namespace Genode; +#include "rtc.h" -static bool verbose = false; - -/** - * Time helper - */ -bool is_leap_year(int year) -{ - if (((year & 3) || !((year % 100) != 0)) && (year % 400 != 0)) return false; - return true; -} - -/** - * Return UNIX time from given date and time. - */ -uint64_t mktime(int day, int mon, int year, int hour, int minutes, int seconds) -{ - bool jan_mar = mon < 3; - uint64_t ret = 0; - ret += (367*(10+mon))/12; - ret += jan_mar*2; - ret -= 719866; - ret += day; - ret += jan_mar * is_leap_year(year); - ret += 365*year; - ret += year/4; - ret -= year/100; - ret += year/400; - ret *= 24; - ret += hour; - ret *= 60; - ret += minutes; - ret *= 60; - ret += seconds; - - return ret; -} - -static uint64_t get_rtc_time(); namespace Rtc { + using namespace Genode; - class Session_component : public Genode::Rpc_object - { - public: - uint64_t get_current_time() - { - uint64_t ret = get_rtc_time(); - - if (verbose) - PINF("Time is: %llx\n", ret); - - return ret; - } - - }; - - class Root_component : public Genode::Root_component - { - protected: - - Session_component *_create_session(const char *args) - { - return new (md_alloc()) Session_component(); - } - public: - Root_component(Genode::Rpc_entrypoint *ep, - Genode::Allocator *allocator) - : Genode::Root_component(ep, allocator) - { - } - }; + struct Session_component; + struct Root; + struct Main; } -/* - * Our RTC port session - */ -Io_port_connection *rtc_ports; - -enum RTC +struct Rtc::Session_component : public Genode::Rpc_object { - RTC_SECONDS = 0, - RTC_SECONDS_ALARM = 1, - RTC_MINUTES = 2, - RTC_MINUTES_ALARM = 3, - RTC_HOURS = 4, - RTC_HOURS_ALARM = 5, - RTC_DAY_OF_WEEK = 6, - RTC_DAY_OF_MONTH = 7, - RTC_MONTH = 8, - RTC_YEAR = 9, + uint64_t get_current_time() override + { + uint64_t ret = Rtc::get_time(); - RTC_REG_A = 10, - RTC_REG_B = 11, - RTC_REG_C = 12, - RTC_REG_D = 13, - - RTC_FREQ_SELECT = RTC_REG_A, - RTC_UIP = 0x80, - RTC_DIV_CTL = 0x70, - RTC_REF_CLCK_4MHZ = 0x00, - RTC_REF_CLCK_1MHZ = 0x10, - RTC_REF_CLCK_32KHZ = 0x20, - RTC_DIV_RESET1 = 0x60, - RTC_DIV_RESET2 = 0x70, - RTC_RATE_SELECT = 0x0F, - - RTC_CONTROL = RTC_REG_B, - RTC_SET = 0x80, - RTC_PIE = 0x40, - RTC_AIE = 0x20, - RTC_UIE = 0x10, - RTC_SQWE = 0x08, - RTC_DM_BINARY = 0x04, - RTC_24H = 0x02, - RTC_DST_EN = 0x01, - - RTC_PORT_BASE = 0x70, - RTC_PORT_ADDR = RTC_PORT_BASE, - RTC_PORT_DATA = RTC_PORT_BASE + 1, - RTC_PORT_SIZE = 2, + return ret; + } }; -static inline unsigned cmos_read(unsigned char addr) +class Rtc::Root : public Genode::Root_component { - unsigned char val; - rtc_ports->outb(RTC_PORT_ADDR, addr); -// iodelay(); - val = rtc_ports->inb(RTC_PORT_DATA); -// iodelay(); - return val; -} + protected: + + Session_component *_create_session(const char *args) + { + return new (md_alloc()) Session_component(); + } + + public: + + Root(Server::Entrypoint &ep, Allocator &md_alloc) + : + Genode::Root_component(&ep.rpc_ep(), &md_alloc) + { + /* trigger initial RTC read */ + Rtc::get_time(); + } +}; -static inline void cmos_write(unsigned char val, unsigned char addr) +struct Rtc::Main { - rtc_ports->outb(RTC_PORT_ADDR, addr); -// iodelay(); - rtc_ports->outb(RTC_PORT_DATA, val); -// iodelay(); -} + Server::Entrypoint &ep; + Sliced_heap sliced_heap { env()->ram_session(), env()->rm_session() }; -#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */ -#define BCD_TO_BIN(val) ((val) = ((val) & 15) + ((val) >> 4) * 10) -#define BIN_TO_BCD(val) ((val) = (((val)/10) << 4) + (val) % 10) + Root root { ep, sliced_heap }; - -/** - * Get current time from CMOS and initialize values. - */ -static uint64_t get_rtc_time(void) -{ - unsigned year, mon, day, hour, min, sec; - int i; - - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. */ - - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) - if (cmos_read(RTC_FREQ_SELECT) & RTC_UIP) break; - - for (i = 0 ; i < 1000000 ; i++) - if (!(cmos_read(RTC_FREQ_SELECT) & RTC_UIP)) break; - - do { - sec = cmos_read(RTC_SECONDS); - min = cmos_read(RTC_MINUTES); - hour = cmos_read(RTC_HOURS); - day = cmos_read(RTC_DAY_OF_MONTH); - mon = cmos_read(RTC_MONTH); - year = cmos_read(RTC_YEAR); - } while (sec != cmos_read(RTC_SECONDS)); - - /* convert BCD to binary format if needed */ - if (!(cmos_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); + Main(Server::Entrypoint &ep) : ep(ep) + { + env()->parent()->announce(ep.manage(root)); } - - if ((year += 1900) < 1970) year += 100; - - if (verbose) - PINF("Date:%02d.%02d.%04d Time:%02d:%02d:%02d\n", day, mon, year, - hour, min, sec); - - /* return microseconds */ - return mktime(day, mon, year, hour, min, sec) * 1000000ULL; -} +}; -int main(int argc, char **argv) -{ - static Io_port_connection ports(RTC_PORT_BASE, RTC_PORT_SIZE); - rtc_ports = &ports; +/********************** + ** Server framework ** + **********************/ - Cap_connection cap; - static Sliced_heap sliced_heap(env()->ram_session(), env()->rm_session()); - - enum { STACK_SIZE = 1024*sizeof(size_t) }; - static Rpc_entrypoint ep(&cap, STACK_SIZE, "rtc_ep"); - static Rtc::Root_component rtc_root(&ep, &sliced_heap); - env()->parent()->announce(ep.manage(&rtc_root)); - - sleep_forever(); - - return 0; -} +char const * Server::name() { return "rtc_ep"; } +Genode::size_t Server::stack_size() { return 1024 * sizeof(long); } +void Server::construct(Server::Entrypoint &ep) { static Rtc::Main inst(ep); } diff --git a/repos/os/src/drivers/rtc/x86/rtc.cc b/repos/os/src/drivers/rtc/x86/rtc.cc new file mode 100644 index 000000000..2d3589b17 --- /dev/null +++ b/repos/os/src/drivers/rtc/x86/rtc.cc @@ -0,0 +1,178 @@ +/* + * \brief RTC/CMOS clock driver + * \author Christian Helmuth + * \author Markus Partheymueller + * \date 2007-04-18 + */ + +/* + * Copyright (C) 2007-2015 Genode Labs GmbH + * Copyright (C) 2012 Intel Corporation + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rtc.h" + +using namespace Genode; + + +/** + * Time helper + */ +static bool is_leap_year(int year) +{ + if (((year & 3) || !((year % 100) != 0)) && (year % 400 != 0)) return false; + return true; +} + +/** + * Return UNIX time from given date and time. + */ +static uint64_t mktime(int day, int mon, int year, int hour, int minutes, int seconds) +{ + bool jan_mar = mon < 3; + uint64_t ret = 0; + ret += (367*(10+mon))/12; + ret += jan_mar*2; + ret -= 719866; + ret += day; + ret += jan_mar * is_leap_year(year); + ret += 365*year; + ret += year/4; + ret -= year/100; + ret += year/400; + ret *= 24; + ret += hour; + ret *= 60; + ret += minutes; + ret *= 60; + ret += seconds; + + return ret; +} + + +enum RTC +{ + RTC_SECONDS = 0, + RTC_SECONDS_ALARM = 1, + RTC_MINUTES = 2, + RTC_MINUTES_ALARM = 3, + RTC_HOURS = 4, + RTC_HOURS_ALARM = 5, + RTC_DAY_OF_WEEK = 6, + RTC_DAY_OF_MONTH = 7, + RTC_MONTH = 8, + RTC_YEAR = 9, + + RTC_REG_A = 10, + RTC_REG_B = 11, + RTC_REG_C = 12, + RTC_REG_D = 13, + + RTC_FREQ_SELECT = RTC_REG_A, + RTC_UIP = 0x80, + RTC_DIV_CTL = 0x70, + RTC_REF_CLCK_4MHZ = 0x00, + RTC_REF_CLCK_1MHZ = 0x10, + RTC_REF_CLCK_32KHZ = 0x20, + RTC_DIV_RESET1 = 0x60, + RTC_DIV_RESET2 = 0x70, + RTC_RATE_SELECT = 0x0F, + + RTC_CONTROL = RTC_REG_B, + RTC_SET = 0x80, + RTC_PIE = 0x40, + RTC_AIE = 0x20, + RTC_UIE = 0x10, + RTC_SQWE = 0x08, + RTC_DM_BINARY = 0x04, + RTC_24H = 0x02, + RTC_DST_EN = 0x01, + + RTC_PORT_BASE = 0x70, + RTC_PORT_ADDR = RTC_PORT_BASE, + RTC_PORT_DATA = RTC_PORT_BASE + 1, + RTC_PORT_SIZE = 2, +}; + + +/* + * Our RTC port session + */ +static Io_port_connection & rtc_ports() +{ + static Io_port_connection inst(RTC_PORT_BASE, RTC_PORT_SIZE); + + return inst; +} + + +static inline unsigned cmos_read(unsigned char addr) +{ + unsigned char val; + rtc_ports().outb(RTC_PORT_ADDR, addr); +// iodelay(); + val = rtc_ports().inb(RTC_PORT_DATA); +// iodelay(); + return val; +} + + +#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */ +#define BCD_TO_BIN(val) ((val) = ((val) & 15) + ((val) >> 4) * 10) +#define BIN_TO_BCD(val) ((val) = (((val)/10) << 4) + (val) % 10) + + +uint64_t Rtc::get_time(void) +{ + unsigned year, mon, day, hour, min, sec; + int i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. */ + + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) + if (cmos_read(RTC_FREQ_SELECT) & RTC_UIP) break; + + for (i = 0 ; i < 1000000 ; i++) + if (!(cmos_read(RTC_FREQ_SELECT) & RTC_UIP)) break; + + do { + sec = cmos_read(RTC_SECONDS); + min = cmos_read(RTC_MINUTES); + hour = cmos_read(RTC_HOURS); + day = cmos_read(RTC_DAY_OF_MONTH); + mon = cmos_read(RTC_MONTH); + year = cmos_read(RTC_YEAR); + } while (sec != cmos_read(RTC_SECONDS)); + + /* convert BCD to binary format if needed */ + if (!(cmos_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + + if ((year += 1900) < 1970) year += 100; + + return mktime(day, mon, year, hour, min, sec) * 1000000ULL; +} diff --git a/repos/os/src/drivers/rtc/x86/rtc.h b/repos/os/src/drivers/rtc/x86/rtc.h new file mode 100644 index 000000000..ee3c0b06a --- /dev/null +++ b/repos/os/src/drivers/rtc/x86/rtc.h @@ -0,0 +1,25 @@ +/* + * \brief RTC driver interface + * \author Christian Helmuth + * \date 2015-01-06 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _RTC_H_ +#define _RTC_H_ + +#include + +namespace Rtc { + + /* Get real time in microseconds since 1970 */ + Genode::uint64_t get_time(); +} + +#endif /* _RTC_H_ */ diff --git a/repos/os/src/drivers/rtc/x86/target.mk b/repos/os/src/drivers/rtc/x86/target.mk index 69285ed74..0dffe3c9a 100644 --- a/repos/os/src/drivers/rtc/x86/target.mk +++ b/repos/os/src/drivers/rtc/x86/target.mk @@ -1,4 +1,12 @@ TARGET = rtc_drv REQUIRES = x86 SRC_CC = main.cc -LIBS = base +LIBS = base server + +# enforce hybrid prg on Linux +ifeq ($(filter-out $(SPECS),linux),) +SRC_CC += linux.cc +LIBS += lx_hybrid +else +SRC_CC += rtc.cc +endif diff --git a/repos/os/src/test/rtc/main.cc b/repos/os/src/test/rtc/main.cc new file mode 100644 index 000000000..7bd519ea5 --- /dev/null +++ b/repos/os/src/test/rtc/main.cc @@ -0,0 +1,41 @@ +/* + * \brief Test for RTC driver + * \author Christian Helmuth + * \date 2015-01-06 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + Genode::printf("--- RTC test started ---\n"); + + /* open sessions */ + static Rtc::Connection rtc; + static Timer::Connection timer; + + for (unsigned i = 0; i < 4; ++i) { + Genode::uint64_t now = rtc.get_current_time(); + + Genode::printf("RTC: %llu.%06llu seconds since 1970\n", + now / 1000000ULL, + now % 1000000ULL); + + timer.msleep(1000); + } + + Genode::printf("--- RTC test finished ---\n"); + + return 0; +} diff --git a/repos/os/src/test/rtc/target.mk b/repos/os/src/test/rtc/target.mk new file mode 100644 index 000000000..6eb1c8509 --- /dev/null +++ b/repos/os/src/test/rtc/target.mk @@ -0,0 +1,3 @@ +TARGET = test-rtc +SRC_CC = main.cc +LIBS = base