Теперь я получаю ошибку страницы, что означает, что я обращаюсь к недопустимому адресу. Скорее всего, это связано с дизайном ядра более высокой половины, которому я решил следовать. Но я не мог понять, где это приводит к ошибке страницы. Вот мое ядро.С++
#include "types.h"
#include "gdt.h"
#include "stdio.h"
#include "serial.h"
#include "mem.h"
#include "idt.h"
#include "timer.h"
#include "isr.h"
#include "kbd.h"
#include "mouse.h"
#include "irq.h"
#include "string.h"
#include "terminal.h"
#include "multiboot.h"
#include "pmm.h"
#include "heap.h"
//Call all class constructor
//for global objects before
//calling the kernel
typedef void (*constructor)();
extern "C" constructor start_ctors;
extern "C" constructor end_ctors;
extern "C" void callConstructors()
{
for(constructor* i = &start_ctors; i != &end_ctors; i++)
(*i)();
}
extern "C" void kernelMain(uint32_t kernel_virtual_end,
uint32_t kernel_physical_end,
uint32_t placeholder,
uint32_t kernel_physical_start, uint32_t kernel_virtual_start,
multiboot_info_t *multiboot_structure,uint32_t magicnumber
)
{
cls();
printf("******KERNEL INFO********\n");
printf("KERNEL START VIRTUAL 0x%x\n" , kernel_virtual_start);
printf("KERNEL START PHYSICAL 0x%x\n" , kernel_physical_start);
printf("KERNEL END VIRTUAL 0x%x\n" , kernel_virtual_end);
printf("KERNEL END PHYSICAL 0x%x\n" , kernel_physical_end);
printf("MAGIC 0x%x\n" , magicnumber);
printf("*************************");
// printf("********RAM INFO*********\n");
//
//
// printf("Memory Upper : %d \n", multiboot_structure->mem_upper);
// printf("Memory Lower : %d \n", multiboot_structure->mem_lower);
//
// printf("*************************\n");
gdt gt;
IDT idt;
ISR isr;
IRQ irq;
SerialPort sp;
isr.install_isrs();
irq.install_irqs();
Timer timer;
timer.install_timer();
KBD kbd;
kbd.install_kbd_driver();
MOUSE mouse;
mouse.install_mouse_driver();
__asm__ __volatile__ ("sti");
PhyiscalMemoryManager pmm(multiboot_structure);
KHEAP kheap;
char *ptr;
Heap heap((&kheap));
heap.k_addBlock(&kheap, (0x100000+0xC0000000), (0x100000+0xC0000000));
//ptr = (char*)heap.k_malloc(&kheap, 256);
//heap.k_free(&kheap, ptr);
while(1);
err:
while(1);
}
Хорошо, вы можете видеть, что я прокомментировал последние строки. k_malloc() - это то, что вызывает весь хаос. по какой-то причине это malloc's() ниже 0xC0100000 , что является минимальным размером, который мы можем использовать для ядра, потому что мы используем виртуальные адреса, а 1 МБ - это материал, связанный с Grub. Говоря, что вот моя куча.С++:
#include "heap.h"
int Heap::k_addBlock(KHEAPLCAB *heap, uintptr_t addr, uint32_t size)
{
KHEAPBLOCKLCAB *hb;
KHEAPHDRLCAB *hdr;
hb = (KHEAPBLOCKLCAB*)addr;
hb->size = size;
hb->used = 0;
hb->next = heap->fblock;
heap->fblock = hb;
hdr = (KHEAPHDRLCAB*)&hb[1];
hdr->flagsize = hb->size - (sizeof(KHEAPBLOCKLCAB) + 32);
++heap->bcnt;
hb->lastdsize = 0;
hb->lastdhdr = 0;
return 1;
}
/*
Look behind and forward to see if we can merge back into some chunks.
*/
void Heap::k_free(KHEAPLCAB *heap, void *ptr)
{
KHEAPHDRLCAB *hdr, *phdr, *nhdr;
KHEAPBLOCKLCAB *hb;
uint32_t sz;
uint8_t fg;
hdr = (KHEAPHDRLCAB*)ptr;
hdr[-1].flagsize &= ~0x80000000;
phdr = 0;
/* find the block we are located in */
for (hb = heap->fblock; hb; hb = hb->next)
{
if (((uintptr_t)ptr > (uintptr_t)hb) && ((uintptr_t)ptr < (uintptr_t)hb + hb->size))
{
hdr = (KHEAPHDRLCAB*)((uintptr_t)ptr - sizeof(KHEAPHDRLCAB));
hdr->flagsize &= ~0x80000000;
hb->used -= hdr->flagsize;
if (hdr->prevsize)
{
phdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr - (sizeof(KHEAPHDRLCAB) + hdr->prevsize));
}
else
{
phdr = 0;
}
/* get next header */
nhdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr[1] + hdr->flagsize);
if ((uintptr_t)nhdr >= ((uintptr_t)hb + hb->size))
{
nhdr = 0;
}
if (nhdr)
{
if (!(nhdr->flagsize & 0x80000000))
{
/* combine with it */
hdr->flagsize += sizeof(KHEAPHDRLCAB) + nhdr->flagsize;
hb->used -= sizeof(KHEAPHDRLCAB);
/* set next header prevsize */
nhdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr[1] + hdr->flagsize);
nhdr->prevsize = hdr->flagsize;
}
}
if (phdr)
{
if (!(phdr->flagsize & 0x80000000))
{
phdr->flagsize += sizeof(KHEAPHDRLCAB) + hdr->flagsize;
hb->used -= sizeof(KHEAPHDRLCAB);
hdr = phdr;
nhdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr[1] + hdr->flagsize);
if ((uintptr_t)nhdr < (uintptr_t)hb + sizeof(KHEAPBLOCKLCAB) + hb->size)
{
nhdr->prevsize = hdr->flagsize;
}
}
}
/* optimization */
if (hdr->flagsize > hb->lastdsize)
{
hb->lastdsize = hdr->flagsize;
hb->lastdhdr = hdr;
}
return;
}
}
printf("uhoh ptr:%p\n", ptr);
for (hb = heap->fblock; hb; hb = hb->next) {
printf("lcab free looking at block:%p next:%p ptr:%p end:%p\n", hb, hb->next, ptr, (uintptr_t)hb + hb->size);
if (((uintptr_t)ptr > (uintptr_t)hb)) {
printf("above\n");
if (((uintptr_t)ptr < ((uintptr_t)hb + hb->size))) {
printf("found\n");
}
}
}
for (;;);
/* uhoh.. this should not happen.. */
return;
}
/*
This will allocate a chunk of memory by the specified size, and if
no memory chunk can be found it will return zero.
*/
void* Heap::k_malloc(KHEAPLCAB *heap, uint32_t size)
{
KHEAPBLOCKLCAB *hb;
KHEAPHDRLCAB *hdr, *_hdr, *phdr;
uint32_t sz;
uint8_t fg;
uint32_t checks;
uint32_t bc;
checks = 0;
bc =0;
for (hb = heap->fblock; hb; hb = hb->next) {
if ((hb->size - hb->used) >= (size + sizeof(KHEAPHDRLCAB))) {
++bc;
hdr = (KHEAPHDRLCAB*)&hb[1];
phdr = 0;
while ((uintptr_t)hdr < ((uintptr_t)hb + hb->size)) {
++checks;
fg = hdr->flagsize >> 31;
sz = hdr->flagsize & 0x7fffffff;
if (!fg)
{
if (sz >= size)
{
if (sz > (size + sizeof(KHEAPHDRLCAB) + 16))
{
_hdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr[1] + size);
_hdr->flagsize = sz - (size + sizeof(KHEAPHDRLCAB));
_hdr->prevsize = size;
hdr->flagsize = 0x80000000 | size;
hb->used += sizeof(KHEAPHDRLCAB);
}
else
{
hdr->flagsize |= 0x80000000;
}
hb->used += size;
return &hdr[1];
}
}
phdr = hdr;
hdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr[1] + sz);
}
}
}
return 0;
}
Heap::Heap(KHEAPLCAB *heap)
{
heap->fblock = 0;
heap->bcnt = 0;
}
Heap::~Heap()
{
}
Я думаю, что проблема с malloc(), потому что, когда я это комментирую, все работает нормально. Я получаю доступ к недопустимому адресу в этой функции:
void* Heap::k_malloc(KHEAPLCAB *heap, uint32_t size)
{
KHEAPBLOCKLCAB *hb;
KHEAPHDRLCAB *hdr, *_hdr, *phdr;
uint32_t sz;
uint8_t fg;
uint32_t checks;
uint32_t bc;
checks = 0;
bc =0;
for (hb = heap->fblock; hb; hb = hb->next) {
if ((hb->size - hb->used) >= (size + sizeof(KHEAPHDRLCAB))) {
++bc;
hdr = (KHEAPHDRLCAB*)&hb[1];
phdr = 0;
while ((uintptr_t)hdr < ((uintptr_t)hb + hb->size)) {
++checks;
fg = hdr->flagsize >> 31;
sz = hdr->flagsize & 0x7fffffff;
if (!fg)
{
if (sz >= size)
{
if (sz > (size + sizeof(KHEAPHDRLCAB) + 16))
{
_hdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr[1] + size);
_hdr->flagsize = sz - (size + sizeof(KHEAPHDRLCAB));
_hdr->prevsize = size;
hdr->flagsize = 0x80000000 | size;
hb->used += sizeof(KHEAPHDRLCAB);
}
else
{
hdr->flagsize |= 0x80000000;
}
hb->used += size;
return &hdr[1];
}
}
phdr = hdr;
hdr = (KHEAPHDRLCAB*)((uintptr_t)&hdr[1] + sz);
}
}
}
return 0;
}
. Помощь будет оценена по достоинству. Вот мой полный исходный код в Github: https://github.com/amanuel2/OS_MIRROR
heap.k_addBlock(&kheap, (0x100000+0xC0000000), (0x100000+0xC0000000));
Я не уверен, какой диапазон адресов вы надеетесь выделить как свободный. Не уверен, почему вы добавили 0xC0000000 к длине, и действительно ли вы хотите добавить 0xC0000000 к базовому адресу? Созданы ли для этой памяти записи каталога страниц и таблицы страниц? В нынешнем видеheap.k_addBlock(&kheap, (0x100000+0xC0000000), (0x100000+0xC0000000));
, похоже, добавляет свободный блок, идущий от 0xC0100000, с длиной0xC0100000
, что предполагает, что вы выходите за пределы 4 ГБ? - person Michael Petch   schedule 23.08.2016+0xC0000000
.. это приведет к ошибке страницы в k_addBlock() .. и я имел в видуheap.k_addBlock(&kheap, (0x0 + 0xC0000000), (0x300000+0xC0000000));
: github.com/amanuel2/OS_Mirror/blob/master/kernel.c%2B%2B#L89 . жаль, что это был несчастный случай. Что я хочу сделать, так это добавить блок размером 3 МБ и выделить для этого блока 256 байт. В основном куча. весь код кучи взят отсюда, поэтому я могу протестировать перед реализацией: wiki.osdev.org/User :Pancakes/EntryBasedHeapImplementation - person amanuel2   schedule 23.08.2016(0x300000+0xC010CB00)
во второй параметр. Эта функция addblock принимает базовый указатель и ДЛИНУ (не конечный адрес). Вы не должны добавлять к нему0xC010CB00
. Если вы хотите добавить свободный блок памяти в кучу, начиная с 0xC010CB00 длиной 0x300000, вы должны использовать что-то вродеheap.k_addBlock(&kheap, 0xC010CB00, 0x300000);
. Этот код предполагает, что в память уже были добавлены записи подкачки. - person Michael Petch   schedule 24.08.2016extern "C" uint64_t BootPageDirectory[1024];
, все в порядке? - person amanuel2   schedule 24.08.2016extern "C" uint32_t BootPageDirectory[1024]
. Каждая запись в каталоге Bootpage имеет длину 4 байта (32 бита). - person Michael Petch   schedule 24.08.2016k_addblock
с базой 0xC0400000 и длиной 0x400000, поскольку они теперь сопоставлены. Тогда вы сможете позвонитьmalloc
. Я действительно считаю, что вы должны были запустить свою ОС без подкачки, пока вы действительно не поняли концепцию. - person Michael Petch   schedule 24.08.2016k_addblock
. Предполагая, что код, который вы скопировали, действительно работает, вы сможете вызватьmalloc
после того, как будут выполнены две описанные выше вещи. - person Michael Petch   schedule 24.08.2016invalidate_page_vm
для аннулирования страницы, начинающейся с заданного адреса виртуальной памяти. Это необходимо, когда вы вносите изменения в кэш TLB. Я также добавил код для отображения, описанного выше, и привел несколько примеров объявления области памяти для кучи с помощьюk_addblock
. Код, кажется, работает здесь. - person Michael Petch   schedule 24.08.2016%x
. Вы действительно должны решить их. - person Michael Petch   schedule 24.08.2016BootPageDirectory[769]=0x400083;
сопоставляет физический адрес 0x400083 с виртуальным адресом 0xC0400000. я знаю, что 83 означает, что биты 7,1 и 2 были установлены, но я нигде не вижу виртуального адреса. А также я вижу, что когда я распечатываюBootPageDirectory[768]
в виде десятичного числа, я получаю227
. Все остальные равны 0 (поскольку мы обнулили первую директорию в boot.asm). Это почему? В основном я спрашиваю, что такого особенного в 768-й странице? Это означает, что ядро находится на 768-й странице и максимальное пространство, которое оно может занять, составляет всего 4 МБ? - person amanuel2   schedule 24.08.2016heap.k_addBlock(&kheap, 0xC0200000, 0x300000);
. Он начинается с адреса 0xC0200000, который уже находится в строках ядра, потому что, опять же, если вы ответите утвердительно на то, что размер ядра всегда равен 4 МБ, тогда его виртуальный адрес будет 0xC0000000-0xC0400000. а также есть комментарий, который говоритThis heap runs from 0xC0200000 to C04FFFFF - 3MB
. Я вообще не понимаю, где это происходит :/ - person amanuel2   schedule 24.08.2016heap.k_addBlock(&kheap, 0xC0200000, 0x300000);
устанавливает кучу размером 3 МБ, работающую с начального адреса 0xC0200000. Вы заметите, что в одном примере в закомментированном коде я показал способ использованияkernel_virtual_end
для поиска базового адреса для кучи. - person Michael Petch   schedule 24.08.2016heap.k_addBlock(&kheap, (kernel_virtual_end+4095)&0xFFFFF000, 0x300000);
, который используетkernel_virtual_end
для размещения кучи после ядра. Я просто решил выровнять его по границе 4 КБ после ядра. По мере роста вашего ядра куча будет появляться после него без перекрытия. - person Michael Petch   schedule 24.08.2016kernelMain
, между 0xC0000000 и 0xC03FFFFF была активна только одна страница размером 4 МБ, на которой находилась старшая половина ядра. - person Michael Petch   schedule 24.08.2016boot.asm
, но по мере работы ЦП и использования каталога страниц биты могут измениться. В не-PAE, использующих страницы размером 4 МБ, значение 227 содержит флаги, но также представляет сопоставляемый физический адрес. Установите все младшие 22 бита равными нулю, и возвращаемое значение будет физическим адресом в памяти, на который сопоставляется запись. В случае 0x000000E3 (десятичное число 227) обнуление младших 22 бит дает нам значение 0x00000000. Это физический адрес кадра размером 4 МБ, отображаемого в этой записи (768). - person Michael Petch   schedule 24.08.20160xC03FFFFF
? Я имею в виду, что если вы добавите 4 МБ к его базовому адресу, он станет0xC0400000
, а не0xC03FFFFF
. Я понимаю почти все об этой частиk_addBlock(&kheap, (kernel_virtual_end+4095)0xFFFFF000, 0x300000);
, вы в основном пытаетесь динамически выделить ее, используя переменные вместо 0xC000000, которая является статической. Но я не понимаю, почему надстройка 4095, каждая страница имеет разделение по 4 КБ? А что с0xFFFFF000
. - person amanuel2   schedule 24.08.20160xC03FFFFF
на единицу меньше, чем0xC0400000
(4MB-1). Это всего 4 МБ, если учесть тот факт, что байты начали считаться с 0xC0000000. Рассмотрим массив, определенный в C какchar arr[10]
. Счет начинается с 0 (не 1). Таким образом, байты идут от 0 до 9 для 10-байтового массива. Байт с индексом 10 в индексации на основе 0 является 11-м элементом (один за краем массива). То же самое относится к последнему байту на странице 0xC03FFFFF, а не на один выше по адресу 0xC0400000. - person Michael Petch   schedule 24.08.2016k_addBlock(&kheap, kernel_virtual_end, 0x300000);
. Я выбрал выравнивание 4 КБ в основном потому, что в вашем скрипте компоновщика вы использовали выравнивание 4 КБ для других разделов, таких как текст, данные, bss. Я решил использовать такое выравнивание для кучи. - person Michael Petch   schedule 24.08.2016kernel_virtual_end
указывает на адрес, следующий за последним использованным байтом вашего ядра. Добавляя 4095, а затем добавляя 0xFFFFF000, вы округляете до следующей границы 4096, ЕСЛИkernel_virtual_end
еще не было на 4 КБ с самого начала. Если бы вы добавили 4096 (вместо 4095), аkernel_virtual_end
уже было на границе 4 КБ, вы бы потратили 4 КБ впустую. - person Michael Petch   schedule 24.08.2016#osdev
на Freenode. Вы можете получить к нему доступ через веб-клиент IRC: kiwiirc.com/client/irc. freenode.net/#osdev - person Michael Petch   schedule 24.08.2016__asm__ __volatile__ ("sti");
, которая разрешает прерывания. Вы делаете это после того, как был установлен обработчик прерывания мыши, но я заметил, что один из ваших коммитов git удалил его. - person Michael Petch   schedule 24.08.2016printf
(с использованием%d
) и вашitoa
написаны таким образом, что вывод подписывается при использовании%d
. Поэтому, если установлен старший бит (бит знака) и вы используете%d
, результатом будет отрицательное значение. Кажется, здесь так и есть. Вы можете записать длину в шестнадцатеричном формате, используя%x
. В качестве альтернативы вам придется улучшить свойprintf
, чтобы обрабатывать печать значений без знака.Printf
обычно имеет%u
для печати целых чисел без знака. - person Michael Petch   schedule 24.08.2016printf("%d MB Of Usable RAM" , bytes_usable/1000000);
Вместо того, чтобы делить на 1000000, вы должны делить на 1048676. - person Michael Petch   schedule 24.08.2016printf
с%d
делает то, что ожидается, просто не слишком полезно печатать число без знака как число со знаком. Реализация%u
вprintf
решит эту проблему. Тогда вы бы использовали%u
вместо%d
. - person Michael Petch   schedule 25.08.2016%u
, это в var_arg, я сделаюva_arg(arg,uint32_t);
вместоva_art(ard,int)
- person amanuel2   schedule 25.08.2016printf("%d MB Of Usable RAM" , bytes_usable/1048676);
. Есть опечатка. Это должно быть 1048576, а не 1048676. Вы также можете написать это какprintf("%d MB Of Usable RAM" , bytes_usable/(1024*1024));
- person Michael Petch   schedule 25.08.2016heap.k_addBlock(&kheap, (kernel_virtual_end+4095)&0xFFFFF000, 0x300000);
, это дает мне ошибку страницы. Если я удалю & 0xFFFFF000 ИЛИ +4095 , все станет хорошо. Или, если я удалю оба, все станет хорошо. Но если все три из них включены, я получаю эту странную ошибку страницы: /. Не замечал этого до сих пор, так как я использовал qemu, который я загрузил из двоичного файла ... когда я попробовал его на vb, он выдал мне ошибку страницы при загрузке из ISO - person amanuel2   schedule 25.08.2016pmm.map_physical_virtual(0x400000,0xC0400000);
я бы сделалpmm.map_physical_virtual(0x800000,0xC0800000);
, если бы я хотел, чтобы 8 МБ было зарезервировано для моей кучи, которая была бы от 0xC0000000-0x800000,0xC0800000? Если это да, то в основном то, что делает эта функция, устанавливает, где мы можем выделить нашу кучу для ... всей коробки ... Я нарисую диаграмму и просто скажите мне, есть ли у меня правильная иллюстрация или нет - person amanuel2   schedule 25.08.2016k_addblock
добавьтеLib::Mem::memset((void *)addr, 0, size);
, чтобы сначала обнулить память. Тогда попробуйте это сheap.k_addBlock(&kheap, (kernel_virtual_end+4095)&0xFFFFF000, 0x300000);
. Части области памяти сразу заkernel_virtual_end
не используются вашим ядром, но могут быть ненулевыми из-за загруженной туда отладочной информации и другой информации GCC. - person Michael Petch   schedule 25.08.2016pmm.map_physical_virtual(0x400000,0xC0400000);
... Пытался объяснить это здесь: stackoverflow.com/questions/39152751/ - person amanuel2   schedule 25.08.2016