#include <stdio.h>
#include <unistd.h>
#include <stropts.h>
#include <strings.h>
#include <signal.h>
#include <setjmp.h>
#include <libgen.h>
#include <sys/vmm.h>
#include <sys/vmm_dev.h>
#include <sys/mman.h>
#include <vmmapi.h>
#include "common.h"
#define LOWER_SZ (256 * 4096)
#define UPPER_SZ LOWER_SZ
#define TOTAL_SZ (LOWER_SZ + UPPER_SZ)
#define LOWER_OFF 0
#define UPPER_OFF LOWER_SZ
enum test_memsegs {
MSEG_LOW = 0,
MSEG_HIGH = 1,
};
static sigjmp_buf segv_env;
void
sigsegv_handler(int sig)
{
siglongjmp(segv_env, 1);
}
int
main(int argc, char *argv[])
{
struct vmctx *ctx;
int res, fd;
void *guest_mem;
const char *suite_name = basename(argv[0]);
ctx = create_test_vm(suite_name);
if (ctx == NULL) {
perror("could open test VM");
return (1);
}
fd = vm_get_device_fd(ctx);
res = alloc_memseg(ctx, MSEG_LOW, LOWER_SZ, "mseg_low");
if (res != 0) {
perror("could not alloc low memseg");
goto bail;
}
res = alloc_memseg(ctx, MSEG_HIGH, UPPER_SZ, "mseg_high");
if (res != 0) {
perror("could not alloc high memseg");
goto bail;
}
res = vm_mmap_memseg(ctx, LOWER_OFF, MSEG_LOW, 0, LOWER_SZ, PROT_ALL);
if (res != 0) {
perror("could not map low memseg");
goto bail;
}
res = vm_mmap_memseg(ctx, UPPER_OFF, MSEG_HIGH, 0, UPPER_SZ, PROT_ALL);
if (res != 0) {
perror("could not map high memseg");
goto bail;
}
guest_mem = mmap(NULL, TOTAL_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
if (guest_mem == MAP_FAILED) {
perror("could not mmap guest memory");
goto bail;
}
for (uintptr_t gpa = 0; gpa < TOTAL_SZ; gpa++) {
uint8_t *ptr = guest_mem + gpa;
*ptr = 0xff;
}
res = vm_munmap_memseg(ctx, LOWER_OFF, LOWER_SZ);
if (guest_mem == NULL) {
perror("could not unmap lower memseg");
goto bail;
}
for (uintptr_t gpa = UPPER_OFF; gpa < UPPER_OFF + UPPER_SZ; gpa++) {
uint8_t *ptr = guest_mem + gpa;
if (*ptr != 0xff) {
(void) printf("invalid mem contents at GPA %lx: %x\n",
gpa, *ptr);
goto bail;
}
*ptr = 0xee;
}
struct sigaction sa = {
.sa_handler = sigsegv_handler,
};
struct sigaction old_sa;
res = sigaction(SIGSEGV, &sa, &old_sa);
if (res != 0) {
perror("could not prep signal handling for bad access");
goto bail;
}
if (sigsetjmp(segv_env, 1) == 0) {
volatile uint8_t *ptr = guest_mem;
uint8_t tmp = *ptr;
(void) printf("access to %p (%x) should have failed\n", tmp);
goto bail;
}
res = munmap(guest_mem, TOTAL_SZ);
if (res != 0) {
perror("could not unmap lower memseg");
goto bail;
}
guest_mem = mmap(NULL, TOTAL_SZ, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
if (guest_mem == MAP_FAILED) {
perror("could not re-mmap guest memory");
goto bail;
}
if (sigsetjmp(segv_env, 1) == 0) {
volatile uint8_t *ptr = guest_mem + UPPER_OFF;
uint8_t tmp = *ptr;
if (tmp != 0xee) {
(void) printf("unexpected value at %p (%x)\n", ptr,
tmp);
goto bail;
}
res = sigaction(SIGSEGV, &old_sa, NULL);
if (res != 0) {
perror("could not restore SIGSEGV handler");
goto bail;
}
} else {
(void) printf("unexpected fault in upper mapping\n");
goto bail;
}
res = vm_munmap_memseg(ctx, UPPER_OFF, UPPER_SZ);
if (guest_mem == NULL) {
perror("could not unmap upper memseg");
goto bail;
}
(void) printf("%s\tPASS\n", suite_name);
vm_destroy(ctx);
return (0);
bail:
vm_destroy(ctx);
return (1);
}