- fixed wrong variable type
[bochs-mirror.git] / memory / memory.cc
blob363c8c7c58ae5830a0729cb353b383902cbe3aab
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: memory.cc,v 1.62 2007/11/01 18:03:48 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "bochs.h"
29 #include "cpu/cpu.h"
30 #include "iodev/iodev.h"
31 #define LOG_THIS BX_MEM_THIS
33 #if BX_PROVIDE_CPU_MEMORY
36 // Memory map inside the 1st megabyte:
38 // 0x00000 - 0x7ffff DOS area (512K)
39 // 0x80000 - 0x9ffff Optional fixed memory hole (128K)
40 // 0xa0000 - 0xbffff Standard PCI/ISA Video Mem / SMMRAM (128K)
41 // 0xc0000 - 0xdffff Expansion Card BIOS and Buffer Area (128K)
42 // 0xe0000 - 0xeffff Lower BIOS Area (64K)
43 // 0xf0000 - 0xfffff Upper BIOS Area (64K)
46 void BX_CPP_AttrRegparmN(3)
47 BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
49 Bit8u *data_ptr;
50 bx_phy_address a20addr = A20ADDR(addr);
51 struct memory_handler_struct *memory_handler = NULL;
53 // Note: accesses should always be contained within a single page now
55 if (cpu != NULL) {
56 #if BX_SUPPORT_IODEBUG
57 bx_iodebug_c::mem_write(cpu, a20addr, len, data);
58 #endif
60 BX_INSTR_PHY_WRITE(cpu->which_cpu(), a20addr, len);
62 #if BX_DEBUGGER
63 // (mch) Check for physical write break points, TODO
64 // (bbd) Each breakpoint should have an associated CPU#, TODO
65 for (unsigned i = 0; i < num_write_watchpoints; i++) {
66 if (write_watchpoint[i] == a20addr) {
67 cpu->watchpoint = a20addr;
68 cpu->break_point = BREAK_POINT_WRITE;
69 break;
72 #endif
74 #if BX_SUPPORT_APIC
75 bx_generic_apic_c *local_apic = &cpu->local_apic;
76 if (local_apic->is_selected(a20addr, len)) {
77 local_apic->write(a20addr, (Bit32u *)data, len);
78 return;
80 #endif
82 if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
84 // SMRAM memory space
85 if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
86 goto mem_write;
90 #if BX_SUPPORT_MONITOR_MWAIT
91 BX_MEM_THIS check_monitor(a20addr, len);
92 #endif
94 memory_handler = BX_MEM_THIS memory_handlers[a20addr >> 20];
95 while (memory_handler) {
96 if (memory_handler->begin <= a20addr &&
97 memory_handler->end >= a20addr &&
98 memory_handler->write_handler(a20addr, len, data, memory_handler->param))
100 return;
102 memory_handler = memory_handler->next;
105 mem_write:
107 // all memory access feets in single 4K page
108 if (a20addr < BX_MEM_THIS len) {
109 #if BX_SUPPORT_ICACHE
110 pageWriteStampTable.decWriteStamp(a20addr);
111 #endif
112 // all of data is within limits of physical memory
113 if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
115 if (len == 8) {
116 WriteHostQWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit64u*)data);
117 BX_DBG_DIRTY_PAGE(a20addr >> 12);
118 return;
120 if (len == 4) {
121 WriteHostDWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit32u*)data);
122 BX_DBG_DIRTY_PAGE(a20addr >> 12);
123 return;
125 if (len == 2) {
126 WriteHostWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit16u*)data);
127 BX_DBG_DIRTY_PAGE(a20addr >> 12);
128 return;
130 if (len == 1) {
131 * ((Bit8u *) (&BX_MEM_THIS vector[a20addr])) = * (Bit8u *) data;
132 BX_DBG_DIRTY_PAGE(a20addr >> 12);
133 return;
135 // len == other, just fall thru to special cases handling
138 #ifdef BX_LITTLE_ENDIAN
139 data_ptr = (Bit8u *) data;
140 #else // BX_BIG_ENDIAN
141 data_ptr = (Bit8u *) data + (len - 1);
142 #endif
144 write_one:
145 if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
147 // addr *not* in range 000A0000 .. 000FFFFF
148 BX_MEM_THIS vector[a20addr] = *data_ptr;
149 BX_DBG_DIRTY_PAGE(a20addr >> 12);
150 inc_one:
151 if (len == 1) return;
152 len--;
153 a20addr++;
154 #ifdef BX_LITTLE_ENDIAN
155 data_ptr++;
156 #else // BX_BIG_ENDIAN
157 data_ptr--;
158 #endif
159 goto write_one;
162 // addr must be in range 000A0000 .. 000FFFFF
164 // SMMRAM
165 if (a20addr <= 0x000bffff) {
166 // devices are not allowed to access SMMRAM under VGA memory
167 if (cpu) {
168 BX_MEM_THIS vector[a20addr] = *data_ptr;
169 BX_DBG_DIRTY_PAGE(a20addr >> 12);
171 goto inc_one;
174 // adapter ROM C0000 .. DFFFF
175 // ROM BIOS memory E0000 .. FFFFF
176 #if BX_SUPPORT_PCI == 0
177 // ignore write to ROM
178 #else
179 // Write Based on 440fx Programming
180 if (BX_MEM_THIS pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
182 switch (DEV_pci_wr_memtype(a20addr)) {
183 case 0x1: // Writes to ShadowRAM
184 BX_DEBUG(("Writing to ShadowRAM: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
185 BX_MEM_THIS vector[a20addr] = *data_ptr;
186 BX_DBG_DIRTY_PAGE(a20addr >> 12);
187 goto inc_one;
189 case 0x0: // Writes to ROM, Inhibit
190 BX_DEBUG(("Write to ROM ignored: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
191 goto inc_one;
193 default:
194 BX_PANIC(("writePhysicalPage: default case"));
195 goto inc_one;
198 #endif
199 goto inc_one;
201 else {
202 // access outside limits of physical memory, ignore
203 BX_DEBUG(("Write outside the limits of physical memory (0x%08x) (ignore)", a20addr));
207 void BX_CPP_AttrRegparmN(3)
208 BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
210 Bit8u *data_ptr;
211 bx_phy_address a20addr = A20ADDR(addr);
212 struct memory_handler_struct *memory_handler = NULL;
214 // Note: accesses should always be contained within a single page now
216 if (cpu != NULL) {
217 #if BX_SUPPORT_IODEBUG
218 bx_iodebug_c::mem_read(cpu, a20addr, len, data);
219 #endif
221 BX_INSTR_PHY_READ(cpu->which_cpu(), a20addr, len);
223 #if BX_DEBUGGER
224 // (mch) Check for physical read break points, TODO
225 // (bbd) Each breakpoint should have an associated CPU#, TODO
226 for (unsigned i = 0; i < num_read_watchpoints; i++) {
227 if (read_watchpoint[i] == a20addr) {
228 cpu->watchpoint = a20addr;
229 cpu->break_point = BREAK_POINT_READ;
230 break;
233 #endif
235 #if BX_SUPPORT_APIC
236 bx_generic_apic_c *local_apic = &cpu->local_apic;
237 if (local_apic->is_selected (a20addr, len)) {
238 local_apic->read(a20addr, data, len);
239 return;
241 #endif
243 if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
245 // SMRAM memory space
246 if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
247 goto mem_read;
251 memory_handler = BX_MEM_THIS memory_handlers[a20addr >> 20];
252 while (memory_handler) {
253 if (memory_handler->begin <= a20addr &&
254 memory_handler->end >= a20addr &&
255 memory_handler->read_handler(a20addr, len, data, memory_handler->param))
257 return;
259 memory_handler = memory_handler->next;
262 mem_read:
264 if (a20addr <= BX_MEM_THIS len) {
265 // all of data is within limits of physical memory
266 if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
268 if (len == 8) {
269 ReadHostQWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit64u*) data);
270 return;
272 if (len == 4) {
273 ReadHostDWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit32u*) data);
274 return;
276 if (len == 2) {
277 ReadHostWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit16u*) data);
278 return;
280 if (len == 1) {
281 * (Bit8u *) data = * ((Bit8u *) (&BX_MEM_THIS vector[a20addr]));
282 return;
284 // len == other case can just fall thru to special cases handling
287 #ifdef BX_LITTLE_ENDIAN
288 data_ptr = (Bit8u *) data;
289 #else // BX_BIG_ENDIAN
290 data_ptr = (Bit8u *) data + (len - 1);
291 #endif
293 read_one:
294 if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
296 // addr *not* in range 00080000 .. 000FFFFF
297 *data_ptr = BX_MEM_THIS vector[a20addr];
298 inc_one:
299 if (len == 1) return;
300 len--;
301 a20addr++;
302 #ifdef BX_LITTLE_ENDIAN
303 data_ptr++;
304 #else // BX_BIG_ENDIAN
305 data_ptr--;
306 #endif
307 goto read_one;
310 // addr must be in range 000A0000 .. 000FFFFF
312 // SMMRAM
313 if (a20addr <= 0x000bffff) {
314 // devices are not allowed to access SMMRAM under VGA memory
315 if (cpu) *data_ptr = BX_MEM_THIS vector[a20addr];
316 goto inc_one;
319 #if BX_SUPPORT_PCI
320 if (BX_MEM_THIS pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
322 switch (DEV_pci_rd_memtype(a20addr)) {
323 case 0x0: // Read from ROM
324 if ((a20addr & 0xfffe0000) == 0x000e0000)
326 *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
328 else
330 *data_ptr = BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
332 goto inc_one;
333 case 0x1: // Read from ShadowRAM
334 *data_ptr = BX_MEM_THIS vector[a20addr];
335 goto inc_one;
336 default:
337 BX_PANIC(("readPhysicalPage: default case"));
339 goto inc_one;
341 else
342 #endif // #if BX_SUPPORT_PCI
344 if ((a20addr & 0xfffc0000) != 0x000c0000) {
345 *data_ptr = BX_MEM_THIS vector[a20addr];
347 else if ((a20addr & 0xfffe0000) == 0x000e0000)
349 *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
351 else
353 *data_ptr = BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
355 goto inc_one;
358 else
359 { // access outside limits of physical memory
361 #ifdef BX_LITTLE_ENDIAN
362 data_ptr = (Bit8u *) data;
363 #else // BX_BIG_ENDIAN
364 data_ptr = (Bit8u *) data + (len - 1);
365 #endif
367 for (unsigned i = 0; i < len; i++) {
368 if (a20addr >= (bx_phy_address)~BIOS_MASK)
369 *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
370 else
371 *data_ptr = 0xff;
372 addr++;
373 a20addr = (addr);
374 #ifdef BX_LITTLE_ENDIAN
375 data_ptr++;
376 #else // BX_BIG_ENDIAN
377 data_ptr--;
378 #endif
383 #endif // #if BX_PROVIDE_CPU_MEMORY