1 ; MMURTL Operating System Source Code
\r
2 ; Copyright 1991,1992,1993,1994 Richard A. Burgess
\r
3 ; ALL RIGHTS RESERVED
\r
6 ; This is the main Data/Code file for the MMURTL OS.
\r
7 ; It contains important structures and initialization code
\r
8 ; including the first instructions executed after a boot!
\r
9 ; This should follow the IDT, GDT, PDR & Public call table in memory.
\r
17 ;=============================================================================
\r
18 ; Kernel Structures - See MOSEDF.INC for structure details.
\r
19 ;=============================================================================
\r
21 PUBLIC MonTSS DB sTSS dup (0) ; Initial TSS for OS/Monitor
\r
22 PUBLIC DbgTSS DB sTSS dup (0) ; Initial TSS for Debugger
\r
23 PUBLIC pFreeTSS DD NIL ; Pointer to Free List of Task State Segs
\r
24 PUBLIC pDynTSSs DD 0 ; ptr to alloced mem for dynamic TSSs
\r
25 PUBLIC _nTSSLeft DD nTSS-2 ; For stats (less static TSSs)
\r
29 PUBLIC rgLBs DB (nLB*sLINKBLOCK) dup (0) ; pool of LBs
\r
30 PUBLIC pFreeLB DD NIL ; Ptr to Free List of Link Block
\r
31 PUBLIC _nLBLeft DD nLB ; For Monitor stats
\r
34 ; The RUN Queue for "Ready to Run" tasks
\r
36 PUBLIC RdyQ DB (sQUEUE*nPRI) dup (0) ; Priority Based Ready Queue
\r
39 ; Two static Job Control Blocks (JCBs) to get us kick-started.
\r
40 ; The rest of them are in allocated memory
\r
42 PUBLIC MonJCB DB sJCB dup (0) ; Monitor JCB
\r
43 PUBLIC DbgJCB DB sJCB dup (0) ; Debugger JCB
\r
47 PUBLIC GDTLimit DW 0000h ;Global Descriptor Table Limit
\r
48 PUBLIC GDTBase DD 00000000h ;base
\r
49 PUBLIC IDTLimit DW 0000h ;Interrupt Descriptor Table Limit
\r
50 PUBLIC IDTBase DD 00000000h ;base
\r
53 PUBLIC rgSVC DB (sSVC*nSVC) dup (0) ; Setup an array of Service Descriptors
\r
56 ;Exchanges take up a fair amount of memory. In order to use certain kernel
\r
57 ;primitives, we need exchanges before they are allocated dynamically.
\r
58 ;We have an array of 3 exchanges set aside for this purpose. After
\r
59 ;the dynamic array is allocated an initialized, we copy these into
\r
60 ;the first three dynamic exchanges. These static exchanges are used
\r
61 ;by the Monitor TSS, Debugger TSS, and memory Management.
\r
63 PUBLIC nExch DD 3 ; This will be changed after allocation
\r
64 ; of dynamic exchanges.
\r
65 rgExchTmp DB (sEXCH * 3) dup (0) ; Setup three static temporary Exchanges
\r
66 ; for Monitor and Debugger TSSs
\r
67 ; These are moved to a dynamic Exch Array
\r
68 ; as soon as it's allocated.
\r
69 PUBLIC prgExch DD OFFSET rgExchTmp ; Pointer to current array of Exchanges.
\r
70 PUBLIC pExchTmp DD 0 ; Pointer to dynamic array Exchanges.
\r
71 PUBLIC _nEXCHLeft DD nDynEXCH ; For Monitor stats
\r
73 ;-------------------
\r
74 ;Scheduling management variables
\r
76 PUBLIC TSS DD 00000000h ; Used for jumping to next task
\r
77 PUBLIC TSS_Sel DW 0000h ; " "
\r
81 PUBLIC pRunTSS DD NIL ; Pointer to the Running TSS
\r
82 PUBLIC SwitchTick DD 0 ; Tick of last task switch
\r
83 PUBLIC dfHalted DD 0 ; nonzero if processor was halted
\r
85 PUBLIC _nSwitches DD 0 ; # of switches for statistics
\r
86 PUBLIC _nSlices DD 0 ; # of sliced switches for stats
\r
87 PUBLIC _nReady DD 0 ; # of task Ready to Run for stats
\r
88 PUBLIC _nHalts DD 0 ; # of times CPU halted for stats
\r
90 ;THESE ARE THE INITIAL STACKS FOR THE OS Monitor AND Debugger
\r
92 OSStack DD 0FFh DUP (00000000h) ;1K OS Monitor Stack
\r
93 OSStackTop DD 00000000h
\r
94 OSStackSize EQU OSStackTop-OSStack
\r
96 Stack1 DD 0FFh DUP (00000000h) ;1K Debugger Stack
\r
97 Stack1Top DD 00000000h
\r
98 Stack1Size EQU Stack1Top-Stack1
\r
102 rgNewJob DB 'New Job' ;Placed in New JCBs
\r
105 rgOSJob DB 'MMOS Monitor' ;Placed in first JCB
\r
108 rgDbgJob DB 'Debugger ' ;Name for Job
\r
109 cbDbgJob DD 12 ;Size of Job Name
\r
111 PUBLIC _BootDrive DD 00 ;Source drive of the boot
\r
112 ;=============================================================================
\r
113 ;=============================================================================
\r
114 ; This begins the OS Code Segment
\r
117 .VIRTUAL 10000h ;64K boundry. This lets the assembler know
\r
118 ;that this is the address where we execute
\r
120 ; BEGIN OS INITIALIZATION CODE
\r
122 ; This code is used to initialize the permanent OS structures
\r
123 ; and calls procedures that initialize dynamic structures too.
\r
125 ; "Will Robinson, WARNING, WARNING!! Dr. Smith is approaching!!!"
\r
126 ; BEWARE ON INITIALIZATION. The kernel structures and their
\r
127 ; initialization routines are so interdependent, you must pay
\r
128 ; close attention before you change the order of ANYTHING.
\r
129 ; (Anything before we jump to the monitor code that is)
\r
131 EXTRN InitCallGates NEAR
\r
132 EXTRN InitOSPublics NEAR
\r
133 EXTRN _Monitor NEAR
\r
135 EXTRN InitFreeLB NEAR
\r
139 EXTRN AddTSSDesc NEAR
\r
140 EXTRN InitMemMgmt NEAR
\r
141 EXTRN InitNewJCB NEAR
\r
142 EXTRN InitVideo NEAR
\r
143 EXTRN InitFreeTSS NEAR
\r
144 EXTRN InitDynamicJCBs NEAR
\r
145 EXTRN InitDynamicRQBs NEAR
\r
147 ;=============================================================================
\r
148 ; Set up the initial Stack Pointer (SS = DS already).
\r
149 ; This is the first code we execute after the loader
\r
150 ; code throws us into protected mode. It's a FAR jump
\r
151 ; from that code...
\r
152 ;=============================================================================
\r
155 PUBLIC OSInitBegin:
\r
156 LEA EAX,OSStackTop ; Setup initial OS Stack
\r
157 MOV ESP,EAX ; FIRST THING IN OS CODE.
\r
158 MOV _BootDrive, EDX ; Left there from BootSector Code
\r
160 ;=============================================================================
\r
161 ; Set up OS Common Public for IDT and GDT Base and Limits - SECOND THING IN OS
\r
162 ;=============================================================================
\r
164 SGDT FWORD PTR GDTLimit ;A formality - we know where they are!
\r
165 SIDT FWORD PTR IDTLimit ;
\r
167 ;=============================================================================
\r
168 ; Setup Operating System Structures and motherboard hardware
\r
169 ; THIS IS RIGHT AFTER WE GET A STACK.
\r
170 ; YOU CAN'T ALLOCATE ANY OS RESOURCES UNTIL THIS CODE EXECUTES!!!
\r
171 ;=============================================================================
\r
173 CALL InitCallGates ; Sets up all call gates as DUMMYs
\r
174 ; except AddCallGate which
\r
175 must be made valid first!
\r
177 CALL InitOSPublics ; Sets up OS PUBLIC call gates
\r
179 CALL InitIDT ;Sets up default Interrupt table
\r
180 ;NOTE: This uses CallGates!
\r
182 MOV ECX,nLB ; count of Link Blocks
\r
183 MOV EDX,sLinkBlock ; EDX is size of a Link Block
\r
184 CALL InitFreeLB ; Init the array of Link Blocks
\r
186 CALL InitDMA ; Sets up DMA with defaults
\r
188 CALL Set8259 ; Set up 8259s for ints (before KBD)
\r
190 CALL InitKBD ; Initialize the Kbd hardware
\r
192 PUSH 0 ; Highest IRQ number (all IRQs)
\r
193 CALL FWORD PTR _EndOfIRQ ; Tell em to work
\r
195 ;Set time counter divisor to 11938 - 10ms ticks
\r
196 ;Freq in is 1.193182 Mhz/11932 = 100 per second
\r
197 ;or 1 every 10 ms. (2E9Ch = 11932 decimal)
\r
199 MOV AL,9Ch ; Makes the timer Tick (lo)
\r
200 OUT 40h,AL ; 10 ms apart by setting
\r
201 MOV AL,02Eh ; clock divisior to (hi byte)
\r
202 OUT 40h,AL ; 11,932
\r
204 STI ; We are ready to GO (for now)
\r
206 ;=============================================================================
\r
207 ; The following code finishes the initialization procedures BEFORE the
\r
208 ; OS goes into paged memory mode.
\r
209 ; We set up an initial Task by filling a static TSS, creating and loading
\r
210 ; a descriptor entry for it in the GDT and we do the same for the debugger.
\r
211 ;=============================================================================
\r
213 ; Make the default TSS for the CPU to switch from a valid one.
\r
214 ; This TSS is a valid TSS after the first task switch.
\r
215 ; IMPORTANT - Allocate Exch and InitMemMgmt calls depend on
\r
216 ; pRunTSS being valid. They can not be called before
\r
217 ; this next block of code!!! Note that this TSS does NOT
\r
218 ; get placed in the linked list with the rest of the TSSs.
\r
219 ; It will never be free. We also have to manaully make it's
\r
220 ; entry in the GDT.
\r
222 ;The following code section builds a descriptor entry for
\r
223 ;the initial TSS (for Montitor program) and places it into the GDT
\r
225 MOV EAX, sTSS ; Limit of TSS (TSS + SOFTSTATE)
\r
226 MOV EBX, 0089h ; G(0),AV(0),LIM(0),P(1),DPL(0),B(0)
\r
227 MOV EDX, OFFSET MonTSS ; Address of TSS
\r
228 MOV EDI, OFFSET rgTSSDesc ; Address of GDT entry to fill
\r
231 ;Now that we have valid Descriptor, we set up the TSS itself
\r
232 ;and Load Task Register with the descriptor (selector)
\r
233 ;Note that none of the TSS register values need to be filled in
\r
234 ;because they will be filled by the processor on the first
\r
237 MOV EBX, OFFSET MonTSS ; Get ptr to initial TSS in EBX
\r
238 MOV pRunTSS,EBX ; this IS our task now!!!
\r
239 MOV EAX, OFFSET rgTSSDesc ; ptr to initial TSS descriptor
\r
240 SUB EAX, OFFSET GDT ; Sub offset of GDT Base to get Sel of TSS
\r
241 MOV WORD PTR [EBX+TSS_IOBitBase], 0FFh; I/O Permission
\r
242 MOV [EBX+Tid],AX ; Store TSS Selector in TSS (Task ID)
\r
243 LTR WORD PTR [EBX+Tid] ; Setup the Task Register
\r
244 MOV BYTE PTR [EBX+Priority], 25 ; Priority 25 (monitor is another APP)
\r
245 MOV DWORD PTR [EBX+TSS_CR3], OFFSET PDir1 ;Physical address of PDir1
\r
246 MOV WORD PTR [EBX+TSSNum], 1 ;Number of first TSS (Duh)
\r
248 ;Set up Job Control Block for Monitor (always Job 1)
\r
249 ;JOB 0 is not allowed. First JCB IS job 1!
\r
251 MOV EAX, OFFSET MonJCB ;
\r
252 MOV DWORD PTR [EAX+JobNum], 1 ;Number the JCB
\r
253 MOV EBX, OFFSET MonTSS ;Must put ptr to JCB in TSS
\r
254 MOV [EBX+TSS_pJCB], EAX ;pJCB into MonTSS
\r
255 MOV EBX, OFFSET PDir1 ;Page Directory
\r
256 MOV ESI, OFFSET rgOSJob ;Job Name
\r
257 MOV ECX, cbOSJob ;Size of Name
\r
258 XOR EDX, EDX ;NO pVirtVid yet (set up later in init)
\r
262 ; IMPORTANT - You can't call AllocExch before pRunTSS is VALID!
\r
264 ; THIS IS THE FIRST POINT AllocExh is valid
\r
267 ADD EAX, TSS_Exch ;Alloc exch for initial (first) TSS
\r
269 CALL FWORD PTR _AllocExch
\r
273 ;=============================================================================
\r
275 ; Set up DEBUGGER Task and Job
\r
276 ; The debugger is set up as another job with its one task.
\r
277 ; The debugger must not be called (Int03) until this code executes,
\r
278 ; AND the video is initialized.
\r
279 ; We can't use NewTask because the debugger operates independent of
\r
280 ; the kernel until it is called (INT 03 or Exception)
\r
282 ;The following code section builds a descriptor entry for
\r
283 ;the initial TSS (for Debugger) and places it into the GDT
\r
285 MOV EAX, sTSS ; Limit of TSS (TSS + SOFTSTATE)
\r
286 MOV EBX, 0089h ; G(0),AV(0),LIM(0),P(1),DPL(0),B(0)
\r
287 MOV EDX, OFFSET DbgTSS ; Address of Debugger TSS
\r
288 MOV EDI, OFFSET rgTSSDesc+8 ; Address of GDT entry to fill in
\r
291 ;Now that we have valid Descriptor, we set up the TSS itself
\r
293 MOV EAX, OFFSET rgTSSDesc+8 ; ptr to second TSS descriptor
\r
294 SUB EAX, OFFSET GDT ; Sub offset of GDT Base to get Sel of TSS
\r
295 MOV EBX, OFFSET DbgTSS ; Get ptr to initial TSS in EBX
\r
296 MOV WORD PTR [EBX+TSS_IOBitBase], 0FFh; I/O Permission
\r
297 MOV [EBX+Tid],AX ; Store TSS Selector in TSS (Task ID)
\r
298 MOV BYTE PTR [EBX+Priority], 1 ; Debugger is HIGH Priority
\r
299 MOV DWORD PTR [EBX+TSS_CR3], OFFSET PDir1 ;Physical address of PDir1
\r
300 MOV EDX, OFFSET DbgTask
\r
301 MOV [EBX+TSS_EIP],EDX
\r
302 MOV WORD PTR [EBX+TSS_CS],OSCodeSel ; Put OSCodeSel in the TSS
\r
303 MOV WORD PTR [EBX+TSS_DS],DataSel ; Put DataSel in the TSS
\r
304 MOV WORD PTR [EBX+TSS_ES],DataSel ;
\r
305 MOV WORD PTR [EBX+TSS_FS],DataSel ;
\r
306 MOV WORD PTR [EBX+TSS_GS],DataSel ;
\r
307 MOV WORD PTR [EBX+TSS_SS],DataSel ;
\r
308 MOV WORD PTR [EBX+TSS_SS0],DataSel ;
\r
309 MOV EAX, OFFSET Stack1Top
\r
310 MOV DWORD PTR [EBX+TSS_ESP],EAX ; A 1K Stack in the Dbg TSS
\r
311 MOV DWORD PTR [EBX+TSS_ESP0],EAX ;
\r
312 MOV DWORD PTR [EBX+TSS_EFlags],00000202h ; Load the Flags Register
\r
313 MOV WORD PTR [EBX+TSSNum], 2 ; Number of Dubegger TSS
\r
315 ;Set up Job Control Block for Debugger
\r
316 ;JOB 0 is not allowed. First JCB IS job 1, debugger is always 2
\r
318 MOV EAX, OFFSET DbgJCB
\r
319 MOV DWORD PTR [EAX+JobNum], 2 ;Number the JCB
\r
320 MOV [EBX+TSS_pJCB], EAX ;EBX still points to DbgTSS
\r
321 MOV EBX, OFFSET PDir1 ;Page Directory (OS PD to start)
\r
322 MOV ESI, OFFSET rgDbgJob ;Name
\r
323 MOV ECX, cbDbgJob ;size of name
\r
324 MOV EDX, 1 ;Debugger gets video 1
\r
327 ;Now allocate the default exchange for Debugger
\r
329 MOV EAX, OFFSET DbgTSS
\r
330 ADD EAX, TSS_Exch ;Alloc exch for Debugger TSS
\r
332 CALL FWORD PTR _AllocExch
\r
334 ;================================================================
\r
335 ; ALSO NOTE: The InitMemMgmt call enables PAGING! Physical addresses
\r
336 ; will not necessarily match Linear addresses beyond this point.
\r
340 CALL InitMemMgmt ;InitMemMgmt allocates an exch so
\r
341 ;this the first point it can be called.
\r
342 ;It also calls SEND!
\r
345 ;================================================================
\r
346 ; FIRST POINT memory management calls are valid
\r
347 ;================================================================
\r
349 ;Now we will allocate two virtual video screens (1 Page each)
\r
350 ;for the Monitor and Debugger and place them in the JCBs
\r
351 ;Also we set pVidMem for Monitor to VGATextBase address
\r
352 ;cause it has the active video by default
\r
355 MOV EAX, OFFSET MonJCB ; Ptr to Monitor JCB
\r
356 ADD EAX, pVirtVid ; Offset in JCB to pVirtVid
\r
358 CALL FWORD PTR _AllocOSPage ; Get 'em!
\r
359 MOV EAX, OFFSET MonJCB ; Make VirtVid Active for Monitor
\r
360 MOV DWORD PTR [EAX+pVidMem], VGATextBase
\r
364 MOV EAX, OFFSET DbgJCB ;
\r
367 CALL FWORD PTR _AllocOSPage ; Get 'em!
\r
368 MOV EAX, OFFSET DbgJCB ;
\r
369 MOV EBX, [EAX+pVirtVid]
\r
370 MOV [EAX+pVidMem], EBX ; Video NOT active for Debugger
\r
372 CALL InitVideo ;Set Text Screen 0
\r
375 ; MOV EAX,30423042h ;BB on CYAN - So we know we are here!
\r
376 ; MOV DS:VGATextBase+00h,EAX
\r
378 ;================================================================
\r
379 ; FIRST POINT video calls are valid
\r
380 ; FIRST POINT Debugger is working (only because it needs the video)
\r
382 ; At this point we can allocate pages for dynamic structures and
\r
384 ;================================================================
\r
386 ; Allocate 8 pages (32768 bytes) for 64 Task State Segments (structures).
\r
387 ; Then call InitFreeTSS (which fills them all in with default values)
\r
389 PUSH 8 ; 8 pages for 64 TSSs (32768 bytes)
\r
390 MOV EAX, OFFSET pDynTSSs ;
\r
392 CALL FWORD PTR _AllocOSPage ; Get 'em!
\r
394 XOR EAX, EAX ; Clear allocated memory for TSSs
\r
395 MOV ECX, 8192 ; (512 * 64 = 32768 = 8192 * 4)
\r
396 MOV EDI, pDynTSSs ; where to store 0s
\r
400 MOV ECX, nTSS-2 ; count of dynamic TSSs (- OS & Dbgr TSS)
\r
401 CALL InitFreeTSS ; Init the array of Process Control Blocks
\r
403 CALL InitDynamicJCBs
\r
404 CALL InitDynamicRQBs
\r
406 ;================================================================
\r
407 ; Allocate 1 page (4096 bytes) for 256 Exchanges (16*256=4096).
\r
408 ; Exchanges are 16 bytes each. Then zero the memory which has
\r
409 ; the effect of initializing them because all fields in an Exch
\r
410 ; are zero if not allocated.
\r
412 PUSH 1 ; 1 pages for 256 Exchs (4096 bytes)
\r
413 MOV EAX, OFFSET pExchTmp ; Returns ptr to allocated mem in pJCBs
\r
415 CALL FWORD PTR _AllocOSPage ; Get it!
\r
417 XOR EAX, EAX ; Clear allocated memory
\r
418 MOV ECX, 1024 ; (4*1024=4096)
\r
419 MOV EDI, pExchTmp ; where to store 0s
\r
420 REP STOSD ; Store EAX in 1024 locations
\r
422 ;Now we move the contents of the 3 static exchanges
\r
423 ;into the dynamic array. This is 60 bytes for 3
\r
426 MOV ESI, prgExch ; Source (static ones)
\r
427 MOV EDI, pExchTmp ; Destination (dynamic ones)
\r
428 MOV ECX, 12 ; 12 DWords (3 Exchanges)
\r
429 REP MOVSD ; Move 'em!
\r
430 MOV EAX, pExchTmp ; The new ones
\r
431 MOV prgExch, EAX ; prgExch now points to new ones
\r
432 MOV nExch, nDynEXCH ; 256 to use (-3 already in use)
\r
434 ;================================================================
\r
436 PUSH 7 ; Look at LPT IRQ
\r
437 CALL FWORD PTR _UnMAskIRQ ;
\r
439 CALL _Monitor ;Head for the Monitor!!
\r
441 ;The Monitor call never comes back (it better not...)
\r
443 HLT ;Well, you never know (I AM human)
\r
448 ;================== End of Main.asm ==============================
\r