История изменений
Исправление firkax, (текущая версия) :
Вот примерная (условная и упрощённая, но суть передаёт) схема работы страничной виртуальной памяти на 32-битной системе с PAE:
struct process {
ptr64 pages[1048576];
};
// этот массив хранится напрямую в физической памяти, на самом деле он конечно выделяется динамически а не хранится для всех возможных pid-ов
struct process processes[MAX_PID];
ptr32 p = 0x12345678;
x = *(char*)p;
p64 = processes[getpid()].pages[p >> 12]; // p>>12 это 0x12345-й элемент массива
// ^ чтобы тут не лазить каждый раз в память, в проце есть специальный кеш, это не тот кеш который L1 L2 L3 а отдельный; он свой у каждого ядра и у каждого гипертрединг-потока, сбрасывается ядром при переключении процесса, либо в нём сбрасываются ядром отдельные записи когда надо подправить таблицу pages[]
if(p64 & FLAG_MISSING) {
raise_page_fault_exception(); // вызов ОС - страницы нет в физ. памяти, назад уже не вернёмся
// ОС либо сегфолтнет процесс, если страницы этой вобще нет и не предполагалсь,
// либо аллоцирует в физ. памяти новую пустую страницу, если это первое обращение к блоку после юзерспейсной аллокации (оверкоммит)
// либо прочитает её из свапа, если она в свапе
// после этого ОС вернёт управление процессу на то же место чтоб он попробовал прочитать ещё раз заново
}
if(!(p64 & FLAG_ALLOW_USERSPACE)) {
raise_page_fault_exception(); // вызов ОС - процесс хочет нарушить права доступа, назад уже не вернёмся
}
p64 = (p64 & 0xFFFFFF000) | (p & 0x0FFF);
// ^ в младших 12 битах p64 - флаги, старшие 28 бит зарезервированы
// младшие биты берём из p, там 0x678
x = *(char*)p64;
Кстати, если PAE выключен, то отличие будет только такое: таблица pages станет 32-битной, и p64 тоже станет 32-битным (назовём p32), вся логика остаётся как была.
Исправление firkax, :
Вот примерная (условная и упрощённая, но суть передаёт) схема работы страничной виртуальной памяти на 32-битной системе с PAE:
struct process {
ptr64 pages[1048576];
};
// этот массив хранится напрямую в физической памяти, на самом деле он конечно выделяется динамически а не хранится для всех возможных pid-ов
struct process processes[MAX_PID];
ptr32 p = 0x12345678;
x = *(char*)p;
p64 = processes[getpid()].pages[p >> 12]; // p>>12 это 0x12345-й элемент массива
// ^ чтобы тут не лазить каждый раз в память, в проце есть специальный кеш, это не тот кеш который L1 L2 L3 а отдельный; он свой у каждого ядра и у каждого гипертрединг-потока, сбрасывается ядром при переключении процесса, либо в нём сбрасываются ядром отдельные записи когда надо подправить таблицу pages[]
if(p64 & FLAG_MISSING) {
raise_page_fault_exception(); // вызов ОС - страницы нет в физ. памяти, назад уже не вернёмся
// ОС либо сегфолтнет процесс, если страницы этой вобще нет и не предполагалсь,
// либо аллоцирует в физ. памяти новую пустую страницу, если это первое обращение к блоку после юзерспейсной аллокации (оверкоммит)
// либо прочитает её из свапа, если она в свапе
// после этого ОС вернёт управление процессу на то же место чтоб он попробовал прочитать ещё раз заново
}
if(!(p64 & FLAG_ALLOW_USERSPACE)) {
raise_page_fault_exception(); // вызов ОС - процесс хочет нарушить права доступа, назад уже не вернёмся
}
p64 = (p64 & 0xFFFFFF000) | (p & 0x0FFF);
// ^ в младших 12 битах p64 - флаги, старшие 28 бит зарезервированы
// младшие биты берём из p, там 0x678
x = *(char*)p64;
Исходная версия firkax, :
Вот примерная (условная и упрощённая, но суть передаёт) схема работы страничной виртуальной памяти на 32-битной системе с PAE:
struct process {
ptr64 pages[1048576];
};
// этот массив хранится напрямую в физической памяти, на самом деле он конечно выделяется динамически а не хранится для всех возможных pid-ов
struct process processes[MAX_PID];
ptr32 p = 0x12345678;
x = *(char*)p;
p64 = processes[getpid()].pages[p >> 12]; // p>>12 это 0x12345-й элемент массива
// ^ чтобы тут не лазить каждый раз в память, в проце есть специальный кеш, это не тот кеш который L1 L2 L3 а отдельный; он свой у каждого ядра и у каждого гипертрединг-потока, сбрасывается ядром при переключении процесса, либо в нём сбрасываются ядром отдельные записи когда надо подправить таблицу pages[]
if(p64 & FLAG_MISSING) {
raise_page_fault_exception(); // вызов ОС - страницы нет в физ. памяти, назад уже не вернёмся
}
if(!(p64 & FLAG_ALLOW_USERSPACE)) {
raise_page_fault_exception(); // вызов ОС - процесс хочет нарушить права доступа, назад уже не вернёмся
}
p64 = (p64 & 0xFFFFFF000) | (p & 0x0FFF);
// ^ в младших 12 битах p64 - флаги, старшие 28 бит зарезервированы
// младшие биты берём из p, там 0x678
x = *(char*)p64;