The simplest answer may be: do not intercept page fault, which is possible only if you’re using nested paging. However, in this case, my guess is that the Exitintinfo field was nonzero when this failure happened, and that’s the value you should be injecting. Be careful of an infinite loop: the #PF will happen again if it’s really a guest #PF. This situation can happen, for example, if the guest’s stack or IDT were paged out by the guest when an exception or interrupt arrived (though most OSes do not page out their system state). And if you’re not intercepting the #PF, the problem is solved. If you must intercept #PF, and if Exitintinfo is nonzero, then you may need to emulate the stack push yourself.
If this is shadow paging, then you must handle the #PF in the hypervisor and decide whether this is really a #PF that the guest caused, or if it’s a #PF induced by the hypervisor’s shadow paging algorithm. You might want to look at Xen or KVM’s implementation to compare what they’re doing.
Actually, I am using nested paging but I want to intercept page fault for the same reason that I want to intercept software interrupt: to intercept guest system calls.
Since intercepting software interrupts is very expensive, it may be better to intentionally create some other event, such as #PF, when the guest make a system call and intercept it instead.
The difference in guest behavior that I mentioned happened in the booting phase (I am using tty Linux as the guest OS).
When Linux boot up, it try to test whether the processor honours WP protection bit. And it does so by creating a #PF on purpose. This is the only #PF that happened. I checked and exitintinfo is 0.
In both case (with or with #PF interception) the result of that test is OK (as you can see in the screen shots below).
But after a while, the difference manifests. With the #PF interception enabled version, Linux complains BIOS handoff failed, USB HC takeover fail... and then keep looping forever at PNP PS/2 Controller ...
while the version without #PF interception gets past that point and boots just fine :
Note that I am running everything inside AMD SVM.
If you want to implement your own BIOS outside the guest, a better solution would be to put a stub BIOS into the guest, and fill each BIOS call with a VMMCALL instruction. Then you’ll get a quick, well-known call to the hypervisor on each guest BIOS call. You’re definitely better off not intercepting #PF, since those occur very frequently.
I’d also suggest you look at how KVM or Xen emulate BIOS.
(This suggestion applies to your other post as well, so I've duplicated this response there.)