Index: uspace/app/barber/barber.c
===================================================================
--- uspace/app/barber/barber.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/app/barber/barber.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -233,5 +233,5 @@
 	getuptime(&cur);
 	
-	plan_frame_timer(tv_sub(&cur, &prev));
+	plan_frame_timer(tv_sub_diff(&cur, &prev));
 }
 
Index: uspace/app/nettest1/nettest1.c
===================================================================
--- uspace/app/nettest1/nettest1.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/app/nettest1/nettest1.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -412,5 +412,5 @@
 	gettimeofday(&time_after, NULL);
 	
-	printf("Tested in %ld microseconds\n", tv_sub(&time_after,
+	printf("Tested in %ld microseconds\n", tv_sub_diff(&time_after,
 	    &time_before));
 	
Index: uspace/app/nettest2/nettest2.c
===================================================================
--- uspace/app/nettest2/nettest2.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/app/nettest2/nettest2.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -370,5 +370,5 @@
 	
 	printf("sendto + recvfrom tested in %ld microseconds\n",
-	    tv_sub(&time_after, &time_before));
+	    tv_sub_diff(&time_after, &time_before));
 	
 	gettimeofday(&time_before, NULL);
@@ -390,5 +390,5 @@
 	
 	printf("sendto, recvfrom tested in %ld microseconds\n",
-	    tv_sub(&time_after, &time_before));
+	    tv_sub_diff(&time_after, &time_before));
 	
 	rc = sockets_close(verbose, socket_ids, sockets);
Index: uspace/app/rcubench/rcubench.c
===================================================================
--- uspace/app/rcubench/rcubench.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/app/rcubench/rcubench.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -264,5 +264,5 @@
 	
 	getuptime(&end);
-	int64_t duration = tv_sub(&end, &start);
+	int64_t duration = tv_sub_diff(&end, &start);
 	
 	uint64_t secs = (uint64_t)duration / 1000 / 1000;
Index: uspace/app/tester/ipc/ping_pong.c
===================================================================
--- uspace/app/tester/ipc/ping_pong.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/app/tester/ipc/ping_pong.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -50,5 +50,5 @@
 		gettimeofday(&now, NULL);
 		
-		if (tv_sub(&now, &start) >= DURATION_SECS * 1000000L)
+		if (tv_sub_diff(&now, &start) >= DURATION_SECS * 1000000L)
 			break;
 		
Index: uspace/app/tester/ipc/starve.c
===================================================================
--- uspace/app/tester/ipc/starve.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/app/tester/ipc/starve.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -52,5 +52,5 @@
 		gettimeofday(&now, NULL);
 		
-		if (tv_sub(&now, &start) >= DURATION_SECS * 1000000L)
+		if (tv_sub_diff(&now, &start) >= DURATION_SECS * 1000000L)
 			break;
 		
Index: uspace/drv/time/cmos-rtc/cmos-rtc.c
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -76,5 +76,5 @@
 	int clients_connected;
 	/** time at which the system booted */
-	time_t boottime;
+	struct timeval boot_time;
 } rtc_t;
 
@@ -97,5 +97,4 @@
 static int rtc_dev_remove(ddf_dev_t *dev);
 static void rtc_register_write(rtc_t *rtc, int reg, int data);
-static time_t uptime_get(void);
 static bool is_battery_ok(rtc_t *rtc);
 static int  rtc_fun_online(ddf_fun_t *fun);
@@ -205,5 +204,6 @@
 	ddf_msg(LVL_DEBUG, "rtc_dev_initialize %s", ddf_dev_get_name(rtc->dev));
 
-	rtc->boottime = 0;
+	rtc->boot_time.tv_sec = 0;
+	rtc->boot_time.tv_usec = 0;
 	rtc->clients_connected = 0;
 
@@ -326,14 +326,16 @@
 	fibril_mutex_lock(&rtc->mutex);
 
-	if (rtc->boottime != 0) {
+	if (rtc->boot_time.tv_sec) {
 		/* There is no need to read the current time from the
 		 * device because it has already been cached.
 		 */
 
-		time_t cur_time = rtc->boottime + uptime_get();
-
+		struct timeval curtime;
+		
+		getuptime(&curtime);
+		tv_add(&curtime, &rtc->boot_time);
 		fibril_mutex_unlock(&rtc->mutex);
 
-		return time_local2tm(cur_time, t);
+		return time_tv2tm(&curtime, t);
 	}
 
@@ -344,21 +346,25 @@
 	}
 
+	/* Microseconds are below RTC's resolution, assume 0. */
+	t->tm_usec = 0;
+
 	/* now read the registers */
 	do {
 		/* Suspend until the update process has finished */
-		while (rtc_update_in_progress(rtc));
-
-		t->tm_sec  = rtc_register_read(rtc, RTC_SEC);
-		t->tm_min  = rtc_register_read(rtc, RTC_MIN);
+		while (rtc_update_in_progress(rtc))
+			;
+
+		t->tm_sec = rtc_register_read(rtc, RTC_SEC);
+		t->tm_min = rtc_register_read(rtc, RTC_MIN);
 		t->tm_hour = rtc_register_read(rtc, RTC_HOUR);
 		t->tm_mday = rtc_register_read(rtc, RTC_DAY);
-		t->tm_mon  = rtc_register_read(rtc, RTC_MON);
+		t->tm_mon = rtc_register_read(rtc, RTC_MON);
 		t->tm_year = rtc_register_read(rtc, RTC_YEAR);
 
 		/* Now check if it is stable */
-	} while(t->tm_sec  != rtc_register_read(rtc, RTC_SEC) ||
-	    t->tm_min  != rtc_register_read(rtc, RTC_MIN) ||
+	} while(t->tm_sec != rtc_register_read(rtc, RTC_SEC) ||
+	    t->tm_min != rtc_register_read(rtc, RTC_MIN) ||
 	    t->tm_mday != rtc_register_read(rtc, RTC_DAY) ||
-	    t->tm_mon  != rtc_register_read(rtc, RTC_MON) ||
+	    t->tm_mon != rtc_register_read(rtc, RTC_MON) ||
 	    t->tm_year != rtc_register_read(rtc, RTC_YEAR));
 
@@ -366,5 +372,4 @@
 	bool _12h_mode = !(rtc_register_read(rtc, RTC_STATUS_B) &
 	    RTC_B_24H);
-
 	if (_12h_mode) {
 		/* The RTC is working in 12h mode, check if it is AM or PM */
@@ -378,11 +383,10 @@
 	/* Check if the RTC is working in BCD mode */
 	bcd_mode = !(rtc_register_read(rtc, RTC_STATUS_B) & RTC_B_BCD);
-
 	if (bcd_mode) {
-		t->tm_sec  = bcd2bin(t->tm_sec);
-		t->tm_min  = bcd2bin(t->tm_min);
+		t->tm_sec = bcd2bin(t->tm_sec);
+		t->tm_min = bcd2bin(t->tm_min);
 		t->tm_hour = bcd2bin(t->tm_hour);
 		t->tm_mday = bcd2bin(t->tm_mday);
-		t->tm_mon  = bcd2bin(t->tm_mon);
+		t->tm_mon = bcd2bin(t->tm_mon);
 		t->tm_year = bcd2bin(t->tm_year);
 	}
@@ -414,5 +418,10 @@
 		result = EINVAL;
 	else {
-		rtc->boottime = r - uptime_get();
+		struct timeval uptime;
+
+		getuptime(&uptime);
+		rtc->boot_time.tv_sec = r;
+		rtc->boot_time.tv_usec = t->tm_usec;	/* normalized */
+		tv_sub(&rtc->boot_time, &uptime);
 		result = EOK;
 	}
@@ -435,5 +444,6 @@
 	bool bcd_mode;
 	time_t norm_time;
-	time_t uptime;
+	struct timeval uptime;
+	struct timeval ntv;
 	int  reg_b;
 	int  reg_a;
@@ -445,6 +455,9 @@
 		return EINVAL;
 
-	uptime = uptime_get();
-	if (norm_time <= uptime) {
+	ntv.tv_sec = norm_time;
+	ntv.tv_usec = t->tm_usec;
+	getuptime(&uptime);
+
+	if (tv_gteq(&uptime, &ntv)) {
 		/* This is not acceptable */
 		return EINVAL;
@@ -458,6 +471,7 @@
 	}
 
-	/* boottime must be recomputed */
-	rtc->boottime = 0;
+	/* boot_time must be recomputed */
+	rtc->boot_time.tv_sec = 0;
+	rtc->boot_time.tv_usec = 0;
 
 	/* Detect the RTC epoch */
@@ -731,14 +745,4 @@
 }
 
-static time_t
-uptime_get(void)
-{
-	struct timeval tv;
-
-	getuptime(&tv);
-
-	return tv.tv_sec;
-}
-
 static int
 rtc_fun_online(ddf_fun_t *fun)
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/lib/c/generic/async.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -820,5 +820,5 @@
 	if (usecs) {
 		getuptime(&conn->wdata.to_event.expires);
-		tv_add(&conn->wdata.to_event.expires, usecs);
+		tv_add_diff(&conn->wdata.to_event.expires, usecs);
 	} else
 		conn->wdata.to_event.inlist = false;
@@ -1214,5 +1214,6 @@
 
 			} else {
-				timeout = tv_sub(&waiter->to_event.expires, &tv);
+				timeout = tv_sub_diff(&waiter->to_event.expires,
+				    &tv);
 				futex_up(&async_futex);
 			}
@@ -1505,5 +1506,5 @@
 
 	getuptime(&msg->wdata.to_event.expires);
-	tv_add(&msg->wdata.to_event.expires, timeout);
+	tv_add_diff(&msg->wdata.to_event.expires, timeout);
 	
 	/*
@@ -1587,5 +1588,5 @@
 	
 	getuptime(&msg->wdata.to_event.expires);
-	tv_add(&msg->wdata.to_event.expires, timeout);
+	tv_add_diff(&msg->wdata.to_event.expires, timeout);
 	
 	futex_down(&async_futex);
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/lib/c/generic/fibril_synch.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -380,5 +380,5 @@
 	if (timeout) {
 		getuptime(&wdata.to_event.expires);
-		tv_add(&wdata.to_event.expires, timeout);
+		tv_add_diff(&wdata.to_event.expires, timeout);
 		async_insert_timeout(&wdata);
 	}
Index: uspace/lib/c/generic/io/console.c
===================================================================
--- uspace/lib/c/generic/io/console.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/lib/c/generic/io/console.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -259,5 +259,5 @@
 	struct timeval t1;
 	gettimeofday(&t1, NULL);
-	*timeout -= tv_sub(&t1, &t0);
+	*timeout -= tv_sub_diff(&t1, &t0);
 	
 	return true;
Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/lib/c/generic/time.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -59,4 +59,5 @@
 #define MINS_PER_HOUR  60
 #define SECS_PER_MIN   60
+#define USECS_PER_SEC  1000000
 #define MINS_PER_DAY   (MINS_PER_HOUR * HOURS_PER_DAY)
 #define SECS_PER_HOUR  (SECS_PER_MIN * MINS_PER_HOUR)
@@ -252,16 +253,17 @@
  * Optionally add specified amount of seconds.
  *
- * @param tm      Broken-down time to normalize.
- * @param sec_add Seconds to add.
+ * @param tm Broken-down time to normalize.
+ * @param tv Timeval to add.
  *
  * @return 0 on success, -1 on overflow
  *
  */
-static int normalize_time(struct tm *tm, time_t sec_add)
+static int normalize_tm_tv(struct tm *tm, const struct timeval *tv)
 {
 	// TODO: DST correction
 	
 	/* Set initial values. */
-	time_t sec = tm->tm_sec + sec_add;
+	time_t usec = tm->tm_usec + tv->tv_usec;
+	time_t sec = tm->tm_sec + tv->tv_sec;
 	time_t min = tm->tm_min;
 	time_t hour = tm->tm_hour;
@@ -271,4 +273,6 @@
 	
 	/* Adjust time. */
+	sec += floor_div(usec, USECS_PER_SEC);
+	usec = floor_mod(usec, USECS_PER_SEC);
 	min += floor_div(sec, SECS_PER_MIN);
 	sec = floor_mod(sec, SECS_PER_MIN);
@@ -319,4 +323,5 @@
 	
 	/* And put the values back to the struct. */
+	tm->tm_usec = (int) usec;
 	tm->tm_sec = (int) sec;
 	tm->tm_min = (int) min;
@@ -335,4 +340,15 @@
 }
 
+static int normalize_tm_time(struct tm *tm, time_t time)
+{
+	struct timeval tv = {
+		.tv_sec = time,
+		.tv_usec = 0
+	};
+
+	return normalize_tm_tv(tm, &tv);
+}
+
+
 /** Which day the week-based year starts on.
  *
@@ -442,4 +458,16 @@
 }
 
+static void tv_normalize(struct timeval *tv)
+{
+	while (tv->tv_usec > USECS_PER_SEC) {
+		tv->tv_sec++;
+		tv->tv_usec -= USECS_PER_SEC;
+	}
+	while (tv->tv_usec < 0) {
+		tv->tv_sec--;
+		tv->tv_usec += USECS_PER_SEC;
+	}
+}
+
 /** Add microseconds to given timeval.
  *
@@ -448,19 +476,27 @@
  *
  */
-void tv_add(struct timeval *tv, suseconds_t usecs)
-{
-	tv->tv_sec += usecs / 1000000;
-	tv->tv_usec += usecs % 1000000;
-	
-	if (tv->tv_usec > 1000000) {
-		tv->tv_sec++;
-		tv->tv_usec -= 1000000;
-	}
-}
-
-/** Subtract two timevals.
+void tv_add_diff(struct timeval *tv, suseconds_t usecs)
+{
+	tv->tv_sec += usecs / USECS_PER_SEC;
+	tv->tv_usec += usecs % USECS_PER_SEC;
+	tv_normalize(tv);
+}
+
+/** Add two timevals.
  *
  * @param tv1 First timeval.
  * @param tv2 Second timeval.
+ */
+void tv_add(struct timeval *tv1, struct timeval *tv2)
+{
+	tv1->tv_sec += tv2->tv_sec;
+	tv1->tv_usec += tv2->tv_usec;
+	tv_normalize(tv1);
+}
+
+/** Subtract two timevals.
+ *
+ * @param tv1 First timeval.
+ * @param tv2 Second timeval.
  *
  * @return Difference between tv1 and tv2 (tv1 - tv2) in
@@ -468,8 +504,21 @@
  *
  */
-suseconds_t tv_sub(struct timeval *tv1, struct timeval *tv2)
+suseconds_t tv_sub_diff(struct timeval *tv1, struct timeval *tv2)
 {
 	return (tv1->tv_usec - tv2->tv_usec) +
-	    ((tv1->tv_sec - tv2->tv_sec) * 1000000);
+	    ((tv1->tv_sec - tv2->tv_sec) * USECS_PER_SEC);
+}
+
+/** Subtract two timevals.
+ *
+ * @param tv1 First timeval.
+ * @param tv2 Second timeval.
+ *
+ */
+void tv_sub(struct timeval *tv1, struct timeval *tv2)
+{
+	tv1->tv_sec -= tv2->tv_sec;
+	tv1->tv_usec -= tv2->tv_usec;
+	tv_normalize(tv1);
 }
 
@@ -573,5 +622,5 @@
 		goto fallback;
 	
-	tv->tv_usec = 0;
+	tv->tv_usec = time.tm_usec;
 	tv->tv_sec = mktime(&time);
 	
@@ -689,5 +738,5 @@
 	// TODO: detect overflow
 	
-	normalize_time(tm, 0);
+	normalize_tm_time(tm, 0);
 	return secs_since_epoch(tm);
 }
@@ -944,4 +993,5 @@
 	
 	/* Set result to epoch. */
+	result->tm_usec = 0;
 	result->tm_sec = 0;
 	result->tm_min = 0;
@@ -951,5 +1001,5 @@
 	result->tm_year = 70; /* 1970 */
 	
-	if (normalize_time(result, time) == -1)
+	if (normalize_tm_time(result, time) == -1)
 		return EOVERFLOW;
 	
@@ -1014,5 +1064,5 @@
  * Time is expressed relative to the user's specified timezone.
  *
- * @param timer  Time to convert.
+ * @param tv     Timeval to convert.
  * @param result Structure to store the result to.
  *
@@ -1020,5 +1070,5 @@
  *
  */
-int time_local2tm(const time_t time, struct tm *restrict result)
+int time_tv2tm(const struct timeval *tv, struct tm *restrict result)
 {
 	// TODO: Deal with timezones.
@@ -1026,4 +1076,5 @@
 	
 	/* Set result to epoch. */
+	result->tm_usec = 0;
 	result->tm_sec = 0;
 	result->tm_min = 0;
@@ -1033,8 +1084,28 @@
 	result->tm_year = 70; /* 1970 */
 	
-	if (normalize_time(result, time) == -1)
+	if (normalize_tm_tv(result, tv) == -1)
 		return EOVERFLOW;
 	
 	return EOK;
+}
+
+/** Converts a time value to a broken-down local time.
+ *
+ * Time is expressed relative to the user's specified timezone.
+ *
+ * @param timer  Time to convert.
+ * @param result Structure to store the result to.
+ *
+ * @return EOK on success or a negative error code.
+ *
+ */
+int time_local2tm(const time_t time, struct tm *restrict result)
+{
+	struct timeval tv = {
+		.tv_sec = time,
+		.tv_usec = 0
+	};
+
+	return time_tv2tm(&tv, result);
 }
 
Index: uspace/lib/c/include/sys/time.h
===================================================================
--- uspace/lib/c/include/sys/time.h	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/lib/c/include/sys/time.h	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -50,4 +50,5 @@
 
 struct tm {
+	int tm_usec;   /* Microseconds [0,999999]. */
 	int tm_sec;    /* Seconds [0,60]. */
 	int tm_min;    /* Minutes [0,59]. */
@@ -71,6 +72,8 @@
 };
 
-extern void tv_add(struct timeval *, suseconds_t);
-extern suseconds_t tv_sub(struct timeval *, struct timeval *);
+extern void tv_add_diff(struct timeval *, suseconds_t);
+extern void tv_add(struct timeval *, struct timeval *);
+extern suseconds_t tv_sub_diff(struct timeval *, struct timeval *);
+extern void tv_sub(struct timeval *, struct timeval *);
 extern int tv_gt(struct timeval *, struct timeval *);
 extern int tv_gteq(struct timeval *, struct timeval *);
@@ -85,4 +88,5 @@
 extern int time_utc2str(const time_t, char *);
 extern void time_tm2str(const struct tm *, char *);
+extern int time_tv2tm(const struct timeval *, struct tm *);
 extern int time_local2tm(const time_t, struct tm *);
 extern int time_local2str(const time_t, char *);
Index: uspace/lib/usbdev/src/hub.c
===================================================================
--- uspace/lib/usbdev/src/hub.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/lib/usbdev/src/hub.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -229,5 +229,5 @@
 	 * above might use much of this time so we should only wait to fill
 	 * up the 100ms quota*/
-	const suseconds_t elapsed = tv_sub(&end_time, &start_time);
+	const suseconds_t elapsed = tv_sub_diff(&end_time, &start_time);
 	if (elapsed < 100000) {
 		async_usleep(100000 - elapsed);
Index: uspace/srv/audio/hound/audio_device.c
===================================================================
--- uspace/srv/audio/hound/audio_device.c	(revision c0c38c7c377b0a40d556f2b53fa830176a19d761)
+++ uspace/srv/audio/hound/audio_device.c	(revision 7f9d97f3ef14161b0334989eea3a64581e2c86cc)
@@ -279,5 +279,5 @@
 			getuptime(&time2);
 			log_verbose("Time to mix sources: %li\n",
-			    tv_sub(&time2, &time1));
+			    tv_sub_diff(&time2, &time1));
 			break;
 		}
