klauspost / cpuid

CPU feature identification for Go
MIT License
1.01k stars 125 forks source link

Possible SCE check issue #113

Closed fpelliccioni closed 1 year ago

fpelliccioni commented 1 year ago

Reference code:

https://github.com/klauspost/cpuid/blob/master/cpuid.go#L996

According to the System V Application Binary Interface - AMD64 Architecture Processor Supplement, section 3.1.1:

Any program can expect that an AMD64 processor implements the baseline features mentioned in table 3.1. Most feature names correspond to CPUID bits, as described in the processor manual. Exceptions are OSFXSR and SCE, which are controlled by bits in the %cr4 register and the IA32_EFER MSR.

I understand that the presence of SCE must be checked using the MSR register

(You can generate the PDF mentioned above from https://gitlab.com/x86-psABIs/x86-64-ABI)

klauspost commented 1 year ago

@fpelliccioni I am not expert on this, but I expect it is set via MSR (by OS) and cpuid reads back this value, similar to OSXSAVE.

fpelliccioni commented 1 year ago

@klauspost do you have a pointer to a document that says SCE have to be taken from EDX[11] ?

klauspost commented 1 year ago

https://www.amd.com/system/files/TechDocs/25481.pdf page 13

fpelliccioni commented 1 year ago

Maybe I am confused but the document you mentioned says

SysEnterSysExit: SYSENTER and SYSEXIT instructions. See “SYSENTER”, “SYSEXIT“ in APM3.

... and according to the Micro-Architecture Levels "spec" the example instruction of SCE is syscall.

syscall is described in page 21 in the doc. you sent.

fpelliccioni commented 1 year ago

This other document also agrees:

https://docs.microsoft.com/es-es/cpp/intrinsics/cpuid-cpuidex?view=msvc-170

(look for syscall)

klauspost commented 1 year ago

Ah, ok, so you are saying a different flag needs to be checked.

klauspost commented 1 year ago

@fpelliccioni Are you able to find anything to confirm if "SCE" is referring to

A) SYSCALL and SYSRET B) SYSENTER and SYSEXIT C) both?

klauspost commented 1 year ago

ok, even more digging. This seems to imply A)

https://github.com/torvalds/linux/blob/68e77ffbfd06ae3ef8f2abf1c3b971383c866983/tools/arch/x86/include/asm/msr-index.h#L26

Though little to no information.

fpelliccioni commented 1 year ago

@klauspost

As per my understanding it is related to A) SYSCALL and SYSRET. Here is what I have found:

CPUID Fn8000_0001_EDX[11]

SysCallSysRet: SYSCALL and SYSRET instructions. See “SYSCALL” and “SYSRET” in APM3.

System-Call Extension (SCE) Bit. Bit 0, read/write. Setting this bit to 1 enables the SYSCALL and SYSRET instructions. Application software can use these instructions for low-latency system calls and returns in a non-segmented (flat) address space. See Section 6.1 “Fast System Call and Return,” on page 170 for additional information.

fpelliccioni commented 1 year ago

@klauspost

So on the one hand I think this code ...

_, _, c, d := cpuid(1)
fs.setIf((d&(1<<11)) != 0, SCE)

should actually be

_, _, c, d := cpuid(0x80000001)
fs.setIf((d&(1<<11)) != 0, SCE)

On the other hand, I am confused about the behavior of the EFER register

klauspost commented 1 year ago

See #115 - I replaced it by two other flags. For microarch I test with SYSCALL.

I doubt anyone is using it, but if they are they need to review their code.

fpelliccioni commented 1 year ago

I usually check GCC x86 march flags and... it is nothing related to it:

https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gcc/x86-Options.html#x86-Options

klauspost commented 1 year ago

The last possibility, the syscall instruction, pretty much allows for the same functionality as the sysenter instruction. The existence of both is due to the fact that one (systenter) was introduced by Intel while the other (syscall) was introduced by AMD.

FWIW. Since AMD design AMD64, it seems like syscall became the "winner", and why there is two.