⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pm.c

📁 AT91RM9200-U-Boot at91rm9200u-boot移植源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Generic DPMI routines common to 16/32 bit code                          *//*-------------------------------------------------------------------------*/#ifndef REALMODEulong PMAPI DPMI_mapPhysicalToLinear(ulong physAddr,ulong limit){    PMREGS  r;    int     i;    ulong   baseAddr,baseOfs,roundedLimit;    /* We can't map memory below 1Mb, but the linear address are already     * mapped 1:1 for this memory anyway so we just return the base address.     */    if (physAddr < 0x100000L)        return physAddr;    /* Search table of existing mappings to see if we have already mapped     * a region of memory that will serve this purpose. We do this because     * DPMI 0.9 does not allow us to free physical memory mappings, and if     * the mappings get re-used in the program we want to avoid allocating     * more mappings than necessary.     */    for (i = 0; i < numMaps; i++) {        if (maps[i].physical == physAddr && maps[i].limit == limit)            return maps[i].linear;        }    /* Find a free slot in our physical memory mapping table */    for (i = 0; i < numMaps; i++) {        if (maps[i].limit == 0)            break;        }    if (i == numMaps) {        i = numMaps++;        if (i == MAX_MEMORY_MAPPINGS)            return NULL;        }    /* Round the physical address to a 4Kb boundary and the limit to a     * 4Kb-1 boundary before passing the values to DPMI as some extenders     * will fail the calls unless this is the case. If we round the     * physical address, then we also add an extra offset into the address     * that we return.     */    baseOfs = physAddr & 4095;    baseAddr = physAddr & ~4095;    roundedLimit = ((limit+baseOfs+1+4095) & ~4095)-1;    r.x.ax = 0x800;    r.x.bx = baseAddr >> 16;    r.x.cx = baseAddr & 0xFFFF;    r.x.si = roundedLimit >> 16;    r.x.di = roundedLimit & 0xFFFF;    PM_int386(0x31, &r, &r);    if (r.x.cflag)        return 0xFFFFFFFFUL;    maps[i].physical = physAddr;    maps[i].limit = limit;    maps[i].linear = ((ulong)r.x.bx << 16) + r.x.cx + baseOfs;    return maps[i].linear;}int PMAPI DPMI_setSelectorBase(ushort sel,ulong linAddr){    PMREGS  r;    r.x.ax = 7;                     /* DPMI set selector base address   */    r.x.bx = sel;    r.x.cx = linAddr >> 16;    r.x.dx = linAddr & 0xFFFF;    PM_int386(0x31, &r, &r);    if (r.x.cflag)        return 0;    return 1;}ulong PMAPI DPMI_getSelectorBase(ushort sel){    PMREGS  r;    r.x.ax = 6;                     /* DPMI get selector base address   */    r.x.bx = sel;    PM_int386(0x31, &r, &r);    return ((ulong)r.x.cx << 16) + r.x.dx;}int PMAPI DPMI_setSelectorLimit(ushort sel,ulong limit){    PMREGS  r;    r.x.ax = 8;                     /* DPMI set selector limit          */    r.x.bx = sel;    r.x.cx = limit >> 16;    r.x.dx = limit & 0xFFFF;    PM_int386(0x31, &r, &r);    if (r.x.cflag)        return 0;    return 1;}uint PMAPI DPMI_createSelector(ulong base,ulong limit){    uint    sel;    PMREGS  r;    /* Allocate 1 descriptor */    r.x.ax = 0;    r.x.cx = 1;    PM_int386(0x31, &r, &r);    if (r.x.cflag) return 0;    sel = r.x.ax;    /* Set the descriptor access rights (for a 32 bit page granular     * segment).     */    if (limit >= 0x10000L) {        r.x.ax = 9;        r.x.bx = sel;        r.x.cx = 0x40F3;        PM_int386(0x31, &r, &r);        }    /* Map physical memory and create selector */    if ((base = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFFUL)        return 0;    if (!DPMI_setSelectorBase(sel,base))        return 0;    if (!DPMI_setSelectorLimit(sel,limit))        return 0;    return sel;}void PMAPI DPMI_freeSelector(uint sel){    PMREGS  r;    r.x.ax = 1;    r.x.bx = sel;    PM_int386(0x31, &r, &r);}int PMAPI DPMI_lockLinearPages(ulong linear,ulong len){    PMREGS  r;    r.x.ax = 0x600;                     /* DPMI Lock Linear Region      */    r.x.bx = (linear >> 16);            /* Linear address in BX:CX      */    r.x.cx = (linear & 0xFFFF);    r.x.si = (len >> 16);               /* Length in SI:DI              */    r.x.di = (len & 0xFFFF);    PM_int386(0x31, &r, &r);    return (!r.x.cflag);}int PMAPI DPMI_unlockLinearPages(ulong linear,ulong len){    PMREGS  r;    r.x.ax = 0x601;                     /* DPMI Unlock Linear Region    */    r.x.bx = (linear >> 16);            /* Linear address in BX:CX      */    r.x.cx = (linear & 0xFFFF);    r.x.si = (len >> 16);               /* Length in SI:DI              */    r.x.di = (len & 0xFFFF);    PM_int386(0x31, &r, &r);    return (!r.x.cflag);}/****************************************************************************REMARKS:Adjust the page table caching bits directly. Requires ring 0 access andonly works with DOS4GW and compatible extenders (CauseWay also works sinceit has direct support for the ring 0 instructions we need from ring 3). Willnot work in a DOS box, but we call into the ring 0 helper VxD so we shouldnever get here in a DOS box anyway (assuming the VxD is present). If wedo get here and we are in windows, this code will be skipped.****************************************************************************/static void PM_adjustPageTables(    ulong linear,    ulong limit,    ibool isCached){#ifdef  DOS4GW    int     startPDB,endPDB,iPDB,startPage,endPage,start,end,iPage;    ulong   andMask,orMask,pageTable,*pPageTable;    andMask = ~0x18;    orMask = (isCached) ? 0x00 : 0x18;    if (_PM_pagingEnabled() == 1 && (PDB = _PM_getPDB()) != 0) {        if (_PM_haveCauseWay) {            /* CauseWay is a little different in the page table handling.             * The code that we use for DOS4G/W does not appear to work             * with CauseWay correctly as it does not appear to allow us             * to map the page tables directly. Instead we can directly             * access the page table entries in extended memory where             * CauseWay always locates them (starting at 1024*4096*1023)             */            startPage = (linear >> 12);            endPage = ((linear+limit) >> 12);            pPageTable = (ulong*)CW_PAGE_TABLE_START;            for (iPage = startPage; iPage <= endPage; iPage++)                pPageTable[iPage] = (pPageTable[iPage] & andMask) | orMask;            }        else {            pPDB = (ulong*)DPMI_mapPhysicalToLinear(PDB,0xFFF);            if (pPDB) {                startPDB = (linear >> 22) & 0x3FF;                startPage = (linear >> 12) & 0x3FF;                endPDB = ((linear+limit) >> 22) & 0x3FF;                endPage = ((linear+limit) >> 12) & 0x3FF;                for (iPDB = startPDB; iPDB <= endPDB; iPDB++) {                    pageTable = pPDB[iPDB] & ~0xFFF;                    pPageTable = (ulong*)DPMI_mapPhysicalToLinear(pageTable,0xFFF);                    start = (iPDB == startPDB) ? startPage : 0;                    end = (iPDB == endPDB) ? endPage : 0x3FF;                    for (iPage = start; iPage <= end; iPage++)                        pPageTable[iPage] = (pPageTable[iPage] & andMask) | orMask;                    }                }            }        PM_flushTLB();        }#endif}void * PMAPI DPMI_mapPhysicalAddr(ulong base,ulong limit,ibool isCached){    PMSREGS     sregs;    ulong       linAddr;    ulong       DSBaseAddr;    /* Get the base address for the default DS selector */    PM_segread(&sregs);    DSBaseAddr = DPMI_getSelectorBase(sregs.ds);    if ((base < 0x100000) && (DSBaseAddr == 0)) {        /* DS is zero based, so we can directly access the first 1Mb of         * system memory (like under DOS4GW).         */        return (void*)base;        }    /* Map the memory to a linear address using DPMI function 0x800 */    if ((linAddr = DPMI_mapPhysicalToLinear(base,limit)) == 0xFFFFFFFF) {        if (base >= 0x100000)            return NULL;        /* If the linear address mapping fails but we are trying to         * map an area in the first 1Mb of system memory, then we must         * be running under a Windows or OS/2 DOS box. Under these         * environments we can use the segment wrap around as a fallback         * measure, as this does work properly.         */        linAddr = base;        }    /* Now expand the default DS selector to 4Gb so we can access it */    if (!DPMI_setSelectorLimit(sregs.ds,0xFFFFFFFFUL))        return NULL;    /* Finally enable caching for the page tables that we just mapped in,     * since DOS4GW and PMODE/W create the page table entries without     * caching enabled which hurts the performance of the linear framebuffer     * as it disables write combining on Pentium Pro and above processors.     *     * For those processors cache disabling is better handled through the     * MTRR registers anyway (we can write combine a region but disable     * caching) so that MMIO register regions do not screw up.     */    if (DSBaseAddr == 0)        PM_adjustPageTables(linAddr,limit,isCached);    /* Now return the base address of the memory into the default DS */    return (void*)(linAddr - DSBaseAddr);}#if defined(PM386)/* Some DOS extender implementations do not directly support calling a * real mode procedure from protected mode. However we can simulate what * we need temporarily hooking the INT 6Ah vector with a small real mode * stub that will call our real mode code for us. */static uchar int6AHandler[] = {    0x00,0x00,0x00,0x00,        /*  __PMODE_callReal variable           */    0xFB,                       /*  sti                                 */    0x2E,0xFF,0x1E,0x00,0x00,   /*  call    [cs:__PMODE_callReal]       */    0xCF,                       /*  iretf                               */    };static uchar *crPtr = NULL; /* Pointer to of int 6A handler         */static uint crRSeg,crROff;  /* Real mode seg:offset of handler      */void PMAPI PM_callRealMode(uint seg,uint off, RMREGS *in,    RMSREGS *sregs){    uchar   *p;    uint    oldSeg,oldOff;    if (!crPtr) {        /* Allocate and copy the memory block only once */        crPtr = PM_allocRealSeg(sizeof(int6AHandler), &crRSeg, &crROff);        memcpy(crPtr,int6AHandler,sizeof(int6AHandler));        }    PM_setWord(crPtr,off);              /* Plug in address to call  */    PM_setWord(crPtr+2,seg);    p = PM_mapRealPointer(0,0x6A * 4);    oldOff = PM_getWord(p);             /* Save old handler address */    oldSeg = PM_getWord(p+2);    PM_setWord(p,crROff+4);             /* Hook 6A handler          */    PM_setWord(p+2,crRSeg);    PM_int86x(0x6A, in, in, sregs);     /* Call real mode code      */    PM_setWord(p,oldOff);               /* Restore old handler      */    PM_setWord(p+2,oldSeg);}#endif  /* PM386 */#endif  /* !REALMODE *//****************************************************************************REMARKS:Allocates a block of locked, physically contiguous memory. The memorymay be required to be below the 16Meg boundary.****************************************************************************/void * PMAPI PM_allocLockedMem(    uint size,    ulong *physAddr,    ibool contiguous,    ibool below16Meg){    uchar           *p,*roundedP;    uint            r_seg,r_off;    uint            roundedSize = (size + 4 + 0xFFF) & ~0xFFF;    PM_lockHandle   lh; /* Unused in DOS */#ifndef REALMODE    VXD_regs        regs;    /* If we have connected to our helper VxD in a Windows DOS box, use the     * helper VxD services to allocate the memory that we need.     */    if (VXD_version) {        memset(&regs,0,sizeof(regs));        regs.eax = API_NUM(PMHELP_ALLOCLOCKED);        regs.ebx = size;        regs.ecx = (ulong)physAddr;        regs.edx = contiguous | (below16Meg << 8);        _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);        return (void*)regs.eax;        }    /* If the memory is not contiguous, we simply need to allocate it     * using regular memory allocation services, and lock it down     * in memory.     *     * For contiguous memory blocks, the only way to guarantee contiguous physical     * memory addresses under DOS is to allocate the memory below the     * 1Meg boundary as real mode memory.     *     * Note that we must page align the memory block, and we also must     * keep track of the non-aligned pointer so we can properly free     * it later. Hence we actually allocate 4 bytes more than the     * size rounded up to the next 4K boundary.     */    if (!contiguous)        p = PM_malloc(roundedSize);    else#endif        p = PM_allocRealSeg(roundedSize,&r_seg,&r_off);    if (p == NULL)        return NULL;    roundedP = (void*)(((ulong)p + 0xFFF) & ~0xFFF);    *((ulong*)(roundedP + size)) = (ulong)p;    PM_lockDataPages(roundedP,size,&lh);    if ((*physAddr = PM_getPhysicalAddr(roundedP)) == 0xFFFFFFFF) {        PM_freeLockedMem(roundedP,size,contiguous);        return NULL;        }    /* Disable caching for the memory since it is probably a DMA buffer */#ifndef REALMODE    PM_adjustPageTables((ulong)roundedP,size-1,false);#endif    return roundedP;}/****************************************************************************REMARKS:Free a block of locked memory.****************************************************************************/void PMAPI PM_freeLockedMem(void *p,uint size,ibool contiguous){#ifndef REALMODE    VXD_regs        regs;    PM_lockHandle   lh; /* Unused in DOS */    if (!p)        return;    if (VXD_version) {        memset(&regs,0,sizeof(regs));        regs.eax = API_NUM(PMHELP_FREELOCKED);        regs.ebx = (ulong)p;        regs.ecx = size;        regs.edx = contiguous;        _PM_VxDCall(&regs,_PM_VXD_off,_PM_VXD_sel);        return;        }    PM_unlockDataPages(p,size,&lh);    if (!contiguous)        free(*((void**)((uchar*)p + size)));    else#endif        PM_freeRealSeg(*((void**)((char*)p + size)));}#ifndef REALMODE/****************************************************************************REMARKS:Allocates a new block of pages for the page block manager.****************************************************************************/static pageblock *PM_addNewPageBlock(void){    int         i,size;    pageblock   *newBlock;    char        *p,*next;    /* Allocate memory for the new page block, and add to head of list */    size = PAGES_PER_BLOCK * PM_PAGE_SIZE + (PM_PAGE_SIZE-1) + sizeof(pageblock);    if ((newBlock = PM_malloc(size)) == NULL)        return NULL;    newBlock->prev = NULL;    newBlock->next = pageBlocks;    if (pageBlocks)        pageBlocks->prev = newBlock;    pageBlocks = newBlock;    /* Initialise the page aligned free list for the page block */    newBlock->freeCount = PAGES_PER_BLOCK;    newBlock->freeList = p = (char*)(((ulong)(newBlock + 1) + (PM_PAGE_SIZE-1)) & ~(PM_PAGE_SIZE-1));    newBlock->freeListStart = newBlock->freeList;    newBlock->freeListEnd = p + (PAGES_PER_BLOCK-1) * PM_PAGE_SIZE;    for (i = 0; i < PAGES_PER_BLOCK; i++,p = next)        FREELIST_NEXT(p) = next = p + PM_PAGE_SIZE;    FREELIST_NEXT(p - PM_PAGE_SIZE) = NULL;    return newBlock;}#endif/****************************************************************************REMARKS:Allocates a page aligned and page sized block of memory****************************************************************************/void * PMAPI PM_allocPage(

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -