refactor ioe
This commit is contained in:
parent
1722e218ef
commit
65b64ea58c
44
DEVICES.md
44
DEVICES.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue