Untitled

 avatar
unknown
c_cpp
a year ago
4.9 kB
6
Indexable
#include "VirtualMemory.h"
#include <sys/types.h>
#include <cmath>
#include <algorithm>
#include "PhysicalMemory.h"

uint64_t find_unused_frame(uint64_t virtual_page, uint64_t protected_frame, uint64_t current_path);
void dfs(uint64_t parent_address, word_t &max_frame, uint64_t &max_distance_frame, uint64_t &max_distance, int level,
         uint64_t virtual_page, uint64_t protected_frame, uint64_t &empty_frame, bool &found_empty, uint64_t current_path);
word_t handle_page_fault(int level, uint64_t &fault_address, uint64_t protected_frame, uint64_t virtual_address);

void clearFrame(uint64_t base_address) {
    for (uint64_t i = 0; i < PAGE_SIZE; i++) {
        PMwrite(base_address * PAGE_SIZE + i, 0);
    }
}

bool is_valid_address(uint64_t virtualAddress) {
    if ((virtualAddress > VIRTUAL_MEMORY_SIZE) || (TABLES_DEPTH > NUM_FRAMES)) {
        return false;
    }
    return true;
}

uint64_t find_unused_frame(uint64_t virtual_page, uint64_t protected_frame, uint64_t current_path) {
    word_t max_frame = 0;
    uint64_t max_distance_frame = 0;
    uint64_t max_distance = 0;
    uint64_t empty_frame = 0;
    bool found_empty = false;

    dfs(0, max_frame, max_distance_frame, max_distance, 0, virtual_page, protected_frame, empty_frame, found_empty, current_path);

    if (found_empty) {
        PMwrite(empty_frame, 0);
        return empty_frame;
    }

    if (max_frame + 1 < NUM_FRAMES) {
        return max_frame + 1;
    }

    PMevict(max_distance_frame, virtual_page);
    return max_distance_frame;
}

word_t handle_page_fault(int level, uint64_t &fault_address, uint64_t protected_frame, uint64_t virtual_address) {
    uint64_t new_frame = find_unused_frame(virtual_address / PAGE_SIZE, protected_frame, 0);

    if (level < TABLES_DEPTH - 1) {
        clearFrame(new_frame);
    } else {
        PMrestore(new_frame, virtual_address / PAGE_SIZE);
    }

    PMwrite(fault_address, new_frame);
    return new_frame;
}

uint64_t cyclic_distance(uint64_t page1, uint64_t page2) {
    return std::min(NUM_PAGES - std::abs(static_cast<int>(page1) - static_cast<int>(page2)), 
                    std::abs(static_cast<int>(page1) - static_cast<int>(page2)));
}

void dfs(uint64_t parent_address, word_t &max_frame, uint64_t &max_distance_frame, uint64_t &max_distance, int level,
         uint64_t virtual_page, uint64_t protected_frame, uint64_t &empty_frame, bool &found_empty, uint64_t current_path) {
    if (level == TABLES_DEPTH) {
        return;
    }

    for (uint64_t i = 0; i < PAGE_SIZE; i++) {
        word_t next_address;
        PMread(parent_address * PAGE_SIZE + i, &next_address);

        if (next_address != 0) {
            uint64_t cur_distance = cyclic_distance(next_address, virtual_page);
            if (cur_distance > max_distance) {
                max_distance_frame = next_address;
                max_distance = cur_distance;
            }
            if (next_address > max_frame) {
                max_frame = next_address;
            }
            if ((current_path & (1ULL << next_address)) == 0) {  // Check if the frame is not in the current path
                dfs(next_address, max_frame, max_distance_frame, max_distance, level + 1, virtual_page, protected_frame, empty_frame, found_empty, current_path | (1ULL << next_address));
            }
        } else if (!found_empty && parent_address != protected_frame && (current_path & (1ULL << parent_address)) == 0) {
            empty_frame = parent_address * PAGE_SIZE + i;
            found_empty = true;
        }
    }
}

void VMinitialize() {
    clearFrame(0);
}

uint64_t translate_address(uint64_t virtualAddress) {
    uint64_t cur_address = 0;
    uint64_t current_path = 1;  // Start with the root frame in the current path
    for (word_t level = 0; level < TABLES_DEPTH; level++) {
        uint64_t trans_level = (virtualAddress >> ((TABLES_DEPTH - level) * OFFSET_WIDTH)) & (PAGE_SIZE - 1);
        word_t next_address;
        PMread(cur_address * PAGE_SIZE + trans_level, &next_address);

        if (next_address == 0) {
            uint64_t base_address = cur_address * PAGE_SIZE + trans_level;
            next_address = handle_page_fault(level, base_address, cur_address, virtualAddress);
        }
        current_path |= (1ULL << next_address);  // Add the current frame to the path
        cur_address = next_address;
    }

    return cur_address * PAGE_SIZE + virtualAddress % PAGE_SIZE;
}

int VMread(uint64_t virtualAddress, word_t *value) {
    if (!is_valid_address(virtualAddress)) {
        return 0;
    }
    uint64_t address = translate_address(virtualAddress);
    PMread(address, value);
    return 1;
}

int VMwrite(uint64_t virtualAddress, word_t value) {
    if (!is_valid_address(virtualAddress)) {
        return 0;
    }
    uint64_t address = translate_address(virtualAddress);
    PMwrite(address, value);
    return 1;
}
Editor is loading...
Leave a Comment