> > > > So the (*) can actually access to the control page IIUC. > > > > Now if we change to map VA of relocate_kernel() to the original one, then (*) > > won't be able to access the control page. > > No, it still will be able to access control page. > > So we call relocate_kernel() in normal kernel text (within > __START_KERNEL_map). > > relocate_kernel() switches to identity mapping, VA is still the same. > > relocate_kernel() jumps to identity_mapped() in the control page: > > > /* > * get physical address of control page now > * this is impossible after page table switch > */ > movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 > > ... > > /* jump to identity mapped page */ > addq $(identity_mapped - relocate_kernel), %r8 > pushq %r8 > ANNOTATE_UNRET_SAFE > ret > > The ADDQ finds offset of identity_mapped() in the control page. > > identity_mapping() finds start of the control page from *relative* > position of relocate_page() to the current RIP in the control page: > > leaq relocate_kernel(%rip), %r8 > > It looks like this in my kernel binary: > > lea -0xfa(%rip),%r8 Ah I see. I missed the *relative* addressing. :-) > > What PA is mapped at the normal kernel text VA of relocate_kernel() makes > zero affect to the calculation. Yeah. > > Does it make sense? > Yes. Thanks for explanation. At later time: call swap_pages movq $virtual_mapped, %rax <---- (1) pushq %rax ANNOTATE_UNRET_SAFE ret <---- (2) (1) will load the VA which has __START_KERNEL_map to %rax, and after (2) the kernel will run at VA of the original relocate_kernel() which maps to the PA of the original relcoate_kernel(). But I think the memory page of the original relocate_kernel() won't get corrupted after returning from the second kernel, so should be safe to use?