From 058af0b4b8e4f6dbe389a72cf60325ea59c3249f Mon Sep 17 00:00:00 2001 From: ElectronixTM Date: Fri, 10 Oct 2025 00:20:58 +0300 Subject: [PATCH] =?UTF-8?q?feat[OS/win4]:=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BB=20=D1=8D=D1=82=D1=83=20=D0=B5=D0=B1**=D1=83=D1=8E=20?= =?UTF-8?q?=D0=BB=D0=B0=D0=B1=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OSs/lab-virt-win/CMakeLists.txt | 11 ++ OSs/lab-virt-win/README.md | 35 +++++ OSs/lab-virt-win/main.c | 222 ++++++++++++++++++++++++++++ OSs/lab-virt-win/simasm.py | 101 +++++++++++++ OSs/lab-virt-win/test_prograsm.sasm | 4 + OSs/lab-virt-win/util.py | 20 +++ OSs/lab-virt-win/vm.bin | Bin 0 -> 120 bytes 7 files changed, 393 insertions(+) create mode 100644 OSs/lab-virt-win/CMakeLists.txt create mode 100644 OSs/lab-virt-win/README.md create mode 100644 OSs/lab-virt-win/main.c create mode 100644 OSs/lab-virt-win/simasm.py create mode 100644 OSs/lab-virt-win/test_prograsm.sasm create mode 100644 OSs/lab-virt-win/util.py create mode 100644 OSs/lab-virt-win/vm.bin diff --git a/OSs/lab-virt-win/CMakeLists.txt b/OSs/lab-virt-win/CMakeLists.txt new file mode 100644 index 0000000..7f5fc79 --- /dev/null +++ b/OSs/lab-virt-win/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.30) + +# Set the project name +project( + lab4_win + LANGUAGES C + VERSION 0.0.1 + DESCRIPTION "Лаба на тему виртуальной памяти" +) + +add_executable(out main.c) diff --git a/OSs/lab-virt-win/README.md b/OSs/lab-virt-win/README.md new file mode 100644 index 0000000..5b91f93 --- /dev/null +++ b/OSs/lab-virt-win/README.md @@ -0,0 +1,35 @@ +# Виртуальная память + +Прошу обратить внимание на файлики report.txt и vm.bin. report.txt - место, куда будут сгружаться отчеты потока-монитора, vm.bin - файл, где находится программа для потока-симулятора. Подробнее про его команды можно почитать в методичке. Также прикладывается скрипт на питоне для генерации программ, его описание приложу, когда напишу + +# Как запускать + +Лаба требует файлов report.txt и vm.bin, и как вы их создадите в общем-то не важно. vm.bin я создавал через SIMASM. report создастся сам. Компилируете лабу любым нормальным для вас способом, она в терминальчик выдаст порядок своих действий. Там 2 потока, один делает вид, что работает с памятью и исполняет команды из vm.bin. Он будет писать какую команду исполнил и успешно ли. Второй поток - монитор, он раз в какое-то время (можно отрегулировать в сорцах) пишет отчетики в report.txt. Там он пишет статистику по занятой памяти, страничному файлу и подобному. Для его более удобного чтения есть скрипт util.py. Он тоже написан за 5 минут, поэтому для него важно, чтобы файл назывался именно report.txt, она помимо свободных страниц выведет еще и процентовку и немного другой инфы, в общем читать это поудобнее будет. + +На выходе сейчас у вас должно получиться что запрашивается сколько-то памяти, потом пишется отчет, потом с памятью заигрывается, пишется новый отчет, потом память освобождается и пишется 3 отчет. на самом деле их будет 5 (все будут в одном файле), но это потому что с таймингами особо не угадаешь + +В общем-то о том, что происходит в рамках отчета и надо будет рассказать на лабе + +Касаемо кода сложно что-то хорошее сказать, только скажу, что не прям все я протестировал, так что если будете заигрывать с чем-то кроме аллокаций и освобождений, то там бог знает что выйдет + +# SIMASM + +Простой скрипт, фактически просто пачка регулярок, которые из человекочитаемого текста собирают бинарь, который надо по условию задачи + +Каждая команда состоит из 5 частей и заканчивается точкой с запятой. Не все команды используют все части, но так как писать нормальный парсер мне лень, а simasm был написан за 10 минут, чтобы я во время тестов по 10 раз байты руками не перекладывал, он требует все поля. Теперь по каждому полю отдельно: + +1. Поле, задающее минимальное время от начала процесса, которое должно пройти, прежде чем команда исполнится. Должно указываться в десятичных цифрах и может заканчиваться на 2 суффикса (ms - миллисекунды, s - секунды) +2. Поле, указывающее адрес региона, над которым будет производиться махинация. регион не должен быть слишком маленьким, потому что первые 64 КБ виртуальной памяти зарезервированы операционкой +3. Команда. Почти полностью соответствуют командам из методички: + - `exit` - выходит из программы, но фактически не используется + - `reserve_region` - резервирует какое-то количество памяти (указывается в 4 параметре), отдает страницы, но фактически еще память из системы не забирает. Чтобы ее забрать надо что-то со страницами поделать. Для этого есть `mess_region` + - `pass_block` - резервирует регион с `MEM_COMMIT`, не знаю, зачем это надо, но это единственное сходное в методичке что есть + - `non_save_block` - аллоцирует страницы, изменения на которых не пойдут на старничный файл + - `free_region` - освобождает занятые страницы + - `lock_block` - блокирует страницы и препятствует их попаданию в swap + - `unlock_block` - разблокирует страницы и разрешает им уходить в swap + - `mess_region` - выполняет тупые операции чтения или записи с блоком, чтобы ось его на самом деле выдала, а не просто сказала, что сделала это +4. Размер области или региона в памяти. Доступны суффиксы Gb - гигабайты, Mb - мегабайты, kb - килобайты +5. Параметр записи - что разрешается делать со страницами r - только читать, `rw` - читать и писать, `rwe` - читать, писать и исполнять, `re` - читать и исполнять, `e` - только исполнять + +если подать флаг `-f FILE` - будет читать из указанного файла команды, иначе будет читать из стандартного потока ввода, если подать `-o OUTPUT` - запишет бинарный вывод в файл, в противном случае выдаст хексы в стандартный вывод diff --git a/OSs/lab-virt-win/main.c b/OSs/lab-virt-win/main.c new file mode 100644 index 0000000..dab361b --- /dev/null +++ b/OSs/lab-virt-win/main.c @@ -0,0 +1,222 @@ +#include +#include +#include + +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; +} diff --git a/OSs/lab-virt-win/simasm.py b/OSs/lab-virt-win/simasm.py new file mode 100644 index 0000000..46994e4 --- /dev/null +++ b/OSs/lab-virt-win/simasm.py @@ -0,0 +1,101 @@ +#/usr/bin/python3 + +""" +Маленький скрипт для сборки бинарных файликов для потока-симулятора из +- человекочитаемого текста +""" + +import argparse +import sys +import struct +import re + +time_suffixes = { + "": 1, + "ms": 1, + "s": 1000, + } +size_suffiexes = { + "": 1, + "kb": 2 ** 10, + "Mb": 2 ** 20, + "Gb": 2 ** 30 + } + +operations = { + "exit": 0x00, + "reserve_region": 0x01, + "pass_block": 0x02, + "non_save_block": 0x03, + "free_region": 0x04, + "return_block": 0x05, + "lock_block": 0x06, + "unlock_block": 0x07, + "mess_region": 0x08 + } + +access = { + "page_noaccess": 0x01, + "page_readonly": 0x02, + "r": 0x02, + "page_readwrite": 0x04, + "rw": 0x04, + "page_execute": 0x10, + "e": 0x10, + "page_execute_read": 0x20, + "re": 0x20, + "page_execute_readwrite": 0x40, + "rwe": 0x40 + } + +def main(): + parser = argparse.ArgumentParser(prog="simasm") + parser.add_argument("--file", "-f", type=str, help="file with program") + parser.add_argument("--output", "-o", type=str, help="file to store program") + args = parser.parse_args() + + program = "" + if args.file: + with open(args.file, "r", encoding="utf-8") as f: + program = f.read() + else: + program = sys.stdin.read() + + program = re.sub("#.*$", "", program, flags=re.M) + program = " ".join(program.split()) + lines = list(filter(lambda s: s!="", program.split(";"))) + binary = bytearray() + for line in lines: + words = line.split() + if len(words) != 5: + print("wrong line") + sys.exit(1) + # timestamp + m = re.match(r"(\d+)(\w*)", words[0]) + assert m + time_offset = int(m.group(1)) * time_suffixes[m.group(2)] + + region_in = words[1] + region = 0 + if region_in.startswith("0x"): + region = int(region_in, 16) + else: + region = int(region_in) + + operation = operations[words[2]] + + m = re.match(r"(\d+)(\w*)", words[3]) + assert m + size = int(m.group(1)) * size_suffiexes[m.group(2)] + + pg_access = access[words[4]] + + binary += struct.pack("QQQQQ", time_offset, operation, region, size, pg_access) + + if args.output: + with open(args.output, "wb") as f: + f.write(binary) + else: + print(binary.hex()) + +if __name__ == "__main__": + main() diff --git a/OSs/lab-virt-win/test_prograsm.sasm b/OSs/lab-virt-win/test_prograsm.sasm new file mode 100644 index 0000000..2840961 --- /dev/null +++ b/OSs/lab-virt-win/test_prograsm.sasm @@ -0,0 +1,4 @@ +# time | region | operation | size | access +1000ms 0x010000 reserve_region 1Gb rw; +3000ms 0x010000 mess_region 1Gb rw; +3000ms 0x010000 return_block 1Gb rw; diff --git a/OSs/lab-virt-win/util.py b/OSs/lab-virt-win/util.py new file mode 100644 index 0000000..5673932 --- /dev/null +++ b/OSs/lab-virt-win/util.py @@ -0,0 +1,20 @@ +#/usr/bin/python3 +# чтобы удобнее было посмотреть разницу + +import re + +with open("report.txt", 'r') as f: + lines = f.readlines() + +while len(lines) > 0: + for line in lines[1:4]: + line = line.strip() + m = re.match(r"([\w ]+): (\d+)/(\d+)", line) + assert m + name = m.group(1) + total = int(m.group(2)) + avail = int(m.group(3)) + print(f"{name}: {total}/{avail} ({avail/total*100:.2f}%, " + f"delta: {total - avail})") + print() + lines = lines[7:] diff --git a/OSs/lab-virt-win/vm.bin b/OSs/lab-virt-win/vm.bin new file mode 100644 index 0000000000000000000000000000000000000000..49c480684285792654be7fce210310454c054e1a GIT binary patch literal 120 mcmaFC%m4l}77zghJGdb<2ZREW_|>rzPzM0_`2$Y? literal 0 HcmV?d00001