8 #define REAL_MEM_BLOCKS 0x100
10 u8
*mem_low
; /* 0x000000 - 0x001000 */
11 u8
*mem_real
; /* 0x010000 - 0x09ffff */
12 u8
*mem_bios
; /* 0x0a0000 - 0x10ffef */
15 unsigned int size
: 20;
16 unsigned int free
: 1;
22 struct mem_block blocks
[REAL_MEM_BLOCKS
];
25 void *vptr(u32 addr
) {
26 if (addr
< IVTBDA_SIZE
)
27 return (mem_low
+ addr
);
28 else if (addr
>= REAL_MEM_BASE
&& addr
< REAL_MEM_BASE
+ REAL_MEM_SIZE
)
29 return (mem_real
+ addr
- REAL_MEM_BASE
);
30 else if (addr
>= BIOS_BASE
&& addr
< BIOS_BASE
+ BIOS_SIZE
)
31 return (mem_bios
+ addr
- BIOS_BASE
);
33 ulog(LOG_WARNING
, "Trying to access an unsupported memory region at %x", addr
);
38 /* We don't care about memory accesses at boundaries of different memory
39 * regions, since our v86 memory is non contiguous anyway. */
41 return *(u8
*) vptr(addr
);
45 return *(u16
*) vptr(addr
);
49 return *(u32
*) vptr(addr
);
52 void v_wrb(u32 addr
, u8 val
) {
57 void v_wrw(u32 addr
, u16 val
) {
62 void v_wrl(u32 addr
, u32 val
) {
67 static void *map_file(void *start
, size_t length
, int prot
, int flags
, char *name
, long offset
)
72 fd
= open(name
, (flags
& MAP_SHARED
) ? O_RDWR
: O_RDONLY
);
75 ulog(LOG_ERR
, "Open '%s' failed with: %s\n", name
, strerror(errno
));
79 m
= mmap(start
, length
, prot
, flags
, fd
, offset
);
81 if (m
== (void *)-1) {
82 ulog(LOG_ERR
, "mmap '%s' failed with: %s\n", name
, strerror(errno
));
91 static int real_mem_init(void)
96 mem_real
= map_file(NULL
, REAL_MEM_SIZE
, PROT_READ
| PROT_WRITE
| PROT_EXEC
,
97 MAP_PRIVATE
, "/dev/zero", 0);
103 mem_info
.blocks
[0].size
= REAL_MEM_SIZE
;
104 mem_info
.blocks
[0].free
= 1;
109 static void real_mem_deinit(void)
111 if (mem_info
.ready
) {
112 munmap(mem_real
, REAL_MEM_SIZE
);
117 static void insert_block(int i
)
119 memmove(mem_info
.blocks
+ i
+ 1, mem_info
.blocks
+ i
,
120 (mem_info
.count
- i
) * sizeof(struct mem_block
));
124 static void delete_block(int i
)
127 memmove(mem_info
.blocks
+ i
, mem_info
.blocks
+ i
+ 1,
128 (mem_info
.count
- i
) * sizeof(struct mem_block
));
131 u32
v86_mem_alloc(int size
)
134 u32 r
= REAL_MEM_BASE
;
139 if (mem_info
.count
== REAL_MEM_BLOCKS
)
142 size
= (size
+ 15) & ~15;
144 for (i
= 0; i
< mem_info
.count
; i
++) {
145 if (mem_info
.blocks
[i
].free
&& size
< mem_info
.blocks
[i
].size
) {
148 mem_info
.blocks
[i
].size
= size
;
149 mem_info
.blocks
[i
].free
= 0;
150 mem_info
.blocks
[i
+ 1].size
-= size
;
155 r
+= mem_info
.blocks
[i
].size
;
161 void v86_mem_free(u32 m
)
164 u32 r
= REAL_MEM_BASE
;
171 r
+= mem_info
.blocks
[i
].size
;
173 if (i
== mem_info
.count
)
177 mem_info
.blocks
[i
].free
= 1;
179 if (i
+ 1 < mem_info
.count
&& mem_info
.blocks
[i
+ 1].free
) {
180 mem_info
.blocks
[i
].size
+= mem_info
.blocks
[i
+ 1].size
;
184 if (i
- 1 >= 0 && mem_info
.blocks
[i
- 1].free
) {
185 mem_info
.blocks
[i
- 1].size
+= mem_info
.blocks
[i
].size
;
190 int v86_mem_init(void)
196 * We have to map the IVTBDA as shared. Without it, setting video
197 * modes will not work correctly on some cards (e.g. nVidia GeForce
198 * 8600M, PCI ID 10de:0425).
200 mem_low
= map_file(NULL
, IVTBDA_SIZE
, PROT_READ
| PROT_WRITE
| PROT_EXEC
,
201 MAP_SHARED
, "/dev/mem", IVTBDA_BASE
);
207 mem_bios
= map_file(NULL
, BIOS_SIZE
, PROT_READ
| PROT_WRITE
| PROT_EXEC
,
208 MAP_SHARED
, "/dev/mem", BIOS_BASE
);
210 munmap(mem_low
, IVTBDA_SIZE
);
218 void v86_mem_cleanup(void)
220 munmap(mem_low
, IVTBDA_SIZE
);
221 munmap(mem_bios
, BIOS_SIZE
);