system.cc revision 943
1/* 2 * Copyright (c) 2004 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/** 30 * @file 31 * linux_system.cc loads the linux kernel, console, pal and patches certain functions. 32 * The symbol tables are loaded so that traces can show the executing function and we can 33 * skip functions. Various delay loops are skipped and their final values manually computed to 34 * speed up boot time. 35 */ 36 37#include "base/loader/aout_object.hh" 38#include "base/loader/elf_object.hh" 39#include "base/loader/object_file.hh" 40#include "base/loader/symtab.hh" 41#include "base/remote_gdb.hh" 42#include "base/trace.hh" 43#include "cpu/exec_context.hh" 44#include "cpu/base_cpu.hh" 45#include "kern/linux/linux_events.hh" 46#include "kern/linux/linux_system.hh" 47#include "kern/system_events.hh" 48#include "mem/functional_mem/memory_control.hh" 49#include "mem/functional_mem/physical_memory.hh" 50#include "sim/builder.hh" 51#include "dev/platform.hh" 52#include "targetarch/isa_traits.hh" 53#include "targetarch/vtophys.hh" 54#include "sim/debug.hh" 55 56extern SymbolTable *debugSymbolTable; 57 58using namespace std; 59 60LinuxSystem::LinuxSystem(const string _name, const uint64_t _init_param, 61 MemoryController *_memCtrl, PhysicalMemory *_physmem, 62 const string &kernel_path, const string &console_path, 63 const string &palcode, const string &boot_osflags, 64 const bool _bin, const vector<string> &_binned_fns) 65 : System(_name, _init_param, _memCtrl, _physmem, _bin, _binned_fns), 66 bin(_bin), binned_fns(_binned_fns) 67{ 68 kernelSymtab = new SymbolTable; 69 consoleSymtab = new SymbolTable; 70 71 /** 72 * Load the kernel, pal, and console code into memory 73 */ 74 // Load kernel code 75 ObjectFile *kernel = createObjectFile(kernel_path); 76 if (kernel == NULL) 77 fatal("Could not load kernel file %s", kernel_path); 78 79 // Load Console Code 80 ObjectFile *console = createObjectFile(console_path); 81 if (console == NULL) 82 fatal("Could not load console file %s", console_path); 83 84 // Load pal file 85 ObjectFile *pal = createObjectFile(palcode); 86 if (pal == NULL) 87 fatal("Could not load PALcode file %s", palcode); 88 pal->loadSections(physmem, true); 89 90 // Load console file 91 console->loadSections(physmem, true); 92 93 // Load kernel file 94 kernel->loadSections(physmem, true); 95 kernelStart = kernel->textBase(); 96 kernelEnd = kernel->bssBase() + kernel->bssSize(); 97 kernelEntry = kernel->entryPoint(); 98 99 // load symbols 100 if (!kernel->loadGlobalSymbols(kernelSymtab)) 101 panic("could not load kernel symbols\n"); 102 debugSymbolTable = kernelSymtab; 103 104 if (!kernel->loadLocalSymbols(kernelSymtab)) 105 panic("could not load kernel local symbols\n"); 106 107 if (!console->loadGlobalSymbols(consoleSymtab)) 108 panic("could not load console symbols\n"); 109 110 DPRINTF(Loader, "Kernel start = %#x\n" 111 "Kernel end = %#x\n" 112 "Kernel entry = %#x\n", 113 kernelStart, kernelEnd, kernelEntry); 114 115 DPRINTF(Loader, "Kernel loaded...\n"); 116 117 118#ifdef DEBUG 119 kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic"); 120 consolePanicEvent = new BreakPCEvent(&pcEventQueue, "console panic"); 121#endif 122 123 skipIdeDelay50msEvent = new SkipFuncEvent(&pcEventQueue, 124 "ide_delay_50ms"); 125 126 skipDelayLoopEvent = new LinuxSkipDelayLoopEvent(&pcEventQueue, 127 "calibrate_delay"); 128 129 skipCacheProbeEvent = new SkipFuncEvent(&pcEventQueue, 130 "determine_cpu_caches"); 131 132 Addr addr = 0; 133 134 /** 135 * find the address of the est_cycle_freq variable and insert it so we don't 136 * through the lengthly process of trying to calculated it by using the PIT, 137 * RTC, etc. 138 */ 139 if (kernelSymtab->findAddress("est_cycle_freq", addr)) { 140 Addr paddr = vtophys(physmem, addr); 141 uint8_t *est_cycle_frequency = 142 physmem->dma_addr(paddr, sizeof(uint64_t)); 143 144 if (est_cycle_frequency) 145 *(uint64_t *)est_cycle_frequency = htoa(ticksPerSecond); 146 } 147 148 149 /** 150 * Copy the osflags (kernel arguments) into the consoles memory. Presently 151 * Linux does use the console service routine to get these command line 152 * arguments, but we might as well make them available just in case. 153 */ 154 if (consoleSymtab->findAddress("env_booted_osflags", addr)) { 155 Addr paddr = vtophys(physmem, addr); 156 char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t)); 157 158 if (osflags) 159 strcpy(osflags, boot_osflags.c_str()); 160 } 161 162 /** 163 * Since we aren't using a bootloader, we have to copy the kernel arguments 164 * directly into the kernels memory. 165 */ 166 { 167 Addr paddr = vtophys(physmem, PARAM_ADDR); 168 char *commandline = (char*)physmem->dma_addr(paddr, sizeof(uint64_t)); 169 if (commandline) 170 strcpy(commandline, boot_osflags.c_str()); 171 } 172 173 174 /** 175 * Set the hardware reset parameter block system type and revision information 176 * to Tsunami. 177 */ 178 if (consoleSymtab->findAddress("xxm_rpb", addr)) { 179 Addr paddr = vtophys(physmem, addr); 180 char *hwprb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); 181 182 if (hwprb) { 183 *(uint64_t*)(hwprb+0x50) = htoa(ULL(34)); // Tsunami 184 *(uint64_t*)(hwprb+0x58) = htoa(ULL(1)<<10); // Plain DP264 185 } 186 else 187 panic("could not translate hwprb addr to set system type/variation\n"); 188 189 } else 190 panic("could not find hwprb to set system type/variation\n"); 191 192 /** 193 * EV5 only supports 127 ASNs so we are going to tell the kernel that the 194 * paritiuclar EV6 we have only supports 127 asns. 195 * @todo At some point we should change ev5.hh and the palcode to support 196 * 255 ASNs. 197 */ 198 if (kernelSymtab->findAddress("dp264_mv", addr)) { 199 Addr paddr = vtophys(physmem, addr); 200 char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t)); 201 202 if (dp264_mv) { 203 *(uint32_t*)(dp264_mv+0x18) = htoa((uint32_t)127); 204 } else 205 panic("could not translate dp264_mv addr to set the MAX_ASN to 127\n"); 206 207 } else 208 panic("could not find dp264_mv to set the MAX_ASN to 127\n"); 209 210 211 212#ifdef DEBUG 213 if (kernelSymtab->findAddress("panic", addr)) 214 kernelPanicEvent->schedule(addr); 215 else 216 panic("could not find kernel symbol \'panic\'"); 217 218 if (consoleSymtab->findAddress("panic", addr)) 219 consolePanicEvent->schedule(addr); 220#endif 221 222 /** 223 * Any time ide_delay_50ms, calibarte_delay or determine_cpu_caches is called 224 * just skip the function. Currently determine_cpu_caches only is used put 225 * information in proc, however if that changes in the future we will have to 226 * fill in the cache size variables appropriately. 227 */ 228 if (kernelSymtab->findAddress("ide_delay_50ms", addr)) 229 skipIdeDelay50msEvent->schedule(addr+sizeof(MachInst)); 230 231 if (kernelSymtab->findAddress("calibrate_delay", addr)) 232 skipDelayLoopEvent->schedule(addr+sizeof(MachInst)); 233 234 if (kernelSymtab->findAddress("determine_cpu_caches", addr)) 235 skipCacheProbeEvent->schedule(addr+sizeof(MachInst)); 236} 237 238LinuxSystem::~LinuxSystem() 239{ 240 delete kernel; 241 delete console; 242 243 delete kernelSymtab; 244 delete consoleSymtab; 245 246 delete kernelPanicEvent; 247 delete consolePanicEvent; 248 delete skipIdeDelay50msEvent; 249 delete skipDelayLoopEvent; 250 delete skipCacheProbeEvent; 251} 252 253 254void 255LinuxSystem::setDelayLoop(ExecContext *xc) 256{ 257 Addr addr = 0; 258 if (kernelSymtab->findAddress("loops_per_jiffy", addr)) { 259 Addr paddr = vtophys(physmem, addr); 260 261 uint8_t *loops_per_jiffy = 262 physmem->dma_addr(paddr, sizeof(uint32_t)); 263 264 Tick cpuFreq = xc->cpu->getFreq(); 265 Tick intrFreq = platform->interrupt_frequency; 266 *(uint32_t *)loops_per_jiffy = 267 (uint32_t)((cpuFreq / intrFreq) * 0.9988); 268 } 269} 270 271int 272LinuxSystem::registerExecContext(ExecContext *xc) 273{ 274 int xcIndex = System::registerExecContext(xc); 275 276 if (xcIndex == 0) { 277 // activate with zero delay so that we start ticking right 278 // away on cycle 0 279 xc->activate(0); 280 } 281 282 RemoteGDB *rgdb = new RemoteGDB(this, xc); 283 GDBListener *gdbl = new GDBListener(rgdb, 7000 + xcIndex); 284 gdbl->listen(); 285 /** 286 * Uncommenting this line waits for a remote debugger to connect 287 * to the simulator before continuing. 288 */ 289 //gdbl->accept(); 290 291 if (remoteGDB.size() <= xcIndex) { 292 remoteGDB.resize(xcIndex+1); 293 } 294 295 remoteGDB[xcIndex] = rgdb; 296 297 return xcIndex; 298} 299 300 301void 302LinuxSystem::replaceExecContext(ExecContext *xc, int xcIndex) 303{ 304 System::replaceExecContext(xcIndex, xc); 305 remoteGDB[xcIndex]->replaceExecContext(xc); 306} 307 308bool 309LinuxSystem::breakpoint() 310{ 311 return remoteGDB[0]->trap(ALPHA_KENTRY_IF); 312} 313 314BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem) 315 316 Param<bool> bin; 317 SimObjectParam<MemoryController *> mem_ctl; 318 SimObjectParam<PhysicalMemory *> physmem; 319 Param<uint64_t> init_param; 320 321 Param<string> kernel_code; 322 Param<string> console_code; 323 Param<string> pal_code; 324 Param<string> boot_osflags; 325 VectorParam<string> binned_fns; 326 327END_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem) 328 329BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxSystem) 330 331 332 INIT_PARAM_DFLT(bin, "is this system to be binned", false), 333 INIT_PARAM(mem_ctl, "memory controller"), 334 INIT_PARAM(physmem, "phsyical memory"), 335 INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0), 336 INIT_PARAM(kernel_code, "file that contains the code"), 337 INIT_PARAM(console_code, "file that contains the console code"), 338 INIT_PARAM(pal_code, "file that contains palcode"), 339 INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", 340 "a"), 341 INIT_PARAM(binned_fns, "functions to be broken down and binned") 342 343 344END_INIT_SIM_OBJECT_PARAMS(LinuxSystem) 345 346CREATE_SIM_OBJECT(LinuxSystem) 347{ 348 LinuxSystem *sys = new LinuxSystem(getInstanceName(), init_param, mem_ctl, 349 physmem, kernel_code, console_code, 350 pal_code, boot_osflags, bin, binned_fns); 351 352 return sys; 353} 354 355REGISTER_SIM_OBJECT("LinuxSystem", LinuxSystem) 356