Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

37KB

Developing Your Own 32-Bit Operating System — Chapter-21: Initialization Code

  • Source: /library/Developing Your Own 32-Bit Operating System/source-file.pdf
  • PDF pages: 441–460
  • Pages without text: 441

Initialization Code

Part PV ■ The Operating System Source Code This chapter contains code from two separate files. The first file is MainASM. It is the entry point in the operating system, the first instruction executed after boot up. The second file is InitCodeASM, a workhorse for Main.ASM. OS Global Data Listing 21.1 begins the data segment after the static tables that were in previous include files. The order of the first five files included in the assembler template file for MMURTL is critical. The tables before this portion of the data segment are the following: The interrupt descriptor table (IDT) The global descriptor table (GDT) The initial OS page directory (PD) The initial OS page table (PT) The public call gate table The public call gate table is not a processor-defined table as the others are. It defines the selec- tors for public call gates so the rest of the OS code can call into the OS. Following these tables is the data segment portion from MainASM, which is presented later in this chapter. In Chapter 7, “OS Initialization,” I covered the basics of a generic sequence that would be re- quired for initialization of an operating system. Certain data structures and variables are allocated that may be used only once during the ini- tialization process. Many things have to be started before you can allocate memory where the dynamic allocation of resources can begin. The code contains comments noting which of these items are temporary. Periodically, you will see the .ALIGN DWORD command issued to the assembler. Even though the Intel processors can operate on data that is not aligned by its size, access to the data is faster if it is. I generally try to align data that is accessed often, and I don't worry about the rest of it. The assembler does no alignment on its own. Everything is packed, unless you tell it otherwise with the .ALIGN command. Listing 21.1. Listing 21.1. Main operating system data. .DATA .INCLUDE MOSEDF.INC .INCLUDE JOB. INC .INCLUDE TSS.INC .ALIGN DWORD ; Kernel Structures - See MOSEDF.INC for structure details.

Chapter 21 Initialization Code PUBLIC MonTSS PUBLIC DbgTSS PUBLIC pFreeTSS PUBLIC pDynTSSs PUBLIC nTSSLeft DB sTSS dup (0) DB sTSS dup (0) DD NIL DD 0 DD nTSS-2 Initial TSS for OS/Monitor Initial TSS for Debugger Pointer to Free List of Task State Segs ptr to alloced mem for dynamic TSSs For stats (less static TSSs) PUBLIC rgLBs DB (nLBsLINKBLOCK) dup (0) PUBLIC pFreeLB DD NIL PUBLIC nLBLeft DD nLB pool of LBs Ptr to Free List of Link Block For Monitor stats ; The RUN Queue for “Ready to Run” tasks PUBLIC RdyQ DB (sQUEUEnPRI) dup (0) ; Priority Based Ready Queue Two static Job Control Blocks (JCBs) to get us kick-started. The rest of them are in allocated memory PUBLIC MonJCB PUBLIC DbgJCB DB sJCB dup (0) DB sJCB dup (0) ; Monitor JCB ; Debugger JCB PUBLIC GDTLimit PUBLIC GDTBase PUBLIC IDTLimit PUBLIC IDTBase DW 0000h DD DW 0000h DD ;Global Descriptor Table Limit ;base ; Interrupt Descriptor Table Limit PUBLIC rgSVC DB (sSVC*nSVC) dup (0) ; Setup an array of Service Descriptors ; Exchanges take up a fair amount of memory. In order to use certain kernel ; primitives, we need exchanges before they are allocated dynamically. ;We have an array of 3 exchanges set aside for this purpose. After ;the dynamic array is allocated an initialized, we copy these into ;the first three dynamic exchanges. These static exchanges are used ;by the Monitor TSS, Debugger TSS, and memory Management. PUBLIC nExch DD 3 rgExchTmp DB (sEXCH * 3) dup (0 PUBLIC prgExch Exchanges. PUBLIC pExchTmp DD 0 PUBLIC _nEXCHLeft DD nDynEXCH This will be changed after allocation of dynamic exchanges. Setup three static temporary Exchanges for Monitor and Debugger TSSs These are moved to a dynamic Exch Array as soon as it's allocated. DD OFFSET rgExchTmp ; Pointer to current array of Pointer to dynamic array Exchanges. For Monitor stats Scheduling management variables

422 Part IV ■ The Operating System Source Code Listing 21.1. continued PUBLIC TSS PUBLIC TSS Sel .ALIGN DWORD DD DW 0000h PUBLIC pRunTSS DD NIL PUBLIC SwitchTick DD 0 PUBLIC dfHalted DD 0 PUBLIC _nSwitches DD 0 PUBLIC _nSlices DD 0 PUBLIC _nReady DD 0 PUBLIC nHalts DD 0 Used for jumping to next task Pointer to the Running TSS Tick of last task switch nonzero if processor was halted

of switches for statistics

of sliced switches for stats

of task Ready to Run for stats

of times CPU halted for stats

; THESE ARE THE INITIAL STACKS FOR THE OS Monitor AND Debugger OSStack DD 0FFh DUP (00000000h) ;1K OS Monitor Stack OSStackTop DD 00000000h OSStackSize EQU OSStackTop -OSStack Stackl DD 0FFh DUP (00000000h) ;1K Debugger Stack StacklTop DD 00000000h StacklSize EQU Stack1Top-Stack1 rgNewJob cbNewJob DB ‘New Job’ EQU 7 rgOSJob cbOSJob DB ‘MMOS Monitor EQU 12 rgDbgJob cbDbgJob DB ‘Debugger DD 12 BootDrive DD 00 Placed in New JCBs ; Placed in first JCB ;Name for Job ;Size of Job Name ;Source drive of the boot Operating System Entry Point The first instruction in MainASM is the entry point to the operating system. This is the first in- struction executed after the operating system is booted. Look for the . START assembler command. The address of this instruction is known in advance because the loader (boot) code moves the data and code segments of the operating system to a specific hard-coded address. The .virtual command allows you to tell the assembler where this code will execute, and all subsequent address calculations by the assembler are offset by this value. It is similar to the MS-DOS assembler ORIGIN command, with one major difference: DASM doesn't try to fill the segment prior to the virtual address with dead space.

Chapter 21 ■ Initialization Code The .VIRTUAL command can be used only once in an entire program, and it must be at the very beginning of the segment it's used in. For MMURTL, the start address is lOOOOh, the first byte of the second 64 K in physical memory. You'll see many warnings about the order of certain initialization routines. I had to make many warnings to myself just to keep from “housekeeping” the code into a nonworking state. I felt it was important to leave all these comments in for you. See Listing 21.2. Listing 21.2. OS initialization code and entry point. ; This begins the OS Code Segment .CODE .VIRTUAL 10000h ;64K boundry. This lets the assembler know ;that this is the address where we execute BEGIN OS INITIALIZATION CODE This code is used to initialize the permanent OS structures and calls procedures that initialize dynamic structures too. “Will Robinson, WARNING, WARNING!! Dr. Smith is approaching!!!” BEWARE ON INITIALIZATION. The kernel structures and their initialization routines are so interdependent, you must pay close attention before you change the order of ANYTHING. (Anything before we jump to the monitor code that is) EXTRN InitCallGates NEAR EXTRN InitOSPublics NEAR EXTRN _Monitor NEAR EXTRN InitlDT NEAR EXTRN InitFreeLB NEAR EXTRN InitDMA NEAR EXTRN Set8259 NEAR EXTRN InitKBD NEAR EXTRN AddTSSDesc NEAR EXTRN InitMemMgmt NEAR EXTRN InitNewJCB NEAR EXTRN InitVideo NEAR EXTRN InitFreeTSS NEAR EXTRN InitDynamicJCBs NEAR EXTRN InitDynamicRQBs NEAR EXTRN DbgTask NEAR Set up the initial Stack Pointer (SS = DS already). This is the first code we execute after the loader code throws us into protected mode. It's a FAR jump from that code. . . . START PUBLIC OSInitBegin: LEA EAX.OSStackTop ; Setup initial OS Stack MOV ESP.EAX ; FIRST THING IN OS CODE. MOV BootDrive, EDX ; Left there from BootSector Code

H Part IV ■ The Operating System Source Code Listing 21.2. continued Set up OS Common Public for IDT and GDT Base and Limits - SECOND THING IN OS SGDT FWORD PTR GDTLimit ;A formality - we know where they are! SIDT FWORD PTR IDTLimit ; Setup Operating System Structures and motherboard hardware THIS IS RIGHT AFTER WE GET A STACK. YOU CAN'T ALLOCATE ANY OS RESOURCES UNTIL THIS CODE EXECUTES!! CALL InitCallGates Sets up all call gates as DUMMYs except AddCallGate which must be made valid first! CALL InitOSPublics CALL InitlDT MOV ECX.nLB MOV EDX.sLinkBlock CALL InitFreeLB CALL InitDMA CALL Set8259 CALL InitKBD PUSH 0 CALL FWORD PTR EndOflRQ ; Sets up OS PUBLIC call gates ;Sets up default Interrupt table ;NOTE: This uses CallGates! ; count of Link Blocks ; EDX is size of a Link Block ; Init the array of Link Blocks ; Sets up DMA with defaults ; Set up 8259s for ints (before KBD) ; Initialize the Kbd hardware ; Highest IRQ number (all IRQs) ; Tell em to work ;Set time counter divisor to 11938 - 10ms ticks ;Freq in is 1.193182 Mhz/11932 = 100 per second ;or 1 every 10 ms. (2E9Ch = 11932 decimal) MOV AL,9Ch OUT 40h,AL MOV AL,02Eh OUT 40h,AL STI Makes the timer Tick (lo) 10 ms apart by setting clock divisior to (hi byte) 11,932 ; We are ready to GO (for now) The following code finishes the initialization procedures BEFORE the OS goes into paged memory mode. We set up an initial Task by filling a static TSS, creating and loading a descriptor entry for it in the GDT and we do the same for the debugger. Make the default TSS for the CPU to switch from a valid one. This TSS is a valid TSS after the first task switch.

Chapter 21 Initialization Code H ; IMPORTANT - Allocate Exch and InitMemMgmt calls depend on ; pRunTSS being valid. They can not be called before ; this next block of code!!! Note that this TSS does NOT ; get placed in the linked list with the rest of the TSSs. ; It will never be free. We also have to manually make its ; entry in the GDT. ;The following code section builds a descriptor entry for ;the initial TSS (for Montitor program) and places it into the GDT MOV EAX, sTSS MOV EBX, 0089h MOV EDX, OFFSET MonTSS MOV EDI, OFFSET rgTSSDesc CALL AddTSSDesc Limit of TSS (TSS + SOFTSTATE) G(0),AV(0),LIM(0),P(1),DPL(0),B(0) Address of TSS Address of GDT entry to fill ;Now that we have valid Descriptor, we set up the TSS itself ;and Load Task Register with the descriptor (selector) ;Note that none of the TSS register values need to be filled in jbecause they will be filled by the processor on the first :task switch. MOV EBX, OFFSET MonTSS MOV pRunTSS.EBX MOV EAX, OFFSET rgTSSDesc SUB EAX, OFFSET GDT Get ptr to initial TSS in EBX this IS our task now! ! ! ptr to initial TSS descriptor Sub offset of GDT Base to get Sel of TSS MOV WORD PTR [EBX+TSS_IOBitBase] , 0FFh; I/O Permission MOV [EBX+Tid],AX ; Store TSS Selector in TSS (Task ID) LTR WORD PTR [EBX+Tid] ; Setup the Task Register MOV BYTE PTR [EBX+Priority] , 25 ; Priority 25 (monitor is another APP) MOV DWORD PTR [EBX+TSS_CR3] , OFFSET PDirl ;Physical address of PDirl MOV WORD PTR [EBX+TSSNum] , 1 ;Number of first TSS (Duh) ;Set up Job Control Block for Monitor (always Job 1) ;JOB 0 is not allowed. First JCB IS job 1! MOV EAX, OFFSET MonJCB MOV DWORD PTR [EAX+JobNum] , 1 MOV EBX, OFFSET MonTSS MOV [EBX+TSS_pJCB], EAX MOV EBX, OFFSET PDirl MOV ESI, OFFSET rgOSJob MOV ECX, cbOSJob XOR EDX, EDX CALL InitNewJCB Number the JCB Must put ptr to JCB in TSS pJCB into MonTSS Page Directory Job Name Size of Name NO pVirtVid yet (set up later in init) ; IMPORTANT - You can't call AllocExch before pRunTSS is VALID! ; THIS IS THE FIRST POINT AllocExh is valid MOV EAX, pRunTSS ADD EAX, TSS_Exch PUSH EAX CALL FWORD PTR AllocExch ;Alloc exch for initial (first) TSS

I
426 Part TV ■ The Operating System Source Code Listing 21.2. continued Set up DEBUGGER Task and Job The debugger is set up as another job with its one task. The debugger must not be called (Int03) until this code executes, AND the video is initialized. We can't use NewTask because the debugger operates independent of the kernel until it is called (INT 03 or Exception) ;The following code section builds a descriptor entry for ;the initial TSS (for Debugger) and places it into the GDT MOV EAX, sTSS ; Limit of TSS (TSS + SOFTSTATE) MOV EBX, 0089h j G(0) ,AV(0) , LIM(0) ,P(1 ) ,DPL(0) ,B(0) MOV EDX, OFFSET DbgTSS ; Address of Debugger TSS MOV EDI, OFFSET rgTSSDesc+8 ; Address of GDT entry to fill in CALL AddTSSDesc ;Now that we have valid Descriptor, we set up the TSS itself MOV EAX, OFFSET rgTSSDesc+8 ; ptr to second TSS descriptor SUB EAX, OFFSET GDT ; Sub offset of GDT Base to get Sel of TSS MOV EBX, OFFSET DbgTSS ; Get ptr to initial TSS in EBX MOV WORD PTR [EBX+TSS_IOBitBase] , 0FFh; I/O Permission MOV [EBX+Tid],AX ; Store TSS Selector in TSS (Task ID) MOV BYTE PTR [EBX+Priority] , 1 ; Debugger is HIGH Priority MOV DWORD PTR [EBX+TSS_CR3] , OFFSET PDirl ;Physical address Of PDirl MOV EDX, OFFSET DbgTask MOV [EBX+TSS_EIP],EDX MOV WORD PTR [EBX+TSS_CS] .OSCodeSel MOV WORD PTR [EBX+TSS_DS] ,DataSel MOV WORD PTR [EBX+TSS_ES] .DataSel MOV WORD PTR [EBX+TSS_FS] , DataSel MOV WORD PTR [EBX+TSS_GS] .DataSel MOV WORD PTR [EBX+TSS_SS] .DataSel MOV WORD PTR [EBX+TSS_SS0] .DataSel MOV EAX, OFFSET StacklTop MOV DWORD PTR [EBX+TSS_ESP] ,EAX ; MOV DWORD PTR [EBX+TSS_ESP0] ,EAX MOV DWORD PTR [EBX+TSS_EFlags] ,00000202h MOV WORD PTR [EBX+TSSNum] , 2 Put OSCodeSel in the TSS Put DataSel in the TSS A 1K Stack in the Dbg TSS ; Load the Flags Register ; Number of Debugger TSS ;Set up Job Control Block for Debugger ;JOB 0 is not allowed. First JCB IS job 1 debugger is always 2 MOV EAX, OFFSET DbgJCB MOV DWORD PTR [EAX+JobNum] MOV [EBX+TSS_pJCB], EAX MOV EBX, OFFSET PDirl MOV ESI, OFFSET rgDbgJob MOV ECX, cbDbgJob MOV EDX, 1 CALL InitNewJCB 2 ;Number the JCB ;EBX still points to DbgTSS ;Page Directory (OS PD to start) ;Name ;size of name ;Debugger gets video 1 ;Now allocate the default exchange for Debugger

Chapter 21 M Initialization Code H MOV EAX, OFFSET DbgTSS ADD EAX, TSS_Exch ;Alloc exch for Debugger TSS PUSH EAX CALL FWORD PTR AllocExch At this point, all of the static data that needs to be initialized is done. You had to set up all the necessary items for kernel messaging so you could initialize memory management. This was necessary because memory management uses messaging. There are many “chickens and eggs” here. Move one incorrectly and whamo — the code doesn't work. Not even the debugger. After about 30 hours of debugging with no debugger, you'll appreciate the importance of keeping the order correct. The memory-management initialization routines were presented in Chapter 19, “Memory Management Code.” See Listing 21.3. Listing 21.3. Continuation of OS initialization. ALSO NOTE: The InitMemMgmt call enables PAGING! Physical addresses will not necessarily match Linear addresses beyond this point. Pay attention! CALL InitMemMgmt ; InitMemMgmt allocates an exch so ;this the first point it can be called. ;It also calls SEND! After you have the memory allocation calls working, you can allocate space for all of the dynamic arrays and structures, such as task state segments, exchanges, and video buffers. See Listing 21.4. Listing 21.4. Continuation of OS initialization. FIRST POINT memory management calls are valid ;Now we will allocate two virtual video screens (1 Page each] ;for the Monitor and Debugger and place them in the JCBs ;Also we set pVidMem for Monitor to VGATextBase address ; cause it has the active video by default 1 page Ptr to Monitor JCB Offset in JCB to pVirtVid PUSH 1 MOV EAX, OFFSET MonJCB ADD EAX, pVirtVid PUSH EAX CALL FWORD PTR _AllocOSPage ; Get ‘em! MOV EAX, OFFSET MonJCB ; Make VirtVid Active for Monitor MOV DWORD PTR [EAX+pVidMem] , VGATextBase

H Part PV ■ 7”/v Operating System Source Code Listing 21.4. continued PUSH 1 MOV EAX, OFFSET DbgJCB ADD EAX, pVirtVid PUSH EAX CALL FWORD PTR _AllocOSPage MOV EAX, OFFSET DbgJCB MOV EBX, [EAX+pVirtVid] MOV [EAX+pVidMem] , EBX CALL InitVideo 1 page Get ‘em! ; Video NOT active for Debugger ;Set Text Screen 0 MOV EAX,30423042h ;BB on CYAN - So we know we are here! MOV DS:VGATextBase+00n,EAX FIRST POINT video calls are valid FIRST POINT Debugger is working (only because it needs the video) At this point we can allocate pages for dynamic structures and initialize them. Allocate 8 pages (32768 bytes) for 64 Task State Segments (structures) Then call InitFreeTSS (which fills them all in with default values) PUSH 8 MOV EAX, OFFSET pDynTSSs ; PUSH EAX CALL FWORD PTR _AllocOSPage ; Get ‘em ; 8 pages for 64 TSSs (32768 bytes) XOR EAX, EAX MOV ECX, 8192 MOV EDI, pDynTSSs REP STOSD Clear allocated memory for TSSs (512 * 64 = 32768 = 8192 * 4) where to store 0s Do it MOV EAX, pDynTSSs MOV ECX, nTSS-2 CALL InitFreeTSS count of dynamic TSSs ( - OS & Dbgr TSS) Init the array of Process Control Blocks CALL InitDynamicJCBs CALL InitDynamicRQBs Allocate 1 page (4096 bytes) for 256 Exchanges (16*256=4096). Exchanges are 16 bytes each. Then zero the memory which has the effect of initializing them because all fields in an Exch are zero if not allocated. PUSH 1 MOV EAX, OFFSET pExchTmp PUSH EAX CALL FWORD PTR _AllocOSPage 1 pages for 256 Exchs (4096 bytes) Returns ptr to allocated mem in pJCBs Get it! XOR EAX, EAX Clear allocated memory

Chapter 21 ■ Initialization Code MOV ECX, 1024 ; (4*1024=4096) MOV EDI, pExchTmp ; where to store 0s REP STOSD ; Store EAX in 1024 locations ;Now we move the contents of the 3 static exchanges ;into the dynamic array. This is 60 bytes for 3 ; exchanges. MOV ESI, prgExch MOV EDI, pExchTmp MOV ECX, 12 REP MOVSD MOV EAX, pExchTmp MOV prgExch, EAX MOV nExch, nDynEXCH Source (static ones) Destination (dynamic ones) 12 DWords (3 Exchanges) Move ‘em! The new ones prgExch now points to new ones 256 to use (-3 already in use) All of the basic resource managers are working at this point. You actually have a working op- erating system. From here, you go to code that will finish off the higher-level initialization functions, such as device drivers and loader tasks. See Listing 21.5. Listing 21.5. End of initialization code. CALL _Monitor ;Head for the Monitor!! ;The Monitor call never comes back (it better not...) HLT ;Well, you never know (I AM human) Initialization Helpers The file InitCodcASM provides much of the support “grunt work” required to get the oper- ating system up and running. The procedure InitOSPublics ( ) sets up all the default values for call gates and interrupt vectors, and it initializes some of the free dynamically allocated struc- tures, such as TSSs and link blocks. Near the end of this file are the little assembly routines to fill in each of the 100-plus call gate entries in the GDT. I have not included them all here in print because they are so repetitive. This is noted in the comments. See Listing 21.6. Listing 21 .6. Initialization subroutines. .CODE EXTRN IntQ NEAR EXTRN IntDivBy0 NEAR EXTRN IntDbgSS NEAR

430 | Part IV ■ The Operating System Source Code Listing 21.6. continued EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN EXTRN IntDebug NEAR IntOverFlow NEAR INTOpCode NEAR IntDblExc INTInvTss INTNoSeg INTStkOvr IntGP INTPgFlt IntPICU2 IntTimer IntKeyBrd NEAR NEAR NEAR NEAR NEAR NEAR NEAR NEAR NEAR The following code initializes structures just after bootup INPUT : ECX, EDX OUTPUT : NONE REGISTERS : EAX, EBX, ECX, FLAGS MODIFIES : pFreeLB, rgLBs This routine will initialize a free pool of link blocks. The data used in this algorithm are an array of ECX link blocks (rgLBs) each EDX bytes long and pointer to a list of free link blocks (pFreeLB) The pFreeLB pointer is set to address the first element in rgLBs. Each element of rgLBs is set to point to the next element of rgLBs. The last element of rgLBs is set to point to nothing (NIL). PUBLIC InitFreeLB: LEA EAX, rgLBs MOV pFreeLB, EAX pFreeLB <= “rgLBs; LBLoop: MOV EBX, EAX ADD EAX, EDX MOV [EBX+NextLB],EAX LOOP LB_Loop MOV DWORD PTR [EBX+NextLB] , 0 RETN for I = 0 TO ECX rgLBs[I] .Next <= ~rgLBs[I+1] ; rgFree[1023] .Next <= NIL; AddTSSDesc Builds a descriptor for a task and places it in the GDT. If you check the Intel documentation the bits of data that hold this information are scattered through the descriptor entry, so we have to do some shifting, moving, anding and oring to get the descriptor the way the processor expects it. See the Intel docs for a complete description of the placement of the bits. Note: The granularity bit represents the TSS itself, that will run under it! not the code IN: EAX - Size of TSS

Chapter 21 Initialization Code H EBX - Decriptor type (default for OS TSS is 0089h) (0089h - G(0),AV(0),LIM(0000),P(1),DPL(00),(010),B(0),(1)) EDX - Address of TSS EDI - Address of Desc in GOT OUT: GDT is updated with descriptor USED: EFlags (all other registers are saved) PUBLIC AddTSSDesc: ;The following code ;the TSS and places PUSH EAX PUSH EBX PUSH EDX PUSH EDI DEC EAX SHL EBX, 16 ROL EDX, 16 MOV BL,DH MOV BH.DL ROR EBX, 8 MOV DX,AX AND EAX,000F0000h OR EBX, EAX MOV [EDI], EDX MOV [EDI+4],EBX POP EDI POP EDX POP EBX POP EAX RETN section builds a descriptor entry for it into the GDT (Limit is size of TSS-1 ) Chinese puzzle rotate Exchange hi & lo words of Base Addr Base 31 . . 24 Base 23 . . 16 Rotate to Final Alignment Limit 15 .. 0 with Base 15 .. 0 Mask Limit 19 . . 16 OR into high order word Store lo double word Store hi double word InitFreeTSS INPUT : EAX, ECX OUTPUT : NONE USED : ALL General registers, FLAGS MODIFIES : pFreeTSS (and the dynamic array of TSSs) This routine initializes the free pool of Task State Segments. On entry: EAX points to the TSSs to initialize (allocated memory). ECX has the count of TSSs to initialize. The size of the TSS is taken from the constant sTSS. The pFreeTSS pointer is set to address the first TSS. The NextTSS field in each TSS is set to point to the next free TSS. The last TSS is set to point to nothing (NIL). The IOBitBase field is also set to FFFFh for NULL I/O permissions in each TSS. NOTE: The allocated memory area for the TSS MUST BE ZEROED before calling this routine. By default, we add the TSS descriptors at OS protection level. If we spawn or add a User level TSS we must OR the DPL bits with 3! PUBLIC InitFreeTSS: MOV pFreeTSS, EAX MOV EDI, OFFSET rgTSSDesc First one free to use ptr to TSS descriptors

Part IV The Operating System Source Code Listing 21.6. continued ADD EDI, 16 ; First two TSSs are Static (Mon & Dbgr) MOV EDX, STSS ; Size of TSS (in bytes) into EDX MOV EBX, 3 ; Number of first dynamic TSS TSS Loop: MOV ESI , EAX ; for I = 0 TO ECX ADD EAX , EDX ; EAX <= rgTSSs[I].Next MOV [ESI+NextTSS] EAX ; “rgTSSs[I+1 ] ; MOV WORD PTR [ESI t-TSS _IOBitB; MOV [ESI+TSSNum], BX ; TSS Number MOV WORD PTR [ESI t-TSS DS] DataSel ;Set up for Data Selectors MOV WORD PTR [ESI t-TSS ES] DataSel MOV WORD PTR [ESI t-TSS FS] DataSel MOV WORD PTR [ESI i-TSS GS] DataSel MOV WORD PTR [ESI+TSS SS] DataSel MOV WORD PTR [ESI t-TSS. SS0 , DataSel PUSH EAX ;Save pTSS MOV EAX, EDI ; Get offset of Curr TssDesc in EAX SUB EAX, OFFSET GDT ; Sub offset of GDT Base to get Sel of TSS MOV WORD PTR [ESI+Tid ,AX ; Store TSS Selector in TSS (later use) PUSH EBX PUSH EDX MOV EAX , EDX Size of TSS (TSS + SOFTSTATE) MOV EDX, ESI ; Address of TSS MOV EBX,0089h ; G(0),AV(0),LIM(0),P(1),DPL(0),B(0) CALL AddTSSDesc ADD EDI, 8 Point to Next GDT Slot (for next one) POP EDX POP EBX POP EAX INC EBX ; TSS Number LOOP TSSJ.OOP MOV DWORD PTR [ESI+NextTSS], 0 ; rgFree[ LastOne] .Next <= NIL; RETN ; DUMMY CALL for uninitialized GDT call gate slots DummyCall: MOV EAX, ercBadCallGate RETF Besides setting up all the call gates with a dummy procedure, InitCallGates takes care of an- other problem. This problem is that the call to AddCallGate ( ) is a public function called through a call gate. This means it can't add itself. This code manually adds the call for AddCallGate ( ) so you can add the rest of them. As I mentioned before, each of the more than 100 calls is placed in the GDT. There is room reserved for more than 600.

Chapter 21 ■ Initialization Code InitlDT, a little further down in the code, sets up each of the known entries in the IDT, as well as filling in all the unknown entries with a dummy ISR that simply returns from the inter- rupts. I have left all these in so that you can see which are interrupt gates and which are interrupt traps. The processor handles each of these a little differently. See Listing 21.7. Listing 21.7. Initialize call gates and the IDT. InitCallGates inits the array of call gates with an entry to a generic handler that returns ErcNotlnstalled when called. This prevents new code running on old MMURTLs or systems where special call gates don't exist without crashing too horribly. IN: Nothing Out : Nothing Used : ALL registers and flags PUBLIC InitCallGates: ; First we set up all call gates to point to a ;dummy procedure MOV ECX, nCallGates ;Number of callgates to init InitCG01 : PUSH ECX DEC ECX SHL ECX, 3 ADD ECX, 40h MOV EAX, 0EC00h MOV DX, OSCodeSel MOV ESI, OFFSET DummyCall Save nCallGates make it an index, not the count Now ecx is selector number DPL 3, 0 Params ;Same code as in PUBLIC AddCallGate MOVZX EBX, CX SUB EBX, 40 ;sub call gate base selector SHR EBX, 3 ;make index vice selector MOVZX EBX, CX ; Extend selector into EBX ADD EBX, GDTBase ;NOW a true offset in GDT MOV WORD PTR [EBX+02], 8 ; Put Code Seg selector into Call gate MOV [EBX], SI SHR ESI, 16 MOV [EBX+06] , SI MOV [EBX+04], AX 0:15 of call offset move upper 16 of offset into SI 16:31 of call offset call DPL & ndParams POP ECX ; ignore error... LOOP InitCG01 ;This decrements ECX till 0 ;Another chicken and egg here.. In order to be able ;to call the FAR PUBLIC “AddCallGate” though a callgate, ;we have to add it as a callgate... ok.... MOV EAX, 08C00h ; AddCallGate - 0 DWord Params DPL 0 MOV ECX, 0C8h MOV DX, OSCodeSel

434 Part TV ■ The Operating System Source Code Listing 21.7. continued MOV ESI, OFFSET _AddCallGate ;Same code as in PUBLIC AddCallGate MOVZX EBX, CX SUB EBX, 40 SHR EBX, 3 MOVZX EBX, CX ADD EBX, GDTBase ;sub call gate base selector ;make index vice selector ; Extend selector into EBX ;NOW a true offset in GDT MOV WORD PTR [EBX+02], 8 ;Put Code Seg selector into Call gate MOV [EBX], SI SHR ESI, 16 MOV [EBX+06], SI MOV [EBX+04], AX RETN 0:15 of call offset move upper 16 of offset into SI 16:31 of call offset call DPL & ndParams InitlDT First, inits the IDT with 256 entries to a generic handler that does nothing (except IRETD) when called. Second, adds each of the basic IDT entries for included software and hardware interrupt handlers. ISRs loaded with device drivers must use SetlRQVector. IN : Nothing Out : Nothing Used : ALL registers and flags 255 PUBLIC InitlDT: MOV ECX, InitID01 : PUSH ECX MOV EAX, MOV EBX, MOV ESI, CALL FWORD PTR POP ECX LOOP InitID01 ;Last IDT Entry 08F00h OSCodeSel OFFSET IntQ AddlDTGate DPL 3, TRAP GATE ;Now we add each of the known interrupts MOV ECX, 0 MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntDivBy0 CALL FWORD PTR AddlDTGate Divide By Zero DPL 3, TRAP GATE MOV ECX, 1 MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, Offset IntDbgSS CALL FWORD PTR AddlDTGate Single Step DPL 3, Trap gate Trying 8E00 (Int gate vice trap gate which leave Ints disabled) MOV ECX, 3 ; Breakpoint MOV EAX, 08E00h ;DPL 3, Trap Gate (for Debugger) WAS 8F00 MOV EBX, OSCodeSel ;This will be filled in with TSS of Dbgr later

Chapter 21 ■ Initialization Code |
435 MOV ESI, OFFSET IntDebug CALL FWORD PTR AddlDTGate MOV ECX, 4 MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntOverFlow CALL FWORD PTR AddlDTGate Overflow DPL 3, TRAP GATE MOV ECX, 6 MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntOpCode CALL FWORD PTR AddlDTGate Invalid OPcode DPL 3, TRAP GATE MOV ECX, 8 MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntDblExc CALL FWORD PTR AddlDTGate Double Exception DPL 3, TRAP GATE MOV ECX, 0Ah MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntlnvTSS CALL FWORD PTR AddlDTGate Invalid TSS DPL 3, TRAP GATE MOV ECX, 0Bh MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntNoSeg CALL FWORD PTR AddlDTGate Seg Not Present DPL 3, TRAP GATE MOV ECX, 0Ch MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntStkOvr CALL FWORD PTR AddlDTGate Int Stack Overflow DPL 3, TRAP GATE MOV ECX, 0Dh MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntGP CALL FWORD PTR AddlDTGate GP fault DPL 3, TRAP GATE MOV ECX, 0Eh MOV EAX, 08F00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntPgFlt CALL FWORD PTR AddlDTGate Int Page Fault DPL 3, TRAP GATE MOV ECX, 20h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntTimer CALL FWORD PTR AddlDTGate Int TIMER DPL 3, INTERRUPT GATE IRQ0

H Part W ■ The Operating System Source Code Listing 21.7. continued MOV ECX, 21 h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntKeyBrd CALL FWORD PTR AddlDTGate Int KEYBOARD DPL 3, INTERRUPT GATE IRQ1 MOV ECX, 22h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntPICU2 CALL FWORD PTR AddlDTGate Int PICU 2 (from PICU) IRQ2 DPL 3, INTERRUPT GATE MOV ECX, 23h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate Int COM2 DPL 3, INTERRUPT GATE MOV ECX, 24h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate Int COM1 DPL 3, INTERRUPT GATE IRQ4 MOV ECX, 25h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate Int LPT2 DPL 3, INTERRUPT GATE IRQ5 MOV ECX, 26h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ Int Floppy DPL 3, INTERRUPT GATE IRQ6 FDD will set this himself CALL FWORD PTR AddlDTGate MOV ECX, 27h MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate IntLPTI DPL 3, INTERRUPT GATE IRQ7 MOV ECX, 28h ;Int MOV EAX, 08E00h ;DPL 3, INTERRUPT GATE MOV EBX, OSCodeSel ; MOV ESI, OFFSET IntQ CALL FWORD PTR _AddIDTGate MOV ECX, 29h ;Int MOV EAX, 08E00h ;DPL 3, INTERRUPT GATE MOV EBX, OSCodeSel ; MOV ESI, OFFSET IntQ CALL FWORD PTR _AddIDTGate MOV ECX, 2Ah ; Int MOV EAX, 08E00h ;DPL 3, INTERRUPT GATE IRQ8 IRQ9 IRQ10

Chapter 21 ■ Initialization Code MOV EBX, OSCodeSel ; MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate MOV ECX, 2Bh MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate Int
DPL 3, INTERRUPT GATE IRQ11 MOV ECX, 2Ch ;Int .. MOV EAX, 08E00h ;DPL 3, MOV EBX, OSCodeSel ; MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate IRQ12 INTERRUPT GATE MOV ECX, 2Dh MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate Int
DPL 3, INTERRUPT GATE IRQ13 MOV ECX, 2Eh ;Int .. MOV EAX, 08E00h ;DPL 3, MOV EBX, OSCodeSel ; MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate IRQ14 INTERRUPT GATE MOV ECX, 2Fh MOV EAX, 08E00h MOV EBX, OSCodeSel MOV ESI, OFFSET IntQ CALL FWORD PTR AddlDTGate Int
DPL 3, INTERRUPT GATE IRQ15 RETN InitOSPublics adds all OS primitives to the array of call gates. This can't be called before initcallgates, but MUST be called before the first far call to any OS primitive thorugh a call gate!!! IF YOU ADD AN OS PUBLIC MAKE SURE IT GETS PUT HERE!!!!! IN : Nothing Out : Nothing Used : ALL registers and flags PUBLIC InitOSPublics: MOV EAX, 0EC02h MOV ECX, 40h MOV DX, OSCodeSel MOV ESI, OFFSET _WaitMsg CALL FWORD PTR AddCallGate WaitMsg - 2 DWord Params, DPL 3

[438 Part PV ■ The Operating System Source Code Listing 21.7. continued MOV EAX, 0EC03h ;SendMsg - 3 DWord Params, DPL 3 MOV ECX, 48h MOV DX, OSCodeSel MOV ESI, OFFSET _SendMsg CALL FWORD PTR _AddCallGate MOV EAX, 08C03h ;ISendMsg - 3 DWord params, DPL 0 MOV ECX, 50h MOV DX, OSCodeSel MOV ESI, OFFSET _ISendMsg CALL FWORD PTR _AddCallGate MOV EAX, 0EC01h ;Set Priority - IDword param, DPL 3 MOV ECX, 58h MOV DX, OSCodeSel MOV ESI, OFFSET _SetPriority CALL FWORD PTR _AddCallGate ;The rest of the call gate set ups go here. RETN

Powered by TurnKey Linux.