Page 1 of 1

Does QEMU support SSE out-of-the-box?

Posted: Sat Aug 24, 2024 7:53 am
by avcado
I was rewriting my ISR handler to dump the SIMD/SSE registers. I read on the x86 registers page that
XCR0 can only be accessed if bit 18 of CR4 is set to 1. XGETBV and XSETBV instructions are used to access XCR0.
So, I check if bit 18 of cr4 is enabled:

Code: Select all

uint32_t cr0 = 0;
asm ("movl %%cr4, %0;" : "=r" (cr4) ::);
if((cr4 & (1 << 18)) == 1){
   printf("XCR0 can be accessed.\n");
}
However, this does not print out "XCR0 can be accessed" there. I try and enable SSE via:
  • Checking if SSE is enable from CPUID
  • Enabling it (from what the OSDev wiki says)
This code is before the kernel is called. It looks like this:

Code: Select all

check_sse:
    mov $0x1, %eax
    cpuid
    test $1<<25, %edx
    jz .NoSSE
    ret

    .NoSSE:
        cli
    2:  hlt
        jmp 2b

enable_sse:
    # Check if SSE is supported
    call check_sse

    mov %cr0, %eax
    and $0xfffb, %ax
    or $0x2, %ax
    mov %eax, %cr0
    mov %cr4, %eax
    or $0x600, %eax
    mov %eax, %cr4
    ret

_start:
    mov $stack_top, %esp
    call enable_sse
    ...
Interestingly, when run with no flags, QEMU actually just halts, implying SSE is not supported (by default). I look at the qemu -cpu command, and I see:

Code: Select all

x86 base                  base CPU model type with no features enabled
x86 host                  processor with all supported host features 
x86 max                   Enables all features supported by the accelerator in the current host
So I run qemu via (since -cpu host wasn't allowed without KVM/HVF)

Code: Select all

qemu-system-i386 -enable-kvm -cpu max -cdrom myos.iso
And it still hangs! What's the deal? How do I test SSE in QEMU?

Re: Does QEMU support SSE out-of-the-box?

Posted: Sat Aug 24, 2024 5:59 pm
by Octocontrabass
avcado wrote: Sat Aug 24, 2024 7:53 amXCR0
XCR0 is part of XSAVE, not SSE.
avcado wrote: Sat Aug 24, 2024 7:53 amInterestingly, when run with no flags, QEMU actually just halts, implying SSE is not supported (by default).
The default "qemu32" CPU should support SSE. Have you used a debugger to check where it's halting?

Re: Does QEMU support SSE out-of-the-box?

Posted: Sat Aug 24, 2024 7:16 pm
by avcado
Octocontrabass wrote: Sat Aug 24, 2024 5:59 pm Have you used a debugger to check where it's halting?
Yes.

Code: Select all

(qemu) x/10i $eip-10
0x00200e50:  20 00                    andb     %al, (%eax)
0x00200e52:  e8 19 07 00 00           calll    0x201570
0x00200e57:  83 c4 10                 addl     $0x10, %esp
0x00200e5a:  eb fe                    jmp      0x200e5a
0x00200e5c:  89 45 08                 movl     %eax, 8(%ebp)
0x00200e5f:  e8 2a f4 ff ff           calll    0x20028e
0x00200e64:  83 ec 0c                 subl     $0xc, %esp
0x00200e67:  68 fa 21 20 00           pushl    $0x2021fa
0x00200e6c:  e8 ff 06 00 00           calll    0x201570
0x00200e71:  e8 32 f7 ff ff           calll    0x2005a8

(qemu) x/1i $eip
0x00200e5a:  eb fe                    jmp      0x200e5a

(qemu) info registers
CPU#0
EAX=00202300 EBX=00000800 ECX=0000010a EDX=00000010
ESI=00000000 EDI=00000000 EBP=00222b10 ESP=00222ae8
EIP=00200e5a EFL=00200006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000010b0 00000020
IDT=     00000000 00000000
CR0=00000013 CR2=00000000 CR3=00000000 CR4=00000600
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000
XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000
XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000
XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
Adding "int $3" to the top of the check_sse.NoSSE does not raise any v=03. Meaning, SSE is enabled for the CPU, like you mentioned.
Next, I wanted to see if check_sse actually does return, by adding int 3 like so:

Code: Select all

enable_sse:
	call check_sse
	int 3
This does raise a breakpoint exception. So it does infact return. Though I'm not entirely sure why it's halting. Everything seems to be running well. Nothing in my kmain has a "return", and I shouldn't even be able to return to the stub since I have

Code: Select all

for(;;) asm("hlt");
I guess I don't really need to check if the host supports SSE, since the "userbase" of my kernel needs to run it on any SSE compliant system -- thereby not requiring me to check for it.
Octocontrabass wrote: Sat Aug 24, 2024 5:59 pm XCR0 is part of XSAVE, not SSE
How can I access the value, if not XCR0, of some SSE register? Would something like this work?

Code: Select all

float xmm0 = 0;
__asm__("movss %0, %%xmm0" :"=r"(xmm0));
// ...

Re: Does QEMU support SSE out-of-the-box?

Posted: Sat Aug 24, 2024 10:58 pm
by Octocontrabass
avcado wrote: Sat Aug 24, 2024 7:16 pmHow can I access the value, if not XCR0, of some SSE register?
If you want to save and restore all of them so your interrupt handlers can use them, FXSAVE/FXRSTOR. Those actually have a separate CPUID bit, but you don't need to check if you already know SSE is supported.

If you're just accessing single XMM registers, probably MOVUPS if you want the entire 128-bit register, or MOVSS if you only want the lower 32 bits.