Я хочу реализовать инициализацию подкачки. Ссылаясь на некоторые ссылки на вики osdev: 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));
}
Я не в том направлении?
Или все тот же?
Всего 1 ответ
Предполагая, что вы пытаетесь идентифицировать первые 4 Мбайт физического адресного пространства:
a) для unsigned int __FIRST_PAGE_TABLE__[0x400] __attribute__((aligned(0x1000)));
это локальная переменная (например, скорее всего, помещенная в стек); и оно не сохранится после возврата функции (например, используемое ею пространство стека будет перезаписано другими функциями позже), что приведет к повреждению таблицы страниц. Это вряд ли закончится хорошо.
б) Для __FIRST_PAGE_TABLE__[i] = ((i * 0x1000) << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
__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;
__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__ << 12) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
адрес уже является адресом (а не «номером страницы», который необходимо __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__) | PAGE_PRESENT(1) | PAGE_READ_WRITE;
), поэтому он должен быть похож на __PAGE_DIRECTORY__[0] = ((unsigned int)__FIRST_PAGE_TABLE__) | 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 битам).