Re: [RFC PATCH 01/19] OvmfPkg: Reserve the Secrets and Cpuid page for the SEV-SNP guest


Lendacky, Thomas
 

On 4/8/21 1:24 AM, Xu, Min M wrote:
On Wednesday, April 7, 2021 11:03 PM, Laszlo wrote:
On 04/07/21 02:44, James Bottomley wrote:
On Wed, 2021-04-07 at 00:21 +0000, Xu, Min M wrote:
Hi, Laszlo

For Intel TDX supported guest, all processors start in 32-bit
protected mode, while for Non-Td guest, it starts in 16-bit real
mode. To make the ResetVector work on both Td-guest and Non-Td guest,
ResetVector are updated as below:
------------------------------------------------------------------
ALIGN 16
resetVector:
;
; Reset Vector
;
; This is where the processor will begin execution
;
nop
nop
smsw ax
test al, 1
jnz EarlyBspPmEntry
jmp EarlyBspInitReal16
Well, then use the rel8 jump like the compiler would in this situation:

smsw ax
test al, 1
jz 1f
jmp EarlyBspPmEntry
1:
jmp EarlyBspInitReal16

So now both entries can be 32k away.
The problem is that we need NASM to generate such *shared* entry code that
behaves correctly when executed in either 16-bit or 32-bit mode.

The rel8 near jumps ("short jumps") are like that -- for example, the
"74 cb" opcode decodes to the same "JZ rel8" in both modes.

But the rel16 ("non-short") near jumps turn into rel32 near jumps when
decoded in 32-bit mode. For example, "E9 cw" decodes to "JMP rel16" in 16-bit
mode, but it gets parsed as "E9 cd" (= "JMP rel32") in 32-bit mode.

So the idea is to add more BITS directives, for covering the non-short near
jumps themselves:
Yes this is the root cause. TDX requires the startup mode to be 32-bit
protected mode while the legacy VM startup mode is 16-bit real mode.
Add more BITS directives can work round this. I have tried it and it works.

So my initial solution is to use *jmp rel8* because it works in both 16-bit
and 32-bit mode. But *jmp rel8* depends on the distance which should
be less than 128 bytes. If more metadata is added in the ResetVector.asm
then we have to use the BITS solution.
To me, it sounds like the BITS solution should be the approach you use
from the start.

Thanks,
Tom



; instructions up to and including the rel8 JZ decode identically ;
between BITS 16 and BITS 32 BITS 16
smsw ax
test al, 1
jz Real

; the unconditional near jumps are mode-specific BITS 32
jmp near EarlyBspPmEntry
BITS 16
Real:
jmp near EarlyBspInitReal16

; --------------------

BITS 16
EarlyBspInitReal16:
nop

BITS 32
EarlyBspPmEntry:
nop
$ nasm -f bin jz.nasmb

Decoded (executed) in 16-bit mode:

$ ndisasm -b 16 -k 7,5 -k 0x10,1 jz
00000000 0F01E0 smsw ax
00000003 A801 test al,0x1
00000005 7405 jz 0xc ; taken
00000007 skipping 0x5 bytes
0000000C E90000 jmp word 0xf
0000000F 90 nop
00000010 skipping 0x1 bytes

Decoded (executed) in 32-bit mode:

$ ndisasm -b 32 -k 0xc,4 jz
00000000 0F01E0 smsw eax
00000003 A801 test al,0x1
00000005 7405 jz 0xc ; not taken
00000007 E904000000 jmp dword 0x10
0000000C skipping 0x4 bytes
00000010 90 nop


With the garbage *not* hidden:

$ ndisasm -b 16 -s 0xc jz

00000000 0F01E0 smsw ax
00000003 A801 test al,0x1
00000005 7405 jz 0xc ; taken
00000007 E90400 jmp word 0xe ; garbage
0000000A 0000 add [bx+si],al ; garbage
0000000C E90000 jmp word 0xf
0000000F 90 nop
00000010 90 nop ; garbage

$ ndisasm -b 32 -s 0x10 jz

00000000 0F01E0 smsw eax
00000003 A801 test al,0x1
00000005 7405 jz 0xc ; not taken
00000007 E904000000 jmp dword 0x10
0000000C E9 db 0xe9 ; garbage
0000000D 0000 add [eax],al ; garbage
0000000F 90 nop ; garbage
00000010 90 nop

Thanks
Laszlo




Join devel@edk2.groups.io to automatically receive all group messages.