/* MMHal.c, 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/MMHal.c,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: MMHal.c,v $ Revision 1.2 1999/12/13 21:48:31 ruf GNU General Public Licence Update Revision 1.1 1999/05/13 17:05:37 jeker Initial revision */ #include "MMHal.h" #include "mmHalAsm.h" #include "SupportAsm.h" #include "Video.h" #include "cpu.h" #include "MemoryLayout.h" #define MEMPAGEUSEDADDR 0x11000 static volatile unsigned short MemSelector; /* definition of most important selectors, used for Kernel Code and Data as for User Code and Data Define all of them as unsigned long even if they are only unsigned short in fact. */ unsigned long KCSEL; unsigned long KDSEL; unsigned long UCSEL; unsigned long UDSEL; unsigned long MaxPhysMem() { return __maxPhysMem(); } unsigned long MaxMemAvail() { return __memPagesAvail(MemSelector)*4096; } void SetMemRangeUsed(unsigned long plow, unsigned long phigh) { unsigned long i; plow = plow >> 12; phigh = phigh >> 12; for (i = plow; (i < phigh); i++) __setPageUsed(MemSelector,i); return; } unsigned long MemUsed() { return __memPagesUsed(MemSelector)*4096; } void MemoryInit() { unsigned long kmem; volatile unsigned long lmem = MaxPhysMem(); volatile unsigned long ltext = __getTextSize(); volatile unsigned long ldata = __getDataSize(); ltext = ((ltext >> 12)+1) << 12; ldata = ((ldata >> 12)+1) << 12; kmem = 0x20000 + ltext + ldata; MemSelector = Get_New_GDTE(); Set_GDTEntry(MemSelector, MEMPAGEUSEDADDR, 1, MM_DATA_B5, MM_DATA_B6); __emptyPUT(MemSelector); printf("Memory Management {Topsy i386, v1.0}\n"); printf("Physical memory : 0x00000000-0x%8x = %iKB (%iMB)\n",(unsigned int)lmem,(unsigned int)lmem>>10, (unsigned int)lmem>>20); printf("Memory management : 0x00000000-0x%8x = %iKB (%iMB)\n",(unsigned int)MaxMemAvail(),(unsigned int)MaxMemAvail()>>10, (unsigned int)MaxMemAvail()>>20); printf("Control structures : 0x00000000-0x00020000\n"); SetMemRangeUsed(0x000000, 0x020000); // IDT, GDT etc. printf("Kernel space : 0x00020000-0x%8x\n",(unsigned int)kmem); SetMemRangeUsed(0x020000, kmem); printf("Hardware IO : 0x000A0000-0x00100000\n"); SetMemRangeUsed(0x0A0000, 0x100000); // Mem Map Region printf("Not physically avail. : 0x%8x-0x%8x\n",(unsigned int)lmem,128*1024*1024); SetMemRangeUsed((unsigned int)lmem,128*1024*1024); printf("Available memory : %iKB (%iMB)\n",(unsigned int)MaxMemAvail()>>10, (unsigned int)MaxMemAvail()>>20); KDSEL = gcKDSEL; /* CONSTANT VALUE from selector.h */ KCSEL = gcKCSEL; printf("Kernel Selectors: CODE 0x%8x DATA 0x%8x\n",(unsigned int)KCSEL,(unsigned int)KDSEL); /* Create USER Segments :-) */ /* SET CORRECT PROTECTION LEVEL !!!! */ /* Code Segment, Protection Level 3 */ UCSEL = Get_New_GDTE(); Set_GDTEntry((unsigned short)UCSEL,KUSEG_BASE,KUSEG_SIZE >> 12, (MM_CODE_B5 | MM_B5_3), MM_CODE_B6); /* Code Segment, Protection Level 3 */ UDSEL = Get_New_GDTE(); Set_GDTEntry((unsigned short)UDSEL,KUSEG_BASE,KUSEG_SIZE >> 12, (MM_DATA_B5 | MM_B5_3), MM_DATA_B6); /* Data Segment, Protection Level 3 */ printf("User Selectors: CODE 0x%8x DATA 0x%8x\n",(unsigned int)UCSEL,(unsigned int)UDSEL); return; } /*GDT*************************************************************************/ static unsigned short gNr_Of_GDTE; void DispGDTRState() { unsigned short llimit; unsigned long lbase; __get_GDTR(&llimit,&lbase); printf("GDT State: GDTR.limit: 0x%x // GDTR.base: 0x%x\n",(int)llimit,(int)lbase); return; } void GDTInit() { gNr_Of_GDTE = 6; DispGDTRState(); return; } void Set_GDTEntry(unsigned short pSelector, unsigned long pBase, unsigned long pSize, unsigned char pAccess, unsigned char pType) { __set_GDTEntry(pSelector, pBase, pSize, pAccess, pType); return; } void Get_GDTE(unsigned short pSelector, GDTEPtr pGDTE) { __get_GDTE(pSelector, pGDTE); return; } unsigned short Get_New_GDTE() { unsigned short llimit; unsigned long lbase; GDTE lGDTE; unsigned short i = 8; // leave dummy selector untouched __get_GDTR(&llimit,&lbase); Get_GDTE(i,&lGDTE); // get free GDTE while ((i < llimit) && (lGDTE.Byte0+lGDTE.Byte1+lGDTE.Byte2+lGDTE.Byte3+ lGDTE.Byte4+lGDTE.Byte5+lGDTE.Byte6+lGDTE.Byte7 != 0)) { i+=8; Get_GDTE(i,&lGDTE); } if ((i >= llimit) && // there is no free GDTE (llimit < (0xFFFF-0x1000))) { // but there is still free room in the GDT Segment __get_GDTR(&llimit,&lbase); llimit+=8; __set_GDTR(llimit,lbase); gNr_Of_GDTE = llimit >> 3; } return i; } /*IDT*************************************************************************/ /* define IDT_BASE locally here to ommit including Constant.h */ #define IDT_BASE 0x00010000 static unsigned short gIDTSel; void Set_IDT_Sel() { gIDTSel = Get_New_GDTE(); printf("IDT Alias Selector : 0x%x\n",(int)gIDTSel); Set_GDTEntry(gIDTSel,IDT_BASE, 1 /*1 Page*/ , MM_DATA_B5, MM_DATA_B6); __reset_TLB(); // make new GDTE acitve return; } void Set_Def_IDTEntry(unsigned char pEntry, unsigned long pOffs, unsigned short pType) { __set_IDTEntry(gIDTSel, pEntry << 3, gcOSCodeSel, pOffs, pType); return; } void ResetIDTR() { __reset_IDTR(); return; } void DispIDTRState() { unsigned short llimit; unsigned long lbase; __get_IDTR(&llimit,&lbase); printf("IDT State: IDTR.limit: 0x%x // IDTR.base: 0x%x\n",(int)llimit,(int)lbase); return; } void IDTInit() { Set_IDT_Sel(); DispIDTRState(); return; } /*TSS*************************************************************************/ #define K_TSS_Base 0x1E000 #define K_TSS_Size 104 /* Size of Selector is BYTE */ #define K_TSS_B5 0x89 /* 10001001b */ #define K_TSS_B6 0x00 /* 00000000b */ unsigned short K_TSS_Selector; unsigned short K_TSS_Alias; #define U_TSS_Base 0x1D000 #define U_TSS_Size 104 /* Size of Selector is BYTE */ #define U_TSS_B5 0xE9 /* 11101001b : USER DPL*/ #define U_TSS_B6 0x00 /* 00000000b */ unsigned short U_TSS_Selector; unsigned short U_TSS_Alias; /* User and Kernel TSS are required for restoring the stack segment of the appropriate privilege level. */ void TSSInit() { K_TSS_Selector = Get_New_GDTE(); // Get New Selector for Kernel TSS Selector Set_GDTEntry(K_TSS_Selector , K_TSS_Base, K_TSS_Size, K_TSS_B5 , K_TSS_B6); K_TSS_Alias = Get_New_GDTE(); // Get New Selector for Kernel TSS Alias Selector Set_GDTEntry(K_TSS_Alias , K_TSS_Base, K_TSS_Size, MM_DATA_B5, MM_DATA_B6_BYTE); __createTSS(K_TSS_Alias); __activateTSS(K_TSS_Selector); printf("Kernel TSS: 0x%x // TSS Alias: 0x%x\n",(int)K_TSS_Selector,(int)K_TSS_Alias); U_TSS_Selector = Get_New_GDTE(); // Get New Selector for User TSS Selector Set_GDTEntry(U_TSS_Selector , U_TSS_Base, U_TSS_Size, U_TSS_B5 , U_TSS_B6); U_TSS_Alias = Get_New_GDTE(); // Get New Selector for User TSS Alias Selector Set_GDTEntry(U_TSS_Alias , U_TSS_Base, U_TSS_Size, MM_DATA_B5, MM_DATA_B6_BYTE); __createTSS(U_TSS_Alias); printf("USER TSS: 0x%x // TSS Alias: 0x%x\n",(int)U_TSS_Selector,(int)U_TSS_Alias); return; }