refactor ioe

This commit is contained in:
Yanyan Jiang 2018-03-25 17:26:12 +08:00
parent 1722e218ef
commit 65b64ea58c
6 changed files with 159 additions and 161 deletions

View File

@ -1,49 +1,33 @@
# AM Devices
[TOC]
设备相关的宏定义在`amdev.h`。设备id为32位十六进制数。
设备相关的宏定义在`dev.h`。设备id为32位十六进制数。
**对于读/写寄存器是结构体的size必须与结构体一致否则行为未定义**。
**对于读/写寄存器是结构体的size必须与结构体一致否则行为未定义**。PCI Conf Space、ATA控制器等支持不同数量字节的读写。
| 设备ID | 设备功能 | 设备描述 |
| --------- | ---------------------------------------- | ------- |
| 0000 ac01 | 若干32位寄存器编号从0开始 | AM性能计数器 |
| 0000 ac02 | | AM Input |
| 0000 ac03 | 从0号寄存器读出系统启动到当前的毫秒数(32bit) | AM定时器 |
| 0000 ac04 | 向1 2 3 4 5写入参数向0写入非0数值绘图。向0写入0重绘屏幕 | AM显示控制器 |
| 0000 0080 | 寄存器为configuration space地址(bus, slot, func, offset组成) | PCI控制器 |
| 0000 0dd0 | ? | ATA控制器0 |
| 0000 0dd1 | ? | ATA控制器1 |
| 0000 ac01 | 若干性能相关的计数器(ro)。 | AM性能计数器 |
| 0000 ac02 | 键盘控制器(#1, ro)。 | AM输入设备 |
| 0000 ac03 | 系统启动时间(#1, ro)和实时日期(#2, ro)。 | AM定时器 |
| 0000 ac04 | 屏幕信息(#1, ro)和显存控制(#2, wo)。 | AM显示控制器 |
| 0000 0080 | PCI Configuration Space (bus, slot, func, offset, rw)。 | PCI控制器 |
| 0000 0dd0 | ATA主控制器(#1-#7, rw)。 | ATA控制器0 |
| 0000 0dd1 | ATA从控制器(#1-#7, rw)。 | ATA控制器1 |
## 0000 ac01 - AM PerfCnt
## 0000 ac02 - AM Input
从`_DEV_INPUT_REG_KBD` (#1)中读出32位整数其中`_KEY_XXX`为keyup事件`_KEY_XXX | 0x8000`为keydown事件
1. (`_DEVREG_INPUT_KBD`): AM键盘控制器。从中读出`_KbdReg`结构体,`keydown`为是否按下;`keycode`为扫描码(`_KEY_XXX`)。没有按键时`keycode = _KEY_NONE`
## 0000 ac03 - AM Timer
从`_DEV_TIMER_REG_UPTIME` (#1)中读出如下结构体:
```
typedef struct _Dev_Timer_Uptime {
uint32_t hi, lo;
} _Dev_Timer_Uptime;
```
1. (`_DEVREG_TIMER_UPTIME`): AM系统启动时间。从中读出`_UptimeReg`结构体,`(hi << 32LL) | lo`是系统启动的毫秒数
2. (`_DEVREG_TIMER_DATE`): AM实时时钟(Real Time Clock)。从中读出`_DateReg`,包含年月日时分秒。
## 0000 ac04 - AM Video
`_DEV_VIDEO_REG_INFO` (#1)中读出如下结构体,其中`width`为屏幕宽度、`height`为屏幕高度。假设AM运行过程中屏幕大小不发生变化
```
typedef struct _Dev_Video_Info {
int32_t width, height;
} _Dev_Video_Info;
```
向`_DEV_VIDEO_REG_FBCTL` (#2)中写入如下结构体,向(`x`,`y`)坐标处绘制`w`*`h`的矩形图案,像素按行优先存储在`pixels`。每个32位整数以`00RRGGBB`描述颜色:
typedef struct _Dev_Video_FBCtl {
int x, y, w, h, sync;
uint32_t *pixels;
} _Dev_Video_FBCtl;
1. (`_DEVREG_VIDEO_INFO`): AM显示控制器信息。从中读出`_VideoInfoReg`结构体。其中`width`为屏幕宽度、`height`为屏幕高度。假设AM运行过程中屏幕大小不发生变化。
2. (`_DEVREG_VIDEO_FBCTL`): AM帧缓冲控制器向其中写入`_FBCtlReg`结构体,向屏幕(`x`,`y`)坐标处绘制`w`*`h`的矩形图案,像素按行优先存储在`pixels`。每个32位整数以`00RRGGBB`描述颜色。
## 0000 0080 - PCI Configuration space
## 0000 0dd0 - ATA0

View File

@ -6,10 +6,12 @@
// =========================== AM Devices ============================
// ((_Device *)dev)->id
// AM virtual devices
#define _DEV_PERFCNT 0x0000ac01
#define _DEV_INPUT 0x0000ac02
#define _DEV_TIMER 0x0000ac03
#define _DEV_VIDEO 0x0000ac04
// Other physical devices
#define _DEV_PCICONF 0x00000080
#define _DEV_ATA0 0x00000dd0
#define _DEV_ATA1 0x00000dd1
@ -58,7 +60,7 @@
// ----------- _DEV_VIDEO: AM Video Controller (0000ac04) ------------
#define _DEVREG_VIDEO_INFO 1
typedef struct {
int32_t width, height; // screen size
int32_t width, height; // screen size: @width * @height
} _VideoInfoReg;
#define _DEVREG_VIDEO_FBCTL 2

View File

@ -0,0 +1,44 @@
#include <am.h>
#include <amdev.h>
#include <x86.h>
static int scan_code[] = {
0,
1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
41, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 43,
58, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 28,
42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
29, 91, 56, 57, 56, 29,
72, 80, 75, 77, 0, 0, 0, 0, 0, 0
};
size_t input_read(uintptr_t reg, void *buf, size_t size) {
_KbdReg *kbd = (_KbdReg *)buf;
int status = inb(0x64);
kbd->keydown = 0;
kbd->keycode = _KEY_NONE;
if ((status & 0x1) == 0) {
} else {
if (status & 0x20) { // mouse
} else {
int code = inb(0x60) & 0xff;
for (unsigned int i = 0; i < sizeof(scan_code) / sizeof(int); i ++) {
if (scan_code[i] == 0) continue;
if (scan_code[i] == code) {
kbd->keydown = 1;
kbd->keycode = i;
break;
} else if (scan_code[i] + 128 == code) {
kbd->keydown = 0;
kbd->keycode = i;
break;
}
}
}
}
return sizeof(*kbd);
}

View File

@ -0,0 +1,86 @@
#include <am.h>
#include <amdev.h>
#include <x86.h>
static _RTCReg boot_date;
static uint32_t freq_mhz;
uint64_t uptsc;
static inline uint64_t rdtsc() {
uint32_t lo, hi;
asm volatile ("rdtsc": "=a"(lo), "=d"(hi));
return ((uint64_t)hi << 32) | lo;
}
static int read_rtc(int reg) {
outb(0x70, reg);
int ret = inb(0x71);
return (ret & 0xf) + (ret >> 4) * 10;
}
static void wait_sec() {
while (1) {
int volatile s1 = read_rtc(0);
for (int volatile i = 0; i < 1000; i++) ;
int volatile s2 = read_rtc(0);
if (s1 != s2) {
return;
}
}
}
static uint32_t estimate_freq() {
int h, m, s, t1, t2;
uint64_t tsc1, tsc2;
wait_sec();
tsc1 = rdtsc();
h = read_rtc(4); m = read_rtc(2); s = read_rtc(0);
t1 = h * 3600 + m * 60 + s;
wait_sec();
tsc2 = rdtsc();
h = read_rtc(4); m = read_rtc(2); s = read_rtc(0);
t2 = h * 3600 + m * 60 + s;
if (t1 >= t2) return 0; // passed a day, unlikely to happen
uint32_t freq = (tsc2 - tsc1) >> 20;
freq /= (t2 - t1);
return freq;
}
static void get_date(_RTCReg *rtc) {
int tmp;
do {
rtc->second = read_rtc(0);
rtc->minute = read_rtc(2);
rtc->hour = read_rtc(4);
rtc->day = read_rtc(7);
rtc->month = read_rtc(8);
rtc->year = read_rtc(9) + 2000;
tmp = read_rtc(0);
} while (tmp != rtc->second);
}
void timer_init() {
freq_mhz = estimate_freq();
get_date(&boot_date);
uptsc = rdtsc();
}
size_t timer_read(uintptr_t reg, void *buf, size_t size) {
switch (reg) {
case _DEVREG_TIMER_UPTIME: {
uint64_t tsc = rdtsc() - uptsc;
uint32_t mticks = (tsc >> 20);
uint32_t ms = mticks * 1000 / freq_mhz;
_UptimeReg *uptime = (_UptimeReg *)buf;
uptime->hi = 0;
uptime->lo = ms;
return sizeof(_UptimeReg);
}
case _DEVREG_TIMER_DATE: {
get_date((_RTCReg *)buf);
return sizeof(_RTCReg);
}
}
return 0;
}

View File

@ -3,73 +3,11 @@
#include <x86.h>
extern "C" { int printf(const char *, ...); }
static uint32_t freq_mhz;
uint64_t uptsc;
static inline uint64_t rdtsc() {
uint32_t lo, hi;
asm volatile ("rdtsc": "=a"(lo), "=d"(hi));
return ((uint64_t)hi << 32) | lo;
}
extern "C" {
extern void vga_init();
static _RTCReg boot_date;
static int read_rtc(int reg) {
outb(0x70, reg);
int ret = inb(0x71);
return (ret & 0xf) + (ret >> 4) * 10;
}
static void wait_sec() {
while (1) {
int volatile s1 = read_rtc(0);
for (int volatile i = 0; i < 1000; i++) ;
int volatile s2 = read_rtc(0);
if (s1 != s2) {
return;
}
}
}
static uint32_t estimate_freq() {
int h, m, s, t1, t2;
uint64_t tsc1, tsc2;
wait_sec();
tsc1 = rdtsc();
h = read_rtc(4); m = read_rtc(2); s = read_rtc(0);
t1 = h * 3600 + m * 60 + s;
wait_sec();
tsc2 = rdtsc();
h = read_rtc(4); m = read_rtc(2); s = read_rtc(0);
t2 = h * 3600 + m * 60 + s;
if (t1 >= t2) return 0; // passed a day, unlikely to happen
uint32_t freq = (tsc2 - tsc1) >> 20;
freq /= (t2 - t1);
return freq;
}
static void get_date(_RTCReg *rtc) {
int tmp;
do {
rtc->second = read_rtc(0);
rtc->minute = read_rtc(2);
rtc->hour = read_rtc(4);
rtc->day = read_rtc(7);
rtc->month = read_rtc(8);
rtc->year = read_rtc(9) + 2000;
tmp = read_rtc(0);
} while (tmp != rtc->second);
}
static void timer_init() {
freq_mhz = estimate_freq();
get_date(&boot_date);
uptsc = rdtsc();
}
extern void timer_init();
int _ioe_init() {
timer_init();
@ -114,66 +52,6 @@ static size_t pciconf_write(uintptr_t reg, void *buf, size_t size) {
return size;
}
static inline int keydown(int e) { return (e & 0x8000) != 0; }
static inline int upevent(int e) { return e; }
static inline int downevent(int e) { return e | 0x8000; }
static size_t input_read(uintptr_t reg, void *buf, size_t size) {
static int scan_code[] = {
0,
1, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88,
41, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 43,
58, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 28,
42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
29, 91, 56, 57, 56, 29,
72, 80, 75, 77, 0, 0, 0, 0, 0, 0
};
int status = inb(0x64), ret = _KEY_NONE;
if ((status & 0x1) == 0) {
ret = _KEY_NONE;
} else {
if (status & 0x20) { // mouse
ret = _KEY_NONE;
} else {
int code = inb(0x60) & 0xff;
for (unsigned int i = 0; i < sizeof(scan_code) / sizeof(int); i ++) {
if (scan_code[i] == 0) continue;
if (scan_code[i] == code) {
ret = downevent(i);
break;
} else if (scan_code[i] + 128 == code) {
ret = upevent(i);
break;
}
}
}
}
*(int *)buf = ret;
return sizeof(int);
}
static size_t timer_read(uintptr_t reg, void *buf, size_t size) {
switch (reg) {
case _DEVREG_TIMER_UPTIME: {
uint64_t tsc = rdtsc() - uptsc;
uint32_t mticks = (tsc >> 20);
uint32_t ms = mticks * 1000 / freq_mhz;
_UptimeReg *uptime = (_UptimeReg *)buf;
uptime->hi = 0;
uptime->lo = ms;
return sizeof(_UptimeReg);
}
case _DEVREG_TIMER_DATE: {
get_date((_RTCReg *)buf);
return sizeof(_RTCReg);
}
}
return 0;
}
static size_t hd_read(uintptr_t reg, void *buf, size_t size) {
*(uint32_t *)buf = port_read(0x1f0 + reg, size);
return 0;
@ -187,13 +65,15 @@ static size_t hd_write(uintptr_t reg, void *buf, size_t size) {
size_t video_read(uintptr_t reg, void *buf, size_t size);
size_t video_write(uintptr_t reg, void *buf, size_t size);
size_t timer_read(uintptr_t reg, void *buf, size_t size);
size_t input_read(uintptr_t reg, void *buf, size_t size);
static _Device x86_dev[] = {
{_DEV_INPUT, "8279 Keyboard Controller", input_read, nullptr},
{_DEV_TIMER, "Dummy Timer", timer_read, nullptr},
{_DEV_VIDEO, "Standard VGA Controller", video_read, video_write},
{_DEV_PCICONF, "PCI Configuration", pciconf_read, pciconf_write},
{_DEV_ATA0, "Primary Parallel ATA Hard Disk Controller", hd_read, hd_write},
{_DEV_TIMER, "RDTSC Timer", timer_read, nullptr},
{_DEV_VIDEO, "Standard VGA Controller", video_read, video_write},
{_DEV_PCICONF, "PCI Configuration", pciconf_read, pciconf_write},
{_DEV_ATA0, "ATA Disk Controller 0", hd_read, hd_write},
};
_Device *_device(int n) {

View File

@ -33,9 +33,11 @@ void gettimeofday(void *rtc) {
int read_key() {
_Device *dev = getdev(&input_dev, _DEV_INPUT);
int32_t key;
dev->read(_DEVREG_INPUT_KBD, &key, sizeof(int32_t));
return key;
_KbdReg key;
dev->read(_DEVREG_INPUT_KBD, &key, sizeof(_KbdReg));
int ret = key.keycode;
if (key.keydown) ret |= 0x8000;
return ret;
}
void draw_rect(uint32_t *pixels, int x, int y, int w, int h) {