>All of the monitor structures are mapped into an address
>space spanned by one page table (a 4MByte span).
>This is done for convenience so we can migrate the such structures
>within the address space efficiently and easily, if the guest ever
>requires the use of a linear address within that range.
>Likely we have placed the monitor in a portion of the address space
>in which the guest doesn't use.
Plus the code to switch between host and guest, you called it 'nexus'.
>We have also allocated memory for the guest's physical memory,
>though for now let's say we have not yet mapped any of it into
>the monitor's address space.
And stored pointers to allocated page frames in a table. This table
we can use for a third level, software implemented address translation,
useful for virtualizing page tables.
>The guest is to begin execution at a given address in
>it's linear address space. As the guest begins executing at this
>address which is not yet mapped into the monitor, the monitor will
>receive a page fault. This is given that we mark all unused address
>space with an entry in the page tables such that a page fault occurs.
Hm, some month ago a asked a question in the same direction: do we need
a own pager in monitor or not? The reaction was that all paging stuff
should do the guest and after a while of thinking I also agreed that this
is a good point. Why do you suggest a pager? For now, we give the
guest all the memory we allocated for it just at start point and spare
performance decreasing page faults. One argument could be: save memory.
But if we give the guest "8 megs of RAM" the guest will try to use this
8 megs. I prefer the method discussed some weeks ago: withdraw pages
dynamically.
And for virtualizing page tables I prefer the method I mailed to you,
Kevin.
>As the guest makes a mode transition (for example into
>protected mode), or attempts to change a value of a register
>which points to these structures (for example the LGDT instruction)
>the monitor will receive an exception, since these instructions
>are all protected from being executed in ring3. (We can
>also virtualize arbitrary instructions with the SBE logic)
>The monitor uses the exception as a chance to emulate the
>offending instruction. At this point, we can see where the
>new value in the register points. By examing the data
>at that address in the guest address space, we can build
>'virtualized' values in the corresponding monitor structures.
>As we know the size of a given data structure, we can also
>determine the range of guest address space occupied, and thus
>the pages which are spanned. Since the monitor needs to be
>aware of any read or write accesses to such regions to virtualize
>the guest GDT, IDT, etc, it must mark these pages as inaccessible
>by the guest running at ring3.
Yes, largly so it's implemented now. We have two data sets: one
(not really used) for guest, another (really used) for monitor.
Guest may set it's own GDT. With IDT I'm not sure - perhaps we
don't let set guest it's IDT and always reflect interrupts to
host?
I've also tryed to simulate segment selector cache. For simple
cases this works fine, I didn't perform advanced tests yet (this
tests will be trying to boot real kernels like fiasco and linux).
"To do" is unmapping guest's GDT from its address space and
branch to the right page fault handling (GDT emulation).
I'll do it while working on other paging stuff. (see also below)
>As page faults are a real part of normal OS protection mechanisms
>and part of a paging strategy, they will occur normally in
>an OS. Since our virtualization strategies rely heavily on the
>paging protections, our page fault handler needs to discern
>between valid page faults and ones generated for virtualization
>purposes. Fortunately, this is not difficult, since we have access
>to the guest page tables and our monitor data. We can simply
>examine the guest page tables to determine if a page fault should
>have been generated naturally by the guest. If this is the case,
>we have to effect (emulate) a page fault for the guest.
Agree. I've to implement splitting into several page fault handling
routines - one for *DT emulation (see above), one for page table
virtualization, one for "real page faults in the guest" and so
on.
>For situations where the guest OS gropes physical memory
>to determine the amount of memory installed, we must handle
>this in such a way that the guest determines that memory
>beyond the amount which we have allocated, does not exist.
There are two situations: guest activated paging unit or not.
Without paging, the guests linear address is its physical address.
An access to an address higher than the range we allocated for
guest should result in a page fault delivered to the guest.
We simply have to compare faulting address with number of bytes
we allocated as guest's physical memory.
With activated paging, the monitor has to parse guest's page
table - just as above with the "real page fault in the guest".
I don't see a real difference.
>The problem with this approach is that it involves heavy
>overhead to handle the execution of such guest code.
Oh, we can hope that a well programmed guest tryes not often
to access non-existent physical memory. ;) And even when
guest applications do so, in most cases they were closed
down and this take a lot longer than our emulation code.
Hm, does anybody know what happens in a real computer while
accessing non-existent memory? Page fault or vanishing access?
jens