forked from shugaoye/platform_external_v86d
-
Notifications
You must be signed in to change notification settings - Fork 2
/
v86_common.c
156 lines (131 loc) · 3.59 KB
/
v86_common.c
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <string.h>
#include "v86.h"
#define addr(t) (((t & 0xffff0000) >> 12) + (t & 0x0000ffff))
#define vbeib_get_string(name) \
{ \
int l; \
t = addr(ib->name); \
if (t < bufend) { \
ib->name = t - lbuf; \
l = strnlen((char*)buf + ib->name, bufend-t); \
if (buf[ib->name + l] != 0) \
buf[ib->name + l] = 0; \
fsize -= l; \
cbuf += l; \
} else if (t > 0xa0000 && fsize > 0) { \
strncpy((char*)cbuf, vptr(t), fsize); \
l = strnlen((char*)cbuf, fsize); \
if (cbuf[l] != 0) \
cbuf[l] = 0; \
ib->name = tsk->buf_len - fsize; \
l++; \
fsize -= l; \
cbuf += l; \
} else { \
ib->name = 0; \
} \
if (fsize < 0) \
fsize = 0; \
}
int v86_task(struct uvesafb_task *tsk, u8 *buf)
{
u32 lbuf = 0;
ulog(LOG_DEBUG, "task flags: 0x%02x\n", tsk->flags);
ulog(LOG_DEBUG, "EAX=0x%08x EBX=0x%08x ECX=0x%08x EDX=0x%08x\n",
tsk->regs.eax, tsk->regs.ebx, tsk->regs.ecx, tsk->regs.edx);
ulog(LOG_DEBUG, "ESP=0x%08x EBP=0x%08x ESI=0x%08x EDI=0x%08x\n",
tsk->regs.esp, tsk->regs.ebp, tsk->regs.esi, tsk->regs.edi);
/* Get the VBE Info Block */
if (tsk->flags & TF_VBEIB) {
struct vbe_ib *ib;
int fsize;
u32 t, bufend;
u16 *td;
u8 *cbuf;
lbuf = v86_mem_alloc(tsk->buf_len);
if (!lbuf) {
ulog(LOG_ERR, "Memory allocation for a VBE IB buffer failed.");
return -1;
}
memcpy(vptr(lbuf), buf, tsk->buf_len);
tsk->regs.es = lbuf >> 4;
tsk->regs.edi = 0x0000;
if (v86_int(0x10, &tsk->regs) || (tsk->regs.eax & 0xffff) != 0x004f)
goto out_vbeib;
ib = (struct vbe_ib*)buf;
bufend = lbuf + sizeof(*ib);
memcpy(buf, vptr(lbuf), tsk->buf_len);
/* The original VBE Info Block is 512 bytes long. */
fsize = tsk->buf_len - 512;
cbuf = buf + 512;
t = addr(ib->mode_list_ptr);
/* Mode list is in the buffer, we're good. */
if (t < bufend) {
ulog(LOG_DEBUG, "The mode list is in the buffer at %.8x.", t);
ib->mode_list_ptr = t - lbuf;
td = (u16*) (buf + ib->mode_list_ptr);
while (fsize > 2 && *td != 0xffff) {
td++;
t += 2;
fsize -= 2;
cbuf += 2;
}
*td = 0xffff;
cbuf += 2;
fsize -= 2;
/* Mode list is in the ROM. We copy as much of it as we can
* to the task buffer. */
} else if (t > 0xa0000) {
u16 tmp;
ulog(LOG_DEBUG, "The mode list is in the Video ROM at %.8x", t);
td = (u16*)cbuf;
while (fsize > 2 && (tmp = v_rdw(t)) != 0xffff) {
fsize -= 2;
*td = tmp;
td++;
t += 2;
cbuf += 2;
}
ib->mode_list_ptr = 512;
*td = 0xffff;
cbuf += 2;
fsize -= 2;
/* Mode list is somewhere else. We're seriously screwed. */
} else {
ulog(LOG_ERR, "Can't retrieve mode list from %x\n", t);
ib->mode_list_ptr = 0;
}
vbeib_get_string(oem_string_ptr);
vbeib_get_string(oem_vendor_name_ptr);
vbeib_get_string(oem_product_name_ptr);
vbeib_get_string(oem_product_rev_ptr);
out_vbeib:
v86_mem_free(lbuf);
} else {
if (tsk->buf_len) {
lbuf = v86_mem_alloc(tsk->buf_len);
if (!lbuf) {
ulog(LOG_ERR, "Memory allocation for a v86d task buffer failed.");
return -1;
}
memcpy(vptr(lbuf), buf, tsk->buf_len);
}
if (tsk->flags & TF_BUF_ESDI) {
tsk->regs.es = lbuf >> 4;
tsk->regs.edi = 0x0000;
}
if (tsk->flags & TF_BUF_ESBX) {
tsk->regs.es = lbuf >> 4;
tsk->regs.ebx = 0x0000;
}
if (v86_int(0x10, &tsk->regs) || (tsk->regs.eax & 0xffff) != 0x004f)
goto out;
if (tsk->buf_len && tsk->flags & TF_BUF_RET) {
memcpy(buf, vptr(lbuf), tsk->buf_len);
}
out:
if (tsk->buf_len)
v86_mem_free(lbuf);
}
return 0;
}