Problem with Bootboot and kernel

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
miky
Posts: 9
Joined: Wed Feb 11, 2009 3:39 am

Problem with Bootboot and kernel

Post by miky »

Hello, I have a problem with BootBoot bootloader and modified kernel for 64 bit intel, from udemy.com course.
Bootboot is known to pass a physical address of the display framebuffer to the kernel.
When paging and virtual memory management is enabled I can no longer locate the display framebuffer address.
Normal because with active paging it is necessary to translate from physical address to virtual address.
In an .H file there are these macros:

#define PTE_P 1
#define PTE_W 2
#define PTE_U 4
#define PTE_ENTRY 0x80
#define KERNEL_BASE 0xffff800000000000
#define PAGE_SIZE (2*1024*1024)

#define PA_UP(v) ((((uint64_t)v + PAGE_SIZE-1) >> 21) << 21)
#define PA_DOWN(v) (((uint64_t)v >> 21) << 21)
#define P2V(p) ((uint64_t)(p) + KERNEL_BASE)
#define V2P(v) ((uint64_t)(v) - KERNEL_BASE)
#define PDE_ADDR(p) (((uint64_t)p >> 12) << 12)
#define PTE_ADDR(p) (((uint64_t)p >> 21) << 21)


how can i locate the frame buffer pointer when paging is set ?

Thanks
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Problem with Bootboot and kernel

Post by Octocontrabass »

According to the documentation, the framebuffer will be mapped either at the virtual address you specified for the "fb" symbol or at virtual address 0xFFFFFFFFFC000000. You're free to map it elsewhere once you set up your own page tables.
miky
Posts: 9
Joined: Wed Feb 11, 2009 3:39 am

Re: Problem with Bootboot and kernel

Post by miky »

thanks for the reply, based on the macros i posted how could i then do this xhe hwi recommended ? could you write an example?


thank you
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Problem with Bootboot and kernel

Post by Octocontrabass »

If you're looking for examples of how to access the framebuffer before switching to your own page tables, you can find them here.

Accessing it after you switch to your own page tables works the same as accessing any other memory.
miky
Posts: 9
Joined: Wed Feb 11, 2009 3:39 am

Re: Problem with Bootboot and kernel

Post by miky »

Hi, I tried in every way but I can't access the framebuffer when the pages are enabled.

Among other things, there is a parameter of the bootboot structure (FB_PTR) to be used to replace FB.
But unfortunately as soon as we call the patient initialization function, it no longer views anything.

thank you
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Problem with Bootboot and kernel

Post by Octocontrabass »

miky wrote:Hi, I tried in every way but I can't access the framebuffer when the pages are enabled.
Paging is always enabled in 64-bit mode.
miky wrote:But unfortunately as soon as we call the patient initialization function, it no longer views anything.
What does your paging initialization function do? If it doesn't assign a virtual address for the framebuffer, you won't be able to access the framebuffer.
miky
Posts: 9
Joined: Wed Feb 11, 2009 3:39 am

Re: Problem with Bootboot and kernel

Post by miky »

This i the file memory.c:


Code: Select all

#include "memory.h"
#include "print.h"
#include "debug.h"
#include "lib.h"
#include "stddef.h"
#include "stdbool.h"

static void free_region(uint64_t v, uint64_t e);

static struct FreeMemRegion free_mem_region[50];
static struct Page free_memory;
static uint64_t memory_end;
static uint64_t total_mem;
extern char end;

void init_memory(void)
{
    int32_t count = *(int32_t*)0x20000;
    struct E820 *mem_map = (struct E820*)0x20008;	
    int free_region_count = 0;

    ASSERT(count <= 50);

	for(int32_t i = 0; i < count; i++) {        
        if(mem_map[i].type == 1) {			
            free_mem_region[free_region_count].address = mem_map[i].address;
            free_mem_region[free_region_count].length = mem_map[i].length;
            total_mem += mem_map[i].length;
            free_region_count++;
        }
        //printk("%x  %uKB  %u\n",mem_map[i].address,mem_map[i].length/1024,(uint64_t)mem_map[i].type);
	}

    for (int i = 0; i < free_region_count; i++) {                  
        uint64_t vstart = P2V(free_mem_region[i].address);
        uint64_t vend = vstart + free_mem_region[i].length;

        if (vstart > (uint64_t)&end) {
            free_region(vstart, vend);
        } 
        else if (vend > (uint64_t)&end) {
            free_region((uint64_t)&end, vend);
        }       
    }
    
    memory_end = (uint64_t)free_memory.next + PAGE_SIZE;   
}

uint64_t get_total_memory(void)
{
    return total_mem/1024/1024;
}

static void free_region(uint64_t v, uint64_t e)
{
    for (uint64_t start = PA_UP(v); start+PAGE_SIZE <= e; start += PAGE_SIZE) {        
        if (start+PAGE_SIZE <= 0xffff800030000000) {            
           kfree(start);
        }
    }
}

void kfree(uint64_t v)
{
    ASSERT(v % PAGE_SIZE == 0);
    ASSERT(v >= (uint64_t) & end);
    ASSERT(v+PAGE_SIZE <= 0xffff800030000000);

    struct Page *page_address = (struct Page*)v;
    page_address->next = free_memory.next;
    free_memory.next = page_address;
}

void* kalloc(void)
{
    struct Page *page_address = free_memory.next;

    if (page_address != NULL) {
        ASSERT((uint64_t)page_address % PAGE_SIZE == 0);
        ASSERT((uint64_t)page_address >= (uint64_t)&end);
        ASSERT((uint64_t)page_address+PAGE_SIZE <= 0xffff800030000000);

        free_memory.next = page_address->next;            
    }

    return page_address;
}

static PDPTR find_pml4t_entry(uint64_t map, uint64_t v, int alloc, uint32_t attribute)
{
    PDPTR *map_entry = (PDPTR*)map;
    PDPTR pdptr = NULL;
    unsigned int index = (v >> 39) & 0x1FF;

    if ((uint64_t)map_entry[index] & PTE_P) {
        pdptr = (PDPTR)P2V(PDE_ADDR(map_entry[index]));       
    } 
    else if (alloc == 1) {
        pdptr = (PDPTR)kalloc();          
        if (pdptr != NULL) {     
            memset(pdptr, 0, PAGE_SIZE);     
            map_entry[index] = (PDPTR)(V2P(pdptr) | attribute);           
        }
    } 

    return pdptr;    
}

static PD find_pdpt_entry(uint64_t map, uint64_t v, int alloc, uint32_t attribute)
{
    PDPTR pdptr = NULL;
    PD pd = NULL;
    unsigned int index = (v >> 30) & 0x1FF;

    pdptr = find_pml4t_entry(map, v, alloc, attribute);
    if (pdptr == NULL)
        return NULL;
       
    if ((uint64_t)pdptr[index] & PTE_P) {      
        pd = (PD)P2V(PDE_ADDR(pdptr[index]));      
    }
    else if (alloc == 1) {
        pd = (PD)kalloc();  
        if (pd != NULL) {    
            memset(pd, 0, PAGE_SIZE);       
            pdptr[index] = (PD)(V2P(pd) | attribute);
        }
    } 

    return pd;
}

bool map_pages(uint64_t map, uint64_t v, uint64_t e, uint64_t pa, uint32_t attribute)
{
    uint64_t vstart = PA_DOWN(v);
    uint64_t vend = PA_UP(e);
    PD pd = NULL;
    unsigned int index;

    ASSERT(v < e);
    ASSERT(pa % PAGE_SIZE == 0);
    ASSERT(pa+vend-vstart <= 1024*1024*1024);

    do {
        pd = find_pdpt_entry(map, vstart, 1, attribute);    
        if (pd == NULL) {
            return false;
        }

        index = (vstart >> 21) & 0x1FF;
        ASSERT(((uint64_t)pd[index] & PTE_P) == 0);

        pd[index] = (PDE)(pa | attribute | PTE_ENTRY);

        vstart += PAGE_SIZE;
        pa += PAGE_SIZE;
    } while (vstart + PAGE_SIZE <= vend);
  
    return true;
}

void switch_vm(uint64_t map)
{
    load_cr3(V2P(map));   
}

uint64_t setup_kvm(void)
{
    uint64_t page_map = (uint64_t)kalloc();

    if (page_map != 0) {
        memset((void*)page_map, 0, PAGE_SIZE);        
        if (!map_pages(page_map, KERNEL_BASE, P2V(0x40000000), V2P(KERNEL_BASE), PTE_P|PTE_W)) {
            free_vm(page_map);
            page_map = 0;
        }
    }
    return page_map;
}

void init_kvm(void)
{
    uint64_t page_map = setup_kvm();
    ASSERT(page_map != 0);
    switch_vm(page_map);
    //printk("memory manager is working now");
}

bool setup_uvm(uint64_t map, uint64_t start, int size)
{
    bool status = false;
    void *page = kalloc();

    if (page != NULL) {
        memset(page, 0, PAGE_SIZE);
        status = map_pages(map, 0x400000, 0x400000+PAGE_SIZE, V2P(page), PTE_P|PTE_W|PTE_U);
        if (status == true) {
            memcpy(page, (void*)start, size);
        }
        else {
            kfree((uint64_t)page);
            free_vm(map);
        }
    }
    
    return status;
}

void free_pages(uint64_t map, uint64_t vstart, uint64_t vend)
{
    unsigned int index; 

    ASSERT(vstart % PAGE_SIZE == 0);
    ASSERT(vend % PAGE_SIZE == 0);

    do {
        PD pd = find_pdpt_entry(map, vstart, 0, 0);

        if (pd != NULL) {
            index = (vstart >> 21) & 0x1FF;
            if (pd[index] & PTE_P) {        
                kfree(P2V(PTE_ADDR(pd[index])));
                pd[index] = 0;
            }
        }

        vstart += PAGE_SIZE;
    } while (vstart+PAGE_SIZE <= vend);
}

static void free_pdt(uint64_t map)
{
    PDPTR *map_entry = (PDPTR*)map;

    for (int i = 0; i < 512; i++) {
        if ((uint64_t)map_entry[i] & PTE_P) {            
            PD *pdptr = (PD*)P2V(PDE_ADDR(map_entry[i]));
            
            for (int j = 0; j < 512; j++) {
                if ((uint64_t)pdptr[j] & PTE_P) {
                    kfree(P2V(PDE_ADDR(pdptr[j])));
                    pdptr[j] = 0;
                }
            }
        }
    }
}

static void free_pdpt(uint64_t map)
{
    PDPTR *map_entry = (PDPTR*)map;

    for (int i = 0; i < 512; i++) {
        if ((uint64_t)map_entry[i] & PTE_P) {          
            kfree(P2V(PDE_ADDR(map_entry[i])));
            map_entry[i] = 0;
        }
    }
}

static void free_pml4t(uint64_t map)
{
    kfree(map);
}

void free_vm(uint64_t map)
{   
    free_pages(map, 0x400000, 0x400000+PAGE_SIZE);
    free_pdt(map);
    free_pdpt(map);
    free_pml4t(map);
}

bool copy_uvm(uint64_t dst_map, uint64_t src_map, int size)
{
    bool status = false;
    unsigned int index;
    PD pd = NULL;
    uint64_t start;

    void *page = kalloc();
    if (page != NULL) {
        memset(page, 0, PAGE_SIZE);
        status = map_pages(dst_map, 0x400000, 0x400000+PAGE_SIZE, V2P(page), PTE_P|PTE_W|PTE_U);

        if (status == true) {
            pd = find_pdpt_entry(src_map, 0x400000, 0, 0);
            if (pd == NULL) {
                free_vm(dst_map);
                return false;
            }

            index = (0x400000U >> 21) & 0x1FF;
            ASSERT(((uint64_t)pd[index] & PTE_P) == 1);
            start = P2V(PTE_ADDR(pd[index]));
            memcpy(page, (void*)start, size);
        }
        else {
            kfree((uint64_t)page);
            free_vm(dst_map);
        }
    }

    return status;
}
miky
Posts: 9
Joined: Wed Feb 11, 2009 3:39 am

Re: Problem with Bootboot and kernel

Post by miky »

and the file memory.h:

Code: Select all

#ifndef _MEMORY_H_
#define _MEMORY_H_

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

struct E820 {
    uint64_t address;
    uint64_t length;
    uint32_t type;
} __attribute__((packed));

struct FreeMemRegion {
    uint64_t address;
    uint64_t length;
};

struct Page {
    struct Page* next;
};

typedef uint64_t PDE;
typedef PDE* PD;
typedef PD* PDPTR;

#define PTE_P 1
#define PTE_W 2
#define PTE_U 4
#define PTE_ENTRY 0x80
//#define KERNEL_BASE 0xffff800000000000
#define KERNEL_BASE 0xffffffffffe00000
#define PAGE_SIZE (2*1024*1024)

#define PA_UP(v) ((((uint64_t)v + PAGE_SIZE-1) >> 21) << 21)
#define PA_DOWN(v) (((uint64_t)v >> 21) << 21)
#define P2V(p) ((uint64_t)(p) + KERNEL_BASE)
#define V2P(v) ((uint64_t)(v) - KERNEL_BASE)
#define PDE_ADDR(p) (((uint64_t)p >> 12) << 12)
#define PTE_ADDR(p) (((uint64_t)p >> 21) << 21)

void* kalloc(void);
void kfree(uint64_t v);
void init_memory(void);
void init_kvm(void);
bool map_pages(uint64_t map, uint64_t v, uint64_t e, uint64_t pa, uint32_t attribute);
void switch_vm(uint64_t map);
void load_cr3(uint64_t map);
void free_vm(uint64_t map);
void free_page(uint64_t map, uint64_t v, uint64_t e);
bool setup_uvm(uint64_t map, uint64_t start, int size);
uint64_t setup_kvm(void);
uint64_t get_total_memory(void);
bool copy_uvm(uint64_t dst_map, uint64_t src_map, int size);


#endif
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Problem with Bootboot and kernel

Post by Octocontrabass »

Your code doesn't assign a virtual address to the framebuffer.
miky
Posts: 9
Joined: Wed Feb 11, 2009 3:39 am

Re: Problem with Bootboot and kernel

Post by miky »

You can writer an example ?

Thanks
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Problem with Bootboot and kernel

Post by Octocontrabass »

Something like this?

Code: Select all

map_pages(map, fb_virtual_address, fb_virtual_address + fb_size, fb_physical_address, PTE_P|PTE_W);
miky
Posts: 9
Joined: Wed Feb 11, 2009 3:39 am

Re: Problem with Bootboot and kernel

Post by miky »

Very good thanks
jimgen
Posts: 1
Joined: Wed Jan 18, 2023 3:39 am

Re: Problem with Bootboot and kernel

Post by jimgen »

Octocontrabass, the page with examples helped me figure it out, by the way I had a similar situation, so thanks.
Post Reply