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));
}