Question

All.

I am trying to print current PC value, when I allocate a new physical page. In linux kernel source, mm/memory.c is responsible for allocating pages, but it does not have information about PC value... Does anyone know where can I find this PC value and use it in memory.c file?

Was it helpful?

Solution

Making my comment into an answer.

What you're looking for is not the current PC (that changes all the time), but the PC of the instruction triggering the page fault. To understand where that is stored and how it can be retrieved, let's dig a little bit deeper.

When an exception (trap or interrupt) occurs in x86, the CPU will do the following:

  • use the vector (trap number / interrupt number - this is HW-implicit and/or configurable through programming the interrupt controller - yes, you could make a network interrupt trigger a pagefault, technically ...) as index into the Interrupt Descriptor Table (IDT)
  • it validates the data structure stored there (a so-called gate descriptor)
  • if not valid ... raise a #GP fault (General Protection [ error ]); since that in itself is an exception ... if the gate for that is invalid as well ... #DF (Double Fault) ... rinse repeat ... if invalid - Triple Fault (which resets the CPU hard).
  • if valid, the gate will specify both the target context (via a code segment) and within that, the handler address. In laymans words, this says "go into the following privilege level and call this handler" (by making the target %cs the kernel one, and the handler some low-level interrupt entry function).
  • if actioning this involves a privilege switch, the CPU changes to the target privilege level, and the stack pointer is switched.
  • the CPU writes interrupt return information onto that stack (note the next #DF opportunity here ... happens if this fails, due to a corrupted kernel stack pointer, or a stack overflow into unmapped memory). The information written contains:
    1. code segment at time of the fault (originating "context")
    2. stack pointer active at time of the fault (i.e. user stack), it stack was switched
    3. flags register
    4. fault address / PC (not for all types of traps, but definitely for page faults)
  • only after all this has happened, the actual interrupt vector handler function is called. From here on, software - kernel code takes over:
    1. in assembler code, the remainder of the general-purpose registers and other "contextual" information necessary is saved - into the exception frame, and then a stack suitable for calling C code is constructed.
    2. a C function is called with struct ptregs* as argument - that's the exception frame, register state saved by trap entry (partially by HW/the CPU itself, partially by the entry stub code). This is what actually used to handle the trap/exception/interrupt.

When returning from the trap / interrupt, the x86 iret instruction is used to unwind the four/five words pushed onto the kernel stack by the CPU in order to resume / return.

This way, every exception-entry in the kernel is given the same data structure, struct ptregs * - which, as said, for most traps/interrupts, amongst other information, contains the program counter / instruction pointer stating where the fault happened. struct pt_regs.ip is the field you'll need to look at.

For page faults in particular, see do_page_fault() and check where / how this is used.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top