]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1994-12-31 11:32:20
authorRichard Burgess <>
Sat, 31 Dec 1994 11:32:20 +0000 (11:32 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:47 +0000 (14:03 +0000)
ossource/main.asm [new file with mode: 0644]

diff --git a/ossource/main.asm b/ossource/main.asm
new file mode 100644 (file)
index 0000000..18135a5
--- /dev/null
@@ -0,0 +1,448 @@
+;   MMURTL Operating System Source Code\r
+;   Copyright 1991,1992,1993,1994  Richard A. Burgess\r
+;   ALL RIGHTS RESERVED\r
+;   Version 1.0\r
+;\r
+; This is the main Data/Code file for the MMURTL OS.\r
+; It contains important structures and initialization code\r
+; including the first instructions executed after a boot!\r
+; This should follow the IDT, GDT, PDR & Public call table in memory.\r
+\r
+.DATA\r
+.INCLUDE MOSEDF.INC\r
+.INCLUDE JOB.INC\r
+.INCLUDE TSS.INC\r
+\r
+.ALIGN DWORD\r
+;=============================================================================\r
+; Kernel Structures - See MOSEDF.INC for structure details.\r
+;=============================================================================\r
+\r
+PUBLIC MonTSS          DB sTSS dup (0) ; Initial TSS for OS/Monitor\r
+PUBLIC DbgTSS          DB sTSS dup (0) ; Initial TSS for Debugger\r
+PUBLIC pFreeTSS                DD NIL                  ; Pointer to Free List of Task State Segs\r
+PUBLIC pDynTSSs                DD 0                    ; ptr to alloced mem for dynamic TSSs\r
+PUBLIC _nTSSLeft       DD nTSS-2               ; For stats (less static TSSs)\r
+\r
+;------------------\r
+\r
+PUBLIC rgLBs    DB (nLB*sLINKBLOCK) dup (0)    ; pool of LBs\r
+PUBLIC pFreeLB  DD NIL                                         ; Ptr to Free List of Link Block\r
+PUBLIC _nLBLeft        DD nLB                                          ; For Monitor stats\r
+\r
+;------------------\r
+; The RUN Queue for "Ready to Run" tasks\r
+\r
+PUBLIC RdyQ  DB (sQUEUE*nPRI) dup (0)  ; Priority Based Ready Queue\r
+\r
+;------------------\r
+; Two static Job Control Blocks (JCBs) to get us kick-started.\r
+; The rest of them are in allocated memory\r
+\r
+PUBLIC MonJCB      DB sJCB dup (0)             ; Monitor JCB\r
+PUBLIC DbgJCB      DB sJCB dup (0)             ; Debugger JCB\r
+\r
+;------------------\r
+\r
+PUBLIC GDTLimit                DW 0000h                ;Global Descriptor Table Limit\r
+PUBLIC GDTBase         DD 00000000h    ;base\r
+PUBLIC IDTLimit                DW 0000h        ;Interrupt Descriptor Table Limit\r
+PUBLIC IDTBase         DD 00000000h    ;base\r
+\r
+;------------------\r
+PUBLIC rgSVC    DB (sSVC*nSVC) dup (0)         ; Setup an array of Service Descriptors\r
+\r
+;------------------\r
+;Exchanges take up a fair amount of memory. In order to use certain kernel\r
+;primitives, we need exchanges before they are allocated dynamically.\r
+;We have an array of 3 exchanges set aside for this purpose.  After\r
+;the dynamic array is allocated an initialized, we copy these into\r
+;the first three dynamic exchanges.  These static exchanges are used\r
+;by the Monitor TSS, Debugger TSS, and memory Management.\r
+\r
+PUBLIC nExch  DD 3                                     ; This will be changed after allocation\r
+                                                                       ; of dynamic exchanges.\r
+rgExchTmp  DB (sEXCH * 3) dup (0)      ; Setup three static temporary Exchanges\r
+                                                                       ; for Monitor and Debugger TSSs\r
+                                                                       ; These are moved to a dynamic Exch Array\r
+                                                                       ; as soon as it's allocated.\r
+PUBLIC          prgExch    DD OFFSET rgExchTmp         ; Pointer to current array of Exchanges.\r
+PUBLIC   pExchTmp   DD 0                               ; Pointer to dynamic array Exchanges.\r
+PUBLIC   _nEXCHLeft DD nDynEXCH                        ; For Monitor stats\r
+\r
+;-------------------\r
+;Scheduling management variables\r
+\r
+PUBLIC TSS                     DD 00000000h    ; Used for jumping to next task\r
+PUBLIC TSS_Sel         DW 0000h                ; "    "\r
+\r
+.ALIGN DWORD\r
+\r
+PUBLIC pRunTSS         DD NIL                  ; Pointer to the Running TSS\r
+PUBLIC SwitchTick      DD 0                    ; Tick of last task switch\r
+PUBLIC dfHalted     DD 0                       ; nonzero if processor was halted\r
+\r
+PUBLIC _nSwitches      DD 0                    ; # of switches for statistics\r
+PUBLIC _nSlices                DD 0                    ; # of sliced switches for stats\r
+PUBLIC _nReady         DD 0                    ; # of task Ready to Run for stats\r
+PUBLIC _nHalts         DD 0                    ; # of times CPU halted for stats\r
+\r
+;THESE ARE THE INITIAL STACKS FOR THE OS Monitor AND Debugger\r
+\r
+OSStack                DD 0FFh DUP (00000000h) ;1K OS Monitor Stack\r
+OSStackTop     DD 00000000h\r
+OSStackSize    EQU OSStackTop-OSStack\r
+\r
+Stack1         DD 0FFh DUP (00000000h) ;1K Debugger Stack\r
+Stack1Top      DD 00000000h\r
+Stack1Size     EQU Stack1Top-Stack1\r
+\r
+;-----------------\r
+\r
+rgNewJob       DB 'New Job'                    ;Placed in New JCBs\r
+cbNewJob       EQU 7\r
+\r
+rgOSJob                DB 'MMOS Monitor'               ;Placed in first JCB\r
+cbOSJob                EQU 12\r
+\r
+rgDbgJob       DB 'Debugger    '               ;Name for Job\r
+cbDbgJob       DD 12                                   ;Size of Job Name\r
+\r
+PUBLIC _BootDrive  DD 00                       ;Source drive of the boot\r
+;=============================================================================\r
+;=============================================================================\r
+; This begins the OS Code Segment\r
+.CODE\r
+;\r
+.VIRTUAL 10000h                                ;64K boundry. This lets the assembler know\r
+                                                       ;that this is the address where we execute\r
+;\r
+; BEGIN OS INITIALIZATION CODE\r
+;\r
+; This code is used to initialize the permanent OS structures\r
+; and calls procedures that initialize dynamic structures too.\r
+;\r
+; "Will Robinson, WARNING, WARNING!! Dr. Smith is approaching!!!"\r
+;  BEWARE ON INITIALIZATION.  The kernel structures and their\r
+;  initialization routines are so interdependent, you must pay\r
+;  close attention before you change the order of ANYTHING.\r
+;  (Anything before we jump to the monitor code that is)\r
+\r
+EXTRN InitCallGates NEAR\r
+EXTRN InitOSPublics NEAR\r
+EXTRN _Monitor NEAR\r
+EXTRN InitIDT NEAR\r
+EXTRN InitFreeLB NEAR\r
+EXTRN InitDMA NEAR\r
+EXTRN Set8259 NEAR\r
+EXTRN InitKBD NEAR\r
+EXTRN AddTSSDesc NEAR\r
+EXTRN InitMemMgmt NEAR\r
+EXTRN InitNewJCB NEAR\r
+EXTRN InitVideo NEAR\r
+EXTRN InitFreeTSS NEAR\r
+EXTRN InitDynamicJCBs NEAR\r
+EXTRN InitDynamicRQBs NEAR\r
+EXTRN DbgTask NEAR\r
+;=============================================================================\r
+; Set up the initial Stack Pointer (SS = DS already).\r
+; This is the first code we execute after the loader\r
+; code throws us into protected mode. It's a FAR jump\r
+; from that code...\r
+;=============================================================================\r
+\r
+.START\r
+PUBLIC OSInitBegin:\r
+               LEA EAX,OSStackTop              ; Setup initial OS Stack\r
+               MOV ESP,EAX                                     ; FIRST THING IN OS CODE.\r
+               MOV _BootDrive, EDX                     ; Left there from BootSector Code\r
+\r
+;=============================================================================\r
+; Set up OS Common Public for IDT and GDT Base and Limits - SECOND THING IN OS\r
+;=============================================================================\r
+\r
+               SGDT FWORD PTR GDTLimit         ;A formality - we know where they are!\r
+               SIDT FWORD PTR IDTLimit         ;\r
+\r
+;=============================================================================\r
+; Setup Operating System Structures and motherboard hardware\r
+; THIS IS RIGHT AFTER WE GET A STACK.\r
+; YOU CAN'T ALLOCATE ANY OS RESOURCES UNTIL THIS CODE EXECUTES!!!\r
+;=============================================================================\r
+\r
+               CALL InitCallGates                      ; Sets up all call gates as DUMMYs\r
+                                                                       ;  except AddCallGate which\r
+                                                                          must be made valid first!\r
+\r
+               CALL InitOSPublics                      ; Sets up OS PUBLIC call gates\r
+\r
+               CALL InitIDT                            ;Sets up default Interrupt table\r
+                                                                       ;NOTE: This uses CallGates!\r
+\r
+               MOV ECX,nLB                                     ; count of Link Blocks\r
+               MOV EDX,sLinkBlock                      ; EDX is size of a Link Block\r
+               CALL InitFreeLB                         ; Init the array of Link Blocks\r
+\r
+               CALL InitDMA                            ; Sets up DMA with defaults\r
+\r
+               CALL Set8259                    ; Set up 8259s for ints (before KBD)\r
+\r
+               CALL InitKBD                    ; Initialize the Kbd hardware\r
+\r
+               PUSH 0                                          ; Highest IRQ number (all IRQs)\r
+               CALL FWORD PTR _EndOfIRQ        ; Tell em to work\r
+\r
+               ;Set time counter divisor to 11938 - 10ms ticks\r
+               ;Freq in is 1.193182 Mhz/11932 = 100 per second\r
+               ;or 1 every 10 ms.  (2E9Ch = 11932 decimal)\r
+\r
+               MOV AL,9Ch                                      ; Makes the timer Tick (lo)\r
+               OUT 40h,AL                      ; 10 ms apart by setting\r
+               MOV AL,02Eh                                     ; clock divisior to (hi byte)\r
+               OUT 40h,AL                      ; 11,932\r
+\r
+               STI                                                     ; We are ready to GO (for now)\r
+\r
+;=============================================================================\r
+; The following code finishes the initialization procedures BEFORE the\r
+; OS goes into paged memory mode.\r
+; We set up an initial Task by filling a static TSS, creating and loading\r
+; a descriptor entry for it in the GDT and we do the same for the debugger.\r
+;=============================================================================\r
+\r
+               ; Make the default TSS for the CPU to switch from a valid one.\r
+               ; This TSS is a valid TSS after the first task switch.\r
+               ; IMPORTANT - Allocate Exch and InitMemMgmt calls depend on\r
+               ; pRunTSS being valid.  They can not be called before\r
+               ; this next block of code!!!  Note that this TSS does NOT\r
+               ; get placed in the linked list with the rest of the TSSs.\r
+               ; It will never be free. We also have to manaully make it's\r
+               ; entry in the GDT.\r
+\r
+               ;The following code section builds a descriptor entry for\r
+               ;the initial TSS (for Montitor program) and places it into the GDT\r
+\r
+               MOV EAX, sTSS                           ; Limit of TSS (TSS + SOFTSTATE)\r
+               MOV EBX, 0089h                  ; G(0),AV(0),LIM(0),P(1),DPL(0),B(0)\r
+               MOV EDX, OFFSET MonTSS          ; Address of TSS\r
+               MOV EDI, OFFSET rgTSSDesc       ; Address of GDT entry to fill\r
+               CALL AddTSSDesc\r
+\r
+               ;Now that we have valid Descriptor, we set up the TSS itself\r
+               ;and Load Task Register with the descriptor (selector)\r
+               ;Note that none of the TSS register values need to be filled in\r
+               ;because they will be filled by the processor on the first\r
+               ;task switch.\r
+\r
+               MOV EBX, OFFSET MonTSS          ; Get ptr to initial TSS in EBX\r
+               MOV pRunTSS,EBX                         ; this IS our task now!!!\r
+               MOV EAX, OFFSET rgTSSDesc       ; ptr to initial TSS descriptor\r
+               SUB EAX, OFFSET GDT         ; Sub offset of GDT Base to get Sel of TSS\r
+               MOV WORD PTR [EBX+TSS_IOBitBase], 0FFh; I/O Permission\r
+               MOV [EBX+Tid],AX                ; Store TSS Selector in TSS (Task ID)\r
+               LTR WORD PTR [EBX+Tid]                          ; Setup the Task Register\r
+               MOV BYTE PTR [EBX+Priority], 25         ; Priority 25 (monitor is another APP)\r
+               MOV DWORD PTR [EBX+TSS_CR3], OFFSET PDir1       ;Physical address of PDir1\r
+               MOV WORD PTR [EBX+TSSNum], 1            ;Number of first TSS (Duh)\r
+\r
+               ;Set up Job Control Block for Monitor (always Job 1)\r
+               ;JOB 0 is not allowed. First JCB IS job 1!\r
+\r
+               MOV EAX, OFFSET MonJCB                  ;\r
+               MOV DWORD PTR [EAX+JobNum], 1   ;Number the JCB\r
+               MOV EBX, OFFSET MonTSS                  ;Must put ptr to JCB in TSS\r
+               MOV [EBX+TSS_pJCB], EAX                 ;pJCB into MonTSS\r
+               MOV EBX, OFFSET PDir1                   ;Page Directory\r
+               MOV ESI, OFFSET rgOSJob                 ;Job Name\r
+               MOV ECX, cbOSJob                                ;Size of Name\r
+               XOR EDX, EDX                                    ;NO pVirtVid yet (set up later in init)\r
+               CALL InitNewJCB\r
+\r
+\r
+; IMPORTANT - You can't call AllocExch before pRunTSS is VALID!\r
+\r
+; THIS IS THE FIRST POINT AllocExh is valid\r
+\r
+               MOV EAX, pRunTSS\r
+               ADD EAX, TSS_Exch                       ;Alloc exch for initial (first) TSS\r
+               PUSH EAX\r
+               CALL FWORD PTR _AllocExch\r
+\r
+\r
+\r
+;=============================================================================\r
+;\r
+; Set up DEBUGGER Task and Job\r
+; The debugger is set up as another job with its one task.\r
+; The debugger must not be called (Int03) until this code executes,\r
+; AND the video is initialized.\r
+; We can't use NewTask because the debugger operates independent of\r
+; the kernel until it is called (INT 03 or Exception)\r
+;\r
+               ;The following code section builds a descriptor entry for\r
+               ;the initial TSS (for Debugger) and places it into the GDT\r
+\r
+               MOV EAX, sTSS                           ; Limit of TSS (TSS + SOFTSTATE)\r
+               MOV EBX, 0089h                  ; G(0),AV(0),LIM(0),P(1),DPL(0),B(0)\r
+               MOV EDX, OFFSET DbgTSS          ; Address of Debugger TSS\r
+               MOV EDI, OFFSET rgTSSDesc+8     ; Address of GDT entry to fill in\r
+               CALL AddTSSDesc\r
+\r
+               ;Now that we have valid Descriptor, we set up the TSS itself\r
+\r
+               MOV EAX, OFFSET rgTSSDesc+8     ; ptr to second TSS descriptor\r
+               SUB EAX, OFFSET GDT         ; Sub offset of GDT Base to get Sel of TSS\r
+               MOV EBX, OFFSET DbgTSS          ; Get ptr to initial TSS in EBX\r
+               MOV WORD PTR [EBX+TSS_IOBitBase], 0FFh; I/O Permission\r
+               MOV [EBX+Tid],AX                ; Store TSS Selector in TSS (Task ID)\r
+               MOV BYTE PTR [EBX+Priority], 1          ; Debugger is HIGH Priority\r
+               MOV DWORD PTR [EBX+TSS_CR3], OFFSET PDir1       ;Physical address of PDir1\r
+               MOV EDX, OFFSET DbgTask\r
+               MOV [EBX+TSS_EIP],EDX\r
+               MOV WORD PTR [EBX+TSS_CS],OSCodeSel             ; Put OSCodeSel in the TSS\r
+               MOV WORD PTR [EBX+TSS_DS],DataSel               ; Put DataSel in the TSS\r
+               MOV WORD PTR [EBX+TSS_ES],DataSel               ;\r
+               MOV WORD PTR [EBX+TSS_FS],DataSel               ;\r
+               MOV WORD PTR [EBX+TSS_GS],DataSel               ;\r
+               MOV WORD PTR [EBX+TSS_SS],DataSel               ;\r
+               MOV WORD PTR [EBX+TSS_SS0],DataSel              ;\r
+               MOV EAX, OFFSET Stack1Top\r
+               MOV DWORD PTR [EBX+TSS_ESP],EAX                 ; A 1K Stack in the Dbg TSS\r
+               MOV DWORD PTR [EBX+TSS_ESP0],EAX                        ;\r
+               MOV DWORD PTR [EBX+TSS_EFlags],00000202h        ; Load the Flags Register\r
+               MOV WORD PTR [EBX+TSSNum], 2                            ; Number of Dubegger TSS\r
+\r
+               ;Set up Job Control Block for Debugger\r
+               ;JOB 0 is not allowed. First JCB IS job 1, debugger is always 2\r
+\r
+               MOV EAX, OFFSET DbgJCB\r
+               MOV DWORD PTR [EAX+JobNum], 2                   ;Number the JCB\r
+               MOV [EBX+TSS_pJCB], EAX         ;EBX still points to DbgTSS\r
+               MOV EBX, OFFSET PDir1           ;Page Directory (OS PD to start)\r
+               MOV ESI, OFFSET rgDbgJob        ;Name\r
+               MOV ECX, cbDbgJob                       ;size of name\r
+               MOV EDX, 1                                      ;Debugger gets video 1\r
+               CALL InitNewJCB\r
+\r
+               ;Now allocate the default exchange for Debugger\r
+\r
+               MOV EAX, OFFSET DbgTSS\r
+               ADD EAX, TSS_Exch                       ;Alloc exch for Debugger TSS\r
+               PUSH EAX\r
+               CALL FWORD PTR _AllocExch\r
+\r
+;================================================================\r
+; ALSO NOTE: The InitMemMgmt call enables PAGING!  Physical addresses\r
+; will not necessarily match Linear addresses beyond this point.\r
+; Pay attention!\r
+;\r
+\r
+               CALL InitMemMgmt                        ;InitMemMgmt allocates an exch so\r
+                                                                       ;this the first point it can be called.\r
+                                                                       ;It also calls SEND!\r
+\r
+\r
+;================================================================\r
+; FIRST POINT memory management calls are valid\r
+;================================================================\r
+\r
+               ;Now we will allocate two virtual video screens (1 Page each)\r
+               ;for the Monitor and Debugger and place them in the JCBs\r
+               ;Also we set pVidMem for Monitor to VGATextBase address\r
+               ;cause it has the active video by default\r
+\r
+               PUSH 1                                          ; 1 page\r
+               MOV EAX, OFFSET MonJCB          ; Ptr to Monitor JCB\r
+               ADD EAX, pVirtVid                       ; Offset in JCB to pVirtVid\r
+               PUSH EAX\r
+               CALL FWORD PTR _AllocOSPage     ; Get 'em!\r
+               MOV EAX, OFFSET MonJCB          ; Make VirtVid Active for Monitor\r
+               MOV DWORD PTR [EAX+pVidMem], VGATextBase\r
+\r
+\r
+               PUSH 1                                          ; 1 page\r
+               MOV EAX, OFFSET DbgJCB          ;\r
+               ADD EAX, pVirtVid\r
+               PUSH EAX\r
+               CALL FWORD PTR _AllocOSPage     ; Get 'em!\r
+               MOV EAX, OFFSET DbgJCB          ;\r
+               MOV EBX, [EAX+pVirtVid]\r
+               MOV [EAX+pVidMem], EBX          ; Video NOT active for Debugger\r
+\r
+               CALL InitVideo                          ;Set Text Screen 0\r
+\r
+\r
+;              MOV EAX,30423042h       ;BB on CYAN - So we know we are here!\r
+;              MOV DS:VGATextBase+00h,EAX\r
+\r
+;================================================================\r
+; FIRST POINT video calls are valid\r
+; FIRST POINT Debugger is working  (only because it needs the video)\r
+\r
+; At this point we can allocate pages for dynamic structures and\r
+; initialize them.\r
+;================================================================\r
+\r
+; Allocate 8 pages (32768 bytes) for 64 Task State Segments (structures).\r
+; Then call InitFreeTSS (which fills them all in with default values)\r
+\r
+               PUSH 8                                          ; 8 pages for 64 TSSs (32768 bytes)\r
+               MOV EAX, OFFSET pDynTSSs        ;\r
+               PUSH EAX\r
+               CALL FWORD PTR _AllocOSPage     ; Get 'em!\r
+\r
+               XOR EAX, EAX                            ; Clear allocated memory for TSSs\r
+               MOV ECX, 8192                           ; (512 * 64 = 32768 = 8192 * 4)\r
+               MOV EDI, pDynTSSs                       ; where to store 0s\r
+               REP STOSD                                       ; Do it\r
+\r
+               MOV EAX, pDynTSSs\r
+               MOV ECX, nTSS-2                         ; count of dynamic TSSs (- OS & Dbgr TSS)\r
+               CALL InitFreeTSS                        ; Init the array of Process Control Blocks\r
+\r
+               CALL InitDynamicJCBs\r
+               CALL InitDynamicRQBs\r
+\r
+;================================================================\r
+; Allocate 1 page (4096 bytes) for 256 Exchanges (16*256=4096).\r
+; Exchanges are 16 bytes each.  Then zero the memory which has\r
+; the effect of initializing them because all fields in an Exch\r
+; are zero if not allocated.\r
+\r
+               PUSH 1                                          ; 1 pages for 256 Exchs (4096 bytes)\r
+               MOV EAX, OFFSET pExchTmp        ; Returns ptr to allocated mem in pJCBs\r
+               PUSH EAX                                        ;\r
+               CALL FWORD PTR _AllocOSPage     ; Get it!\r
+\r
+               XOR EAX, EAX                            ; Clear allocated memory\r
+               MOV ECX, 1024                           ; (4*1024=4096)\r
+               MOV EDI, pExchTmp                       ; where to store 0s\r
+               REP STOSD                                       ; Store EAX in 1024 locations\r
+\r
+               ;Now we move the contents of the 3 static exchanges\r
+               ;into the dynamic array.  This is 60 bytes for 3\r
+               ;exchanges.\r
+\r
+               MOV ESI, prgExch                        ; Source (static ones)\r
+               MOV EDI, pExchTmp                       ; Destination (dynamic ones)\r
+               MOV ECX, 12                                     ; 12 DWords (3 Exchanges)\r
+               REP MOVSD                                       ; Move 'em!\r
+               MOV EAX, pExchTmp                       ; The new ones\r
+               MOV prgExch, EAX                        ; prgExch now points to new ones\r
+               MOV nExch, nDynEXCH                     ; 256 to use (-3 already in use)\r
+\r
+;================================================================\r
+\r
+               PUSH 7                                          ; Look at LPT IRQ\r
+               CALL FWORD PTR _UnMAskIRQ       ;\r
+\r
+               CALL _Monitor                                   ;Head for the Monitor!!\r
+\r
+               ;The Monitor call never comes back (it better not...)\r
+\r
+               HLT                     ;Well, you never know (I AM human)\r
+\r
+\r
+;\r
+\r
+;================== End of Main.asm ==============================\r