Как я могу реализовать пейджинг и найти адрес физической памяти, зная виртуальный адрес - PullRequest
4 голосов
/ 13 января 2020

Я хочу реализовать инициализацию подкачки. Ссылаясь на некоторые ссылки на osdev wiki: https://wiki.osdev.org/Paging, https://wiki.osdev.org/Setting_Up_Paging, моя собственная версия сильно отличается. Потому что, когда мы смотрим на каталог страницы , они говорят, что 12 бит для флага, а остальные для адреса таблицы страниц, поэтому я попробовал что-то вроде этого:

void init_paging() {
    unsigned int i = 0;

    unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000)));

    for (i = 0; i < 0x400; i++) __PAGE_DIRECTORY__[i] = PAGE_PRESENT(0) | PAGE_READ_WRITE;

    for (i = 0; i < 0x400; i++) __FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;

    __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__  << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;

    _EnablingPaging_();
} 

эта функция помогает мне узнать физический адрес, зная виртуальный адрес:

void *get_phyaddr(void *virtualaddr) {
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;

unsigned long *pd = (unsigned long *)__PAGE_DIRECTORY__[pdindex];

unsigned long *pt = (unsigned long *)pd[ptindex];

return (void *)(pt + ((unsigned int)virtualaddr & 0xFFF));

}

Я не в том направлении?

Или все же то же самое?

Ответы [ 2 ]

4 голосов
/ 13 января 2020

Предполагается, что вы пытаетесь идентифицировать первые 4 Мбайт физического адресного пространства:

a) для unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000))); это локальная переменная (например, вероятно, помещена в стек); и оно не сохранится после возврата функции (например, используемое ею пространство стека будет перезаписано другими функциями позже), что приведет к повреждению таблицы страниц. Это вряд ли закончится хорошо.

b) Для __FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE; вы сдвигаете i дважды, один раз с * 0x1000 (что совпадает с << 12) и снова с << 12. Это слишком много, и это должно быть больше похоже на __FIRST_PAGE_TABLE__[i] = (i << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;.

c). Для __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__ << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE; адрес уже является адресом (а не "номером страницы", который необходимо сместить ), так что это должно быть больше похоже на __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__) | PAGE_PRESENT(1) | PAGE_READ_WRITE;.

Помимо этого; Я бы очень предпочел лучшее использование типов. В частности, вы, вероятно, должны привыкнуть использовать uint32_t (или uint64_t, или typedef своего) для физических адресов, чтобы не случайно случайно перепутать виртуальный адрес с физическим адресом (и убедиться, что компилятор жалуется на неправильный тип при совершении ошибки); потому что (хотя это не очень важно сейчас, потому что вы отображаете личность), это станет важным "скоро". Я также рекомендовал бы использовать uint32_t для записей таблицы страниц и записей каталога страниц, потому что они должны быть 32-битными, а не «какого бы размера не считал компилятор int» (обратите внимание, что это разница в том, как вы думаете о коде, который важнее того, что на самом деле делает компилятор, или о том, что int в любом случае 32-битный).

0 голосов
/ 17 января 2020

Когда мы просим страницу, но страницы не было, у нас есть pageFault Interrupt. Поэтому, чтобы избежать этого, мы можем проверить, есть ли страница, иначе я могу выбрать 0x0:

physaddr_t *get_phyaddr(void *virtualaddr) {
    uint32_t pdindex = (uint32_t)virtualaddr >> 22;
    uint32_t ptindex = (uint32_t)virtualaddr >> 12 & 0x03FF;

    uint32_t *pd, *pt, ptable;

    if ((page_directory[pdindex] & 0x3) == 0x3) {
        pd = (uint32_t *)(page_directory[pdindex] & 0xFFFFF000);

        if ((pd[ptindex] & 0x3) == 0x3) {
            ptable = pd[ptindex] & 0xFFFFF000;

            pt = (uint32_t *)ptable;

            return (physaddr_t *)(pt + ((uint32_t)(virtualaddr)&0xFFF));
        } else
            return 0x0;
    } else
        return 0x0;
}
...