/* * \brief Platform implementation specific for hw * \author Martin Stein * \author Stefan Kalkowski * \date 2011-12-21 */ /* * Copyright (C) 2011-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ /* Genode includes */ #include /* core includes */ #include #include #include #include "map_local.h" #include #include #include #include #include "kernel/kernel.h" #include #include "kernel/cpu.h" /* base-internal includes */ #include #include using namespace Genode; /************** ** Platform ** **************/ Hw::Boot_info const & Platform::_boot_info() { return *reinterpret_cast*>(Hw::Mm::boot_info().base); } addr_t Platform::mmio_to_virt(addr_t mmio) { return _boot_info().mmio_space.virt_addr(mmio); } addr_t Platform::core_page_table() { return (addr_t)_boot_info().table; } Hw::Page_table::Allocator & Platform::core_page_table_allocator() { using Allocator = Hw::Page_table::Allocator; using Array = Allocator::Array; addr_t virt_addr = Hw::Mm::core_page_tables().base + sizeof(Hw::Page_table); return *unmanaged_singleton(_boot_info().table_allocator, virt_addr); } void Platform::_init_io_mem_alloc() { /* add entire adress space minus the RAM memory regions */ _io_mem_alloc.add_range(0, ~0x0UL); _boot_info().ram_regions.for_each([this] (Hw::Memory_region const &r) { _io_mem_alloc.remove_range(r.base, r.size); }); }; Hw::Memory_region_array const & Platform::_core_virt_regions() { return *unmanaged_singleton( Hw::Memory_region(stack_area_virtual_base(), stack_area_virtual_size())); } addr_t Platform::core_phys_addr(addr_t virt) { addr_t ret = 0; _boot_info().elf_mappings.for_each([&] (Hw::Mapping const & m) { if (virt >= m.virt() && virt < (m.virt() + m.size())) ret = (virt - m.virt()) + m.phys(); }); return ret; } addr_t Platform::_rom_module_phys(addr_t virt) { Hw::Mapping m = _boot_info().boot_modules; if (virt >= m.virt() && virt < (m.virt() + m.size())) return (virt - m.virt()) + m.phys(); return 0; } void Platform::_init_platform_info() { unsigned const pages = 1; size_t const rom_size = pages << get_page_size_log2(); void *phys_ptr = nullptr; void *virt_ptr = nullptr; const char *rom_name = "platform_info"; if (!ram_alloc().alloc(get_page_size(), &phys_ptr)) { error("could not setup platform_info ROM - ram allocation error"); return; } if (!region_alloc().alloc(rom_size, &virt_ptr)) { error("could not setup platform_info ROM - region allocation error"); ram_alloc().free(phys_ptr); return; } addr_t const phys_addr = reinterpret_cast(phys_ptr); addr_t const virt_addr = reinterpret_cast(virt_ptr); if (!map_local(phys_addr, virt_addr, pages, Hw::PAGE_FLAGS_KERN_DATA)) { error("could not setup platform_info ROM - map error"); region_alloc().free(virt_ptr); ram_alloc().free(phys_ptr); return; } Genode::Xml_generator xml(reinterpret_cast(virt_addr), rom_size, rom_name, [&] () { xml.node("kernel", [&] () { xml.attribute("name", "hw"); }); _init_additional_platform_info(xml); }); if (!unmap_local(virt_addr, pages)) { error("could not setup platform_info ROM - unmap error"); return; } region_alloc().free(virt_ptr); _rom_fs.insert( new (core_mem_alloc()) Rom_module(phys_addr, rom_size, rom_name)); } Platform::Platform() : _io_mem_alloc(&core_mem_alloc()), _io_port_alloc(&core_mem_alloc()), _irq_alloc(&core_mem_alloc()) { struct Kernel_resource : Exception { }; _core_mem_alloc.virt_alloc().add_range(Hw::Mm::core_heap().base, Hw::Mm::core_heap().size); _core_virt_regions().for_each([this] (Hw::Memory_region const & r) { _core_mem_alloc.virt_alloc().remove_range(r.base, r.size); }); _boot_info().elf_mappings.for_each([this] (Hw::Mapping const & m) { _core_mem_alloc.virt_alloc().remove_range(m.virt(), m.size()); }); _boot_info().ram_regions.for_each([this] (Hw::Memory_region const & region) { _core_mem_alloc.phys_alloc().add_range(region.base, region.size); }); _init_io_port_alloc(); /* make all non-kernel interrupts available to the interrupt allocator */ for (unsigned i = 0; i < Board::Pic::NR_OF_IRQ; i++) { bool kernel_resource = false; Kernel::cpu_pool().for_each_cpu([&] (Kernel::Cpu & cpu) { if (i == cpu.timer().interrupt_id()) { kernel_resource = true; } }); if (i == Board::Pic::IPI) { kernel_resource = true; } if (kernel_resource) { continue; } _irq_alloc.add_range(i, 1); } _init_io_mem_alloc(); _init_rom_modules(); _init_platform_info(); /* core log as ROM module */ { void * core_local_ptr = nullptr; void * phys_ptr = nullptr; unsigned const pages = 1; size_t const log_size = pages << get_page_size_log2(); ram_alloc().alloc_aligned(log_size, &phys_ptr, get_page_size_log2()); addr_t const phys_addr = reinterpret_cast(phys_ptr); /* let one page free after the log buffer */ region_alloc().alloc_aligned(log_size, &core_local_ptr, get_page_size_log2()); addr_t const core_local_addr = reinterpret_cast(core_local_ptr); map_local(phys_addr, core_local_addr, pages); memset(core_local_ptr, 0, log_size); _rom_fs.insert(new (core_mem_alloc()) Rom_module(phys_addr, log_size, "core_log")); init_core_log(Core_log_range { core_local_addr, log_size } ); } log(_rom_fs); } /**************************************** ** Support for core memory management ** ****************************************/ bool Genode::map_local(addr_t from_phys, addr_t to_virt, size_t num_pages, Page_flags flags) { Platform_pd &pd = Kernel::core_pd().platform_pd(); return pd.insert_translation(to_virt, from_phys, num_pages * get_page_size(), flags); } bool Genode::unmap_local(addr_t virt_addr, size_t num_pages) { Platform_pd &pd = Kernel::core_pd().platform_pd(); pd.flush(virt_addr, num_pages * get_page_size()); return true; } bool Mapped_mem_allocator::_map_local(addr_t virt_addr, addr_t phys_addr, unsigned size) { return ::map_local(phys_addr, virt_addr, size / get_page_size()); } bool Mapped_mem_allocator::_unmap_local(addr_t virt_addr, addr_t, unsigned size) { return ::unmap_local(virt_addr, size / get_page_size()); }