4 * Copyright 1995 Alexandre Julliard
5 * Copyright 1996 Marcus Meissner
21 HANDLE16 DOSMEM_BiosSeg
; /* BIOS data segment at 0x40:0 */
28 WORD Com1Addr
; /* 00: COM1 I/O address */
29 WORD Com2Addr
; /* 02: COM2 I/O address */
30 WORD Com3Addr
; /* 04: COM3 I/O address */
31 WORD Com4Addr
; /* 06: COM4 I/O address */
32 WORD Lpt1Addr
; /* 08: LPT1 I/O address */
33 WORD Lpt2Addr
; /* 0a: LPT2 I/O address */
34 WORD Lpt3Addr
; /* 0c: LPT3 I/O address */
35 WORD Lpt4Addr
; /* 0e: LPT4 I/O address */
36 WORD InstalledHardware
; /* 10: Installed hardware flags */
37 BYTE POSTstatus
; /* 12: Power-On Self Test status */
38 WORD MemSize WINE_PACKED
; /* 13: Base memory size in Kb */
39 WORD unused1 WINE_PACKED
; /* 15: Manufacturing test scratch pad */
40 BYTE KbdFlags1
; /* 17: Keyboard flags 1 */
41 BYTE KbdFlags2
; /* 18: Keyboard flags 2 */
42 BYTE unused2
; /* 19: Keyboard driver workspace */
43 WORD NextKbdCharPtr
; /* 1a: Next character in kbd buffer */
44 WORD FirstKbdCharPtr
; /* 1c: First character in kbd buffer */
45 WORD KbdBuffer
[16]; /* 1e: Keyboard buffer */
46 BYTE DisketteStatus1
; /* 3e: Diskette recalibrate status */
47 BYTE DisketteStatus2
; /* 3f: Diskette motor status */
48 BYTE DisketteStatus3
; /* 40: Diskette motor timeout */
49 BYTE DisketteStatus4
; /* 41: Diskette last operation status */
50 BYTE DiskStatus
[7]; /* 42: Disk status/command bytes */
51 BYTE VideoMode
; /* 49: Video mode */
52 WORD VideoColumns
; /* 4a: Number of columns */
53 WORD VideoPageSize
; /* 4c: Video page size in bytes */
54 WORD VideoPageStartAddr
; /* 4e: Video page start address */
55 BYTE VideoCursorPos
[16]; /* 50: Cursor position for 8 pages */
56 WORD VideoCursorType
; /* 60: Video cursor type */
57 BYTE VideoCurPage
; /* 62: Video current page */
58 WORD VideoCtrlAddr WINE_PACKED
; /* 63: Video controller address */
59 BYTE VideoReg1
; /* 65: Video mode select register */
60 BYTE VideoReg2
; /* 66: Video CGA palette register */
61 DWORD ResetEntry WINE_PACKED
; /* 67: Warm reset entry point */
62 BYTE LastIRQ
; /* 6b: Last unexpected interrupt */
63 DWORD Ticks
; /* 6c: Ticks since midnight */
64 BYTE TicksOverflow
; /* 70: Timer overflow if past midnight */
65 BYTE CtrlBreakFlag
; /* 71: Ctrl-Break flag */
66 WORD ResetFlag
; /* 72: POST Reset flag */
67 BYTE DiskOpStatus
; /* 74: Last hard-disk operation status */
68 BYTE NbHardDisks
; /* 75: Number of hard disks */
69 BYTE DiskCtrlByte
; /* 76: Disk control byte */
70 BYTE DiskIOPort
; /* 77: Disk I/O port offset */
71 BYTE LptTimeout
[4]; /* 78: Timeouts for parallel ports */
72 BYTE ComTimeout
[4]; /* 7c: Timeouts for serial ports */
73 WORD KbdBufferStart
; /* 80: Keyboard buffer start */
74 WORD KbdBufferEnd
; /* 82: Keyboard buffer end */
80 static BIOSDATA
*pBiosData
= NULL
;
83 struct dosmem_entry
*next
;
88 /***********************************************************************
89 * DOSMEM_InitCollateTable
91 * Initialises the collate table (character sorting, language dependend)
93 DWORD DOSMEM_CollateTable
;
95 static void DOSMEM_InitCollateTable()
101 x
=GlobalDOSAlloc(258);
102 DOSMEM_CollateTable
=MAKELONG(0,(x
>>16));
103 tbl
=DOSMEM_RealMode2Linear(DOSMEM_CollateTable
);
106 for (i
=0;i
<0x100;i
++)
111 /***********************************************************************
114 * Create the dos memory segments, and store them into the KERNEL
117 BOOL32
DOSMEM_Init(void)
119 /* Allocate 1 MB dosmemory */
120 /* Yes, allocating 1 MB of memory, which is usually not even used, is a
121 * waste of memory. But I (MM) don't see any easy method to use
122 * GlobalDOS{Alloc,Free} within an area of memory, with protected mode
123 * selectors pointing into it, and the possibilty, that the userprogram
124 * calls SetSelectorBase(,physical_address_in_DOSMEM); that includes
125 * dynamical enlarging (reallocing) the dosmem area.
126 * Yes, one could walk the ldt_copy on every realloc() on DOSMEM, but
127 * this feels more like a hack to me than this current implementation is.
128 * If you find another, better, method, just change it. -Marcus Meissner
130 DOSMEM_dosmem
= VirtualAlloc(NULL
,0x100000,MEM_COMMIT
,PAGE_EXECUTE_READWRITE
);
133 fprintf( stderr
, "Could not allocate DOS memory.\n" );
136 DOSMEM_BiosSeg
= GLOBAL_CreateBlock(GMEM_FIXED
,DOSMEM_dosmem
+0x400,0x100,
137 0, FALSE
, FALSE
, FALSE
, NULL
);
138 DOSMEM_FillBiosSegment();
139 DOSMEM_InitMemoryHandling();
140 DOSMEM_InitCollateTable();
144 /***********************************************************************
145 * DOSMEM_InitMemoryHandling
147 * Initialises the DOS Memory structures.
150 DOSMEM_InitMemoryHandling()
152 struct dosmem_entry
*dm
;
154 dm
= (struct dosmem_entry
*)(DOSMEM_dosmem
+0x10000);
156 dm
->next
= (struct dosmem_entry
*)(DOSMEM_dosmem
+0x9FFF0);
162 /***********************************************************************
165 * Increment the BIOS tick counter. Called by timer signal handler.
167 void DOSMEM_Tick(void)
169 if (pBiosData
) pBiosData
->Ticks
++;
173 /***********************************************************************
174 * DOSMEM_FillBiosSegment
176 * Fill the BIOS data segment with dummy values.
178 void DOSMEM_FillBiosSegment(void)
180 pBiosData
= (BIOSDATA
*)GlobalLock16( DOSMEM_BiosSeg
);
182 /* Clear all unused values */
183 memset( pBiosData
, 0, sizeof(*pBiosData
) );
185 /* FIXME: should check the number of configured drives and ports */
187 pBiosData
->Com1Addr
= 0x3e8;
188 pBiosData
->Com2Addr
= 0x2e8;
189 pBiosData
->Lpt1Addr
= 0x378;
190 pBiosData
->Lpt2Addr
= 0x278;
191 pBiosData
->InstalledHardware
= 0x8443;
192 pBiosData
->MemSize
= 640;
193 pBiosData
->NextKbdCharPtr
= 0x1e;
194 pBiosData
->FirstKbdCharPtr
= 0x1e;
195 pBiosData
->VideoMode
= 0;
196 pBiosData
->VideoColumns
= 80;
197 pBiosData
->VideoPageSize
= 80 * 25 * 2;
198 pBiosData
->VideoPageStartAddr
= 0xb800;
199 pBiosData
->VideoCtrlAddr
= 0x3d4;
200 pBiosData
->Ticks
= INT1A_GetTicksSinceMidnight();
201 pBiosData
->NbHardDisks
= 2;
202 pBiosData
->KbdBufferStart
= 0x1e;
203 pBiosData
->KbdBufferEnd
= 0x3e;
206 /***********************************************************************
207 * GlobalDOSAlloc (KERNEL.184)
209 * Allocates a piece of DOS Memory, in the first 1 MB physical memory.
211 * operates on the preallocated DOSMEM_dosmem (1MB). The useable area
212 * starts at 1000:0000 and ends at 9FFF:FFEF
213 * Memory allocation strategy is First Fit. (FIXME: Yes,I know that First Fit
214 * is a rather bad strategy. But since those functions are rather seldom
215 * called, it's easyness fits the purpose well.)
219 DWORD
GlobalDOSAlloc(DWORD size
)
221 struct dosmem_entry
*dm
,*ndm
;
222 DWORD start
,blocksize
;
224 HMODULE16 hModule
=GetModuleHandle("KERNEL");
228 dm
= (struct dosmem_entry
*)(DOSMEM_dosmem
+0x10000);
229 size
= (size
+0xf)&~0xf;
230 while (dm
&& dm
->next
) {
231 blocksize
= ((char*)dm
->next
-(char*)dm
)-16;
232 if ((dm
->isfree
) && (blocksize
>=size
)) {
234 start
= ((((char*)dm
)-DOSMEM_dosmem
)+0x10)& ~0xf;
235 if ((blocksize
-size
) >= 0x20) {
236 /* if enough memory is left for a new block
237 * split this area into two blocks
239 ndm
=(struct dosmem_entry
*)((char*)dm
+0x10+size
);
241 ndm
->next
= dm
->next
;
250 sel
=GLOBAL_CreateBlock(
251 GMEM_FIXED
,DOSMEM_dosmem
+start
,size
,
252 hModule
,FALSE
,FALSE
,FALSE
,NULL
254 return MAKELONG(sel
,start
>>4);
257 /***********************************************************************
258 * GlobalDOSFree (KERNEL.185)
260 * Frees allocated dosmemory and corresponding selector.
264 GlobalDOSFree(WORD sel
)
267 struct dosmem_entry
*dm
;
269 base
= GetSelectorBase(sel
);
270 /* base has already been conversed to a physical address */
273 dm
= (struct dosmem_entry
*)(DOSMEM_dosmem
+base
-0x10);
275 fprintf(stderr
,"Freeing already freed DOSMEM.\n");
280 /* collapse adjunct free blocks into one */
281 dm
= (struct dosmem_entry
*)(DOSMEM_dosmem
+0x10000);
282 while (dm
&& dm
->next
) {
283 if (dm
->isfree
&& dm
->next
->isfree
)
284 dm
->next
= dm
->next
->next
;
287 GLOBAL_FreeBlock(sel
);
291 /***********************************************************************
292 * DOSMEM_RealMode2Linear
294 * Converts a realmode segment:offset address into a linear pointer
296 LPVOID
DOSMEM_RealMode2Linear(DWORD x
)
300 lin
=DOSMEM_dosmem
+(x
&0xffff)+(((x
&0xffff0000)>>16)*16);
301 dprintf_selector(stddeb
,"DOSMEM_RealMode2Linear(0x%08lx) returns 0x%p.\n",
307 /***********************************************************************
308 * DOSMEM_AllocSelector
310 * Allocates a protected mode selector for a realmode segment.
312 WORD
DOSMEM_AllocSelector(WORD realsel
)
314 HMODULE16 hModule
=GetModuleHandle("KERNEL");
317 sel
=GLOBAL_CreateBlock(
318 GMEM_FIXED
,DOSMEM_dosmem
+realsel
*16,0x10000,
319 hModule
,FALSE
,FALSE
,FALSE
,NULL
321 dprintf_selector(stddeb
,"DOSMEM_AllocSelector(0x%04x) returns 0x%04x.\n",