Presentation is loading. Please wait.

Presentation is loading. Please wait.

Page-Faults in Linux How can we study the handling of page-fault exceptions?

Similar presentations


Presentation on theme: "Page-Faults in Linux How can we study the handling of page-fault exceptions?"— Presentation transcript:

1 Page-Faults in Linux How can we study the handling of page-fault exceptions?

2 Why page-faults happen Trying to access a virtual memory-address Instruction-operand / instruction-address Read-data/write-data, or fetch-instruction Maybe page is ‘not present’ Maybe page is ‘not readable’ Maybe page is ‘not writable’ Maybe page is ‘not visible’

3 Page-fault examples movl%eax, (%ebx); writable? movl(%ebx), %eax; readable? jmpahead; present? Everything depends on the entries in the current page-directory and page-tables, and on the cpu’s Current Privilege Level

4 Current Privilege Level (CPL) segment-selector RPL TITI 0123 15 TI = Table-IndicatorRPL=Requested Privilege Level Layout of segment-register contents (16 bits) CPL is determined by the value of RPL field in CS and SS

5 What does the CPU do? Whenever the cpu detects a page-fault, its action depends on Current Privilege Level If CPL == 0 (executing in kernel mode): 1) push EFLAGS register 2) push CS register 3) push EIP register 4) push error-code 5) jump to page-fault service-routine

6 Alternative action in user-mode If CPL == 3 (executing in user mode) the CPU will switch to its kernel-mode stack: 0) push SS and ESP 1) push EFLAGS 2) push CS 3) push EIP 4) push error-code 5) jump to the page-fault service-routine

7 How CPU finds new stack Special CPU segment-register: TR TR is the ‘Task Register’ TR holds ‘selector’ for a GDT descriptor Descriptor is for a ‘Task State Segment’ So TR points indirectly to current TSS TSS stores address of kernel-mode stack

8 Stack Switching mechanism GDTR TSS descriptor TR ESP0 SS0 TASK STATE SEGMENT GLOBAL DESCRIPTOR TABLE IDTR INTERRUPT DESCRIPTOR TABLE Gate descriptor CSEIP SSESP kernel stack kernel code user code user stack user-space kernel-space

9 Let’s ‘intercept’ page-faults Use our systems programming knowledge We build a ‘new’ Interrupt Descriptor Table With our own ‘customized’ interrupt-gates Use a ‘new’ gate for page-fault exceptions Other existing gates we can simply copy Why not just modify the existing IDT? It’s ‘write-protected’ in some Linux kernels But we can still ‘read’ it (i.e., for copying)

10 Very delicate to implement Will need to use some assembly language Using C language doesn’t give full control C Compiler designers didn’t plan for this! (except they did allow for using assembly) Assembly requires us to be very precise So try keeping assembly to a minimum We can use a mixture of assembly and C

11 Allocate a mapped page Device interrupts are ‘asynchronous’ CPU requires instant access to the IDT We must insure CPU can find new IDT Cannot risk putting it in ‘high memory’ We can use ‘get_free_page()’ function With flags: GFP_KERNEL and GFP_DMA (This insures page will be always mapped) No memory available? Cannot continue.

12 Must find address of current IDT We’ll need it for copying the existing gates We’ll need it for restoring old IDT upon exit We can use the ‘sidt’ instruction to find it But ‘sidt’ needs a 48-bit memory-operand No such type is directly supported in C We could use a 64-bit type (i.e., long long) Better to use array of three 16-bit values

13 Getting hold of current IDT We need to declare a global variable Because ‘init_module()’ needs it And also ‘cleanup_module()’ needs it Use ‘static’ to make it private Use ‘short’ to get 16-bit array-entries Use ‘unsigned’ to avoid sign-extensions static unsigned short oldidtr[ 3 ];

14 Activating a ‘new’ IDT When we’re ready, we can use ‘sidt’ Instruction will change the IDTR register Instruction needs 48-bit memory operand So again we will declare a suitable array static unsigned short newidtr[ 3 ];

15 Initializations We need to initialize our ‘idtr’ array We need to initialize new Descriptor Table Use ‘memcpy()’ for copying within kernel Page-Fault’s gate-descriptor must be built Must conform to CPU’s expected layout Need to use a local 64-bit variable unsigned long longgate_desc;

16 Format for a Gate Descriptor segment-selectoroffset[ 15…0 ] offset[ 31…16 ] gate type 063 Quadword (64-bits) The address of the fault-handler is ‘split’ into a hiword and a loword

17 Declaring our fault-handler Tell the C compiler our handler’s name: asmlinkage void isr0x0E( void ); Its type and value are set by assembler: asm(“.text“); asm(“.typeisr0x0E, @function “); asm(“isr0x0E:“);

18 Save/Restore cpu registers Upon entering: asm(“pushal“); asm(“pushl%ds“); asm(“pushl%es“); Upon leaving: asm(“popl%es“); asm(“popl%ds“); asm(“popal“); asm(“jmp*old_isr“);

19 Handler must access kernel data Registers CS and SS get set up by the CPU But its our job to set up DS and ES registers Linux uses same segments for data and stack asm(“ mov%ss, %eax“); asm(“ mov%eax, %ds“); asm(“ mov%eax, %es“); (Current kernel version doesn’t use FS or GS)

20 Transfer to a C function Handler will need some info from the stack The ‘error-code’ will be needed for sure So C function will need an ‘argument’ So here’s our C function prototype: static void handler( unsigned long *tos );


Download ppt "Page-Faults in Linux How can we study the handling of page-fault exceptions?"

Similar presentations


Ads by Google