/* * Initialize page allocator. * page_init() must be called prior to other memory manager's * initializations. */ void page_init(void) { struct physmem *ram; int i; total_size = 0; bootdisk_size = 0; page_head.next = page_head.prev = &page_head; /* * First, create a free list from the boot information. */ for (i = 0; i < bootinfo->nr_rams; i++) { ram = &bootinfo->ram[i]; if (ram->type == MT_USABLE) { page_free((void *)ram->base, ram->size); total_size += ram->size; } } /* * Then, reserve un-usable memory. */ for (i = 0; i < bootinfo->nr_rams; i++) { ram = &bootinfo->ram[i]; switch (ram->type) { case MT_BOOTDISK: bootdisk_size = ram->size; /* FALLTHROUGH */ case MT_MEMHOLE: total_size -= ram->size; /* FALLTHROUGH */ case MT_RESERVED: page_reserve((void *)ram->base, ram->size); break; } } #ifdef DEBUG page_dump(); #endif }
// The main function int init(unsigned long magic, multiboot_info_t* hdr) { setGDT(); init_heap(); #ifdef SLAB slab_alloc_init(); #endif textInit(); /** * \todo Make complement_heap so that it allocates memory from pte */ complement_heap(&end, HEAPSIZE); addr_t tmp = (addr_t)hdr + offset; hdr = (multiboot_info_t*)tmp; if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { printf("\nInvalid magic word: %X\n", magic); panic(""); } if (hdr->flags & MULTIBOOT_INFO_MEMORY) { memsize = hdr->mem_upper; memsize += 1024; } else panic("No memory flags!"); if (!(hdr->flags & MULTIBOOT_INFO_MEM_MAP)) panic("Invalid memory map"); mmap = (multiboot_memory_map_t*) hdr->mmap_addr; /** Build the memory map and allow for allocation */ x86_pte_init(); page_alloc_init(mmap, (unsigned int)hdr->mmap_length); vm_init(); #ifdef PA_DBG // endProg(); #endif /** In the progress of phasing out */ /** Set up paging administration */ x86_page_init(memsize); mboot_page_setup(mmap, (uint32_t)hdr->mmap_length); mboot_map_modules((void*)hdr->mods_addr, hdr->mods_count); /** For now this is the temporary page table map */ build_map(mmap, (unsigned int) hdr->mmap_length); /** end of deprication */ task_init(); page_init(); printf(WELCOME); // The only screen output that should be maintained page_unmap_low_mem(); pic_init(); setIDT(); setup_irq_data(); if (dev_init() != -E_SUCCESS) panic("Couldn't initialise /dev"); ol_pit_init(1024); // program pic to 1024 hertz debug("Size of the heap: 0x%x\tStarting at: %x\n", HEAPSIZE, heap); acpi_init(); ol_cpu_t cpu = kalloc(sizeof (*cpu)); if (cpu == NULL) panic("OUT OF MEMORY!"); ol_cpu_init(cpu); ol_ps2_init_keyboard(); ol_apic_init(cpu); init_ioapic(); ol_pci_init(); debug("Little endian 0xf in net endian %x\n", htons(0xf)); #ifdef DBG #ifdef __IOAPIC_DBG ioapic_debug(); #endif #ifdef __MEMTEST ol_detach_all_devices(); /* free's al the pci devices */ #endif #ifdef __DBG_HEAP printf("Heap list:\n"); ol_dbg_heap(); #endif printf("\nSome (temp) debug info:\n"); printf("CPU vendor: %s\n", cpus->vendor); if(systables->magic == SYS_TABLE_MAGIC) { printf("RSDP ASCII signature: 0x%x%x\n", *(((uint32_t*) systables->rsdp->signature) + 1), *(((uint32_t*) systables->rsdp->signature))); printf("MP specification signature: 0x%x\n", systables->mp->signature); } #endif #ifdef PA_DBG addr_t p = (addr_t)page_alloc(); page_free((void*)p); printf("Allocated: %X\n", p); page_dump(); #endif #ifdef PA_DBG addr_t p = (addr_t)page_alloc(); page_free((void*)p); printf("Allocated: %X\n", p); page_dump(); #endif core_loop(); return 0; // To keep the compiler happy. }
/* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset) { abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; unsigned long host_start; mmap_lock(); #ifdef DEBUG_MMAP { printf("mmap: start=0x" TARGET_FMT_lx " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', prot & PROT_EXEC ? 'x' : '-'); if (flags & MAP_FIXED) printf("MAP_FIXED "); if (flags & MAP_ANONYMOUS) printf("MAP_ANON "); switch(flags & MAP_TYPE) { case MAP_PRIVATE: printf("MAP_PRIVATE "); break; case MAP_SHARED: printf("MAP_SHARED "); break; default: printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); break; } printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset); } #endif if (offset & ~TARGET_PAGE_MASK) { errno = EINVAL; goto fail; } len = TARGET_PAGE_ALIGN(len); if (len == 0) goto the_end; real_start = start & qemu_host_page_mask; if (!(flags & MAP_FIXED)) { abi_ulong mmap_start; void *p; host_offset = offset & qemu_host_page_mask; host_len = len + offset - host_offset; host_len = HOST_PAGE_ALIGN(host_len); mmap_start = mmap_find_vma(real_start, host_len); if (mmap_start == (abi_ulong)-1) { errno = ENOMEM; goto fail; } /* Note: we prefer to control the mapping address. It is especially important if qemu_host_page_size > qemu_real_host_page_size */ p = mmap(g2h(mmap_start), host_len, prot, flags | MAP_FIXED, fd, host_offset); if (p == MAP_FAILED) goto fail; /* update start so that it points to the file position at 'offset' */ host_start = (unsigned long)p; if (!(flags & MAP_ANONYMOUS)) host_start += offset - host_offset; start = h2g(host_start); } else { int flg; target_ulong addr; if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; goto fail; } end = start + len; real_end = HOST_PAGE_ALIGN(end); /* * Test if requested memory area fits target address space * It can fail only on 64-bit host with 32-bit target. * On any other target/host host mmap() handles this error correctly. */ if ((unsigned long)start + len - 1 > (abi_ulong) -1) { errno = EINVAL; goto fail; } for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { flg = page_get_flags(addr); if (flg & PAGE_RESERVED) { errno = ENXIO; goto fail; } } /* worst case: we cannot map the file because the offset is not aligned, so we read it */ if (!(flags & MAP_ANONYMOUS) && (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { /* msync() won't work here, so we return an error if write is possible while it is a shared mapping */ if ((flags & MAP_TYPE) == MAP_SHARED && (prot & PROT_WRITE)) { errno = EINVAL; goto fail; } retaddr = target_mmap(start, len, prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (retaddr == -1) goto fail; pread(fd, g2h(start), len, offset); if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); if (ret != 0) { start = ret; goto the_end; } } goto the_end; } /* handle the start of the mapping */ if (start > real_start) { if (real_end == real_start + qemu_host_page_size) { /* one single host page */ ret = mmap_frag(real_start, start, end, prot, flags, fd, offset); if (ret == -1) goto fail; goto the_end1; } ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, prot, flags, fd, offset); if (ret == -1) goto fail; real_start += qemu_host_page_size; } /* handle the end of the mapping */ if (end < real_end) { ret = mmap_frag(real_end - qemu_host_page_size, real_end - qemu_host_page_size, real_end, prot, flags, fd, offset + real_end - qemu_host_page_size - start); if (ret == -1) goto fail; real_end -= qemu_host_page_size; } /* map the middle (easier) */ if (real_start < real_end) { void *p; unsigned long offset1; if (flags & MAP_ANONYMOUS) offset1 = 0; else offset1 = offset + real_start - start; p = mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (p == MAP_FAILED) goto fail; } } the_end1: page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP printf("ret=0x" TARGET_FMT_lx "\n", start); page_dump(stdout); printf("\n"); #endif mmap_unlock(); return start; fail: mmap_unlock(); return -1; }
static void do_export (vbi_pgno pgno, vbi_subno subno, double timestamp) { vbi_page *pg; vbi_bool success; if (option_delay > 1) { --option_delay; return; } if (pgno >= 0x100) { if (0 != option_override_cs) { pg = vbi_decoder_get_page (vbi, NULL /* current network */, pgno, subno, VBI_HEADER_ONLY, option_header_only, VBI_PADDING, option_padding, VBI_PANELS, option_panels, VBI_NAVIGATION, option_navigation, VBI_HYPERLINKS, option_hyperlinks, VBI_PDC_LINKS, option_pdc_links, VBI_WST_LEVEL, VBI_WST_LEVEL_3p5, VBI_OVERRIDE_CHARSET_0, option_override_cs, VBI_END); } else { pg = vbi_decoder_get_page (vbi, NULL /* current network */, pgno, subno, VBI_HEADER_ONLY, option_header_only, VBI_PADDING, option_padding, VBI_PANELS, option_panels, VBI_NAVIGATION, option_navigation, VBI_HYPERLINKS, option_hyperlinks, VBI_PDC_LINKS, option_pdc_links, VBI_WST_LEVEL, VBI_WST_LEVEL_3p5, VBI_DEFAULT_CHARSET_0, option_default_cs, VBI_END); } } else { pg = vbi_decoder_get_page (vbi, NULL /* current network */, pgno, subno, VBI_PADDING, option_padding, VBI_DEFAULT_FOREGROUND, option_default_fg, VBI_DEFAULT_BACKGROUND, option_default_bg, VBI_ROW_CHANGE, option_row_update, VBI_END); } assert (NULL != pg); if (option_dump_pg) { page_dump (pg); } switch (option_target) { char *file_name; void *buffer; void *buffer2; FILE *fp; size_t size; ssize_t ssize; case 1: buffer = malloc (1 << 20); if (NULL == buffer) no_mem_exit (); ssize = vbi_export_mem (ex, buffer, 1 << 20, pg); success = (ssize >= 0); if (success) { ssize_t ssize2; fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, ssize, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); /* Test. */ ssize2 = vbi_export_mem (ex, buffer, 0, pg); assert (ssize == ssize2); assert (ssize > 0); ssize2 = vbi_export_mem (ex, buffer, ssize - 1, pg); assert (ssize == ssize2); } free (buffer); break; case 2: buffer = NULL; buffer2 = vbi_export_alloc (ex, &buffer, &size, pg); /* Test. */ assert (buffer == buffer2); success = (NULL != buffer); if (success) { fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, size, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); free (buffer); } break; case 3: /* This is the default target. The other cases are only implemented for tests and will be removed when I wrote proper unit tests. */ fp = open_output_file (pgno, subno); /* For proper timing of subtitles. */ vbi_export_set_timestamp (ex, timestamp); success = vbi_export_stdio (ex, fp, pg); close_output_file (fp); break; case 5: file_name = output_file_name (pgno, subno); success = vbi_export_file (ex, file_name, pg); free (file_name); break; default: error_exit ("Invalid target %u.", option_target); break; } if (!success) { error_exit (_("Export of page %x failed: %s"), pgno, vbi_export_errstr (ex)); } if (option_pdc_enum) { pdc_dump (pg); } vbi_page_delete (pg); pg = NULL; }
static void do_export (vbi_pgno pgno, vbi_subno subno) { vbi_page page; vbi_bool success; if (option_delay > 1) { --option_delay; return; } success = vbi_fetch_vt_page (vbi, &page, pgno, subno, VBI_WST_LEVEL_3p5, /* n_rows */ 25, /* navigation */ TRUE); if (!success) { /* Shouldn't happen. */ error_exit (_("Unknown error.")); } if (option_dump_pg) { page_dump (&page); } switch (option_target) { char *file_name; void *buffer; void *buffer2; FILE *fp; size_t size; ssize_t ssize; case 1: buffer = malloc (1 << 20); if (NULL == buffer) no_mem_exit (); ssize = vbi_export_mem (ex, buffer, 1 << 20, &page); success = (ssize >= 0); if (success) { ssize_t ssize2; fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, ssize, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); /* Test. */ ssize2 = vbi_export_mem (ex, buffer, 0, &page); assert (ssize == ssize2); assert (ssize > 0); ssize2 = vbi_export_mem (ex, buffer, ssize - 1, &page); assert (ssize == ssize2); } free (buffer); break; case 2: buffer = NULL; buffer2 = vbi_export_alloc (ex, &buffer, &size, &page); /* Test. */ assert (buffer == buffer2); success = (NULL != buffer); if (success) { fp = open_output_file (pgno, subno); if (1 != fwrite (buffer, size, 1, fp)) write_error_exit (/* msg: errno */ NULL); close_output_file (fp); free (buffer); } break; case 3: /* This is the default target. The other cases are only implemented for tests and will be removed when I wrote proper unit tests. */ fp = open_output_file (pgno, subno); success = vbi_export_stdio (ex, fp, &page); close_output_file (fp); break; case 5: file_name = output_file_name (pgno, subno); success = vbi_export_file (ex, file_name, &page); free (file_name); break; default: error_exit ("Invalid target %u.", option_target); break; } if (!success) { error_exit (_("Export of page %x failed: %s"), pgno, vbi_export_errstr (ex)); } vbi_unref_page (&page); }
/* NOTE: all the constants are the HOST ones */ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, int flags, int fd, abi_ulong offset) { abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; mmap_lock(); #ifdef DEBUG_MMAP { printf("mmap: start=0x" TARGET_ABI_FMT_lx " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c flags=", start, len, prot & PROT_READ ? 'r' : '-', prot & PROT_WRITE ? 'w' : '-', prot & PROT_EXEC ? 'x' : '-'); if (flags & MAP_FIXED) printf("MAP_FIXED "); if (flags & MAP_ANONYMOUS) printf("MAP_ANON "); switch(flags & MAP_TYPE) { case MAP_PRIVATE: printf("MAP_PRIVATE "); break; case MAP_SHARED: printf("MAP_SHARED "); break; default: printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); break; } printf("fd=%d offset=" TARGET_ABI_FMT_lx "\n", fd, offset); } #endif if (offset & ~TARGET_PAGE_MASK) { errno = EINVAL; goto fail; } len = TARGET_PAGE_ALIGN(len); if (len == 0) goto the_end; real_start = start & qemu_host_page_mask; host_offset = offset & qemu_host_page_mask; /* If the user is asking for the kernel to find a location, do that before we truncate the length for mapping files below. */ if (!(flags & MAP_FIXED)) { host_len = len + offset - host_offset; host_len = HOST_PAGE_ALIGN(host_len); start = mmap_find_vma(real_start, host_len); if (start == (abi_ulong)-1) { errno = ENOMEM; goto fail; } } /* When mapping files into a memory area larger than the file, accesses to pages beyond the file size will cause a SIGBUS. For example, if mmaping a file of 100 bytes on a host with 4K pages emulating a target with 8K pages, the target expects to be able to access the first 8K. But the host will trap us on any access beyond 4K. When emulating a target with a larger page-size than the hosts, we may need to truncate file maps at EOF and add extra anonymous pages up to the targets page boundary. */ if ((qemu_real_host_page_size < TARGET_PAGE_SIZE) && !(flags & MAP_ANONYMOUS)) { struct stat sb; if (fstat (fd, &sb) == -1) goto fail; /* Are we trying to create a map beyond EOF?. */ if (offset + len > sb.st_size) { /* If so, truncate the file map at eof aligned with the hosts real pagesize. Additional anonymous maps will be created beyond EOF. */ len = (sb.st_size - offset); len += qemu_real_host_page_size - 1; len &= ~(qemu_real_host_page_size - 1); } } if (!(flags & MAP_FIXED)) { unsigned long host_start; void *p; host_len = len + offset - host_offset; host_len = HOST_PAGE_ALIGN(host_len); /* Note: we prefer to control the mapping address. It is especially important if qemu_host_page_size > qemu_real_host_page_size */ p = mmap(g2h(start), host_len, prot, flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) goto fail; /* update start so that it points to the file position at 'offset' */ host_start = (unsigned long)p; if (!(flags & MAP_ANONYMOUS)) { p = mmap(g2h(start), len, prot, flags | MAP_FIXED, fd, host_offset); if (p == MAP_FAILED) { munmap(g2h(start), host_len); goto fail; } host_start += offset - host_offset; } start = h2g(host_start); } else { if (start & ~TARGET_PAGE_MASK) { errno = EINVAL; goto fail; } end = start + len; real_end = HOST_PAGE_ALIGN(end); /* * Test if requested memory area fits target address space * It can fail only on 64-bit host with 32-bit target. * On any other target/host host mmap() handles this error correctly. */ if ((unsigned long)start + len - 1 > (abi_ulong) -1) { errno = EINVAL; goto fail; } /* worst case: we cannot map the file because the offset is not aligned, so we read it */ if (!(flags & MAP_ANONYMOUS) && (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { /* msync() won't work here, so we return an error if write is possible while it is a shared mapping */ if ((flags & MAP_TYPE) == MAP_SHARED && (prot & PROT_WRITE)) { errno = EINVAL; goto fail; } retaddr = target_mmap(start, len, prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (retaddr == -1) goto fail; if (pread(fd, g2h(start), len, offset) == -1) goto fail; if (!(prot & PROT_WRITE)) { ret = target_mprotect(start, len, prot); if (ret != 0) { start = ret; goto the_end; } } goto the_end; } /* handle the start of the mapping */ if (start > real_start) { if (real_end == real_start + qemu_host_page_size) { /* one single host page */ ret = mmap_frag(real_start, start, end, prot, flags, fd, offset); if (ret == -1) goto fail; goto the_end1; } ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, prot, flags, fd, offset); if (ret == -1) goto fail; real_start += qemu_host_page_size; } /* handle the end of the mapping */ if (end < real_end) { ret = mmap_frag(real_end - qemu_host_page_size, real_end - qemu_host_page_size, real_end, prot, flags, fd, offset + real_end - qemu_host_page_size - start); if (ret == -1) goto fail; real_end -= qemu_host_page_size; } /* map the middle (easier) */ if (real_start < real_end) { void *p; unsigned long offset1; if (flags & MAP_ANONYMOUS) offset1 = 0; else offset1 = offset + real_start - start; p = mmap(g2h(real_start), real_end - real_start, prot, flags, fd, offset1); if (p == MAP_FAILED) goto fail; } } the_end1: page_set_flags(start, start + len, prot | PAGE_VALID); the_end: #ifdef DEBUG_MMAP printf("ret=0x" TARGET_ABI_FMT_lx "\n", start); page_dump(stdout); printf("\n"); #endif tb_invalidate_phys_range(start, start + len); mmap_unlock(); return start; fail: mmap_unlock(); return -1; }