Куча выдает ошибку страницы

Теперь я получаю ошибку страницы, что означает, что я обращаюсь к недопустимому адресу. Скорее всего, это связано с дизайном ядра более высокой половины, которому я решил следовать. Но я не мог понять, где это приводит к ошибке страницы. Вот мое ядро.С++

#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


person amanuel2    schedule 23.08.2016    source источник
comment
Я очень смущен. Какую область памяти вы ожидаете использовать 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
comment
@MichaelPetch Если я удалю +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
comment
Это произойдет потому, что вы уже сопоставили память с начальной таблицей страниц и каталогом, когда создавали старшую половину ядра. Вы знаете, что фактически указали этому коду перезаписать ваше ядро ​​как область кучи. Чего не хватает этому коду, так это добавления таблиц страниц и каталогов страниц, которые сопоставляют фрейм страницы с физическим адресом. Это почти похоже на то, что код, который у вас здесь, был написан для ОС без выгрузки страниц, которая отображала всю область 4 ГБ с помощью селектора данных. Вы включили пейджинг здесь, так что вы должны принять это во внимание.   -  person Michael Petch    schedule 23.08.2016
comment
Рассматривали ли вы возможность более простого запуска с ядром не старшей половины без подкачки? Возможно, вы перешли к этому без предварительного понимания пейджинга, таблиц страниц, каталогов страниц, фреймов страниц и т. д.   -  person Michael Petch    schedule 23.08.2016
comment
@MichaelPetch Я понимаю концепцию пейджинга, pt, pd и pf ... (на самом деле мне не нужно беспокоиться о pt из-за PAE). Этот код я не полностью понял   -  person amanuel2    schedule 23.08.2016
comment
@MichaelPetch Когда вы говорите перезаписать ядро, это потому, что я добавляю блок в 0xC000000 - 0xC030000, где ядро ​​хранится правильно? Но это не дало никакой ошибки, что странно. Хорошо, теперь знаю, что этого больше не должно происходить, потому что я делаю `heap.k_addBlock(&kheap, (0x0 + 0xC010CB00), (0x300000+0xC010CB00));`. А 0xC010CA00 — это конец моего ядра.   -  person amanuel2    schedule 24.08.2016
comment
Это не выдает ошибку, потому что именно вам нужно отслеживать, какая память используется для каких целей. Ошибки нет, потому что ЦП с радостью понимает, что в памяти выше 0xC0000000 уже выделено несколько страниц, затем вы записываете информацию о куче в эту область (потенциально перезаписывая ядро). Вам нужно выбрать область, которая еще не используется вашим ядро и добавьте записи подкачки для этой области памяти (и их привилегии доступа). Если вы не используете PAE, вам нужны как таблицы страниц, так и каталоги страниц. Если PAE включен, вам нужны и те, и другие, а также таблица указателей каталогов страниц.   -  person Michael Petch    schedule 24.08.2016
comment
Вдобавок ко всему, что я сказал о необходимости создавать записи подкачки, я до сих пор не знаю, почему вы добавляете (0x300000+0xC010CB00) во второй параметр. Эта функция addblock принимает базовый указатель и ДЛИНУ (не конечный адрес). Вы не должны добавлять к нему 0xC010CB00. Если вы хотите добавить свободный блок памяти в кучу, начиная с 0xC010CB00 длиной 0x300000, вы должны использовать что-то вроде heap.k_addBlock(&kheap, 0xC010CB00, 0x300000); . Этот код предполагает, что в память уже были добавлены записи подкачки.   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch хорошо, я случайно добавил 0xC010Cb00, моя голова думала, что это конечный адрес .. я преобразовал его в 260, чтобы представить размер 260 байтов сейчас   -  person amanuel2    schedule 24.08.2016
comment
@MichaelPetch хорошо, так что .. Отличие PAE заключается в том, что вы используете страницы размером 4 МБ вместо фреймов страницы 4 КБ ... концепция таблиц страниц исчезает при использовании PAE. В каталоге страниц 1024 страницы, и каждая из страниц содержит 1024 (4096 байт) страничных фреймов. Вот разница, которую PAE приносит к столу   -  person amanuel2    schedule 24.08.2016
comment
@MichaelPetch я спрашиваю, что мне нужно сделать, чтобы завершить этот процесс кучи и избежать этой ошибки страницы, которую я получаю   -  person amanuel2    schedule 24.08.2016
comment
Я уже сказал вам. Прежде чем вызывать функцию addblock, вам нужно создать записи страниц для региона, который вы хотите использовать в качестве кучи. Эта функция addblock не делает этого за вас. Что касается PAE - без PAE система может фактически использовать страницы размером 4 КБ или 4 МБ. При включенном PAE у вас есть выбор между страницами размером 4 КБ и 2 МБ.   -  person Michael Petch    schedule 24.08.2016
comment
Я думаю, вы путаете PAE и PSE. Глядя на ваш код boot.asm, PAE не включен, но установлен бит PSE. Это переключило вас на страницы размером 4 МБ, но вы не используете PAE. Если вы не измените это где-то еще в своем коде после kernelMain.   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch о ... я думал, что PAE и PSE - одно и то же :/   -  person amanuel2    schedule 24.08.2016
comment
Если вы собираетесь использовать 4-мегабайтные страницы (PSE) без PAE, вам нужно учитывать, что у вас есть только структура каталога страниц (до 1024 записей по 4 байта каждая), указывающая на 4-мегабайтные страницы. 4 МБ * 1024 = 4 ГБ, как здесь ">диаграмма . Я предполагаю, что ядро ​​BareBones, на которое вы изначально смотрели, решило, что проще иметь дело с фреймами страниц размером 4 МБ, чем с фреймами 4 КБ. Конечно, можно создать более старшую половину ядра со страницами размером 4 КБ, но у вас больше работы по настройке таблиц, связанных со страницами (3 из них).   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch Какого типа BootPageDirectory, чтобы я мог его внедрить? github.com/amanuel2/OS_Mirror/blob/master/boot.asm# L24 .. extern "C" uint64_t BootPageDirectory[1024]; , все в порядке?   -  person amanuel2    schedule 24.08.2016
comment
Нет, скорее extern "C" uint32_t BootPageDirectory[1024] . Каждая запись в каталоге Bootpage имеет длину 4 байта (32 бита).   -  person Michael Petch    schedule 24.08.2016
comment
Хорошо, и должно быть, потому что не могу читать выше 32 бит из-за x86   -  person amanuel2    schedule 24.08.2016
comment
Ни один 32-разрядный процессор не может использовать память выше 4 ГБ с включенным PAE, поскольку те процессоры, которые поддерживают PAE, фактически имеют дополнительные 4 адресные строки (вы можете адресовать до 64 ГБ ОЗУ). Но с учетом того, как работает режим без PAE и фреймы страниц размером 4 МБ (с одним каталогом страниц входа 1024), вы ограничены 4 ГБ (4 МБ * 1024 = 4 ГБ) или меньше. Большинство современных процессоров в наши дни поддерживают PAE. Если вы включите PAE, вы можете использовать до 64 ГБ оперативной памяти либо с фреймами страниц 2 МБ, либо с фреймами страниц 4 КБ. Без PAE вы можете адресовать 4 ГБ с кадрами страниц 4 МБ или кадрами страниц 4 КБ.   -  person Michael Petch    schedule 24.08.2016
comment
Вы можете увидеть, как все таблицы страниц работают для No-PAE/4MB, No-PAE/4KB, PAE/2MB и PAE/4KB в этой статье Wiki на PAE   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch Хорошо, я понимаю .. Я не собираюсь делать PAE сейчас, потому что это меня сильно смутит. Я лучше пока буду придерживаться этого, а затем, когда я перепишу свою ОС, на самом деле включу и изучу PAE.   -  person amanuel2    schedule 24.08.2016
comment
@MichaelPetch Хорошо, так что мне нужно сделать в моем конструкторе, чтобы несколько неиспользуемых страниц использовались в качестве кучи?   -  person amanuel2    schedule 24.08.2016
comment
Вы бы создали столько сопоставлений по 4 МБ, сколько вам нужно для вашей кучи. Но, как вы, вероятно, теперь поняли, у вас есть гранулярность размера страницы только в 4 МБ, если вы собираетесь использовать полные 4 ГБ ОЗУ - это означает, что минимальное пространство кучи будет 4 МБ, и вы можете добавлять к нему куски по 4 МБ. Вы также хотите использовать память в регионах, которые, по карте памяти, действительно доступны. Первый фрагмент размером 4 МБ после вашего ядра будет иметь адрес 0xC0400000 (и иметь длину 4 МБ). Вы создадите сопоставление с линейным адресом, поместив запись в BootPageDirectory с индексом 769 (769 ‹‹ 22 = 0xC0400000).   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch хорошо, на данный момент позвольте мне предположить, что единственный malloc(), который я делаю, - это 26-байтовый, который начинается с адреса 0xC0450000 . Итак, сначала в конструкторе. Как мне создать столько сопоставлений по 4 МБ, сколько вам нужно для вашей кучи? Я знаю, что BootPageDirectory[0] — это первая страница размером 4 МБ. Но как мне его отобразить?   -  person amanuel2    schedule 24.08.2016
comment
Есть 2 разные проблемы. вам нужно настроить сопоставления с помощью пейджинга, прежде чем вы сможете даже беспокоиться о addblock, а затем о malloc. Итак, обо всем по порядку. Предположим, что ваша куча имеет максимальный размер 4 МБ (одна страница) для экспериментов, какой адрес физической памяти, доступный в вашей системе (посмотрите на карту памяти), который начинается с границы 4 МБ, вы хотите использовать (в идеальном мире вы бы написали код который просматривает карту памяти, переданную GRUB, чтобы найти ее, но для целей тестирования вы можете ее найти.   -  person Michael Petch    schedule 24.08.2016
comment
Я должен указать в качестве разъяснения (для других читателей), что включение PSE не включает автоматически страницы размером 4 МБ, а включает их поддержку. Фактический размер страницы устанавливается в записи каталога страниц. Теоретически вы можете использовать смесь фреймов страниц размером 4 МБ и 4 КБ с соответствующими записями в записи каталога страниц.   -  person Michael Petch    schedule 24.08.2016
comment
Если вы используете QEMU и вывод вашего скриншота правильный, у вас есть физическая память, начинающаяся с 0x100000 длины 133038080 . В нем может поместиться несколько страниц размером 4 МБ. Поскольку мы, вероятно, не хотим снова отображать младшие 4 МБ (часть нашего ядра старшей половины), мы можем использовать область 4 МБ, начиная с физического адреса 0x400000 (это на границе 4 МБ) до 0x7FFFFF. Мы хотим сопоставить кадр страницы размером 4 МБ, начинающийся с физического адреса 0x400000 (0x400000››22)=1, где-то в виртуальной памяти.   -  person Michael Petch    schedule 24.08.2016
comment
Следующий вопрос заключается в том, куда мы хотим отобразить этот 4-мегабайтный страничный фрейм. Кажется, вы намереваетесь разместить его сразу после уже выделенной страницы ядра. В вашем BootPageDirectory уже есть запись с индексом 768. (768‹22)=0xC0000000 (длина 0x400000 байт). Следующий адрес старшей половины памяти размером 4 МБ начинается с 0xC0400000. (0xC0400000››22)=769. Таким образом, чтобы сопоставить фрейм страницы размером 4 МБ по виртуальному адресу 0xC0400000 с физическим (линейным адресом), нам нужно обновить BootPageDirectory[769] . Так вот вопрос с чем?   -  person Michael Petch    schedule 24.08.2016
comment
При отсутствии PAE и подкачке 4 МБ мы, вероятно, захотим установить биты чтения/записи (бит 0) и присутствия (бит 1) вместе с битами 4 МБ (бит 7). Все нижние 12 бит определены в этом диаграмма . При установленном бите подкачки 4 МБ (бит 7) биты 12-21 устанавливаются равными нулю. Верхние 10 бит – это номер таблицы страниц физического адреса, который, как мы определили, равен 1 для второй области размером 4 МБ. (1‹‹22)|(0x83) = 0x400083 (0x83 = чтение/запись, настоящее, битовые значения 4 МБ). Мы присваиваем значение 0x400083 BootPageDirectory[769]. Это сопоставит 0xC0400000 с 4MB @ physaddress 0x400000.   -  person Michael Petch    schedule 24.08.2016
comment
Дополнительную информацию о подкачке можно найти здесь: wiki.osdev.org/Paging   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch, ты меня сейчас сбиваешь с толку .. Сначала ты сказал, что мне нужно, чтобы ты настроил сопоставления с помощью пейджинга. Итак, вы сообщаете мне об экспериментальной карте 4MB To Heap.. Как мне это сделать?   -  person amanuel2    schedule 24.08.2016
comment
Вы разбираетесь в подкачке или просто скопировали код из какого-то туториала и все заработало? Все вышеприведенное обсуждение посвящено тому, чтобы выполнить PAGING для адреса памяти, который вы будете использовать с кучей. Затем вы можете вызвать k_addblock с базой 0xC0400000 и длиной 0x400000, поскольку они теперь сопоставлены. Тогда вы сможете позвонить malloc. Я действительно считаю, что вы должны были запустить свою ОС без подкачки, пока вы действительно не поняли концепцию.   -  person Michael Petch    schedule 24.08.2016
comment
Итак, теперь я сказал вам, какую именно запись BootPageDirectory изменить для этого случая, какое значение в нее вставить и что передать в k_addblock. Предполагая, что код, который вы скопировали, действительно работает, вы сможете вызвать malloc после того, как будут выполнены две описанные выше вещи.   -  person Michael Petch    schedule 24.08.2016
comment
Я действительно понимаю пейджинг .. я изо всех сил постараюсь понять, что вы пытаетесь сказать выше   -  person amanuel2    schedule 24.08.2016
comment
Если вы понимаете пейджинг, то почему вы спросили меня: «Как мне это сделать?» `. Если вы понимаете пейджинг, вам будет очень легко настроить каталог пейджинга и значения внутри.   -  person Michael Petch    schedule 24.08.2016
comment
Я понимаю пейджинг, но это совсем не просто.   -  person amanuel2    schedule 24.08.2016
comment
Хорошо, в основном происходит то, что вы пытаетесь поместить HEAP в физический адрес с 4 МБ (4 МБ для расширения).   -  person amanuel2    schedule 24.08.2016
comment
Реальность такова, что как только вы включите подкачку (что вы делаете в boot.asm), вы не сможете использовать любой произвольный адрес памяти без создания записей подкачки, которые говорят, что здесь есть отображение виртуального адреса на физический (линейный адрес) и память присутствует, и вы можете читать/писать в него. Пока вы этого не сделаете, чтение или запись любых данных вызовет ошибку страницы.   -  person Michael Petch    schedule 24.08.2016
comment
Куча — это всего лишь одна вещь, которая требует памяти. Когда вы хотите загружать приложения в память, вам нужно знать, как создавать страницы для запуска этого кода.   -  person Michael Petch    schedule 24.08.2016
comment
Лично я бы использовал подкачку 4 КБ, но я не уверен, что вы понимаете, как создать каталог страниц и таблицу страниц для этого. 4 МБ - это то, что использовал ваш boot.asm (и, похоже, он скопирован из онлайн-учебника), упрощает его, используя один массив для создания сопоставлений и установки битов страницы.   -  person Michael Petch    schedule 24.08.2016
comment
это как 10 строк кода.. нет никаких улучшений, которые я могу сделать для этого.. и только потому, что я скопировал некоторые строки кода, это не значит, что я не полностью понимаю его   -  person amanuel2    schedule 24.08.2016
comment
Кстати, это то, что меня беспокоит. Если вы используете QEMU, и вывод вашего снимка экрана правильный, у вас есть физическая память, начинающаяся с 0x100000 длины 133038080 . В нем может поместиться несколько страниц размером 4 МБ. Поскольку мы, вероятно, не хотим снова отображать младшие 4 МБ (часть нашего ядра старшей половины), мы можем использовать область 4 МБ, начиная с физического адреса 0x400000 (это на границе 4 МБ) до 0x7FFFFF. Мы хотим сопоставить кадр страницы размером 4 МБ, начинающийся с физического адреса 0x400000 (0x400000››22)=1, где-то в виртуальной памяти. – . Откуда вы взяли 0x400000?   -  person amanuel2    schedule 24.08.2016
comment
Преобразование 0x400000 в десятичное число. Если вы понимаете пейджинг, вы поймете. 0x400000, если у вас нет чего-то, что конвертирует, составляет 4 мегабайта. Каждая страница размером 4 МБ выравнивается по границе 4 МБ в памяти. Вы можете отображать только те страницы, которые находятся на границе (линейный/физический адрес), которая без остатка делится на 0x400000 (или 4 МБ). Если вы использовали страницы размером 4 КБ, то каждый фрейм страницы находится на границе 4 КБ. 4 МБ = 1024*4096=4194304=0x400000   -  person Michael Petch    schedule 24.08.2016
comment
Позвольте мне попытаться поднять это завтра утром ... Я не способен понять это прямо сейчас..   -  person amanuel2    schedule 24.08.2016
comment
Первая страница размером 4 МБ выполняется с физического (линейного) адреса от 0x00000000 до 0x003FFFFF, вторая — от 0x00400000 до 0x007FFFFF, третья — от 0x00800000 до 0x00BFFFFFF и так далее. 1024 региона по 4 МБ = 4 ГБ (1024*4*1024*1024)   -  person Michael Petch    schedule 24.08.2016
comment
Я разместил 3 измененных файла, которые должны помочь: capp-sysware.com/ разное/stackoverflow/39109581 . Я добавил ассемблерную функцию invalidate_page_vm для аннулирования страницы, начинающейся с заданного адреса виртуальной памяти. Это необходимо, когда вы вносите изменения в кэш TLB. Я также добавил код для отображения, описанного выше, и привел несколько примеров объявления области памяти для кучи с помощью k_addblock. Код, кажется, работает здесь.   -  person Michael Petch    schedule 24.08.2016
comment
Я также модифицировал stdio.c++, чтобы, по крайней мере, найти некоторые обходные пути для ошибок, связанных с печатью, которые могут отображать неправильные адреса памяти (и значения) при использовании %x . Вы действительно должны решить их.   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch, я не понимаю, как этот BootPageDirectory[769]=0x400083; сопоставляет физический адрес 0x400083 с виртуальным адресом 0xC0400000. я знаю, что 83 означает, что биты 7,1 и 2 были установлены, но я нигде не вижу виртуального адреса. А также я вижу, что когда я распечатываю BootPageDirectory[768] в виде десятичного числа, я получаю 227. Все остальные равны 0 (поскольку мы обнулили первую директорию в boot.asm). Это почему? В основном я спрашиваю, что такого особенного в 768-й странице? Это означает, что ядро ​​находится на 768-й странице и максимальное пространство, которое оно может занять, составляет всего 4 МБ?   -  person amanuel2    schedule 24.08.2016
comment
@MichaelPetch И Если вы ответили выше, что ядро ​​имеет размер 4 МБ, как этот код не перезаписывает ядро? heap.k_addBlock(&kheap, 0xC0200000, 0x300000); . Он начинается с адреса 0xC0200000, который уже находится в строках ядра, потому что, опять же, если вы ответите утвердительно на то, что размер ядра всегда равен 4 МБ, тогда его виртуальный адрес будет 0xC0000000-0xC0400000. а также есть комментарий, который говорит This heap runs from 0xC0200000 to C04FFFFF - 3MB . Я вообще не понимаю, где это происходит :/   -  person amanuel2    schedule 24.08.2016
comment
Раньше я не мог позволить себе роскошь точно знать, сколько памяти занимает ваше ядро, пока я не построил ваш проект. Размещение его на отдельной странице имело смысл. Но пока используемые адреса не конфликтуют с тем, что уже использует ваше ядро, вы можете их использовать. Ранее в комментариях вы просили кучу 3 МБ, которая равна 0x300000. heap.k_addBlock(&kheap, 0xC0200000, 0x300000); устанавливает кучу размером 3 МБ, работающую с начального адреса 0xC0200000. Вы заметите, что в одном примере в закомментированном коде я показал способ использования kernel_virtual_end для поиска базового адреса для кучи.   -  person Michael Petch    schedule 24.08.2016
comment
На данный момент 0xC0200000 выходит за рамки кода и данных вашего ядра, но по мере роста вашего ядра вам необходимо настроить это значение. Вот почему я предложил в комментариях к коду этот метод heap.k_addBlock(&kheap, (kernel_virtual_end+4095)&0xFFFFF000, 0x300000);, который использует kernel_virtual_end для размещения кучи после ядра. Я просто решил выровнять его по границе 4 КБ после ядра. По мере роста вашего ядра куча будет появляться после него без перекрытия.   -  person Michael Petch    schedule 24.08.2016
comment
Что касается вопроса о числе 768. Возьмите десятичное значение (индекс) 768 и сдвиньте его влево на 22 бита (768‹‹22). В шестнадцатеричном виде вы получите 0xC0000000 . Это базовый виртуальный адрес вашей старшей половины ядра. И да, из-за того, как boot.asm выполнял пейджинг, страница ядра занимала 4 МБ. Фактически он временно выделил вторую страницу для сопоставления идентификаторов нижних 4 МБ памяти, пока подкачка не была полностью настроена, а затем удалила ее. К тому времени, когда boot.asm вызвал kernelMain, между 0xC0000000 и 0xC03FFFFF была активна только одна страница размером 4 МБ, на которой находилась старшая половина ядра.   -  person Michael Petch    schedule 24.08.2016
comment
И эта старшая половина ядра отображается на первые 4 МБ физической памяти между 0x00000000 и 0x003FFFFF.   -  person Michael Petch    schedule 24.08.2016
comment
Что касается значения 227 в записи страницы 768. Оно начинается с 0x083 для младших 12 бит в boot.asm, но по мере работы ЦП и использования каталога страниц биты могут измениться. В не-PAE, использующих страницы размером 4 МБ, значение 227 содержит флаги, но также представляет сопоставляемый физический адрес. Установите все младшие 22 бита равными нулю, и возвращаемое значение будет физическим адресом в памяти, на который сопоставляется запись. В случае 0x000000E3 (десятичное число 227) обнуление младших 22 бит дает нам значение 0x00000000. Это физический адрес кадра размером 4 МБ, отображаемого в этой записи (768).   -  person Michael Petch    schedule 24.08.2016
comment
Многое из этого обсуждается (хотя и кратко для подкачки 4 МБ) здесь: wiki.osdev.org/Paging . Он говорит, что Установка бита S делает точку входа каталога страниц непосредственно на страницу размером 4 МБ. В преобразовании адресов не участвует таблица подкачки. Примечание. Для страниц размером 4 МБ биты с 21 по 12 зарезервированы! Таким образом, физический адрес также должен быть выровнен по 4 МБ. . Дополнительную информацию о PSE/4MB можно найти здесь: en.wikipedia.org/wiki/Page_Size_Extension   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch Сейчас я читаю ваши два нижних комментария .. но перед этим у меня есть пара вопросов .. Почему конец памяти моего ядра равен 0xC03FFFFF ? Я имею в виду, что если вы добавите 4 МБ к его базовому адресу, он станет 0xC0400000, а не 0xC03FFFFF. Я понимаю почти все об этой части k_addBlock(&kheap, (kernel_virtual_end+4095)0xFFFFF000, 0x300000); , вы в основном пытаетесь динамически выделить ее, используя переменные вместо 0xC000000, которая является статической. Но я не понимаю, почему надстройка 4095, каждая страница имеет разделение по 4 КБ? А что с 0xFFFFF000.   -  person amanuel2    schedule 24.08.2016
comment
0xC03FFFFF на единицу меньше, чем 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.2016
comment
4 КБ было несколько произвольным. На самом деле вы могли бы начать свою кучу прямо в конце ядра с помощью k_addBlock(&kheap, kernel_virtual_end, 0x300000); . Я выбрал выравнивание 4 КБ в основном потому, что в вашем скрипте компоновщика вы использовали выравнивание 4 КБ для других разделов, таких как текст, данные, bss. Я решил использовать такое выравнивание для кучи.   -  person Michael Petch    schedule 24.08.2016
comment
Технически говоря, kernel_virtual_end указывает на адрес, следующий за последним использованным байтом вашего ядра. Добавляя 4095, а затем добавляя 0xFFFFF000, вы округляете до следующей границы 4096, ЕСЛИ kernel_virtual_end еще не было на 4 КБ с самого начала. Если бы вы добавили 4096 (вместо 4095), а kernel_virtual_end уже было на границе 4 КБ, вы бы потратили 4 КБ впустую.   -  person Michael Petch    schedule 24.08.2016
comment
Этот тип справки не совсем подходит для формата вопросов и ответов Stackoverflow. Возможно, вам лучше использовать IRC-чат, где общаются люди из OSDev. Они находятся на канале #osdev на Freenode. Вы можете получить к нему доступ через веб-клиент IRC: kiwiirc.com/client/irc. freenode.net/#osdev   -  person Michael Petch    schedule 24.08.2016
comment
Хорошо, @MichaelPetch, я начинаю это понимать. Во-первых, ваш комментарий относительно «#osdev», я был там в течение довольно долгого времени, и поверьте мне, вы намного лучше объясняете такие темы, как эта, спасибо, сэр. Опять же, я действительно начинаю понимать это, у меня есть только два вопроса (один, который я попытаюсь решить самостоятельно), другой - почему я получаю, как вы можете видеть: github.com/amanuel2/OS_Mirror/blob/master/kernel.c%2B%2B, у меня есть два malloc.. И оба распечатывают malloc, возвращают C020001C... Почему у обоих одинаково?   -  person amanuel2    schedule 24.08.2016
comment
О, извините, я удалил свой последний комментарий (он не применим). Вы выделили некоторое пространство, а затем освободили его. Затем вы снова использовали malloc. Free возвращает эту память из первого malloc обратно в кучу для потенциального повторного использования. Удалите свободные между mallocs и они должны быть разными.   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch хорошо .. Теперь понял. Мне нужно сделать какую-то функцию, которая обрабатывает, если он освободил всю свою память. Если не сделать паническую ошибку. Итак, моя последняя проблема заключается в том, что ни один из моих IRQ больше не работает. Моя клавиатура, мышь или драйвер таймера. Я постараюсь исправить это самостоятельно, если я не могу в течение длительного времени, я спрошу, можете ли вы дать мне какие-либо подсказки. Спасибо!   -  person amanuel2    schedule 24.08.2016
comment
Я заметил то же самое, и причина в том, что вы удалили строку __asm__ __volatile__ ("sti");, которая разрешает прерывания. Вы делаете это после того, как был установлен обработчик прерывания мыши, но я заметил, что один из ваших коммитов git удалил его.   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch да .. вау, я случайно удалил его, пытаясь прокомментировать .. мой плохой. Хорошо, я буду глубоко разбираться в этом на весь день и осваивать эту концепцию в своей голове. Если у меня есть вопросы, которые я не могу найти в Интернете или не могу решить, надеюсь, я смогу их задать. Благодарю вас!   -  person amanuel2    schedule 24.08.2016
comment
@MichaelPetch - это отрицательная длина записи № 3 для моего компьютера или функции printf? i.imgur.com/s3alkTF.png   -  person amanuel2    schedule 24.08.2016
comment
Я упомянул эту проблему в другом комментарии где-то вдоль линии. Ваш printf (с использованием %d) и ваш itoa написаны таким образом, что вывод подписывается при использовании %d. Поэтому, если установлен старший бит (бит знака) и вы используете %d, результатом будет отрицательное значение. Кажется, здесь так и есть. Вы можете записать длину в шестнадцатеричном формате, используя %x. В качестве альтернативы вам придется улучшить свой printf, чтобы обрабатывать печать значений без знака. Printf обычно имеет %u для печати целых чисел без знака.   -  person Michael Petch    schedule 24.08.2016
comment
PS: 1 мегабайт (1 МБ) = 1024 * 1024 = 1048576. Я заметил, что у вас есть printf("%d MB Of Usable RAM" , bytes_usable/1000000); Вместо того, чтобы делить на 1000000, вы должны делить на 1048676.   -  person Michael Petch    schedule 24.08.2016
comment
@MichaelPetch хорошо, я только что проверил его на моем реальном оборудовании ПК. Кажется, когда он сложился, он добавил его правильно.. Но раньше он сказал мне, что вторая запись была отрицательной.. теперь мне пришлось изменить ее на шестнадцатеричный, чтобы проверить если сумма МБ была права. printf ошибается, когда я пытаюсь напечатать большое число, например 2 миллиарда...   -  person amanuel2    schedule 25.08.2016
comment
@MichaelPetch хм странно, потому что деление на 1000000 дало мне правильный ответ .. И конвертер Google говорит мне, что я прав, разделив на 1000000 .. :/ странно   -  person amanuel2    schedule 25.08.2016
comment
Ну, printf с %d делает то, что ожидается, просто не слишком полезно печатать число без знака как число со знаком. Реализация %u в printf решит эту проблему. Тогда вы бы использовали %u вместо %d.   -  person Michael Petch    schedule 25.08.2016
comment
@MichaelPetch, да, да, я все еще занимаюсь исследованиями в этой области.   -  person amanuel2    schedule 25.08.2016
comment
@MichaelPetch, о, единственное изменение, которое я должен сделать для %u, это в var_arg, я сделаю va_arg(arg,uint32_t); вместо va_art(ard,int)   -  person amanuel2    schedule 25.08.2016
comment
Единственная отрасль, которая делится на 1000000, — это индустрия жестких дисков, и это немного притворство. Для всех остальных на компе 1Мегабайт это 1024*1024. На одном из ваших скриншотов (может быть это было в QEMU) было показано необычное число 133Мб и мне показалось это странным. Затем я понял, что вы разделили на 10000000. Если бы вы разделили на 1048576, то получилось бы очень близко к 128 МБ (что, как я полагаю, является конфигурацией памяти для сеанса QEMU по умолчанию).   -  person Michael Petch    schedule 25.08.2016
comment
@MichaelPetch О, вот почему у меня была эта 5-байтовая застенчивая память в VB .. Хорошо, я вижу   -  person amanuel2    schedule 25.08.2016
comment
@MichaelPetch хорошо, кажется, мы исправили печать целых чисел без знака. Тот же шестнадцатеричный код, который печатал отрицательное значение до того, как печатает правильное число, когда я сейчас делаю %u .. фиксирует изменения: github.com/amanuel2/OS_Mirror/commit/   -  person amanuel2    schedule 25.08.2016
comment
Я вижу, вы изменили его на printf("%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.2016
comment
@MichaelPetch, о, окей .. причина, по которой я ошибся на 1 МБ. Ну, у меня есть еще один вопрос. Вопрос в том, что я не получаю здесь какой-либо ошибки: github.com/amanuel2/OS_Mirror/blob/master/heap.c%2B%2B#L226 .. Вы можете видеть, что я перезаписываю 0x400083 со страницы 769 на 770. Думаю, я действительно не понимаю эту часть процесса. Например, не могли бы вы показать мне небольшой пример того, как я бы выделил 8 МБ? чтобы я мог видеть, как выделить несколько страниц? Спасибо   -  person amanuel2    schedule 25.08.2016
comment
Вам нужно передать только виртуальный адрес и физический адрес (оба должны делиться нацело на 0x400000 (4 МБ) при использовании 4 МБ страниц, как вы здесь. Вам вообще не нужен 3-й аргумент, поэтому удалите его. Индекс основан на VirtualAddress.Возьмите виртуальный адрес и сдвиньте его вправо на 22 бита.Это будет индекс, который вы используете для BootPageDirectory.   -  person Michael Petch    schedule 25.08.2016
comment
@MichaelPetch хорошо, я вижу прямо противоположный способ получить индекс страницы. Ну, у меня происходит эта странная вещь, когда я делаю это heap.k_addBlock(&kheap, (kernel_virtual_end+4095)&0xFFFFF000, 0x300000); , это дает мне ошибку страницы. Если я удалю & 0xFFFFF000 ИЛИ +4095 , все станет хорошо. Или, если я удалю оба, все станет хорошо. Но если все три из них включены, я получаю эту странную ошибку страницы: /. Не замечал этого до сих пор, так как я использовал qemu, который я загрузил из двоичного файла ... когда я попробовал его на vb, он выдал мне ошибку страницы при загрузке из ISO   -  person amanuel2    schedule 25.08.2016
comment
@MichaelPetch И вместо pmm.map_physical_virtual(0x400000,0xC0400000); я бы сделал pmm.map_physical_virtual(0x800000,0xC0800000);, если бы я хотел, чтобы 8 МБ было зарезервировано для моей кучи, которая была бы от 0xC0000000-0x800000,0xC0800000? Если это да, то в основном то, что делает эта функция, устанавливает, где мы можем выделить нашу кучу для ... всей коробки ... Я нарисую диаграмму и просто скажите мне, есть ли у меня правильная иллюстрация или нет   -  person amanuel2    schedule 25.08.2016
comment
Я могу только представить, что в вашем коде кучи есть ошибка. У меня нет времени на его отладку, но, похоже, может потребоваться, чтобы область памяти была установлена ​​​​на ноль, прежде чем он начнет строить структуру данных кучи. В качестве первой строки вашей подпрограммы k_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.2016
comment
@MichaelPetch Извините, это заняло много времени, нужно было куда-то идти. Хм, ну, я хорошо об этом подумал, и вот что я понял об этой схеме управления памятью. Это правильная идея? Ничего плохого? i.imgur.com/Wvfp4iY.png (уменьшите масштаб, чтобы увидеть больше)   -  person amanuel2    schedule 25.08.2016
comment
Это более-менее правильно. Что немного не так, находится внутри пространства кучи. 0x100=256 байт (не 0x10c), но для каждого запрашиваемого фрагмента памяти есть небольшой фрагмент данных, который куча помещает перед возвращаемым указателем. Эти данные используются для отслеживания использования памяти в куче, чтобы он мог искать свободное пространство, когда вы выполняете malloc, и освобождать место, когда оно освобождается.   -  person Michael Petch    schedule 25.08.2016
comment
@MichaelPetch одна вещь, которая меня немного беспокоит, это то, что, как вы можете видеть, конец ядра - 0xC010CB20 . Вы сказали, что 0x100 - это 256 байт. Поэтому, если вы добавите 0x100 к 0xC010CC20 . Если это конец k_malloc() , то как он говорит, что malloc вернул 0xC010CB3C ? это больше, чем конечный адрес этого конкретного malloc:/ ...   -  person amanuel2    schedule 25.08.2016
comment
Как я уже сказал, перед каждым элементом, созданным с помощью malloc, есть данные. Вы выделили 256 байт, но куче пришлось добавить дополнительное количество байтов непосредственно перед возвращаемым указателем.   -  person Michael Petch    schedule 25.08.2016
comment
@MichaelPetch, о, заголовок, который получает флаг и размер. Хорошо, я понимаю   -  person amanuel2    schedule 25.08.2016
comment
@MichaelPetch Хорошо, вот моя улучшенная версия. Мне пора спать. Спасибо! i.imgur.com/oAkKu13.png   -  person amanuel2    schedule 25.08.2016
comment
@MichaelPetch хорошо, они сказали, что одна вещь, которую мне не хватает, это динамическое увеличение кучи. И они сказали, что вам это не нужно pmm.map_physical_virtual(0x400000,0xC0400000);... Пытался объяснить это здесь: stackoverflow.com/questions/39152751/   -  person amanuel2    schedule 25.08.2016