#define MBS_USED_SIGNATURE        0x1020304
#define MBS_UNUSED_SIGNATURE        0x4030201
class MemBlk
{
 MemBlk *next,*last;
 U4 signature;
 U4 pages;
};

#define HEAP_DBG        FALSE

#if HEAP_DBG
//See $LK,"Redundant Struct","PF:D:/LT/OSMain/OSDefs.ASZ,UUM_SIZE"$

class UnusedAllocatedMem
{
 U8 size;
 HeapCtrl *hc;
 U1 *caller1,*caller2;
 UnusedAllocatedMem *next;
};
class UsedAllocatedMem
{
 U8 size;
 HeapCtrl *hc;
 U1 *caller1,*caller2;
 UsedAllocatedMem *next,*last;
 U0 start;
};
#else
class UnusedAllocatedMem
{
 U8 size;
 U0 hc;
 U0 caller1,caller2;
 UnusedAllocatedMem *next;
};
class UsedAllocatedMem
{
 U8 size;
 HeapCtrl *hc;
 U0 caller1,caller2;
 U0 next,last;
 U0 start;
};
#endif

//MEM RELATED
#define PAGE_SIZE        0x200
#define PAGE_BITS        9
#define DEFAULT_STACK        (PAGE_SIZE*256)
#define FREE_PAGE_HASH_SIZE        0x100

#define MAXIO                                0x10000
#define HEAP_HASH_SIZE                        1024

#define BPf_LOCKED                0
class BlkPool
{
 U8 size;
 U8 flags;
 MemBlk *mem_free_list;
 MemBlk *mem_free_2meg_list;
 MemBlk *free_page_hash[FREE_PAGE_HASH_SIZE];
 MemBlk *free_page_hash2[64];
};

#define HCf_LOCKED                0
#define HCf_NON_TASK_QUEUE        1
class HeapCtrl
{
 U8 flags;
 BlkPool *bp;
 TssStruct *mem_tss;
 MemBlk *next_mem_blk,*last_mem_blk;
 UnusedAllocatedMem *malloc_free_list;
 UsedAllocatedMem *next_um,*last_um;
 UnusedAllocatedMem *heap_hash[HEAP_HASH_SIZE/sizeof(void *)];
};

$PJ,"Project: OSMain","/LT/OSMain/OS.SPZ"$
asm {
//The heap cache technique I first saw at Ticketmaster.
//I don't know who owns it.

             USE32
INIT_MEM::
//Set-up Page Tables
             MOV        EDI,0x100000
             XOR        EAX,EAX
             MOV        ECX,0x1000*(NUM_PML1+NUM_PML2+NUM_PML3+NUM_PML4)/4
             REP_STOSD

//PML1
             MOV        EAX,0x103
             XOR        EDX,EDX
             MOV        EDI,0x100000
             MOV        ECX,0x200*NUM_PML1
@@1:        MOV        U4 [EDI],EAX
             ADD        EDI,4
             MOV        U4 [EDI],EDX
             ADD        EDI,4
             ADD        EAX,0x1000
             ADC        EDX,0
             LOOP        @@1

//video ram=write through
             MOV        EAX,8
             XOR        EDX,EDX
             MOV        EDI,0x100000+0xA0*8
             MOV        ECX,0xC0-0xA0
@@2:        OR        U4 [EDI],EAX
             ADD        EDI,4
             OR        U4 [EDI],EDX
             ADD        EDI,4
             LOOP        @@2

//PML2
             MOV        EAX,0x100000+3
             XOR        EDX,EDX
             MOV        EDI,0x100000+0x1000*NUM_PML1
             MOV        ECX,NUM_PML1
@@3:        MOV        U4 [EDI],EAX
             ADD        EDI,4
             MOV        U4 [EDI],EDX
             ADD        EDI,4
             ADD        EAX,0x1000
             ADC        EDX,0
             LOOP        @@3

             MOV        EAX,0x83+NUM_PML1*0x200000
             XOR        EDX,EDX
             MOV        EDI,0x100000+0x1000*NUM_PML1+8*NUM_PML1
             MOV        ECX,NUM_PML2*0x200-NUM_PML1
@@4:        MOV        U4 [EDI],EAX
             ADD        EDI,4
             MOV        U4 [EDI],EDX
             ADD        EDI,4
             ADD        EAX,0x200000
             ADC        EDX,0
             LOOP        @@4

//APIC=No Cache
             MOV        EAX,0x10
             XOR        EDX,EDX
             MOV        EDI,0x100000+0x1000*NUM_PML1+8*0x700
             MOV        ECX,0x800-0x700
@@5:        OR        U4 [EDI],EAX
             ADD        EDI,4
             OR        U4 [EDI],EDX
             ADD        EDI,4
             LOOP        @@5

//PML3
             MOV        EAX,3+0x100000+NUM_PML1*0x1000
             XOR        EDX,EDX
             MOV        EDI,0x100000+0x1000*(NUM_PML1+NUM_PML2)
             MOV        ECX,NUM_PML2
@@6:        MOV        U4 [EDI],EAX
             ADD        EDI,4
             MOV        U4 [EDI],EDX
             ADD        EDI,4
             ADD        EAX,0x1000
             ADC        EDX,0
             LOOP        @@6

//PML4
             MOV        EAX,3+0x100000+(NUM_PML1+NUM_PML2)*0x1000
             XOR        EDX,EDX
             MOV        EDI,0x100000+0x1000*(NUM_PML1+NUM_PML2+NUM_PML3)
             MOV        ECX,1
@@7:        MOV        U4 [EDI],EAX
             ADD        EDI,4
             MOV        U4 [EDI],EDX
             ADD        EDI,4
             ADD        EAX,0x1000
             ADC        EDX,0
             LOOP        @@7

             MOV        U4 [SYS_CODE_BP],SYS_BP_SIZE
             MOV        U4 [SYS_CODE_BP+4],0

             MOV        U4 [SYS_DATA_BP],0
             MOV        U4 [SYS_DATA_BP+4],0

             MOV        U4 [SYS_BP_SIZE],0
             MOV        U4 [SYS_BP_SIZE+4],0
             MOV        U4 [SYS_BP_FLAGS],0
             MOV        U4 [SYS_BP_FLAGS+4],0

             MOV        EDI,U4 SYS_BP_FREE_PAGE_HASH
             MOV        ECX,FREE_PAGE_HASH_SIZE*2
             XOR        EAX,EAX
             REP_STOSD
             MOV        EDI,U4 SYS_BP_FREE_PAGE_HASH2
             MOV        ECX,64*2
             REP_STOSD

             MOV        U4 [SYS_BP_MEM_FREE_LIST],0
             MOV        U4 [SYS_BP_MEM_FREE_LIST+4],0
             MOV        U4 [SYS_BP_MEM_FREE_2MEG_LIST],0
             MOV        U4 [SYS_BP_MEM_FREE_2MEG_LIST+4],0

             MOV        EBX,U4 [SYS_HEAP_BASE]
             MOV        EAX,U4 [SYS_MEMBLKS]
             CMP        EAX,CODE_HEAP_LIMIT
             JB        @@8
             MOV        EAX,CODE_HEAP_LIMIT
@@8:        DEC        EAX
             MOV        U4 [SYS_HEAP_LIMIT],EAX
             INC        EAX

             TEST        U1 [SYS_MEM_INIT_FLAG],1
             JZ        @@100
             PUSH        EAX
             MOV        EDI,EBX
             MOV        ECX,EAX
             SUB        ECX,EDI
             MOV        AL,U1 [SYS_MEM_INIT_VAL]
             REP_STOSB
             POP        EAX

@@100:        SUB        EAX,EBX
             SHR        EAX,PAGE_BITS
             MOV        EDI,U4 [SYS_BP_MEM_FREE_LIST]
             MOV        U4 MB_NEXT[EBX],EDI
             MOV        U4 MB_NEXT+4[EBX],0
             MOV        U4 [SYS_BP_MEM_FREE_LIST],EBX
             MOV        U4 [SYS_BP_MEM_FREE_LIST+4],0
             MOV        U4 MB_SIGNATURE[EBX],MBS_UNUSED_SIGNATURE
             MOV        U4 MB_SIZE[EBX],EAX
             RET
};

void SysOutOfMem()
{
 Debugger("Out Of Mem\r\nCPU:",Gs->num);
}

asm {CP_BAD_MEM_FREE::};
void SysBadMemFree(U8 *ptr)
{
 Debugger("Bad Mem Free:",ptr);
}

U8 *MemPointAtPageTableEntry(void *a)
{
 if (a<NUM_PML1*0x1000*0x200)
     return 0x100000+ a>>12 *8;
 else
     return 0x100000+NUM_PML1*0x1000+
                   a>>(12+9) *8;
}

void *AllocNonTaskMemBlks(U8 *pages512,BlkPool *bp=NULL)
//This will allocate a 512 byte pages from
//the code heap mem range and not
//link them to any task.  (Linking to a task
//means it will be freed when the task
//dies.)
//It might give you more than you asked for
//so a ptr to a page count is passed.
{
 MemBlk *result=NULL,*m;
 U8 i,num=*pages512,old_flags=GetFlags;
 if (!bp) bp=sys_code_bp;
 Cli;
 while (LBts(&bp->flags,BPf_LOCKED));
 if (num<FREE_PAGE_HASH_SIZE) {
     if (result=bp->free_page_hash[num]) {
         bp->free_page_hash[num]=result->next;
         LBtr(&bp->flags,BPf_LOCKED);
         SetFlags(old_flags);
         return result;
     }
 } else {
     num-=2;
     i=Bsr(num)+1;
     num=0;
     Bts(&num,i);
     num+=2;
     *pages512=num;
     if (result=bp->free_page_hash2[i]) {
         bp->free_page_hash2[i]=result->next;
         LBtr(&bp->flags,BPf_LOCKED);
         SetFlags(old_flags);
         return result;
     }
 }
 m=&bp->mem_free_list;
 do {
     if (!(result=m->next)) {
         SysOutOfMem;
         LBtr(&bp->flags,BPf_LOCKED);
         SetFlags(old_flags);
         return NULL;
     }
     if (result->pages<num)
         m=result;
     else {
         if (result->pages==num) {
             m->next=result->next;
             LBtr(&bp->flags,BPf_LOCKED);
             SetFlags(old_flags);
             return result;
         } else {
             result->pages-=num;
             result><(U1 *)+=result->pages<<PAGE_BITS;
             result->pages=num;
             LBtr(&bp->flags,BPf_LOCKED);
             SetFlags(old_flags);
             return result;
         }
     }
 } while (TRUE);
}

void FreeNonTaskMemBlks(MemBlk *m,U8 pages512,BlkPool *bp=NULL)
{
 U8 i,old_flags;
 if (m) {
     if (!bp) bp=sys_code_bp;
     old_flags=GetFlags;
     Cli;
     while (LBts(&bp->flags,BPf_LOCKED));
     m->signature=MBS_UNUSED_SIGNATURE;
     m->pages=pages512;
     if (pages512<FREE_PAGE_HASH_SIZE) {
         m->next=bp->free_page_hash[pages512];
         bp->free_page_hash[pages512]=m;
     } else {
         pages512-=2;
         i=Bsr(pages512);
         m->next=bp->free_page_hash2[i];
         bp->free_page_hash2[i]=m;
     }
     LBtr(&bp->flags,BPf_LOCKED);
     SetFlags(old_flags);
 }
}

void *Alloc2MegMemBlks(U8 *pages2Meg,BlkPool *bp=NULL)
//This will allocate 2Meg pages from
//the code heap mem range and not
//link it to any task.        (Linking to a task
//means they will be freed when the task
//dies.)
//It might give you more than you asked for
//so a ptr to a page count is passed.
{
 U8 *pte;
 MemBlk *result=NULL,*m,*m1;
 U8 i,j,num=*pages2Meg,old_flags=GetFlags;

 if (!bp) bp=sys_code_bp;
 Cli;
 while (LBts(&bp->flags,BPf_LOCKED));
 num<<=12;

 m=&bp->mem_free_2meg_list;
 do {
     if (!(result=m->next))
         break;
     if (result->pages<num)
         m=result;
     else {
         if (result->pages==num) {
             m->next=result->next;
             goto done;
         } else {
             result->pages-=num;
             result><(U1 *)+=result->pages<<PAGE_BITS;
             result->pages=num;
             goto done;
         }
     }
 } while (TRUE);

 m=&bp->mem_free_list;
 do {
     if (!(result=m->next)) {
         SysOutOfMem;
         LBtr(&bp->flags,BPf_LOCKED);
         SetFlags(old_flags);
         return NULL;
     }
     if (result->pages<num)
         m=result;
     else {
         if (result->pages==num) {
             if (result><(U1 *)&0x1FFFFF)
                 m=result;
             else {
                 m->next=result->next;
                 goto done;
             }
         } else {
             if (i=(result><(U1 *)&0x1FFFFF)>>PAGE_BITS) {
                 j=1<<12-i;
                 if (result->pages<num+j)
                     m=result;
                 else if (result->pages==num+j) {
                     result->pages-=num;
                     result><(U1 *)+=result->pages<<PAGE_BITS;
                     result->pages=num;
                     goto done;
                 } else {
                     m1=result;
                     result><(U1 *)+=j<<PAGE_BITS;
                     result->pages=num;
                     m=result><(U1 *)+num<<PAGE_BITS;
                     m->pages=m1->pages-num-j;
                     m1->pages=j;
                     m->next=m1->next;
                     m1->next=m;
                     m->signature=MBS_UNUSED_SIGNATURE;
                     goto done;
                 }
             } else {
                 m=m->next=result><(U1 *)+num<<PAGE_BITS;
                 m->next=result->next;
                 m->pages=result->pages-num;
                 m->signature=MBS_UNUSED_SIGNATURE;
                 result->pages=num;
                 goto done;
             }
         }
     }
 } while (TRUE);
done:
 m=result;
 num=*pages2Meg;
 for (i=0;i<num;i++) {
     pte=MemPointAtPageTableEntry(m);
     *pte &= ~0x18;
     m><(U1 *)+=0x200000;
 }
 LBtr(&bp->flags,BPf_LOCKED);
 SetFlags(old_flags);
 return result;
}

void *AllocUncachedMemBlks(U8 *pages2Meg,BlkPool *bp=NULL)
//This will allocate 2Meg pages from
//the code heap mem range and not
//link them to any task.  (Linking to a task
//means it will be freed when the task
//dies.)  It will be marked uncached.
//It might give you more than you asked for
//so a ptr to a page count is passed.
{
 MemBlk *result,*m;
 U8 i,num=*pages2Meg,*pte;

 result=Alloc2MegMemBlks(pages2Meg,bp);
 m=result;
 num=*pages2Meg;
 for (i=0;i<num;i++) {
     pte=MemPointAtPageTableEntry(m);
     *pte= *pte& ~0x18 |0x10;
     m><(U1 *)+=0x200000;
 }
 return result;
}

void *AllocWriteThroughMemBlks(U8 *pages2Meg,BlkPool *bp=NULL)
//This will allocate 2Meg pages from
//the code heap mem range and not
//link them to any task.  (Linking to a task
//means they will be freed when the task
//dies.)  It will be marked write-through.
//It might give you more than you asked for
//so a ptr to a page count is passed.
{
 MemBlk *result,*m;
 U8 i,num=*pages2Meg,*pte;

 result=Alloc2MegMemBlks(pages2Meg,bp);
 m=result;
 num=*pages2Meg;
 for (i=0;i<num;i++) {
     pte=MemPointAtPageTableEntry(m);
     *pte= *pte& ~0x18 |8;
     m><(U1 *)+=0x200000;
 }
 return result;
}

void Free2MegMemBlks(MemBlk *m,U8 pages2Meg,BlkPool *bp=NULL)
{
 U8 old_flags,*pte;
 MemBlk *m1;
 U8 i;
 if (m) {
     if (!bp) bp=sys_code_bp;
     m1=m;
     for (i=0;i<pages2Meg;i++) {
         pte=MemPointAtPageTableEntry(m1);
         *pte=*pte & ~0x18;
         m1><(U1 *)+=0x200000;
     }
     old_flags=GetFlags;
     Cli;
     while (LBts(&bp->flags,BPf_LOCKED));
     m->signature=MBS_UNUSED_SIGNATURE;
     m->pages=pages2Meg<<12;
     m->next=bp->mem_free_2meg_list;
     bp->mem_free_2meg_list=m;
     LBtr(&bp->flags,BPf_LOCKED);
     SetFlags(old_flags);
 }
}

asm {ALLOCATE_MEM_BLKS::};
MemBlk *AllocMemBlks(U8 *num_,HeapCtrl *hc)
{
 MemBlk *result;
 U8 old_flags=GetFlags;
 Cli;
 result=AllocNonTaskMemBlks(num_,hc->bp);
 if (!Bt(&hc->flags,HCf_NON_TASK_QUEUE))
     InsQue(result,hc->last_mem_blk);
 result->signature=MBS_USED_SIGNATURE;
 SetFlags(old_flags);
 return result;
}

asm {FREE_MEM_BLKS::};
void FreeMemBlks(MemBlk *m,HeapCtrl *hc)
{
 U8 old_flags;
 if (m) {
     old_flags=GetFlags;
     Cli;
     if (m->signature!=MBS_USED_SIGNATURE) {
         SysBadMemFree(m);
         goto done;
     }
     if (!Bt(&hc->flags,HCf_NON_TASK_QUEUE))
         RemQue(m);
     FreeNonTaskMemBlks(m,m->pages,hc->bp);
done:
     SetFlags(old_flags);
 }
}


void FreeMemBlkList(HeapCtrl *hc)
{
 U8 old_flags=GetFlags;
 MemBlk *m,*m1;
 Cli;
 while (LBts(&hc->flags,HCf_LOCKED));
 m=hc->next_mem_blk;
 while (m!=&hc->next_mem_blk) {
     m1=m->next;
     FreeMemBlks(m,hc);
     m=m1;
 }
 LBtr(&hc->flags,HCf_LOCKED);
 SetFlags(old_flags);
}

asm {
////**************************PROCEDURE*************************
// OUT:  RAX=BASE ADDRESS
//
CP_MALLOC_HC::
             PUSH        EBP
             MOV        RBP,RSP
             PUSH        ESI
             PUSH        EDI

             MOV        RDX,U8 SF_ARG2[RBP]

MALLOC_HC_JOIN::
             MOV        RAX,U8 SF_ARG1[RBP]
             PUSHFD
             ADD        RAX,UM_START+7        //round-up to U8
             AND        RAX,~7
#assert UM_START>=UUM_STRUCT_SIZE
             CMP        RAX,UM_START
             JAE        @@4
             MOV        RAX,UM_START
@@4:

//Multicore issues: structure must be uncached, like $LK,"mp_heap","MN:mp_heap"$
             CLI
@@32:        LOCK
             BTS        U4 HC_FLAGS[RDX],HCf_LOCKED
             JC        @@32

             CMP        RAX,HEAP_HASH_SIZE
             JAE        @@10
             MOV        RSI,U8 HC_HEAP_HASH[RAX+RDX]
             OR        RSI,RSI
             JZ        @@13
             MOV        RCX,U8 UUM_NEXT[RSI]
             MOV        U8 HC_HEAP_HASH[RAX+RDX],RCX
             JMP        I4 @@5

@@10:        ADD        RAX,MB_STRUCT_SIZE+PAGE_SIZE-1
             SHR        RAX,PAGE_BITS

             PUSH        EDX
             PUSH        EAX
             MOV        RAX,RSP
             PUSH        EDX
             PUSH        EAX
             CALL        ALLOCATE_MEM_BLKS
             MOV        RSI,RAX
             ADD        RSP,16
             POP        EAX
             POP        EDX

             SHL        RAX,PAGE_BITS
             SUB        RAX,MB_STRUCT_SIZE
             ADD        RSI,MB_STRUCT_SIZE
             JMP        @@5

@@13:        LEA        RSI,U8 HC_MALLOC_FREE_LIST-UUM_NEXT[RDX]

@@1:        MOV        RBX,RSI
             MOV        RSI,U8 UUM_NEXT[RBX]
             OR        RSI,RSI
             JNZ        @@2
             PUSH        EAX                //-****
             ADD        RAX,16*PAGE_SIZE-1
             SHR        RAX,PAGE_BITS

             PUSH        EDX
             PUSH        EAX //num blks
             MOV        RAX,RSP
             PUSH        EDX
             PUSH        EAX //address of num blks out
             CALL        ALLOCATE_MEM_BLKS
             MOV        RSI,RAX
             ADD        RSP,16
             POP        EAX
             POP        EDX

             LEA        RSI,U8 MB_STRUCT_SIZE[RSI]
             SHL        RAX,PAGE_BITS
             SUB        RAX,MB_STRUCT_SIZE
             LEA        RBX,U8 HC_MALLOC_FREE_LIST-UUM_NEXT[RDX]
             MOV        RDI,U8 UUM_NEXT[RBX]
             MOV        U8 UUM_NEXT[RSI],RDI
             MOV        U8 UUM_SIZE[RSI],RAX
             MOV        U8 UUM_NEXT[RBX],RSI
             POP        EAX                //+****
             JMP        @@3
@@2:        CMP        U8 UUM_SIZE[RSI],RAX
             JB        @@1
             JNE        @@3

@@8:        MOV        RDI,U8 UUM_NEXT[RSI]
             MOV        U8 UUM_NEXT[RBX],RDI
             JMP        @@5

@@3:        SUB        U8 UUM_SIZE[RSI],RAX        //UPDATE FREE ENTRY
             CMP        U8 UUM_SIZE[RSI],UUM_STRUCT_SIZE
             JAE        @@7
             ADD        U8 UUM_SIZE[RSI],RAX
             MOV        RAX,U8 UUM_SIZE[RSI]
             JMP        @@8

@@7:        ADD        RSI,U8 UUM_SIZE[RSI]                 //SET ESI TO @ALLOCATED
PAGES

@@5:
#if HEAP_DBG
//InsQue
             MOV        RDI,U8 HC_LAST_UM[RDX]
             MOV        U8 UM_NEXT[RDI],RSI
             MOV        U8 HC_LAST_UM[RDX],RSI
             MOV        U8 UM_LAST[RSI],RDI
             LEA        RDI,U8 HC_NEXT_UM-UM_NEXT[RDX]
             MOV        U8 UM_NEXT[RSI],RDI

//Caller1/Caller2
             PUSH        RDX
             MOV        RDX,U8 [SYS_HEAP_LIMIT]
             MOV        RDI,U8 SF_RIP[RBP]
             CMP        RDI,RDX
             JB        @@46
             XOR        EDI,EDI
             MOV        U8 UM_CALLER1[RSI],RDI
             JMP        @@48
@@46:        MOV        U8 UM_CALLER1[RSI],RDI
             MOV        RDI,U8 SF_RBP[RBP]
             CMP        RDI,RDX
             JB        @@47
             XOR        EDI,EDI
             JMP        @@48
@@47:        MOV        RDI,U8 SF_RIP[RDI]
             CMP        RDI,RDX
             JB        @@48
             XOR        EDI,EDI
@@48:        MOV        U8 UM_CALLER2[RSI],RDI
             POP        RDX

#endif
             LOCK
             BTR        U4 HC_FLAGS[RDX],HCf_LOCKED
             POPFD

             MOV        U8 UM_SIZE[RSI],RAX
             MOV        U8 UM_HEAP_CTRL[RSI],RDX
             LEA        RAX,U8 UM_START[RSI]

             BT        U4 [SYS_SEMAS+SYS_SEMA_HEAPLOG*SEMA_STRUCT_SIZE],0
             JNC        @@200
             PUSH_C_REGS
             PUSH        EDX
             PUSH        EAX
             MOV        RAX,U8 [SYS_EXTERN_TABLE]
             MOV        RAX,U8 EXT_HEAPLOG_MALLOC*8[RAX]
             OR        RAX,RAX
             JZ        @@202
             CALL        RAX
@@202:        ADD        RSP,16
             POP_C_REGS

@@200:        TEST        U1 [SYS_HEAP_INIT_FLAG],1
             JZ        @@210

             PUSH        EAX
             PUSH        ECX
             MOV        RCX,U8 UM_SIZE-UM_START[RAX]
             SUB        RCX,UM_START
             MOV        RDI,RAX
             MOV        AL,U1 [SYS_HEAP_INIT_VAL]
             REP_STOSB
             POP        ECX
             POP        EAX

@@210:        POP        EDI
             POP        ESI
             POP        EBP
             RET
////**************************PROCEDURE*************************
CP_FREE_HC::
             PUSH        EBP
             MOV        RBP,RSP
             PUSH        ESI
             PUSH        EDI

             BT        U4 [SYS_SEMAS+SYS_SEMA_HEAPLOG*SEMA_STRUCT_SIZE],0
             JNC        @@1
             PUSH_C_REGS
             PUSH        U8 SF_ARG1[RBP]
             MOV        RAX,U8 [SYS_EXTERN_TABLE]
             MOV        RAX,U8 EXT_HEAPLOG_FREE*8[RAX]
             OR        RAX,RAX
             JZ        @@2
             CALL        RAX
@@2:        ADD        RSP,8
             POP_C_REGS

@@1:        MOV        RSI,U8 SF_ARG1[RBP]
             OR        RSI,RSI

#if HEAP_DBG
             JZ        I4 FREE_HC_DONE
#else
             JZ        FREE_HC_DONE
#endif

FREE_HC_JOIN::
             PUSHFD
             SUB        RSI,UM_START
             MOV        RDX,U8 UM_HEAP_CTRL[RSI]
             MOV        RAX,U8 UM_SIZE[RSI]

//Multicore issues: structure must be uncached, like $LK,"mp_heap","MN:mp_heap"$
             CLI
@@32:        LOCK
             BTS        U4 HC_FLAGS[RDX],HCf_LOCKED
             JC        @@32
#if HEAP_DBG
//RemQue
             MOV        RDX,U8 UM_NEXT[RSI]
             MOV        RDI,U8 UM_LAST[RSI]
             MOV        U8 UM_LAST[RDX],RDI
             MOV        U8 UM_NEXT[RDI],RDX

//Caller1/Caller2
             MOV        RDX,U8 [SYS_HEAP_LIMIT]
             MOV        RDI,U8 SF_RIP[RBP]
             CMP        RDI,RDX
             JB        @@46
             XOR        EDI,EDI
             MOV        U8 UUM_CALLER1[RSI],RDI
             JMP        @@48
@@46:        MOV        U8 UUM_CALLER1[RSI],RDI
             MOV        RDI,U8 SF_RBP[RBP]
             CMP        RDI,RDX
             JB        @@47
             XOR        EDI,EDI
             JMP        @@48
@@47:        MOV        RDI,U8 SF_RIP[RDI]
             CMP        RDI,RDX
             JB        @@48
             XOR        EDI,EDI
@@48:        MOV        U8 UUM_CALLER2[RSI],RDI

             MOV        RDX,U8 UM_HEAP_CTRL[RSI]
#endif
             CMP        RAX,HEAP_HASH_SIZE
             JAE        @@5

#assert UUM_SIZE==UM_SIZE
//        MOV        U8 UUM_SIZE[RSI],RAX

             MOV        RBX,U8 HC_HEAP_HASH[RAX+RDX]
             MOV        U8 UUM_NEXT[RSI],RBX
             MOV        U8 HC_HEAP_HASH[RAX+RDX],RSI
             JMP        @@101

@@5:        SUB        RSI,MB_STRUCT_SIZE
             PUSH        EDX
             PUSH        ESI
             CALL        FREE_MEM_BLKS
             ADD        RSP,8
             POP        EDX

@@101:        LOCK
             BTR        U4 HC_FLAGS[RDX],HCf_LOCKED
             POPFD
FREE_HC_DONE:
             POP        EDI
             POP        ESI
             POP        EBP
             RET
////**************************PROCEDURE*************************
// OUT:  RAX=BASE ADDRESS
//
CP_MALLOC::
             PUSH        EBP
             MOV        RBP,RSP
             PUSH        ESI
             PUSH        EDI

             XOR        EBX,EBX
             MOV        RDX,U8 SF_ARG2[RBP]
             OR        RDX,RDX
             JNZ        @@30
             MOV        RDX,U8 FS:TSS_ADDRESS[RBX]
@@30:        MOV        RDX,U8 TSS_DATA_HEAP[RDX]
             JMP        I4 MALLOC_HC_JOIN
////**************************PROCEDURE*************************
CP_MSIZE::
             PUSH        EBP
             MOV        RBP,RSP
             MOV        RBX,U8 SF_ARG1[RBP]
             XOR        EAX,EAX
             OR        RBX,RBX
             JZ        @@100
             MOV        RAX,U8 UM_SIZE-UM_START[RBX]
             SUB        RAX,UM_START
@@100:        POP        EBP
             RET
////**************************PROCEDURE*************************
CP_MSIZE2::
             PUSH        EBP
             MOV        RBP,RSP
             MOV        RBX,U8 SF_ARG1[RBP]
             XOR        EAX,EAX
             OR        RBX,RBX
             JZ        @@100
             MOV        RAX,U8 UM_SIZE-UM_START[RBX]
@@100:        POP        EBP
             RET
////**************************PROCEDURE*************************
CP_MHEAP_CTRL::
             PUSH        EBP
             MOV        RBP,RSP
             MOV        RBX,U8 SF_ARG1[RBP]
             XOR        EAX,EAX
             OR        RBX,RBX
             JZ        @@100
             MOV        RAX,U8 UM_HEAP_CTRL-UM_START[RBX]
@@100:        POP        EBP
             RET
};

LTextern CP_MALLOC void *MAlloc(U8 size,TssStruct *tss=NULL);
LTextern CP_FREE_HC void Free(void *add);
LTextern CP_MSIZE U8 MSize(void *src);        //size of heap object
LTextern CP_MSIZE2 U8 MSize2(void *src); //Internal size

void *MAllocZ(U8 size,TssStruct *tss=NULL)
{
 void *result=MAlloc(size,tss);
 MemSet(result,0,size);

 return result;
}

void *AMAlloc(U8 size)
{
 return MAlloc(size,adam_tss);
}

void *MAllocIdentical(void *src,TssStruct *tss=NULL)
{
 U8 size=MSize(src);
 void *result=MAlloc(size,tss);
 MemCpy(result,src,size);
}

void *AMAllocIdentical(void *src)
{
 return MAllocIdentical(src,adam_tss);
}

I1 *StrNew(I1 *buf,TssStruct *tss=NULL)
{
 U8 size;
 I1 *result;
 if (buf) {
     size=StrLen(buf)+1;
     result=MAlloc(size,tss);
     MemCpy(result,buf,size);
 } else {
     result=MAlloc(1);
     *result=0;
 }
 return result;
}

I1 *AStrNew(I1 *buf)
{
 return StrNew(buf,adam_tss);
}

void *AMAllocZ(U8 size)
{
 return MAllocZ(size,adam_tss);
}

void LinkedListDel(void **list)
{
 void **d;
 while (list) {
     d=*list;
     Free(list);
     list=d;
 }
}

U8 LinkedListSize(void **list)
{
 U8 result=0;
 while (list) {
     result+=MSize2(list);
     list=*list;
 }
 return result;
}

void InitBlkPool(BlkPool *bp,U8 pages512)
{
 MemBlk *m;
 MemSet(bp,0,sizeof(BlkPool));
 bp->size=pages512;
 m=(bp><(U1 *)+sizeof(BlkPool)+PAGE_SIZE-1)&~(PAGE_SIZE-1);
 bp->mem_free_list=m;
 m->next=NULL;
 m->pages=(bp><(U1 *)+pages512<<PAGE_BITS-m><(U1 *))>>PAGE_BITS;
 m->signature=MBS_UNUSED_SIGNATURE;
}

LTextern CP_MALLOC_HC void *MAllocHC(U8 size,HeapCtrl *hc);
LTextern CP_MSIZE U8 MSizeHC(void *src);        //size of heap object
LTextern CP_MHEAP_CTRL HeapCtrl *MHeapCtrl(void *src);        //HC of heap object

void *MAllocHCZ(U8 size,HeapCtrl *hc)
{
 void *result=MAllocHC(size,hc);
 MemSet(result,0,size);
 return result;
}

void *MAllocIdenticalHC(void *src,HeapCtrl *hc)
{
 U8 size=MSize(src);
 void *result=MAllocHC(size,hc);
 MemCpy(result,src,size);
}

I1 *StrNewHC(I1 *buf,HeapCtrl *hc)
{
 U8 size;
 I1 *result;
 if (buf) {
     size=StrLen(buf)+1;
     result=MAllocHC(size,hc);
     MemCpy(result,buf,size);
 } else {
     result=MAllocHC(1,hc);
     *result=0;
 }
 return result;
}

HeapCtrl *InitTssHeapCtrl(TssStruct *tss,BlkPool *bp,HeapCtrl *hc_original)
{
 void *b;
 HeapCtrl *hc;
//$LK,"Adam Tss","FF:::/LT/OSMain/OSStartUp.ASZ,HC_BP"$
 hc=MAllocHCZ(sizeof(HeapCtrl),hc_original);
 hc->bp=bp;
 hc->mem_tss=tss;
 b=&hc->next_mem_blk;
 hc->next_mem_blk=hc->last_mem_blk=b;
 hc->next_um=hc->last_um=(&hc->next_um)><(U1 *)-offset(UsedAllocatedMem.next);
 return hc;
}

HeapCtrl *InitIndependentHeapCtrl(BlkPool *bp,U8 pages512)
{
 HeapCtrl *hc=bp><(U1 *)+sizeof(BlkPool);
 MemBlk *m;
 MemSet(bp,0,sizeof(BlkPool)+sizeof(HeapCtrl));
 Bts(&hc->flags,HCf_NON_TASK_QUEUE);
 hc->bp=bp;
 hc->next_um=hc->last_um=(&hc->next_um)><(U1 *)-offset(UsedAllocatedMem.next);
 bp->size=pages512;
 m=(bp><(U1 *)+sizeof(BlkPool)+sizeof(HeapCtrl)+PAGE_SIZE-1)&~(PAGE_SIZE-1);
 bp->mem_free_list=m;
 m->next=NULL;
 m->pages=(bp><(U1 *)+pages512<<PAGE_BITS-m><(U1 *))>>PAGE_BITS;
 m->signature=MBS_UNUSED_SIGNATURE;
 return hc;
}
Home

Kernel
StartUp
Scheduler
Memory
MultiCore
Interrupts
BitMaps
Screen
Plot
Compiler Frontend
Compiler Mid
Compiler Backend
Memory Manager