static phys_addr_t sfi_syst_phys(void) { phys_addr_t phys = SFI_SYST_SEARCH_BEGIN; do { char *virt = map_virtual_page((phys & 0xFFFFF000) | 3); if(virt == NULL) { panic("Failed to map virtual page in sfi_present"); } int i; for(i = 0; i < 0x1000; i+=16) { if(strncmp(&virt[i], SFI_SIG_SYST, SFI_SIG_SIZE) == 0) { unmap_virtual_page(virt); return phys + i; } } unmap_virtual_page(virt); phys += 0x1000; } while(phys < SFI_SYST_SEARCH_END); return -1; }
static void print_xsdt_table(sfi_info_t *sfi_info) { if(sfi_info->xsdt_table) { size_t i; DLOGV("Number of XSDT table entries: %u", SFI_NUM_XSDT_ENTRIES(sfi_info->xsdt_table)); DLOGV("(addr, name)"); for(i = 0; i < SFI_NUM_XSDT_ENTRIES(sfi_info->xsdt_table); i++) { ACPI_TABLE_HEADER *table = (ACPI_TABLE_HEADER*) map_virtual_page((sfi_info->xsdt_table->TableOffsetEntry[i] & 0xFFFFF000) | 3); if(table == NULL) { panic("Failed to map XSDT sub-table"); } table = (ACPI_TABLE_HEADER*)(uint32) (((uint32)table) | (sfi_info->xsdt_table->TableOffsetEntry[i] & 0xFFF)); DLOGV("(0x%llX, %c%c%c%c)", sfi_info->xsdt_table->TableOffsetEntry[i], table->Signature[0], table->Signature[1], table->Signature[2], table->Signature[3]); if(strncmp(table->Signature, SFI_SIG_MCFG, 4) == 0) { sfi_info->mcfg_table = (sfi_mcfg_table_t*)table; print_mcfg_table(sfi_info); } else { unmap_virtual_page(table); } } } else { DLOGV("NO XSDT Table"); } }
/** * alloc_virtual_pages - varataan virtuaalisia sivuja muuhun kuin aktiiviseen tauluun * @phys_pd: käytettävän sivuhakemiston fyysinen sivu * @count: haluttujen sivujen määrä * @user: sivuja kernelille (0) vai käyttäjälle (1) **/ uint_t alloc_virtual_pages(uint_t phys_pd, uint_t count, int user) { uint_t first, page; if (!user || !phys_pd) { // Kaikilla on samat kernelsivut phys_pd = cur_phys_pd(); } first = find_free_virtual_pages(phys_pd, count, user); if (!first) { return 0; } for (page = first; page < first + count; ++page) { if (map_virtual_page(phys_pd, page, 0, user)) { goto free_pages_on_error; } } return first; free_pages_on_error: while (page > first) { --page; unmap_virtual_page(phys_pd, page); } return 0; }
/** * alloc_program_space - ladataan ohjelma omaan sivutauluunsa * @phys_pd: sivuhakemiston fyysinen sijainti * @size: koodin koko * * Palauttaa ensimmäisen ohjelmasivun numeron **/ uint_t alloc_program_space(uint_t phys_pd, uint_t size, const void *code, int user) { char *pptr; const char *cptr = code; if (!code || !size) { return 0; } uint_t first, page, count = 1 + ((size - 1) / MEMORY_PAGE_SIZE); first = alloc_virtual_pages(phys_pd, count, user); if (!first) { return 0; } for (page = first; page < first + count; ++page) { if (!(pptr = temp_virt_page(0, phys_pd, page))) { goto free_pages_on_error; } if (size >= MEMORY_PAGE_SIZE) { memcpy(pptr, cptr, MEMORY_PAGE_SIZE); cptr += MEMORY_PAGE_SIZE; size -= MEMORY_PAGE_SIZE; } else { memcpy(pptr, cptr, size); memset(pptr + size, 0, MEMORY_PAGE_SIZE - size); cptr += size; size = 0; } temp_virt_page(0, phys_pd, page); } return first; free_pages_on_error: while (page > first) { --page; unmap_virtual_page(phys_pd, page); } return 0; }
/** * resize_stack - laajennetaan säikeen pinoa * @phys_pd: sivuhakemiston fyysinen sijainti * @stack_num: pinon numero (prosessin pinoista) * @size: pinon uusi vähimmäiskoko (tavuina) * * return 0 = onnistui **/ int resize_stack(uint_t phys_pd, int stack_num, uint_t size, int user) { if ((stack_num < 0 || stack_num > MAX_STACKS) || size > MAX_STACK_SIZE) { return -1; } uint_t pages, alloced, i; if (!size) { pages = 0; } else { pages = 1 + ((size - 1) / MEMORY_PAGE_SIZE); } i = STACK_TOP_PAGE(stack_num); alloced = 0; while (alloced < pages && temp_virt_page(0, phys_pd, i)) { temp_virt_page(0, 0, 0); ++alloced; ++i; } while (alloced < pages) { if (temp_virt_page(0, phys_pd, i)) { temp_virt_page(0, 0, 0); } else { if (map_virtual_page(phys_pd, i, 0, user) != 0) { panic("resize_stack: map_virtual_page != 0\n"); } } ++alloced; ++i; } while (temp_virt_page(0, phys_pd, i)) { temp_virt_page(0, 0, 0); unmap_virtual_page(phys_pd, i); ++i; } return 0; }
/* Create an address space for boot modules */ static uint16 load_module (multiboot_module * pmm, int mod_num) { uint32 *plPageDirectory = get_phys_addr (pg_dir[mod_num]); uint32 *plPageTable = get_phys_addr (pg_table[mod_num]); void *pStack = get_phys_addr (ul_stack[mod_num]); /* temporarily map pmm->pe in order to read pph->p_memsz */ Elf32_Ehdr *pe, *pe0 = map_virtual_page ((uint) pmm->pe | 3); Elf32_Phdr *pph = (void *) pe0 + pe0->e_phoff; void *pEntry = (void *) pe0->e_entry; int i, c, j; uint32 *stack_virt_addr; uint32 page_count = 1; /* find out how many pages for the module */ for (i = 0; i < pe0->e_phnum; i++) { if (pph->p_type == PT_LOAD) page_count += (pph->p_memsz >> 12); pph = (void *) pph + pe0->e_phentsize; } /* now map the entire module */ pe = map_contiguous_virtual_pages ((uint) pmm->pe | 3, page_count); unmap_virtual_page (pe0); pph = (void *) pe + pe->e_phoff; /* Populate ring 3 page directory with kernel mappings */ memcpy (&plPageDirectory[1023], (void *) (((uint32) get_pdbr ()) + 4092), 4); /* LAPIC/IOAPIC mappings */ memcpy (&plPageDirectory[1019], (void *) (((uint32) get_pdbr ()) + 4076), 4); /* Populate ring 3 page directory with entries for its private address space */ plPageDirectory[0] = (uint32) plPageTable | 7; plPageDirectory[1022] = (uint32) get_phys_addr (kls_pg_table[mod_num]) | 3; kls_pg_table[mod_num][0] = (uint32) get_phys_addr (kl_stack[mod_num]) | 3; /* Walk ELF header */ for (i = 0; i < pe->e_phnum; i++) { if (pph->p_type == PT_LOAD) { /* map pages loaded from file */ c = (pph->p_filesz + 0xFFF) >> 12; /* #pages to load for module */ for (j = 0; j < c; j++) plPageTable[((uint32) pph->p_vaddr >> 12) + j] = (uint32) pmm->pe + (pph->p_offset & 0xFFFFF000) + (j << 12) + 7; /* zero remainder of final page */ memset ((void *) pe + pph->p_offset + pph->p_filesz, 0, (pph->p_memsz - pph->p_filesz) & 0x0FFF); /* map additional zeroed pages */ c = (pph->p_memsz + 0xFFF) >> 12; /* Allocate space for bss section. Use temporary virtual memory for * memset call to clear physical frame(s) */ for (; j <= c; j++) { uint32 page_frame = (uint32) alloc_phys_frame (); void *virt_addr = map_virtual_page (page_frame | 3); memset (virt_addr, 0, 0x1000); plPageTable[((uint32) pph->p_vaddr >> 12) + j] = page_frame + 7; unmap_virtual_page (virt_addr); } } pph = (void *) pph + pe->e_phentsize; }
int sfi_early_init(sfi_info_t *sfi_info) { int i; size_t syst_num; phys_addr_t low_frame; phys_addr_t high_frame; phys_addr_t syst_phys; memset(sfi_info, 0, sizeof(*sfi_info)); syst_phys = sfi_syst_phys(); if(syst_phys == -1) { return 0; } low_frame = high_frame = syst_phys; sfi_info->system_table = (sfi_system_table_t*) (((char*)map_virtual_page((syst_phys & 0xFFFFF000) | 3)) + (syst_phys & 0xFFF)); syst_num = SFI_NUM_SYST_ENTRIES(sfi_info->system_table); for(i = 0; i < syst_num; i++) { if(sfi_info->system_table->entries[i] > 0xFFFFFFFF) { panic("SFI table above 4G region"); } if(sfi_info->system_table->entries[i] < low_frame) { low_frame = sfi_info->system_table->entries[i]; } if(sfi_info->system_table->entries[i] > high_frame) { high_frame = sfi_info->system_table->entries[i]; } } sfi_info->low_frame = low_frame = low_frame & 0xFFFFF000; high_frame &= 0xFFFFF000; unmap_virtual_page(sfi_info->system_table); sfi_info->num_frames = ((high_frame - low_frame) / 0x1000) + 1; sfi_info->start_addr = map_contiguous_virtual_pages(low_frame | 3, sfi_info->num_frames); if(sfi_info->start_addr == NULL) { panic("Failed to map STI"); } sfi_info->system_table = (sfi_system_table_t*) SFI_PHYS_TO_VIRT(sfi_info, syst_phys); print_syst_table(sfi_info); sfi_info->cpus_table = get_sfi_table(sfi_info, SFI_SIG_CPUS); print_cpus_table(sfi_info); sfi_info->apic_table = get_sfi_table(sfi_info, SFI_SIG_APIC); print_apic_table(sfi_info); sfi_info->mmap_table = get_sfi_table(sfi_info, SFI_SIG_MMAP); print_mmap_table(sfi_info); sfi_info->freq_table = get_sfi_table(sfi_info, SFI_SIG_FREQ); print_freq_table(sfi_info); sfi_info->mtmr_table = get_sfi_table(sfi_info, SFI_SIG_MTMR); print_mtmr_table(sfi_info); sfi_info->mrtc_table = get_sfi_table(sfi_info, SFI_SIG_MRTC); print_mrtc_table(sfi_info); sfi_info->wake_table = get_sfi_table(sfi_info, SFI_SIG_WAKE); print_wake_table(sfi_info); sfi_info->devs_table = get_sfi_table(sfi_info, SFI_SIG_DEVS); print_devs_table(sfi_info); sfi_info->gpio_table = get_sfi_table(sfi_info, SFI_SIG_GPIO); print_gpio_table(sfi_info); sfi_info->xsdt_table = get_sfi_table(sfi_info, SFI_SIG_XSDT); print_xsdt_table(sfi_info); return 0; }