Files
AwesomePolytech/OSs/lab-virt-win/main.c
2025-10-10 00:20:58 +03:00

223 lines
5.5 KiB
C

#include <stdio.h>
#include <windows.h>
#include <stdint.h>
enum {
THREAD_SIM,
THREAD_MONITOR,
THREAD_NUM
};
HANDLE threads[THREAD_NUM];
int threads_params[THREAD_NUM];
SYSTEM_INFO sys_info;
DWORD WINAPI thread_sim(LPVOID param);
DWORD WINAPI thread_monitor(LPVOID param);
#define SIMOP_EXIT 0x00
#define SIMOP_RESERVE 0x01
#define SIMOP_PASS_BLOCK 0x02
#define SIMOP_NON_SAVE 0x03
#define SIMOP_FREE_REG 0x04
#define SIMOP_RETURN_BLOCK 0x05
#define SIMOP_LOCK_BLOCK 0x06
#define SIMOP_UNLOCK_BLOCK 0x07
#define SIMOP_MESS_REGION 0x08
#define SLEEP_MILLIS 2000
// Некоторые поля увелчены для выравнивания
struct sim_cmd{
uint64_t millis_offset;
uint64_t op;
uint64_t region;
uint64_t reg_sz;
uint64_t access;
};
int main()
{
int ret = 0;
GetSystemInfo(&sys_info);
threads[THREAD_SIM] = CreateThread(NULL, 0, thread_sim,
&threads_params[THREAD_SIM], 0, NULL);
if (!threads[THREAD_SIM]) {
printf("Couldn't create simulator\n");
return EXIT_FAILURE;
}
threads[THREAD_MONITOR] = CreateThread(NULL, 0, thread_monitor,
&threads_params[THREAD_MONITOR], 0, NULL);
if (!threads[THREAD_MONITOR]) {
printf("Couldn't create monitor\n");
ret = EXIT_FAILURE;
goto close_sim_thread;
}
printf("waiting...\n");
DWORD status = WaitForMultipleObjects(THREAD_NUM, threads, TRUE, INFINITE);
printf("done waiting (%lu).\n", GetLastError());
close_monitor_thread:
CloseHandle(&threads[THREAD_MONITOR]);
close_sim_thread:
CloseHandle(&threads[THREAD_SIM]);
return ret;
}
int read_sim_cmd(FILE *src, struct sim_cmd *dest)
{
const size_t cmd_sz = sizeof(struct sim_cmd);
size_t bytes_read = fread(dest, sizeof(char), cmd_sz, src);
if (bytes_read != cmd_sz) return -ENODATA;
return 0;
}
int write_sim_cmd(FILE *src, struct sim_cmd *dest)
{
const size_t cmd_sz = sizeof(struct sim_cmd);
size_t bytes_written = fwrite(dest, sizeof(char), cmd_sz, src);
if (bytes_written != cmd_sz) return -ENODATA;
return 0;
}
#define QUIT_NUMBER 'q'
static uint64_t last_clock = 0;
static int do_cmd(struct sim_cmd *cmd)
{
if (cmd->millis_offset > last_clock) Sleep(cmd->millis_offset - last_clock);
switch (cmd->op) {
case SIMOP_RESERVE:
if (!VirtualAlloc((LPVOID)cmd->region, cmd->reg_sz,
MEM_RESERVE | MEM_COMMIT, cmd->access)) {
return -ENOMEM;
}
break;
case SIMOP_FREE_REG:
if (VirtualFree((LPVOID)cmd->region, cmd->reg_sz, MEM_DECOMMIT) == 0) {
return -EFAULT;
}
break;
case SIMOP_LOCK_BLOCK:
if (VirtualLock((LPVOID)cmd->region, cmd->reg_sz) == 0) {
return -ENOLCK;
}
break;
case SIMOP_UNLOCK_BLOCK:
if(VirtualUnlock((LPVOID)cmd->region, cmd->reg_sz) == 0) {
return -ENOLCK;
}
break;
case SIMOP_PASS_BLOCK:
if (!VirtualAlloc((LPVOID)cmd->region, cmd->reg_sz, MEM_COMMIT, cmd->access)) {
return -ENOMEM;
}
break;
case SIMOP_NON_SAVE:
if (!VirtualAlloc((LPVOID)cmd->region, cmd->reg_sz,
MEM_RESERVE | MEM_RESET, cmd->access)) {
return -ENOMEM;
}
case SIMOP_RETURN_BLOCK:
if (!VirtualFree((LPVOID)cmd->region, 0, MEM_RELEASE)) {
printf("error was %lu\n", GetLastError());
return -EFAULT;
}
break;
case SIMOP_MESS_REGION:
printf("messing with pages...\n");
if (cmd->access == PAGE_READWRITE || cmd->access == PAGE_EXECUTE_READWRITE) {
printf("memsetting\n");
memset((LPVOID)cmd->region, 0x77, cmd->reg_sz);
} else if (cmd->access == PAGE_READONLY) {
#define BUFF_SIZE 256
printf("reading to buffer...\n");
char buff[BUFF_SIZE] = {0};
for (size_t i = 0; i < cmd->reg_sz; i += BUFF_SIZE) {
memcpy(buff, &((char*)(cmd->region))[i], BUFF_SIZE);
}
}
break;
case SIMOP_EXIT:
return QUIT_NUMBER;
default:
break;
}
return 0;
}
DWORD WINAPI thread_sim(LPVOID param)
{
DWORD status = 0;
FILE *program = fopen("vm.bin", "r");
if (!program) {
printf("can't open file vm.bin\n");
status = EFAULT;
goto exit;
}
static struct sim_cmd cmd;
while(read_sim_cmd(program, &cmd) == 0) {
int ret = do_cmd(&cmd);
printf("command (%02llx) done with code (%d)\n", cmd.op, ret);
status = abs(ret);
if (ret < 0) {
break;
} else if (ret == QUIT_NUMBER) {
status = 0;
break;
}
}
close_program:
fclose(program);
exit:
printf("return from vm\n");
return status;
}
int write_report(FILE *f)
{
MEMORYSTATUS ms;
GlobalMemoryStatus(&ms);
size_t bytes_written = fprintf(
f,
"Memory status (Total/Avail):\n"
"Physical: %zu/%zu\n"
"Virtual: %zu/%zu\n"
"Page file: %zu/%zu\n"
"Page size (bytes): %lu\n"
"Granularity: %lu\n\n",
ms.dwTotalPhys, ms.dwAvailPhys,
ms.dwTotalVirtual, ms.dwAvailVirtual,
ms.dwTotalPageFile, ms.dwAvailPageFile,
sys_info.dwPageSize,
sys_info.dwAllocationGranularity
);
if (bytes_written < 1) {
return -EFAULT;
}
return 0;
}
DWORD WINAPI thread_monitor(LPVOID param)
{
DWORD status = 0;
FILE *report = fopen("report.txt", "w");
if (!report) {
printf("fault\n");
status = EFAULT;
goto close_report;
}
for (size_t i = 0; i < 5; i++) {
Sleep(SLEEP_MILLIS);
printf("report written with status: %d\n", write_report(report));
}
close_report:
fclose(report);
return status;
}