Преобразование виртуального адреса в физический из многоуровневых таблиц страниц

Я пытаюсь преобразовать адрес виртуальной памяти в физический, но не могу заставить его работать. В настоящее время я выполняю операционную систему в качестве задания, и теперь мне нужно реализовать функцию printf для пользовательского режима, поэтому, когда вы вызываете системный вызов записи, система должна печатать содержимое массива в пользовательском режиме на последовательный порт (на данный момент ), и для этого мне нужно преобразовать адрес из виртуального в физический.

Вот мой код из обработчика системного вызова:

Pcb* pcb = getCR3(); // contains the page directory for usermode
setCR3(kernelPageDir); // set the CR3 register to the kernel page directory

uint32_t tableNum = (vAddr >> 22) & 0x3ffUL; // get the upper 10 bits
uint32_t pageIndex = (vAddr >> 12) & 0x3ffUL // get the middle 10 bits
uint32_t offset = vAddr & 0xfffUL; // get the 12 lower bits

uint32_t* topTable = pcb->pageDirectory[tableNum]; // Access the top level table
uint32_t lowTable = topTable[pageIndex]; // Entry to the 2nd table
uint32_t* addr = lowTable + offset; // Should be the physical address

serialPrintf("Structure: tableNum=%08x pageIndex=%08x  offset=%08x\n", tableNum, pageIndex, offset);
serialPrintf("Address: topTable=%08x lowTable=%08x addr=%08x\n",topTable, lowTable, addr);
serialPrintf("Char:%c", (char*)addr[0]);

Когда я запускаю код, он дает мне ошибку страницы при попытке получить доступ к его значению:

Structure: tableNum=00000020 pageIndex=00000048  offset=00000378
Address: topTable=00000000 lowTable=0015d000 addr=0015d378
Page fault! errcode=00000000 addr=0015d378

Вот часть из книги, которая объясняет структуру страниц:

Структура уровней таблицы страниц


person agenten    schedule 24.09.2018    source источник
comment
(Предполагая, что ваш другой код верен...) вы не можете использовать (т.е. разыменовывать) физический адрес непосредственно при доступе к памяти. Физический адрес используется только самим оборудованием. Весь код (даже код режима ядра) использует виртуальные адреса для доступа к памяти. Обойти это невозможно. Теперь, предполагая, что страница данных присутствует, доступ к фактическим данным будет выполняться с помощью *((char *)vAddr) (хотя на практике код ядра получает доступ к виртуальным адресам пользователей только через специальные функции, которые обеспечивают соблюдение ограничений адресации пользовательского режима, а ошибки страниц правильно обрабатываются и поэтому далее).   -  person Gil Hamilton    schedule 25.09.2018
comment
1. Как получить адрес pgd ядра? Он хранится в структуре init_mm. Надеюсь, ты бы позаботился об этом. 2. Поскольку это обработчик системных вызовов, я надеюсь, что этот код выполняется в пространстве ядра. 3. Вы не можете разыменовывать физические адреса напрямую в ядре. Вместо этого вам нужно выполнять kmap() при каждом обходе таблицы и использовать этот VA для обхода следующей записи таблицы. Прежде всего, я не вижу никакого принуждения к обходу таблицы страниц для вашего варианта использования. Вы можете напрямую использовать *((char *)vAddr) (приведите его к типу на основе аргумента, переданного в ваш собственный printf), чтобы напечатать значение.   -  person Subbu M    schedule 25.09.2018


Ответы (1)


Если вы заполните pte для последней (индекс 1023) записи в таблице второго уровня, на которую указывает последняя (индекс 1023) запись первого уровня, то:

0xfffff000 .. 0xfffffffc will by an alias of the first level table,

а также

0xffc00000 .. 0xffffffff will be an alias of the entire (sparse) page table.

Например:

int vtop(unsigned vaddr, unsigned *pa) {
    unsigned *pdtb = (unsigned *)0xfffff000;
    unsigned *pte = (unsigned *)0xffc00000;
    if (ptdb[vaddr>>20] & 1) {
         if (pte[vaddr>>12] & 1) {
              *pa = pte[vaddr>>12] &~0xfff;
              return 0;
         }
         return 2;
    }
    return 1;
}

Вы можете сделать это для любого индекса и настроить значения указателя, но если это становится более запутанным, и 0xffc/20 не подходит.

person mevets    schedule 27.11.2020