Verified Commit 3e5a94d6 authored by Allie Sargente's avatar Allie Sargente 😑

Added a RTC driver

Moved multiboot into it's own file
Signed-off-by: Allie Sargente's avatarAllison Sargente <[email protected]>
parent e29ec663
No preview for this file type
No preview for this file type
No preview for this file type
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (c) 2019 Apollo Project Developers ;;
;; For terms, see LICENSE ;;
;; multiboot.s - talk to multiboot ;;
;; This will eventually have multiboot 2 as well ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[GLOBAL mboot]
; Multiboot Macro Definitions
MULTIBOOT_PAGE_ALIGN equ 1<<0
MULTIBOOT_MEMORY_INFO equ 1<<1
MULTIBOOT_VIDEO_MODE equ 1<<2
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
MULTIBOOT_HEADER_FLAGS equ (MULTIBOOT_PAGE_ALIGN + MULTIBOOT_MEMORY_INFO)
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
; Multiboot Header
;==================
section .init
align 32
; This is the multiboot header.
mboot:
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd MULTIBOOT_CHECKSUM
; Multiboot Padding
section .init.bss nobits
pd: resb 0x1000
pt: resb 0x1000
/*
* (c) 2019 Apollo Developers
* For terms, see LICENSE
* rtc.c - Real time clock and the CMOS backup battery
* TODO: periodic interrupts
*/
#include <sys/hal.h>
#include <arch/x86/ports.h>
#include <arch/x86/cmos.h>
// This is cumulative days, not real "days"
const uint32_t days_from_month[12] = {
// Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
const uint32_t seconds_in_a_day = 86400;
const uint32_t seconds_in_a_year = 31536000;
static void read_RTC(cmos_register_t cmos);
// Returns number of leap days since beginning of epoch (January 1970)
// This doesn't work for divisible by 100 non-leap years (2100, for example)
// TODO: Fix that ^
int leap_days(uint8_t year, uint8_t month)
{
int days;
year -= 1972; // 1972 was a leap year (good starting point)
days = (year / 4) + 1; // Add one for 1972
// If it's not march or later in a leap year, fix the off by one error
if ((year/4 == 0) && (month <= 2)) {
days--;
}
return days;
}
// Returns the number of seconds since January 1st, 1970.
uint32_t get_time()
{
uint32_t time;
// Init one of these so gcc doesn't yell at us
cmos_register_t cmos = {.day = 0};
// Populate cmos
read_RTC(cmos);
// Start adding seconds
time = cmos.second;
time += cmos.minute * 60;
time += cmos.hour * 3600;
time += cmos.day * seconds_in_a_day;
time += days_from_month[cmos.month] * seconds_in_a_day;
time += (cmos.year - 1970) * seconds_in_a_year;
// Add in Leap year's extra days
time += (leap_days(cmos.year, cmos.month) * seconds_in_a_day);
return time;
}
static uint8_t get_CMOS_register(uint8_t reg)
{
// It's important for this to be atomic, since we're grabbing a timestamp
int interrupt_state = get_interrupt_state();
uint8_t ret;
disable_interrupts();
outb(CMOS_INDEX_PORT, reg);
ret = inb(CMOS_DATA_PORT);
set_interrupt_state(interrupt_state);
return ret;
}
static int cmos_update_in_progress()
{
uint8_t ret;
ret = get_CMOS_register(CMOS_REGISTER_STATUSA);
return ret & 0x80;
}
static void read_RTC(cmos_register_t cmos)
{
while(cmos_update_in_progress()); // Wait until CMOS finished an update
cmos.second = get_CMOS_register(CMOS_REGISTER_SECOND);
cmos.minute = get_CMOS_register(CMOS_REGISTER_MINUTE);
cmos.hour = get_CMOS_register(CMOS_REGISTER_HOUR);
cmos.day = get_CMOS_register(CMOS_REGISTER_DAY);
cmos.month = get_CMOS_register(CMOS_REGISTER_MONTH);
cmos.year = get_CMOS_register(CMOS_REGISTER_YEAR);
cmos.registera = get_CMOS_register(CMOS_REGISTER_STATUSA);
cmos.registerb = get_CMOS_register(CMOS_REGISTER_STATUSB);
cmos.registerc = get_CMOS_register(CMOS_REGISTER_STATUSC);
cmos.registerd = get_CMOS_register(CMOS_REGISTER_STATUSD);
// Check if the time is in BCD format
if (!(cmos.registerb & CMOS_BINARY_DATE_MODE)) {
// Convert out of BCD, very simple
cmos.second = (cmos.second & 0xF) + ((cmos.second / 16) * 10);
cmos.minute = (cmos.minute & 0xF) + ((cmos.minute / 16) * 10);
cmos.hour = (cmos.hour & 0xF) + ((cmos.hour / 16) * 10);
cmos.day = (cmos.day & 0xF) + ((cmos.day / 16) * 10);
cmos.month = (cmos.month & 0xF) + ((cmos.month / 16) * 10);
cmos.year = (cmos.year & 0xF) + ((cmos.year / 16) * 10);
}
// Assume it's not 21xx year
cmos.year += 2000;
}
......@@ -4,24 +4,10 @@
;; start.s - x86 bootloader passover ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Multiboot Macro Definitions
MULTIBOOT_PAGE_ALIGN equ 1<<0
MULTIBOOT_MEMORY_INFO equ 1<<1
MULTIBOOT_VIDEO_MODE equ 1<<2
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
MULTIBOOT_HEADER_FLAGS equ (MULTIBOOT_PAGE_ALIGN + MULTIBOOT_MEMORY_INFO)
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
; Kernel Stack size definition up here for visibility
KERNEL_STACK_SIZE equ 0x4000
[BITS 32]
[GLOBAL mboot]
[GLOBAL start]
[EXTERN arch_init]
[GLOBAL KERNEL_STACK]
......@@ -29,21 +15,6 @@ KERNEL_STACK_SIZE equ 0x4000
[EXTERN bss]
[EXTERN end]
; Multiboot Header
;==================
section .init
align 32
; This is the multiboot header.
mboot:
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd MULTIBOOT_CHECKSUM
resb 0x24 ; just some more space for rest of the header
;==========================;
; Bootloader dropoff point ;
;==========================;
......@@ -61,11 +32,6 @@ start:
jmp $ ; In case we get an NMI
;;;;;;;;;;;;;;;;;;;;;;;;;
; Multiboot Padding
section .init.bss nobits
pd: resb 0x1000
pt: resb 0x1000
; Stack
;=======
section .bss
......
/*
* <arch/x86/cmos.h> - RTC and CMOS definitions
*/
#ifndef __ARCH_X86_CMOS_H
#define __ARCH_X86_CMOS_H
#include <stdint.h>
typedef struct cmos_register {
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t day;
uint8_t month;
uint8_t year;
uint8_t century;
uint8_t registera;
uint8_t registerb;
uint8_t registerc;
uint8_t registerd;
} cmos_register_t;
#define CMOS_INDEX_PORT 0x70
#define CMOS_DATA_PORT 0x71
#define CMOS_REGISTER_SECOND 0x00
#define CMOS_REGISTER_MINUTE 0x02
#define CMOS_REGISTER_HOUR 0x04
#define CMOS_REGISTER_DAY 0x07
#define CMOS_REGISTER_MONTH 0x08
#define CMOS_REGISTER_YEAR 0x09
#define CMOS_REGISTER_STATUSA 0x0A
#define CMOS_REGISTER_STATUSB 0x0B
#define CMOS_REGISTER_STATUSC 0x0C
#define CMOS_REGISTER_STATUSD 0x0D
#define CMOS_BASE_FREQUENCY 32768
// Register A flags
#define CMOS_UPDATE_IN_PROGRESS 0x80
// Bits 4-6 are frequency divider for base clock, you shouldn't touch that
// Bits 0-3 are the interrupt frequency divider
// Register B flags
#define CMOS_UPDATE_CLOCK 0x80
#define CMOS_PERIODIC_INTERRUPT 0x40
#define CMOS_ALARM_INTERRUPT 0x20
#define CMOS_UPDATE_ENDED_INT 0x10
#define CMOS_SQUARE_WAVE 0x08
#define CMOS_BINARY_DATE_MODE 0x04
#define CMOS_24_HOUR_MODE 0x02
#define CMOS_DAYLIGHT_SAVINGS 0x01
// Register C flag
#define CMOS_INTERRUPT_REQUEST 0x80
#define CMOS_INTERRUPT_OCCURED 0x40
#define CMOS_ALARM_OCCURED 0x20
#define CMOS_UPDATE_ENDED_OCCURED 0x10
// Bottom 4 bits are reserved
// Register D flags
#define CMOS_VALID_RAM 0x80
// The bottom 7 bits are reserved.
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment