| /* | |
| * Copyright 2019 Google Inc. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include "sim/kernel_workload.hh" | |
| #include "debug/Loader.hh" | |
| #include "params/KernelWorkload.hh" | |
| #include "sim/system.hh" | |
| namespace gem5 | |
| { | |
| KernelWorkload::KernelWorkload(const Params &p) : Workload(p), | |
| _loadAddrMask(p.load_addr_mask), _loadAddrOffset(p.load_addr_offset), | |
| commandLine(p.command_line) | |
| { | |
| if (params().object_file == "") { | |
| inform("No kernel set for full system simulation. " | |
| "Assuming you know what you're doing."); | |
| } else { | |
| kernelObj = loader::createObjectFile(params().object_file); | |
| inform("kernel located at: %s", params().object_file); | |
| fatal_if(!kernelObj, | |
| "Could not load kernel file %s", params().object_file); | |
| image = kernelObj->buildImage(); | |
| _start = image.minAddr(); | |
| _end = image.maxAddr(); | |
| // If load_addr_mask is set to 0x0, then calculate the smallest mask to | |
| // cover all kernel addresses so gem5 can relocate the kernel to a new | |
| // offset. | |
| if (_loadAddrMask == 0) | |
| _loadAddrMask = mask(findMsbSet(_end - _start) + 1); | |
| image.move([this](Addr a) { | |
| return (a & _loadAddrMask) + _loadAddrOffset; | |
| }); | |
| kernelSymtab = kernelObj->symtab(); | |
| auto initKernelSymtab = kernelSymtab.mask(_loadAddrMask) | |
| ->offset(_loadAddrOffset) | |
| ->rename([](std::string &name) { | |
| name = "kernel_init." + name; | |
| }); | |
| loader::debugSymbolTable.insert(*initKernelSymtab); | |
| loader::debugSymbolTable.insert(kernelSymtab); | |
| } | |
| // Loading only needs to happen once and after memory system is | |
| // connected so it will happen in initState() | |
| std::vector<Addr> extras_addrs = p.extras_addrs; | |
| if (extras_addrs.empty()) | |
| extras_addrs.resize(p.extras.size(), MaxAddr); | |
| fatal_if(p.extras.size() != extras_addrs.size(), | |
| "Additional kernel objects, not all load addresses specified\n"); | |
| for (int ker_idx = 0; ker_idx < p.extras.size(); ker_idx++) { | |
| const std::string &obj_name = p.extras[ker_idx]; | |
| const bool raw = extras_addrs[ker_idx] != MaxAddr; | |
| auto *obj = loader::createObjectFile(obj_name, raw); | |
| fatal_if(!obj, "Failed to build additional kernel object '%s'.\n", | |
| obj_name); | |
| extras.push_back(obj); | |
| } | |
| } | |
| void | |
| KernelWorkload::initState() | |
| { | |
| auto &phys_mem = system->physProxy; | |
| /** | |
| * Load the kernel code into memory. | |
| */ | |
| auto mapper = [this](Addr a) { | |
| return (a & _loadAddrMask) + _loadAddrOffset; | |
| }; | |
| if (params().object_file != "") { | |
| if (params().addr_check) { | |
| // Validate kernel mapping before loading binary | |
| fatal_if(!system->isMemAddr(mapper(_start)) || | |
| !system->isMemAddr(mapper(_end)), | |
| "Kernel is mapped to invalid location (not memory). " | |
| "start (%#x) - end (%#x) %#x:%#x\n", | |
| _start, _end, mapper(_start), mapper(_end)); | |
| } | |
| // Load program sections into memory | |
| image.write(phys_mem); | |
| DPRINTF(Loader, "Kernel start = %#x\n", _start); | |
| DPRINTF(Loader, "Kernel end = %#x\n", _end); | |
| DPRINTF(Loader, "Kernel entry = %#x\n", kernelObj->entryPoint()); | |
| DPRINTF(Loader, "Kernel loaded...\n"); | |
| } | |
| std::vector<Addr> extras_addrs = params().extras_addrs; | |
| if (extras_addrs.empty()) | |
| extras_addrs.resize(params().extras.size(), MaxAddr); | |
| for (int idx = 0; idx < extras.size(); idx++) { | |
| const Addr load_addr = extras_addrs[idx]; | |
| auto image = extras[idx]->buildImage(); | |
| if (load_addr != MaxAddr) | |
| image = image.offset(load_addr); | |
| else | |
| image = image.move(mapper); | |
| image.write(phys_mem); | |
| } | |
| } | |
| void | |
| KernelWorkload::serialize(CheckpointOut &cp) const | |
| { | |
| kernelSymtab.serialize("symtab", cp); | |
| } | |
| void | |
| KernelWorkload::unserialize(CheckpointIn &cp) | |
| { | |
| kernelSymtab.unserialize("symtab", cp); | |
| } | |
| } // namespace gem5 |