/* mmHalAsm.S, Copyright (c) by Lukas Ruf, lr@lpr.ch, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/Memory/ia32/mmHalAsm.S,v $ Author(s): Lukas Ruf, lr@lpr.ch Affiliation: ETH Zuerich, TIK Version: $Revision: 1.2 $ Creation Date: Last Date of Change: $Date: 1999/12/13 21:48:31 $ by: $Author: ruf $ $Log: mmHalAsm.S,v $ Revision 1.2 1999/12/13 21:48:31 ruf GNU General Public Licence Update Revision 1.1 1999/05/13 17:05:40 jeker Initial revision */ .section .sasm .align 4,0x9090 #include "asm.h" /* Topsy/i386/ */ #include "MemoryLayout.h" /* Memory/i386/ */ #define KILOBYTE 1024 #define MEGABYTE 1024*KILOBYTE #define HALFMEGA 512*KILOBYTE #define BITSPERPAGE 4096*8 //// // void _emptyPUT(ushort MemSelector); //// FRAME(__emptyPUT) ENTER pushl %eax pushl %ecx pushl %edi pushw %es movl 8(%ebp),%eax movw %ax,%es xorl %eax,%eax xorl %edi,%edi movl $4095,%ecx rep stosb popw %es popl %edi popl %ecx popl %eax LEAVE //// // ulong _maxPhysMem(); /// FRAME(__maxPhysMem) ENTER pushl %ebx pushw %ds movl $gcOSGlobalSel,%eax movw %ax,%ds movl $HALFMEGA,%eax movl $0x12345678,%ebx _mPML1: movl %ebx,(%eax) cmpl %ebx,(%eax) jne _mPML2 addl $HALFMEGA,%eax jmp _mPML1 _mPML2: popw %ds popl %ebx LEAVE //// // ulong _memPagesAvail(ushort pPUTSelector); // return number of free pages in PUT /// FRAME(__memPagesAvail) ENTER pushl %ebx pushl %esi pushw %ds movl 8(%ebp),%eax movw %ax,%ds xorl %eax,%eax xorl %ebx,%ebx xorl %esi,%esi _mPAL1: bt %ebx,(%esi) jc _mPAL2 incl %eax _mPAL2: incl %ebx cmpl $BITSPERPAGE,%ebx jl _mPAL1 popw %ds popl %esi popl %ebx LEAVE //// // ulong _memPagesUsed(ushort pPUTSelector); // return number of occupied pages in PUT /// FRAME(__memPagesUsed) ENTER pushl %ebx pushl %esi pushw %ds movl 8(%ebp),%eax movw %ax,%ds xorl %eax,%eax xorl %ebx,%ebx xorl %esi,%esi _mMAL1: bt %ebx,(%esi) jnc _mMAL2 incl %eax _mMAL2: incl %ebx cmpl $BITSPERPAGE,%ebx jl _mMAL1 popw %ds popl %esi popl %ebx LEAVE //// // ulong _getFreePage(ushort pPageOrganizerSelector); //// FRAME(__getFreePage) ENTER pushl %esi pushw %ds movl 8(%ebp),%eax movw %ax,%ds xorl %eax,%eax xorl %esi,%esi _gFPL1: bt %eax,(%esi) jnc _gFPL2 incl %eax jmp _gFPL1 _gFPL2: popw %ds popl %esi LEAVE //// // uchar _setPageUsed(ushort pPageOrganizerSelector, ulong pPage); // report previous state //// FRAME(__setPageUsed) ENTER pushl %esi pushw %ds movl 8(%ebp),%eax movw %ax,%ds movl 12(%ebp),%eax movl $0,%esi bts %eax,(%esi) jc _sPU1 xorl %eax,%eax jmp _sPU2 _sPU1: movl $1,%eax _sPU2: popw %ds popl %esi LEAVE //// // uchar _setPageUnUsed(ushort pPageOrganizerSelector, ulong pPage); // report previous state //// FRAME(__setPageUnUsed) ENTER pushl %eax pushl %esi pushw %ds movl 8(%ebp),%eax movw %ax,%ds movl 12(%ebp),%eax movl $0,%esi btr %eax,(%esi) jc _sPUU1 xorl %eax,%eax jmp _sPUU2 _sPUU1: movl $1,%eax _sPUU2: popw %ds popl %esi popl %eax LEAVE /*GDT*************************************************************************/ //// // _set_GDTEntry(ushort uSelector, ulong uBASE, ulong uLIMIT, byte uACCESS_B5, byte uTYPE_B6); // pushl %edx : %dl = uTYPE_B6 (+24) // pushl %ecx : %cl = uACCESS_B5 (+20) // pushl %ebx : uLIMIT (REMEMBER: Granularity) (+16) // pushl %eax : uBASE (+12) // pushl %eax : uSelector (+08) // call _set_GDTEntry FRAME(__set_GDTEntry) ENTER pushl %eax pushl %ebx pushl %ecx pushl %edx pushl %edi pushw %es movl $gcGDTSel,%eax movw %ax,%es movl 8(%ebp),%ebx movl %ebx,%edi //es:[edi] = Byte0(Descriptor) movl 12(%ebp),%eax // BASE movl 16(%ebp),%ebx // LIMIT movl 20(%ebp),%ecx // ACCESS Byte 5 movl 24(%ebp),%edx // TYPE Byte 6 // now: fill descriptor movb %bl,%es:(%edi) incl %edi movb %bh,%es:(%edi) incl %edi // Limit 00..15 set shrl $16,%ebx movb %al,%es:(%edi) incl %edi movb %ah,%es:(%edi) incl %edi // Base 00..15 set shrl $16,%eax movb %al,%es:(%edi) incl %edi // Base 16..23 set movb %cl,%es:(%edi) incl %edi // Access Byte 5 set andb $0xf0,%dl // Blank out lower nibble of uTYPE_B6 andb $0x0f,%bl // Blank out upper nibble of uLIMIT orb %dl,%bl // Create Byte 6 !!! movb %bl,%es:(%edi) incl %edi // Type Byte 6 set movb %ah,%es:(%edi) incl %edi // Base 24..31 set call __reset_TLB popw %es popl %edi popl %edx popl %ecx popl %ebx popl %eax LEAVE //// // void _reset_TLB(); //// FRAME(__reset_TLB) ENTER pushfl pushl %eax cli movl %cr3,%eax // perform a reset by reloading the movl %eax,%cr3 // page directory table popl %eax popfl LEAVE //// // _set_GDTE(ushort pEntry, t_GDTE *pGDTE) // pushl %eax (%eax = pointer to GDTE) // pushl %eax (%ax = entry number of GDTE) // call _set_GDTE //// FRAME(__set_GDTE) ENTER pushl %eax pushl %ecx pushl %edi pushw %esi pushw %es movl $gcGDTSel,%eax movw %ax,%es movl 8(%ebp),%eax // get entry number movl %eax,%edi movl 12(%ebp),%esi movl $8,%ecx rep movsb call __reset_TLB popw %es popl %esi popl %edi popl %ecx popl %eax LEAVE //// // _get_GDTE(ushort pEntry, t_GDTE *pGDTE) // pushl %eax (%eax = pointer to GDTE) // pushl %eax (%ax = entry number of GDTE) // call _set_GDTE //// FRAME(__get_GDTE) ENTER pushl %eax pushl %ecx pushl %edi pushw %esi pushw %ds movl $gcGDTSel,%eax movw %ax,%ds movl 8(%ebp),%esi // get entry number movl 12(%ebp),%edi movl $8,%ecx rep movsb popw %ds popl %esi popl %edi popl %ecx popl %eax LEAVE //// // void _set_GDTR(ushort plimit, ulong pbase); //// FRAME(__set_GDTR) ENTER subl $16,%esp pushfl pushl %eax pushl %ebx pushl %edi movl 8(%ebp),%ebx // plimit movl 12(%ebp),%eax // pbase leal -8(%ebp),%edi // temp. storage of t_GDTR lGDTR; movw %bx,(%edi) // lGDTR.limit = plimit; movl %eax,2(%edi) // lGDTR.base = pbase; cli lgdt (%edi) popl %edi popl %ebx popl %eax popfl LEAVE //// // void _get_GDTR(ushort *plimit, ulong *pbase); //// FRAME(__get_GDTR) ENTER subl $16,%esp pushl %eax pushl %ebx pushl %ecx pushl %edi leal -8(%ebp),%edi // temp. storage of t_GDTR lGDTR; sgdt (%edi) // write GDTR movl 8(%ebp),%ebx // plimit movl 12(%ebp),%eax // pbase xorl %ecx,%ecx // clear high 16b of %ecx movw (%edi),%cx movw %cx,(%ebx) // *plimit = lGDTR.limit; movl 2(%edi),%ecx movl %ecx,(%eax) // *pbase = lGDTR.base; popl %edi popl %ecx popl %ebx popl %eax LEAVE /*IDT*************************************************************************/ //// // _set_IDTEntry(ushort pIDTSel, ushort uINTNo, ushort pCodeSel, ulong uOFFS, ushort INTType); // pushl uINTType (al = INTType) {Interrupt, Trap or Task Gate} // pushl uOFFS // pushl pCodeSel // pushl uINTNo (al == INTNo) // pushl pIDTSel : Selector of active IDT // call _setIDTEntry // // !! PRECONDITION: Valid Selector for IDT_Segment is existing !! //// FRAME(__set_IDTEntry) ENTER pushl %eax pushl %ebx pushl %edx pushl %edi pushw %es movl 8(%ebp),%eax // pIDTSel movw %ax,%es movl 12(%ebp),%eax // INT No. in %ax (OFFSET to ISR Reference) movl %eax,%edi // es:[edi] -> ITDE[0] movl 16(%ebp),%eax // Code Selector movl 20(%ebp),%ebx // Offset movl 24(%ebp),%edx // INT Type (%dx) movw %bx,%es:(%edi) // Offset 00:15 movw %ax,%es:2(%edi) // Code Selector movw %dx,%es:4(%edi) // INT Type (%dx) shrl $16,%ebx movw %bx,%es:6(%edi) // Offset 16:31 popw %es popl %edi popl %edx popl %ebx popl %eax LEAVE //// // void _get_IDTE(ushort pIDTSel, ushort pEntry, t_IDTE *pIDTE); //// FRAME(_get_IDTE) ENTER pushl %eax pushl %ecx pushl %edi pushw %esi pushw %ds movl 8(%ebp),%eax movw %ax,%ds movl 12(%ebp),%esi // get entry number movl 16(%ebp),%edi movl $8,%ecx rep movsb popw %ds popl %esi popl %edi popl %ecx popl %eax LEAVE //// // void _reset_IDTR(); //// FRAME(__reset_IDTR) ENTER subl $8,%esp pushfl cli pushl %eax leal -8(%ebp),%eax sidt (%eax) lidt (%eax) popl %eax popfl LEAVE //// // void _set_IDTR(ushort plimit, ulong pbase); //// FRAME(__set_IDTR) ENTER subl $8,%esp pushfl pushl %eax pushl %ebx pushl %edi movl 8(%ebp),%ebx // plimit movl 12(%ebp),%eax // pbase leal -8(%ebp),%edi // temp. storage of t_IDTR lIDTR; movw %bx,(%edi) // lIDTR.limit = plimit; movl %eax,2(%edi) // lIDTR.base = pbase; cli lidt (%edi) popl %edi popl %ebx popl %eax popfl LEAVE //// // void _get_IDTR(ushort *plimit, ulong *pbase); //// FRAME(__get_IDTR) ENTER subl $8,%esp pushl %eax pushl %ebx pushl %ecx pushl %edi leal -8(%ebp),%edi // temp. storage of t_IDTR lIDTR; sidt (%edi) // write IDTR movl 8(%ebp),%ebx // plimit movl 12(%ebp),%eax // pbase xorl %ecx,%ecx // clear high 16b of %ecx movw (%edi),%cx movw %cx,(%ebx) // *plimit = lIDTR.limit; movl 2(%edi),%ecx movl %ecx,(%eax) // *pbase = lIDTR.base; popl %edi popl %ecx popl %ebx popl %eax LEAVE /*TSS*************************************************************************/ //// // void _createTSS(unsigned short pAliasSel); //// FRAME(__createTSS) ENTER pushl %eax pushl %ecx pushl %edi pushl %esi push %es push %ds movl ARG1,%eax // get Selector Alias movw %ax,%es push %es // set data to Alias for easy modification pop %ds xorl %edi,%edi pushl %edi movl $25,%ecx // 104 / 4 = 26 - 1 xorl %eax,%eax rep stosl // Clear out TSS popl %edi // Create TSS in TSS-Alias movw %ss,_SS0(%edi) // SS of Kernel movl $BOOTSTACKTOP,%eax movl %eax,_ESP0(%edi) // Exception Stack Top movw %es,_ES(%edi) movw %cs,_CS(%edi) movw %ss,_SS(%edi) movw %ds,_DS(%edi) movw %fs,_FS(%edi) movw %gs,_GS(%edi) movw $0xFFFF,_IOBASE(%edi) // No IO Permission Bit Map is required pop %ds pop %es popl %esi popl %edi popl %ecx popl %eax LEAVE /* __activateTSS(unsigned short pTSS_Selector); as the name tells you:-) */ FRAME(__activateTSS) ENTER pushl %eax movl ARG1,%eax // Get TSS Selector ltr %ax // Load Task State Register popl %eax LEAVE