physical memory

2017-04-20  本文已影响56人  101dog

1.read disk to memory in bootasm.S

disk_addr_packet:
    .byte   0x10                        # [0] size of packet 16 bytes
    .byte   0x00                        # [1] reserved always 0
    .word   0x01                        # [2] blocks to read
    .word   0x00                        # [6] transfer buffer(16 bit segment)
    .word   0x00                        # [6] transfer buffer(16 bit offset)
    .long   0x01                        # [8] starting LBA
    .long   0x00                        # [12]used for upper part of 48 bit LBAs

read_a_sect_hd:
    lea     disk_addr_packet,   %si
    movb    $0x42,              %ah
    movb    $0x80,              %dl
    int     $0x13
    ret

read_intbios:
    lea     disk_addr_packet, %si
    movw    $0x7e00>>4, 6(%si)
    xorw    %cx, %cx
loop:   
    call    read_a_sect_hd
    lea     disk_addr_packet,   %si
    movl    8(%si),             %eax
    addl    $0x01,              %eax
    movl    %eax,               (disk_addr_packet + 8)

    movl    6(%si),             %eax
    addl    $512>>4,            %eax
    movl    %eax,               (disk_addr_packet + 6)

    incw    %cx
    cmpw    $0x02+1, %cx
    jne     loop
    
    ret 

2. detect the physical memory and store it in a E820 struct

probe_memory:
    movl $0, 0x8000
    xorl %ebx, %ebx
    movw $0x8004, %di
start_probe:
    movl $0xE820, %eax
    movl $20, %ecx 
    movl $SMAP, %edx
    int $0x15
    jnc cont 
    movw $12345, 0x8000
    jmp finish_probe
cont:
    addw $20, %di 
    incl 0x8000
    cmpl $0, %ebx 
    jnz start_probe
finish_probe:

the struct e820map is as follows:

struct e820map
{
    int nr_map;
    struct 
    {
        uint64_t addr;
        uint64_t size;
        uint32_t type;
    }map[E820MAX];
};
struct Page
{
    uint32_t flags;
    unsigned int order;
    list_entry_t page_link;
};
typedef struct 
{
    list_entry_t free_list;
    unsigned int nr_free;   // # of free pages 
} free_area_t;

3. pmm_init()

a. pmm_manager

---buddy_pmm_manager, later will reach

struct pmm_manager
{
    const char *name;
    void (*init)(void);
    void (*init_memmap)(struct Page *base, size_t n);
    struct Page *(*alloc_pages)(size_t n);
    void (*free_pages)(struct Page *base, size_t n);
    void (*check)(void);
};

b.page_init()

static void page_init(void)
{
    struct e820map *memmap = (struct e820map *)(0x8000 + KERNBASE);

there is a KERNBASE because it uses VA
VA = PA+KERNBASE

    uint64_t maxpa = 0, begin, free_end;

    for (int i = 0; i < memmap->nr_map; ++i)
    {
        begin = memmap->map[i].addr;
        free_end = begin + memmap->map[i].size;
        cprintf("map[%d]: begin:%08llx free_end:%08llx size:%08llx type:%d\n", 
            i, begin, free_end-1, memmap->map[i].size, memmap->map[i].type);
        if(memmap->map[i].type == E820_ARM) {
            if(maxpa < free_end && begin < KMEMSIZE)
                maxpa = free_end;
        }
    }
    if(maxpa > KMEMSIZE) maxpa = KMEMSIZE;

choose a bigger memory and make sure maxpa<KEMSIZE

end(0xC..1.....) is the actual end of OS, and the later memory can be used to store the struct of PAGES

and after that is the memory we can use

    extern char end[];
    npage = maxpa / PGSIZE;
    pages = (struct Page *)ROUND_UP((void*)end, PGSIZE);

   //mark the pages that can be used
    for(int i=0; i<npage; ++i)
        SetPageReserved(pages+i);

    uintptr_t freemem = PADDR((uintptr_t)pages + sizeof(struct Page)*npage);

    for (int i=0; i<memmap->nr_map; ++i) {
        begin = memmap->map[i].addr;
        free_end = begin + memmap->map[i].size;
        if(memmap->map[i].type == E820_ARM) 
        {
            if(begin < freemem) begin = freemem;
            if(free_end > KMEMSIZE) free_end = KMEMSIZE;
            if(begin < free_end) 
            {
                begin = ROUND_UP(begin, PGSIZE);
                free_end = ROUND_DOWN(free_end, PGSIZE);
                if(begin < free_end) {
                    cprintf("------- begin:%8llx free_end:%8llx\n", begin, free_end);
                    init_memmap(pa2page(begin), (free_end-begin)/PGSIZE);

init_memmap above make buddy know the number of pages and the begin of pages
remember it mus be begin+KERNBASE because we are using the VA now, there must be a 0xC0000000

                }
            }
        }
    }
    cprintf("free_end:%x \n", free_end);

    cprintf("maxpa:%x \n", maxpa);
    cprintf("npage:%d  pages:%x", npage, pages);
}

4.the convert between struct Page and VA & PA

#define PADDR(kva) ({uintptr_t __m_kva = (uintptr_t)(kva); \
                    __m_kva - KERNBASE;})

#define VADDR(kpa) ({uintptr_t __m_kpa = (uintptr_t)(kpa); \
                    __m_kpa + KERNBASE;})


static inline struct Page* n2page(int n)
{
    return &pages[n];
}
static inline int page2n(struct Page* page)
{
    return page - pages;
}
static inline uintptr_t page2pa(struct Page *page)
{
    return page2n(page) << 12;
}
static inline struct Page* pa2page(uintptr_t p)
{
    return &pages[PAGE_NUM(p)];
}
static inline uintptr_t page2va(struct Page *page)
{
    return VADDR(page2pa(page));
}
static inline struct Page* va2page(uintptr_t p)
{
    return pa2page(PADDR(p));
}
上一篇 下一篇

猜你喜欢

热点阅读