kern

changeset 36:e70b1ab9613e

- added cmos rtc code - added time/date functions in klibc - implemented an iowait macro with output to 0x80
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 10 Jun 2011 05:33:38 +0300
parents 06172322fb76
children 2c401f69128e
files src/asmops.h src/klibc/time.c src/klibc/time.h src/main.c src/rtc.c src/rtc.h
diffstat 6 files changed, 215 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- a/src/asmops.h	Thu Jun 09 05:09:49 2011 +0300
     1.2 +++ b/src/asmops.h	Fri Jun 10 05:33:38 2011 +0300
     1.3 @@ -32,4 +32,6 @@
     1.4  	"outl %0, %1\n\t" \
     1.5  	:: "a" ((unsigned long)(src)), "dN" ((unsigned short)(port)))
     1.6  
     1.7 +#define iodelay() outb(0, 0x80)
     1.8 +
     1.9  #endif	/* ASMOPS_H_ */
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/klibc/time.c	Fri Jun 10 05:33:38 2011 +0300
     2.3 @@ -0,0 +1,70 @@
     2.4 +#include <stdio.h>
     2.5 +#include "time.h"
     2.6 +
     2.7 +#define MINSEC		60
     2.8 +#define HOURSEC		(60 * MINSEC)
     2.9 +#define DAYSEC		(24 * HOURSEC)
    2.10 +
    2.11 +static int is_leap_year(int yr);
    2.12 +
    2.13 +
    2.14 +static char *wday[] = {
    2.15 +	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    2.16 +};
    2.17 +static char *mon[] = {
    2.18 +	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
    2.19 +	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    2.20 +};
    2.21 +
    2.22 +
    2.23 +char *asctime(struct tm *tm)
    2.24 +{
    2.25 +	static char buf[64];
    2.26 +
    2.27 +	sprintf(buf, "%s %s %d %02d:%02d:%02d %d\n", wday[tm->tm_wday],
    2.28 +			mon[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
    2.29 +			tm->tm_sec, tm->tm_year + 1900);
    2.30 +	return buf;
    2.31 +}
    2.32 +
    2.33 +time_t mktime(struct tm *tm)
    2.34 +{
    2.35 +	int i, num_years = tm->tm_year - 70;
    2.36 +	int year = 1970;
    2.37 +	int days = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1);
    2.38 +
    2.39 +	for(i=0; i<num_years; i++) {
    2.40 +		days += is_leap_year(year++) ? 366 : 365;
    2.41 +	}
    2.42 +
    2.43 +	return (time_t)days * DAYSEC + tm->tm_hour * HOURSEC +
    2.44 +		tm->tm_min * MINSEC + tm->tm_sec;
    2.45 +}
    2.46 +
    2.47 +int day_of_year(int year, int mon, int day)
    2.48 +{
    2.49 +	static int commdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    2.50 +	static int leapdays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    2.51 +	int *mdays, i, yday;
    2.52 +
    2.53 +	mdays = is_leap_year(year) ? leapdays : commdays;
    2.54 +
    2.55 +	yday = day;
    2.56 +	for(i=0; i<mon; i++) {
    2.57 +		yday += mdays[i];
    2.58 +	}
    2.59 +	return yday;
    2.60 +}
    2.61 +
    2.62 +static int is_leap_year(int yr)
    2.63 +{
    2.64 +	/* exceptions first */
    2.65 +	if(yr % 400 == 0) {
    2.66 +		return 1;
    2.67 +	}
    2.68 +	if(yr % 100 == 0) {
    2.69 +		return 0;
    2.70 +	}
    2.71 +	/* standard case */
    2.72 +	return yr % 4 == 0;
    2.73 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/klibc/time.h	Fri Jun 10 05:33:38 2011 +0300
     3.3 @@ -0,0 +1,25 @@
     3.4 +#ifndef _TIME_H_
     3.5 +#define _TIME_H_
     3.6 +
     3.7 +typedef long time_t;
     3.8 +
     3.9 +struct tm {
    3.10 +	int tm_sec;
    3.11 +	int tm_min;
    3.12 +	int tm_hour;
    3.13 +	int tm_mday;
    3.14 +	int tm_mon;
    3.15 +	int tm_year;
    3.16 +	int tm_wday;
    3.17 +	int tm_yday;
    3.18 +	int tm_isdst;
    3.19 +};
    3.20 +
    3.21 +char *asctime(struct tm *tm);
    3.22 +time_t mktime(struct tm *tm);
    3.23 +
    3.24 +/* non-standard helpers */
    3.25 +int day_of_year(int year, int mon, int day);
    3.26 +
    3.27 +
    3.28 +#endif	/* _TIME_H_ */
     4.1 --- a/src/main.c	Thu Jun 09 05:09:49 2011 +0300
     4.2 +++ b/src/main.c	Fri Jun 10 05:33:38 2011 +0300
     4.3 @@ -5,6 +5,7 @@
     4.4  #include "asmops.h"
     4.5  #include "segm.h"
     4.6  #include "intr.h"
     4.7 +#include "rtc.h"
     4.8  #include "timer.h"
     4.9  #include "mem.h"
    4.10  #include "vm.h"
    4.11 @@ -54,6 +55,7 @@
    4.12  	init_segm();
    4.13  	init_intr();
    4.14  
    4.15 +	init_rtc();
    4.16  	init_timer();
    4.17  
    4.18  	/* initialize the physical memory manager */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/rtc.c	Fri Jun 10 05:33:38 2011 +0300
     5.3 @@ -0,0 +1,109 @@
     5.4 +#include <stdio.h>
     5.5 +#include <time.h>
     5.6 +#include <asmops.h>
     5.7 +
     5.8 +/* CMOS I/O ports */
     5.9 +#define PORT_CTL	0x70
    5.10 +#define PORT_DATA	0x71
    5.11 +
    5.12 +/* CMOS RTC registers */
    5.13 +#define REG_SEC			0
    5.14 +#define REG_ALARM_SEC	1
    5.15 +#define REG_MIN			2
    5.16 +#define REG_ALARM_MIN	3
    5.17 +#define REG_HOUR		4
    5.18 +#define REG_ALARM_HOUR	5
    5.19 +#define REG_WEEKDAY		6
    5.20 +#define REG_DAY			7
    5.21 +#define REG_MONTH		8
    5.22 +#define REG_YEAR		9
    5.23 +#define REG_STATA		10
    5.24 +#define REG_STATB		11
    5.25 +#define REG_STATC		12
    5.26 +#define REG_STATD		13
    5.27 +
    5.28 +#define STATA_BUSY	(1 << 7)
    5.29 +#define STATB_24HR	(1 << 1)
    5.30 +#define STATB_BIN	(1 << 2)
    5.31 +
    5.32 +#define HOUR_PM_BIT		(1 << 7)
    5.33 +
    5.34 +#define BCD_TO_BIN(x)	((((x) >> 4) & 0xf) * 10 + ((x) & 0xf))
    5.35 +
    5.36 +static void read_rtc(struct tm *tm);
    5.37 +static int read_reg(int reg);
    5.38 +
    5.39 +static unsigned long start_time;
    5.40 +
    5.41 +
    5.42 +void init_rtc(void)
    5.43 +{
    5.44 +	struct tm tm;
    5.45 +
    5.46 +	read_rtc(&tm);
    5.47 +	printf("System real-time clock: %s", asctime(&tm));
    5.48 +	printf("time_t: %ld\n", mktime(&tm));
    5.49 +}
    5.50 +
    5.51 +static void read_rtc(struct tm *tm)
    5.52 +{
    5.53 +	int statb, pm;
    5.54 +
    5.55 +	/* wait for any clock updates to finish */
    5.56 +	while(read_reg(REG_STATA) & STATA_BUSY);
    5.57 +
    5.58 +	tm->tm_sec = read_reg(REG_SEC);
    5.59 +	tm->tm_min = read_reg(REG_MIN);
    5.60 +	tm->tm_hour = read_reg(REG_HOUR);
    5.61 +	tm->tm_mday = read_reg(REG_DAY);
    5.62 +	tm->tm_mon = read_reg(REG_MONTH);
    5.63 +	tm->tm_year = read_reg(REG_YEAR);
    5.64 +	tm->tm_wday = read_reg(REG_WEEKDAY);
    5.65 +
    5.66 +	/* in 12hour mode, bit 7 means post-meridiem */
    5.67 +	pm = tm->tm_hour & HOUR_PM_BIT;
    5.68 +	tm->tm_hour &= ~HOUR_PM_BIT;
    5.69 +
    5.70 +	/* convert to binary if needed */
    5.71 +	statb = read_reg(REG_STATB);
    5.72 +	if(!(statb & STATB_BIN)) {
    5.73 +		tm->tm_sec = BCD_TO_BIN(tm->tm_sec);
    5.74 +		tm->tm_min = BCD_TO_BIN(tm->tm_min);
    5.75 +		tm->tm_hour = BCD_TO_BIN(tm->tm_hour);
    5.76 +		tm->tm_mday = BCD_TO_BIN(tm->tm_mday);
    5.77 +		tm->tm_mon = BCD_TO_BIN(tm->tm_mon);
    5.78 +		tm->tm_year = BCD_TO_BIN(tm->tm_year);
    5.79 +		tm->tm_wday = BCD_TO_BIN(tm->tm_wday);
    5.80 +	}
    5.81 +
    5.82 +	/* make the year an offset from 1900 */
    5.83 +	if(tm->tm_year < 100) {
    5.84 +		tm->tm_year += 100;
    5.85 +	} else {
    5.86 +		tm->tm_year -= 1900;
    5.87 +	}
    5.88 +
    5.89 +	/* if tm_hour is in 12h mode, convert to 24h */
    5.90 +	if(!(statb & STATB_24HR)) {
    5.91 +		if(tm->tm_hour == 12) {
    5.92 +			tm->tm_hour = 0;
    5.93 +		}
    5.94 +		if(pm) {
    5.95 +			tm->tm_hour += 12;
    5.96 +		}
    5.97 +	}
    5.98 +
    5.99 +	tm->tm_mon -= 1;	/* we want months to start from 0 */
   5.100 +	tm->tm_wday -= 1;	/* we want weekdays to start from 0 */
   5.101 +	tm->tm_yday = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1);
   5.102 +}
   5.103 +
   5.104 +static int read_reg(int reg)
   5.105 +{
   5.106 +	unsigned char val;
   5.107 +	outb(reg, PORT_CTL);
   5.108 +	iodelay();
   5.109 +	inb(val, PORT_DATA);
   5.110 +	iodelay();
   5.111 +	return val;
   5.112 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/rtc.h	Fri Jun 10 05:33:38 2011 +0300
     6.3 @@ -0,0 +1,7 @@
     6.4 +#ifndef _RTC_H_
     6.5 +#define _RTC_H_
     6.6 +
     6.7 +void init_rtc(void);
     6.8 +
     6.9 +
    6.10 +#endif	/* _RTC_H_ */