system.cc revision 885
112952Sgabeblack@google.com/* 212952Sgabeblack@google.com * Copyright (c) 2003 The Regents of The University of Michigan 312952Sgabeblack@google.com * All rights reserved. 412952Sgabeblack@google.com * 512952Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 612952Sgabeblack@google.com * modification, are permitted provided that the following conditions are 712952Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 812952Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 912952Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1012952Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1112952Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1212952Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1312952Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1412952Sgabeblack@google.com * this software without specific prior written permission. 1512952Sgabeblack@google.com * 1612952Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712952Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812952Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912952Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012952Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112952Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212952Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312952Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412952Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512952Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612952Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712952Sgabeblack@google.com */ 2812952Sgabeblack@google.com 2912952Sgabeblack@google.com/** 3012952Sgabeblack@google.com * @file 3112957Sgabeblack@google.com * linux_system.cc loads the linux kernel, console, pal and patches certain functions. 3212957Sgabeblack@google.com * The symbol tables are loaded so that traces can show the executing function and we can 3312957Sgabeblack@google.com * skip functions. Various delay loops are skipped and their final values manually computed to 3413288Sgabeblack@google.com * speed up boot time. 3512953Sgabeblack@google.com */ 3613196Sgabeblack@google.com 3713102Sgabeblack@google.com#include "base/loader/aout_object.hh" 3812998Sgabeblack@google.com#include "base/loader/elf_object.hh" 3912998Sgabeblack@google.com#include "base/loader/object_file.hh" 4012952Sgabeblack@google.com#include "base/loader/symtab.hh" 4112952Sgabeblack@google.com#include "base/remote_gdb.hh" 4212952Sgabeblack@google.com#include "base/trace.hh" 4312952Sgabeblack@google.com#include "cpu/exec_context.hh" 4412952Sgabeblack@google.com#include "cpu/base_cpu.hh" 4512952Sgabeblack@google.com#include "kern/linux/linux_events.hh" 4612952Sgabeblack@google.com#include "kern/linux/linux_system.hh" 4712995Sgabeblack@google.com#include "kern/system_events.hh" 4812952Sgabeblack@google.com#include "mem/functional_mem/memory_control.hh" 4912952Sgabeblack@google.com#include "mem/functional_mem/physical_memory.hh" 5012952Sgabeblack@google.com#include "sim/builder.hh" 5112952Sgabeblack@google.com#include "dev/platform.hh" 5212952Sgabeblack@google.com#include "targetarch/isa_traits.hh" 5312995Sgabeblack@google.com#include "targetarch/vtophys.hh" 5412952Sgabeblack@google.com 5512952Sgabeblack@google.comextern SymbolTable *debugSymbolTable; 5612952Sgabeblack@google.com 5712952Sgabeblack@google.comusing namespace std; 5812952Sgabeblack@google.com 5912952Sgabeblack@google.comLinuxSystem::LinuxSystem(const string _name, const uint64_t _init_param, 6012952Sgabeblack@google.com MemoryController *_memCtrl, PhysicalMemory *_physmem, 6112952Sgabeblack@google.com const string &kernel_path, const string &console_path, 6212952Sgabeblack@google.com const string &palcode, const string &boot_osflags, 6312952Sgabeblack@google.com const bool _bin, const vector<string> &_binned_fns) 6412952Sgabeblack@google.com : System(_name, _init_param, _memCtrl, _physmem, _bin, _binned_fns), 6512952Sgabeblack@google.com bin(_bin), binned_fns(_binned_fns) 6612952Sgabeblack@google.com{ 6712952Sgabeblack@google.com kernelSymtab = new SymbolTable; 6812952Sgabeblack@google.com consoleSymtab = new SymbolTable; 6912952Sgabeblack@google.com 7012952Sgabeblack@google.com /** 7112952Sgabeblack@google.com * Load the kernel, pal, and console code into memory 7212952Sgabeblack@google.com */ 7312952Sgabeblack@google.com // Load kernel code 7412952Sgabeblack@google.com ObjectFile *kernel = createObjectFile(kernel_path); 7512952Sgabeblack@google.com if (kernel == NULL) 7612952Sgabeblack@google.com fatal("Could not load kernel file %s", kernel_path); 7712952Sgabeblack@google.com 7812952Sgabeblack@google.com // Load Console Code 7912952Sgabeblack@google.com ObjectFile *console = createObjectFile(console_path); 8012952Sgabeblack@google.com if (console == NULL) 8112952Sgabeblack@google.com fatal("Could not load console file %s", console_path); 8212952Sgabeblack@google.com 8312952Sgabeblack@google.com // Load pal file 8412952Sgabeblack@google.com ObjectFile *pal = createObjectFile(palcode); 8512952Sgabeblack@google.com if (pal == NULL) 8613133Sgabeblack@google.com fatal("Could not load PALcode file %s", palcode); 8712952Sgabeblack@google.com pal->loadSections(physmem, true); 8813133Sgabeblack@google.com 8913133Sgabeblack@google.com // Load console file 9013133Sgabeblack@google.com console->loadSections(physmem, true); 9113133Sgabeblack@google.com 9213133Sgabeblack@google.com // Load kernel file 9313133Sgabeblack@google.com kernel->loadSections(physmem, true); 9413133Sgabeblack@google.com kernelStart = kernel->textBase(); 9513133Sgabeblack@google.com kernelEnd = kernel->bssBase() + kernel->bssSize(); 9612952Sgabeblack@google.com kernelEntry = kernel->entryPoint(); 9712952Sgabeblack@google.com 9812952Sgabeblack@google.com // load symbols 9912952Sgabeblack@google.com if (!kernel->loadGlobalSymbols(kernelSymtab)) 10012952Sgabeblack@google.com panic("could not load kernel symbols\n"); 10112952Sgabeblack@google.com debugSymbolTable = kernelSymtab; 10212952Sgabeblack@google.com 10312952Sgabeblack@google.com if (!kernel->loadLocalSymbols(kernelSymtab)) 10412952Sgabeblack@google.com panic("could not load kernel local symbols\n"); 10512952Sgabeblack@google.com 10612952Sgabeblack@google.com if (!console->loadGlobalSymbols(consoleSymtab)) 10712959Sgabeblack@google.com panic("could not load console symbols\n"); 10813133Sgabeblack@google.com 10912959Sgabeblack@google.com DPRINTF(Loader, "Kernel start = %#x\n" 11012952Sgabeblack@google.com "Kernel end = %#x\n" 11112952Sgabeblack@google.com "Kernel entry = %#x\n", 11212952Sgabeblack@google.com kernelStart, kernelEnd, kernelEntry); 11312952Sgabeblack@google.com 11412952Sgabeblack@google.com DPRINTF(Loader, "Kernel loaded...\n"); 11512952Sgabeblack@google.com 11612952Sgabeblack@google.com 11712952Sgabeblack@google.com#ifdef DEBUG 11812952Sgabeblack@google.com kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic"); 11912999Sgabeblack@google.com consolePanicEvent = new BreakPCEvent(&pcEventQueue, "console panic"); 12013206Sgabeblack@google.com#endif 12112999Sgabeblack@google.com 12212999Sgabeblack@google.com skipIdeDelay50msEvent = new SkipFuncEvent(&pcEventQueue, 12312999Sgabeblack@google.com "ide_delay_50ms"); 12412999Sgabeblack@google.com 12512999Sgabeblack@google.com skipDelayLoopEvent = new LinuxSkipDelayLoopEvent(&pcEventQueue, 12612999Sgabeblack@google.com "calibrate_delay"); 12712952Sgabeblack@google.com 12812952Sgabeblack@google.com skipCacheProbeEvent = new SkipFuncEvent(&pcEventQueue, 12912952Sgabeblack@google.com "determine_cpu_caches"); 13012952Sgabeblack@google.com 13112952Sgabeblack@google.com Addr addr = 0; 13212952Sgabeblack@google.com 13312952Sgabeblack@google.com /** 13412952Sgabeblack@google.com * find the address of the est_cycle_freq variable and insert it so we don't 13512952Sgabeblack@google.com * through the lengthly process of trying to calculated it by using the PIT, 13612952Sgabeblack@google.com * RTC, etc. 13712952Sgabeblack@google.com */ 13812952Sgabeblack@google.com if (kernelSymtab->findAddress("est_cycle_freq", addr)) { 13912952Sgabeblack@google.com Addr paddr = vtophys(physmem, addr); 14012952Sgabeblack@google.com uint8_t *est_cycle_frequency = 14112952Sgabeblack@google.com physmem->dma_addr(paddr, sizeof(uint64_t)); 14212952Sgabeblack@google.com 14313102Sgabeblack@google.com if (est_cycle_frequency) 14413102Sgabeblack@google.com *(uint64_t *)est_cycle_frequency = ticksPerSecond; 14513102Sgabeblack@google.com } 14613102Sgabeblack@google.com 14713102Sgabeblack@google.com 14813102Sgabeblack@google.com /** 14912952Sgabeblack@google.com * Copy the osflags (kernel arguments) into the consoles memory. Presently 15012952Sgabeblack@google.com * Linux does use the console service routine to get these command line 15112952Sgabeblack@google.com * arguments, but we might as well make them available just in case. 15212952Sgabeblack@google.com */ 15312952Sgabeblack@google.com if (consoleSymtab->findAddress("env_booted_osflags", addr)) { 15412952Sgabeblack@google.com Addr paddr = vtophys(physmem, addr); 15512952Sgabeblack@google.com char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t)); 15612952Sgabeblack@google.com 15712995Sgabeblack@google.com if (osflags) 15812998Sgabeblack@google.com strcpy(osflags, boot_osflags.c_str()); 15912995Sgabeblack@google.com } 16012995Sgabeblack@google.com 16112998Sgabeblack@google.com /** 16212998Sgabeblack@google.com * Since we aren't using a bootloader, we have to copy the kernel arguments 16312998Sgabeblack@google.com * directly into the kernels memory. 16412998Sgabeblack@google.com */ 16512998Sgabeblack@google.com { 16612998Sgabeblack@google.com Addr paddr = vtophys(physmem, PARAM_ADDR); 16712952Sgabeblack@google.com char *commandline = (char*)physmem->dma_addr(paddr, sizeof(uint64_t)); 16812952Sgabeblack@google.com if (commandline) 16912952Sgabeblack@google.com strcpy(commandline, boot_osflags.c_str()); 17012952Sgabeblack@google.com } 17112952Sgabeblack@google.com 17213102Sgabeblack@google.com 17313102Sgabeblack@google.com /** 17413102Sgabeblack@google.com * Set the hardware reset parameter block system type and revision information 17513102Sgabeblack@google.com * to Tsunami. 17613102Sgabeblack@google.com */ 17713102Sgabeblack@google.com if (consoleSymtab->findAddress("xxm_rpb", addr)) { 17812952Sgabeblack@google.com Addr paddr = vtophys(physmem, addr); 17912952Sgabeblack@google.com char *hwprb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); 18012952Sgabeblack@google.com 18112952Sgabeblack@google.com if (hwprb) { 18212952Sgabeblack@google.com *(uint64_t*)(hwprb+0x50) = 34; // Tsunami 18312952Sgabeblack@google.com *(uint64_t*)(hwprb+0x58) = (1<<10); // Plain DP264 18412952Sgabeblack@google.com } 18512952Sgabeblack@google.com else 18612995Sgabeblack@google.com panic("could not translate hwprb addr to set system type/variation\n"); 18713261Sgabeblack@google.com 18813261Sgabeblack@google.com } else 18912998Sgabeblack@google.com panic("could not find hwprb to set system type/variation\n"); 19012998Sgabeblack@google.com 19112998Sgabeblack@google.com#ifdef DEBUG 19212998Sgabeblack@google.com if (kernelSymtab->findAddress("panic", addr)) 19312998Sgabeblack@google.com kernelPanicEvent->schedule(addr); 19412998Sgabeblack@google.com else 19512952Sgabeblack@google.com panic("could not find kernel symbol \'panic\'"); 19612952Sgabeblack@google.com 19712952Sgabeblack@google.com if (consoleSymtab->findAddress("panic", addr)) 19812952Sgabeblack@google.com consolePanicEvent->schedule(addr); 19912952Sgabeblack@google.com#endif 20013102Sgabeblack@google.com 20113102Sgabeblack@google.com /** 20213102Sgabeblack@google.com * Any time ide_delay_50ms, calibarte_delay or determine_cpu_caches is called 20313102Sgabeblack@google.com * just skip the function. Currently determine_cpu_caches only is used put 20413102Sgabeblack@google.com * information in proc, however if that changes in the future we will have to 20513102Sgabeblack@google.com * fill in the cache size variables appropriately. 20612952Sgabeblack@google.com */ 20712952Sgabeblack@google.com if (kernelSymtab->findAddress("ide_delay_50ms", addr)) 20812998Sgabeblack@google.com skipIdeDelay50msEvent->schedule(addr+sizeof(MachInst)); 20913307Sgabeblack@google.com 21013307Sgabeblack@google.com if (kernelSymtab->findAddress("calibrate_delay", addr)) 21113307Sgabeblack@google.com skipDelayLoopEvent->schedule(addr+sizeof(MachInst)); 21213307Sgabeblack@google.com 21313306Sgabeblack@google.com if (kernelSymtab->findAddress("determine_cpu_caches", addr)) 21413307Sgabeblack@google.com skipCacheProbeEvent->schedule(addr+sizeof(MachInst)); 21513306Sgabeblack@google.com} 21613306Sgabeblack@google.com 21712952Sgabeblack@google.comLinuxSystem::~LinuxSystem() 21812952Sgabeblack@google.com{ 21912952Sgabeblack@google.com delete kernel; 22012952Sgabeblack@google.com delete console; 22112952Sgabeblack@google.com 22212952Sgabeblack@google.com delete kernelSymtab; 22312995Sgabeblack@google.com delete consoleSymtab; 22412952Sgabeblack@google.com 22512952Sgabeblack@google.com delete kernelPanicEvent; 22612952Sgabeblack@google.com delete consolePanicEvent; 22712952Sgabeblack@google.com delete skipIdeDelay50msEvent; 22812952Sgabeblack@google.com delete skipDelayLoopEvent; 22912952Sgabeblack@google.com delete skipCacheProbeEvent; 23012952Sgabeblack@google.com} 23112952Sgabeblack@google.com 23212952Sgabeblack@google.com 23312952Sgabeblack@google.comvoid 23412952Sgabeblack@google.comLinuxSystem::setDelayLoop(ExecContext *xc) 23512952Sgabeblack@google.com{ 23612952Sgabeblack@google.com Addr addr = 0; 23712952Sgabeblack@google.com if (kernelSymtab->findAddress("loops_per_jiffy", addr)) { 23812952Sgabeblack@google.com Addr paddr = vtophys(physmem, addr); 23912952Sgabeblack@google.com 24012952Sgabeblack@google.com uint8_t *loops_per_jiffy = 24112952Sgabeblack@google.com physmem->dma_addr(paddr, sizeof(uint32_t)); 24212952Sgabeblack@google.com 24312952Sgabeblack@google.com Tick cpuFreq = xc->cpu->getFreq(); 24412952Sgabeblack@google.com Tick intrFreq = platform->interrupt_frequency; 24513260Sgabeblack@google.com *(uint32_t *)loops_per_jiffy = 24613260Sgabeblack@google.com (uint32_t)((cpuFreq / intrFreq) * 0.9988); 24713260Sgabeblack@google.com } 24813260Sgabeblack@google.com} 24913260Sgabeblack@google.com 25013260Sgabeblack@google.comint 25113260Sgabeblack@google.comLinuxSystem::registerExecContext(ExecContext *xc) 25213260Sgabeblack@google.com{ 25313260Sgabeblack@google.com int xcIndex = System::registerExecContext(xc); 25413260Sgabeblack@google.com 25513260Sgabeblack@google.com if (xcIndex == 0) { 25613260Sgabeblack@google.com // activate with zero delay so that we start ticking right 25713260Sgabeblack@google.com // away on cycle 0 25813260Sgabeblack@google.com xc->activate(0); 25913260Sgabeblack@google.com } 26013260Sgabeblack@google.com 26113260Sgabeblack@google.com RemoteGDB *rgdb = new RemoteGDB(this, xc); 26213260Sgabeblack@google.com GDBListener *gdbl = new GDBListener(rgdb, 7000 + xcIndex); 26313260Sgabeblack@google.com gdbl->listen(); 26413260Sgabeblack@google.com /** 26513260Sgabeblack@google.com * Uncommenting this line waits for a remote debugger to connect 26612953Sgabeblack@google.com * to the simulator before continuing. 26712952Sgabeblack@google.com */ 26812953Sgabeblack@google.com //gdbl->accept(); 26912953Sgabeblack@google.com 27012953Sgabeblack@google.com if (remoteGDB.size() <= xcIndex) { 27112953Sgabeblack@google.com remoteGDB.resize(xcIndex+1); 27212953Sgabeblack@google.com } 27313175Sgabeblack@google.com 27413175Sgabeblack@google.com remoteGDB[xcIndex] = rgdb; 27512995Sgabeblack@google.com 27612953Sgabeblack@google.com return xcIndex; 27712995Sgabeblack@google.com} 27813182Sgabeblack@google.com 27913182Sgabeblack@google.com 28012953Sgabeblack@google.comvoid 28112953Sgabeblack@google.comLinuxSystem::replaceExecContext(ExecContext *xc, int xcIndex) 28213093Sgabeblack@google.com{ 28312953Sgabeblack@google.com System::replaceExecContext(xcIndex, xc); 28412952Sgabeblack@google.com remoteGDB[xcIndex]->replaceExecContext(xc); 28512957Sgabeblack@google.com} 28613206Sgabeblack@google.com 28712957Sgabeblack@google.combool 28813206Sgabeblack@google.comLinuxSystem::breakpoint() 28912957Sgabeblack@google.com{ 29012957Sgabeblack@google.com return remoteGDB[0]->trap(ALPHA_KENTRY_IF); 29112957Sgabeblack@google.com} 29213206Sgabeblack@google.com 29312957Sgabeblack@google.comBEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem) 29413206Sgabeblack@google.com 29513206Sgabeblack@google.com Param<bool> bin; 29613206Sgabeblack@google.com SimObjectParam<MemoryController *> mem_ctl; 29713206Sgabeblack@google.com SimObjectParam<PhysicalMemory *> physmem; 29812957Sgabeblack@google.com Param<uint64_t> init_param; 29913206Sgabeblack@google.com 30013206Sgabeblack@google.com Param<string> kernel_code; 30113206Sgabeblack@google.com Param<string> console_code; 30213288Sgabeblack@google.com Param<string> pal_code; 30313260Sgabeblack@google.com Param<string> boot_osflags; 30413288Sgabeblack@google.com VectorParam<string> binned_fns; 30513260Sgabeblack@google.com 30613260Sgabeblack@google.comEND_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem) 30713260Sgabeblack@google.com 30813206Sgabeblack@google.comBEGIN_INIT_SIM_OBJECT_PARAMS(LinuxSystem) 30913206Sgabeblack@google.com 31013206Sgabeblack@google.com 31113206Sgabeblack@google.com INIT_PARAM_DFLT(bin, "is this system to be binned", false), 31213206Sgabeblack@google.com INIT_PARAM(mem_ctl, "memory controller"), 31313206Sgabeblack@google.com INIT_PARAM(physmem, "phsyical memory"), 31413206Sgabeblack@google.com INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), 31513206Sgabeblack@google.com INIT_PARAM(kernel_code, "file that contains the code"), 31613206Sgabeblack@google.com INIT_PARAM(console_code, "file that contains the console code"), 31713206Sgabeblack@google.com INIT_PARAM(pal_code, "file that contains palcode"), 31813206Sgabeblack@google.com INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", 31913206Sgabeblack@google.com "a"), 32013206Sgabeblack@google.com INIT_PARAM(binned_fns, "functions to be broken down and binned") 32113206Sgabeblack@google.com 32213206Sgabeblack@google.com 32313206Sgabeblack@google.comEND_INIT_SIM_OBJECT_PARAMS(LinuxSystem) 32413206Sgabeblack@google.com 32513206Sgabeblack@google.comCREATE_SIM_OBJECT(LinuxSystem) 32613206Sgabeblack@google.com{ 32713206Sgabeblack@google.com LinuxSystem *sys = new LinuxSystem(getInstanceName(), init_param, mem_ctl, 32813206Sgabeblack@google.com physmem, kernel_code, console_code, 32913206Sgabeblack@google.com pal_code, boot_osflags, bin, binned_fns); 33013206Sgabeblack@google.com 33113206Sgabeblack@google.com return sys; 33213206Sgabeblack@google.com} 33312957Sgabeblack@google.com 33412957Sgabeblack@google.comREGISTER_SIM_OBJECT("LinuxSystem", LinuxSystem) 33512959Sgabeblack@google.com