Map the system and video BIOSes with PROT_WRITE for x86emu.
[v86d.git] / v86_common.c
blob421b85006fa46b0561f5940eeb9f5e04b2c0dd09
1 #include <string.h>
2 #include "v86.h"
4 #define addr(t) (((t & 0xffff0000) >> 12) + (t & 0x0000ffff))
6 #define vbeib_get_string(name) \
7 { \
8 int l; \
9 t = addr(ib->name); \
10 if (t < bufend) { \
11 ib->name = t - lbuf; \
12 l = strnlen((char*)buf + ib->name, bufend-t); \
13 if (buf[ib->name + l] != 0) \
14 buf[ib->name + l] = 0; \
15 fsize -= l; \
16 cbuf += l; \
17 } else if (t > 0xa0000 && fsize > 0) { \
18 strncpy((char*)cbuf, vptr(t), fsize); \
19 l = strnlen((char*)cbuf, fsize); \
20 if (cbuf[l] != 0) \
21 cbuf[l] = 0; \
22 ib->name = tsk->buf_len - fsize; \
23 l++; \
24 fsize -= l; \
25 cbuf += l; \
26 } else { \
27 ib->name = 0; \
28 } \
29 if (fsize < 0) \
30 fsize = 0; \
33 int v86_task(struct uvesafb_task *tsk, u8 *buf)
35 u32 lbuf = 0;
37 ulog(LOG_DEBUG, "task flags: 0x%02x\n", tsk->flags);
38 ulog(LOG_DEBUG, "EAX=0x%08x EBX=0x%08x ECX=0x%08x EDX=0x%08x\n",
39 tsk->regs.eax, tsk->regs.ebx, tsk->regs.ecx, tsk->regs.edx);
40 ulog(LOG_DEBUG, "ESP=0x%08x EBP=0x%08x ESI=0x%08x EDI=0x%08x\n",
41 tsk->regs.esp, tsk->regs.ebp, tsk->regs.esi, tsk->regs.edi);
43 /* Get the VBE Info Block */
44 if (tsk->flags & TF_VBEIB) {
45 struct vbe_ib *ib;
46 int fsize;
47 u32 t, bufend;
48 u16 *td;
49 u8 *cbuf;
51 lbuf = v86_mem_alloc(tsk->buf_len);
52 if (!lbuf) {
53 ulog(LOG_ERR, "Memory allocation for a VBE IB buffer failed.");
54 return -1;
56 memcpy(vptr(lbuf), buf, tsk->buf_len);
57 tsk->regs.es = lbuf >> 4;
58 tsk->regs.edi = 0x0000;
60 if (v86_int(0x10, &tsk->regs) || (tsk->regs.eax & 0xffff) != 0x004f)
61 goto out_vbeib;
63 ib = (struct vbe_ib*)buf;
64 bufend = lbuf + sizeof(*ib);
65 memcpy(buf, vptr(lbuf), tsk->buf_len);
67 /* The original VBE Info Block is 512 bytes long. */
68 fsize = tsk->buf_len - 512;
69 cbuf = buf + 512;
71 t = addr(ib->mode_list_ptr);
72 /* Mode list is in the buffer, we're good. */
73 if (t < bufend) {
74 ulog(LOG_DEBUG, "The mode list is in the buffer at %.8x.", t);
75 ib->mode_list_ptr = t - lbuf;
76 td = (u16*) (buf + ib->mode_list_ptr);
78 while (fsize > 2 && *td != 0xffff) {
79 td++;
80 t += 2;
81 fsize -= 2;
82 cbuf += 2;
85 *td = 0xffff;
86 cbuf += 2;
87 fsize -= 2;
89 /* Mode list is in the ROM. We copy as much of it as we can
90 * to the task buffer. */
91 } else if (t > 0xa0000) {
92 u16 tmp;
94 ulog(LOG_DEBUG, "The mode list is in the Video ROM at %.8x", t);
96 td = (u16*)cbuf;
98 while (fsize > 2 && (tmp = v_rdw(t)) != 0xffff) {
99 fsize -= 2;
100 *td = tmp;
101 td++;
102 t += 2;
103 cbuf += 2;
106 ib->mode_list_ptr = 512;
107 *td = 0xffff;
108 cbuf += 2;
109 fsize -= 2;
111 /* Mode list is somewhere else. We're seriously screwed. */
112 } else {
113 ulog(LOG_ERR, "Can't retrieve mode list from %x\n", t);
114 ib->mode_list_ptr = 0;
117 vbeib_get_string(oem_string_ptr);
118 vbeib_get_string(oem_vendor_name_ptr);
119 vbeib_get_string(oem_product_name_ptr);
120 vbeib_get_string(oem_product_rev_ptr);
121 out_vbeib:
122 v86_mem_free(lbuf);
123 } else {
124 if (tsk->buf_len) {
125 lbuf = v86_mem_alloc(tsk->buf_len);
126 if (!lbuf) {
127 ulog(LOG_ERR, "Memory allocation for a v86d task buffer failed.");
128 return -1;
130 memcpy(vptr(lbuf), buf, tsk->buf_len);
133 if (tsk->flags & TF_BUF_ESDI) {
134 tsk->regs.es = lbuf >> 4;
135 tsk->regs.edi = 0x0000;
138 if (tsk->flags & TF_BUF_ESBX) {
139 tsk->regs.es = lbuf >> 4;
140 tsk->regs.ebx = 0x0000;
143 if (v86_int(0x10, &tsk->regs) || (tsk->regs.eax & 0xffff) != 0x004f)
144 goto out;
146 if (tsk->buf_len && tsk->flags & TF_BUF_RET) {
147 memcpy(buf, vptr(lbuf), tsk->buf_len);
149 out:
150 if (tsk->buf_len)
151 v86_mem_free(lbuf);
154 return 0;