First a picture:
New copy of every accessed data made by fork for a child task,
- System starts with empty extremely simple linear page tables (task0, not real task, has initialized page table).
- TLB- fault handling copies data for task to a physical block. Fork system call copies all parent's accessed pages for children. Elf binary is a simulated disc from where we get pages as from disc.
- Pages are very small to illustrate the small system clearly. If pages would be pig, fault would happen seldom.
- Itanium gcc has not gnu style inline assembly!
- Simple code tlb fault serving:
/************************************************************************
This fault handler serves the tlb data fault at 0x1000 (IVT).
It has purposes:
-It implements an example of tlb fault handling
-It implements an example of page table usage
-It implements an example how to continue after a task crashing
(the registers demonstrated: cr.ifa, cr.itir, the in instructions demonstrated: itr.d dtr[] , srlz.d)
PSEUDO CODE (shared memory as example but code and other data is using the same techique):
if (the faulting address is not in the area of shared memory)
if (the faulting address differs from the allowed area to the running task)
call a fault handler which marks the task as crashed and continues the system
else
copy data from "disc" to a new physical block and update page table
set up the correct tlb translation for a shared memory virtual access
(phys page number finds out from PHYS_pages table)
"PHYS_pages" table for The 64kb shared memory segment:
Virtual page Physical page
4000000000040000 04f000 (4kb)
4000000000041000 04e000 (4kb)
4000000000042000 04d000 (4kb)
......
400000000004f000 040000
The PHYS_pages created during the startup (k_start.c):
pps = 0x4f000;//Poor man's page table
for(_index=0;_index<0x10;_index++) {
PHYS_pages[_index]=pps;
pps=pps - 0x1000;
}
Then: How to see paging to work?
One application task has the code lines:
................
T4_ptr =(long *)(SHM_PTR+0x2200);//SHM_PTR is 0x4000000000040000
...............
*(T4)=*(T4)+1;
...............
Run the ski. Set break. Make command: dj 42200
You get:
0000000000042200 xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx
Make command: dj 4d200 //IF TRANSLATION EXISTS (REGION =0)
You get:
000000000004d200 0000000000000190 0000000000000000 0000000000000000 0000000000000000
(190 is incrementing message value)
VIRTUAL/PHYSICAL!
************************************************************************/
void k_tlb_fault_sub(void) {
__asm__("mov r16=pr;;mov ar.k1=r16;;mov r16=ar.lc;;mov ar.k2=r16;;mov r16=b0;;mov ar.k6=r16;");
//Save task's pr, lc and b0 to kernel registers
__asm__("mov r16=cr.ifa;"); //Faulting address
__asm__("add r17=@gprel(ifa_v),gp;;st8 [r17]=r16;;");
itir_v = (TASK_KEY<<8)|(12<<2);
if((ifa_v & 0xffffffffffff0000) != SHM_PTR ) {//Two cases task's data nad shared memory
if ((ifa_v & 0xffffffffffff0000) != IFA )//Task tries access out of it's rights
__asm__(" add r29= @gprel(fault_handler),gp;;mov b6=r29;;br.sptk.few b6;");
//Task is not crashing system but taken away
Index=(ifa_v & 0xff000)>>12;
X=((DS_M >>12) & 0xff);
Index = Index -X;
PD=PHYS_data[found][Index];//Page table found is TASK NUMBER AND INDEX PAGE NUMBER
if(PD==0) //We must create new from virtual to physical transaltion and copy data (FORK)
{
SRC = PHYS_data[0][Index] ;
next_block+=0x200;
cpy_dest = next_block; //NEXT available physical block to use
PD =(long) next_block;
cpy_src = (long *)SRC;
for(ix=0;ix<0x200;ix++)//Copy backing storage 0x1000 chars is 0x200 long is 4kb
*cpy_dest++= *cpy_src++;
PHYS_data[found][Index]=PD;
}
itrd_v= 0x0010000000000000| (3 << 7) | (3 << 9 )|(1 << 6) | ( 1 << 5 ) | (1 << 0) | PD;
index_v= 7;
}
else { //Now we set the correct tlb translation's physical page from the page table PYS_pages.
itrd_v = 0x0010000000000000| (3 << 7) | (3 << 9 )|(1 << 6) | ( 1 << 5 ) | (1 << 0) | PHYS_pages[ ((ifa_v & 0xf000) >> 12) ];
index_v = SHM_INDEX;
}
__asm__("add r17=@gprel(index_v),gp;;ld8 r19=[r17];;");//Set up transltion registers cr.itir and dtr
__asm__("add r17=@gprel(itir_v),gp;;ld8 r18=[r17];;");
__asm__("mov cr.itir=r18");
__asm__("add r17=@gprel(itrd_v),gp;;ld8 r18=[r17];;");
__asm__("itr.d dtr[r19] = r18; srlz.d");
__asm__("mov r16=ar.k1;;mov pr=r16;;mov r16=ar.k2;;mov ar.lc=r16;;mov r16=ar.k6;;mov b0=r16;");
__asm__("movl r31=0x4000000000000000;"); __asm__("or r1=r1,r31;bsw.1;rfi"); // set up task gp
}
}