2024-11-11 14:57:09 +01:00
# include <stdio.h>
# include <stdint.h>
# include <stdbool.h>
# include <sys/stat.h>
# include <errno.h>
# include <string.h>
2024-11-17 19:10:22 +01:00
# define eprintf(...) fprintf(stderr, __VA_ARGS__)
# define OUTPUT_DIR " / run / qemu-server"
# define OUTPUT_FILENAME "host-hw-capabilities.json"
# define OUTPUT_PATH OUTPUT_DIR " / " OUTPUT_FILENAME
2024-11-17 18:51:14 +01:00
typedef struct {
bool sev_support ;
bool sev_es_support ;
bool sev_snp_support ;
uint8_t cbitpos ;
uint8_t reduced_phys_bits ;
} cpu_caps_t ;
void query_cpu_capabilities ( cpu_caps_t * res ) {
2024-11-11 14:57:09 +01:00
uint32_t eax , ebx , ecx , edx ;
// query Encrypted Memory Capabilities, see:
// https://en.wikipedia.org/wiki/CPUID#EAX=8000001Fh:_Encrypted_Memory_Capabilities
uint32_t query_function = 0x8000001F ;
asm volatile ( " cpuid "
2024-11-17 18:43:15 +01:00
: " =a " ( eax ) , " =b " ( ebx ) , " =c " ( ecx ) , " =d " ( edx )
: " 0 " ( query_function )
2024-11-11 14:57:09 +01:00
) ;
2024-11-17 18:51:14 +01:00
res - > sev_support = ( eax & ( 1 < < 1 ) ) ! = 0 ;
res - > sev_es_support = ( eax & ( 1 < < 3 ) ) ! = 0 ;
res - > sev_snp_support = ( eax & ( 1 < < 4 ) ) ! = 0 ;
2024-11-11 14:57:09 +01:00
2024-11-17 18:51:14 +01:00
res - > cbitpos = ebx & 0x3f ;
res - > reduced_phys_bits = ( ebx > > 6 ) & 0x3f ;
}
2024-11-17 19:12:39 +01:00
int prepare_output_directory ( ) {
2024-11-11 14:57:09 +01:00
// Check that the directory exists and create it if it does not.
struct stat statbuf ;
2024-11-17 19:10:22 +01:00
int ret = stat ( OUTPUT_DIR , & statbuf ) ;
2024-11-11 14:57:09 +01:00
if ( ret = = 0 ) {
2024-11-17 18:43:15 +01:00
if ( ! S_ISDIR ( statbuf . st_mode ) ) {
2024-11-17 19:10:22 +01:00
eprintf ( " Path ' " OUTPUT_DIR " ' already exists but is not a directory. \n " ) ;
2024-11-17 19:12:39 +01:00
return 0 ;
2024-11-17 18:43:15 +01:00
}
2024-11-11 14:57:09 +01:00
} else if ( errno = = ENOENT ) {
2024-11-17 19:10:22 +01:00
if ( mkdir ( OUTPUT_DIR , 0755 ) ! = 0 ) {
eprintf ( " Error creating directory ' " OUTPUT_DIR " ': %s \n " , strerror ( errno ) ) ;
2024-11-17 19:12:39 +01:00
return 0 ;
2024-11-17 18:43:15 +01:00
}
2024-11-11 14:57:09 +01:00
} else {
2024-11-17 19:10:22 +01:00
eprintf ( " Error checking path ' " OUTPUT_DIR " ': %s \n " , strerror ( errno ) ) ;
2024-11-17 19:12:39 +01:00
return 0 ;
}
return 1 ;
}
int main ( ) {
if ( ! prepare_output_directory ( ) ) {
2024-11-17 18:43:15 +01:00
return 1 ;
2024-11-11 14:57:09 +01:00
}
2024-11-17 19:12:39 +01:00
cpu_caps_t caps ;
query_cpu_capabilities ( & caps ) ;
2024-11-17 19:10:22 +01:00
FILE * file = fopen ( OUTPUT_PATH , " w " ) ;
2024-11-11 14:57:09 +01:00
if ( file = = NULL ) {
2024-11-17 19:10:22 +01:00
eprintf ( " Error opening to file ' " OUTPUT_PATH " ': %s \n " , strerror ( errno ) ) ;
2024-11-17 18:43:15 +01:00
return 1 ;
2024-11-11 14:57:09 +01:00
}
2024-11-17 19:12:39 +01:00
int ret = fprintf ( file ,
2024-11-17 18:43:15 +01:00
" { "
" \" amd-sev \" : { "
" \" cbitpos \" : %u, "
" \" reduced-phys-bits \" : %u, "
" \" sev-support \" : %s, "
" \" sev-support-es \" : %s, "
" \" sev-support-snp \" : %s "
" } "
" } \n " ,
2024-11-17 18:51:14 +01:00
caps . cbitpos ,
caps . reduced_phys_bits ,
caps . sev_support ? " true " : " false " ,
caps . sev_es_support ? " true " : " false " ,
caps . sev_snp_support ? " true " : " false "
2024-11-11 14:57:09 +01:00
) ;
if ( ret < 0 ) {
2024-11-17 19:10:22 +01:00
eprintf ( " Error writing to file ' " OUTPUT_PATH " ': %s \n " , strerror ( errno ) ) ;
2024-11-11 14:57:09 +01:00
}
ret = fclose ( file ) ;
if ( ret ! = 0 ) {
2024-11-17 19:10:22 +01:00
eprintf ( " Error closing file ' " OUTPUT_PATH " ': %s \n " , strerror ( errno ) ) ;
2024-11-11 14:57:09 +01:00
}
return 0 ;
}