Map the IVTBDA as a shared.
[v86d.git] / v86_mem.c
blob41562f005869a220e5bb85d347298b99aa79ffbf
1 #include <fcntl.h>
2 #include <string.h>
3 #include <sys/mman.h>
4 #include <unistd.h>
5 #include "v86.h"
7 #define REAL_MEM_BLOCKS 0x100
9 u8 *real_mem = NULL;
11 struct mem_block {
12 unsigned int size : 20;
13 unsigned int free : 1;
16 static struct {
17 int ready;
18 int count;
19 struct mem_block blocks[REAL_MEM_BLOCKS];
20 } mem_info = { 0 };
22 static int map_file(void *start, size_t length, int prot, int flags, char *name, long offset)
24 void *m;
25 int fd;
27 fd = open(name, (flags & MAP_SHARED) ? O_RDWR : O_RDONLY);
29 if (fd == -1) {
30 perror("open");
31 return 0;
34 m = mmap(start, length, prot, flags, fd, offset);
36 if (m == (void *)-1) {
37 perror("mmap");
38 close(fd);
39 return 0;
42 close(fd);
43 return 1;
46 static int real_mem_init(void)
48 if (mem_info.ready)
49 return 0;
51 if (!map_file((void *)REAL_MEM_BASE, REAL_MEM_SIZE,
52 PROT_READ | PROT_WRITE | PROT_EXEC,
53 MAP_FIXED | MAP_PRIVATE, "/dev/zero", 0))
54 return 0;
56 real_mem = (u8*)0;
58 mem_info.ready = 1;
59 mem_info.count = 1;
60 mem_info.blocks[0].size = REAL_MEM_SIZE;
61 mem_info.blocks[0].free = 1;
63 return 0;
66 static void real_mem_deinit(void)
68 if (mem_info.ready) {
69 munmap((void *)REAL_MEM_BASE, REAL_MEM_SIZE);
70 mem_info.ready = 0;
74 static void insert_block(int i)
76 memmove(mem_info.blocks + i + 1, mem_info.blocks + i,
77 (mem_info.count - i) * sizeof(struct mem_block));
78 mem_info.count++;
81 static void delete_block(int i)
83 mem_info.count--;
84 memmove(mem_info.blocks + i, mem_info.blocks + i + 1,
85 (mem_info.count - i) * sizeof(struct mem_block));
88 void *v86_mem_alloc(int size)
90 int i;
91 char *r = (char *)REAL_MEM_BASE;
93 if (!mem_info.ready)
94 return NULL;
96 if (mem_info.count == REAL_MEM_BLOCKS)
97 return NULL;
99 size = (size + 15) & ~15;
101 for (i = 0; i < mem_info.count; i++) {
102 if (mem_info.blocks[i].free && size < mem_info.blocks[i].size) {
103 insert_block(i);
105 mem_info.blocks[i].size = size;
106 mem_info.blocks[i].free = 0;
107 mem_info.blocks[i + 1].size -= size;
109 return (void *)r;
112 r += mem_info.blocks[i].size;
115 return NULL;
118 void v86_mem_free(void *m)
120 int i;
121 char *r = (char *)REAL_MEM_BASE;
123 if (!mem_info.ready)
124 return;
126 i = 0;
127 while (m != (void *)r) {
128 r += mem_info.blocks[i].size;
129 i++;
130 if (i == mem_info.count)
131 return;
134 mem_info.blocks[i].free = 1;
136 if (i + 1 < mem_info.count && mem_info.blocks[i + 1].free) {
137 mem_info.blocks[i].size += mem_info.blocks[i + 1].size;
138 delete_block(i + 1);
141 if (i - 1 >= 0 && mem_info.blocks[i - 1].free) {
142 mem_info.blocks[i - 1].size += mem_info.blocks[i].size;
143 delete_block(i);
147 static inline void set_bit(unsigned int bit, void *array)
149 unsigned char *a = array;
150 a[bit / 8] |= (1 << (bit % 8));
153 inline u16 get_int_seg(int i)
155 return *(u16 *)(uptr)(i * 4 + 2);
158 inline u16 get_int_off(int i)
160 return *(u16 *)(uptr)(i * 4);
163 int v86_mem_init(void)
165 if (real_mem_init())
166 return 1;
169 * We have to map the IVTBDA as shared. Without it, setting video
170 * modes will not work correctly on some cards (e.g. nVidia GeForce
171 * 8600M, 10de:0425).
173 if (!map_file((void *)IVTBDA_BASE, IVTBDA_SIZE,
174 PROT_READ | PROT_WRITE | PROT_EXEC,
175 MAP_FIXED | MAP_SHARED, "/dev/mem", 0))
177 real_mem_deinit();
178 return 1;
181 if (!map_file((void *)0xa0000, MEM_SIZE - 0xa0000,
182 PROT_READ | PROT_WRITE | PROT_EXEC,
183 MAP_FIXED | MAP_SHARED, "/dev/mem", 0xa0000))
185 munmap((void *)IVTBDA_BASE, IVTBDA_SIZE);
186 real_mem_deinit();
187 return 1;
190 return 0;
193 void v86_mem_cleanup(void)
195 munmap((void *)IVTBDA_BASE, IVTBDA_SIZE);
196 munmap((void *)0xa0000, MEM_SIZE - 0xa0000);
198 real_mem_deinit();