From 031216b1b3ef1570ca1d14e02685285584fe49ea Mon Sep 17 00:00:00 2001 From: "Andrew D. Zonenberg" Date: Mon, 7 May 2018 22:10:23 -0700 Subject: [PATCH] Lots of debugging and bringup on ARM memory debug. Still working on figuring things out. --- ARMCortexA9.cpp | 25 ++++++-- ARMCortexA9.h | 1 + ARMDebugAccessPort.h | 2 + ARMDebugMemAccessPort.cpp | 82 ++++++++++++++---------- ARMDebugMemAccessPort.h | 12 +++- ARMDebugPort.cpp | 130 ++++++++++++++++++++++++++++++-------- ARMDebugPort.h | 23 +++++-- 7 files changed, 204 insertions(+), 71 deletions(-) diff --git a/ARMCortexA9.cpp b/ARMCortexA9.cpp index ba8f53a..7abb1e1 100644 --- a/ARMCortexA9.cpp +++ b/ARMCortexA9.cpp @@ -70,6 +70,8 @@ ARMCortexA9::ARMCortexA9(ARMDebugMemAccessPort* ap, uint32_t address, ARMDebugPe //Print it out PrintIDRegister(did); + //DBGDSMCR turn off MMU + //TODO: Write to DBGDRCR to halt the CPU (C11.11.17) //TODO: Write to DBGDSCCR to force write-through cache (C11.11.19) @@ -77,13 +79,28 @@ ARMCortexA9::ARMCortexA9(ARMDebugMemAccessPort* ap, uint32_t address, ARMDebugPe //DBGDEVID[3:0] 2226 //Read DBGDSCR to get status stuff (TODO: make struct) for this - //uint32_t foo = ReadRegisterByIndex(DBGDSCR_EXT); - //LogDebug("foo = %x\n", foo); + //uint32_t dbgdscr = ReadRegisterByIndex(DBGDSCR_EXT); + //LogDebug("DBGDSCR = %x\n", dbgdscr); + + //Pins of interest are MIO bank 1, pins 50/51 + + //Read PSS_IDCODE + //uint32_t pss_idcode = ReadMemory(0xF8000530); + //uint32_t pss_idcode = m_ap->ReadWord(0xF8000530); + //LogDebug("pss_idcode = %08x\n", pss_idcode); + + //MIO LED @ MIO7 + //MIO inputs at MIO50, 51 + //GPIO controller is at 0xe0000000 + //Read DIRM to see what + //Read DATA_RO? + + //Read L0_SEL - // //Read the PC and dump the instruction at that address - //uint32_t pc = SampleProgramCounter(); + uint32_t pc = SampleProgramCounter(); + LogDebug("PC = %08x\n", pc); //uint32_t value = ReadMemory(0xE0000000);//m_ap->ReadWord(0x80000000); //ReadMemory(0xFC000000); //LogDebug(" value = %08x\n", value); diff --git a/ARMCortexA9.h b/ARMCortexA9.h index 6626ac9..6896617 100644 --- a/ARMCortexA9.h +++ b/ARMCortexA9.h @@ -249,6 +249,7 @@ class ARMCortexA9 : public DebuggableDevice DBGLAR = 1004, DBGLSR = 1005, DBGAUTHSTATUS = 1006, + DBGDEVID = 1010 }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/ARMDebugAccessPort.h b/ARMDebugAccessPort.h index 7ec2563..39cae3d 100644 --- a/ARMDebugAccessPort.h +++ b/ARMDebugAccessPort.h @@ -85,6 +85,8 @@ class ARMDebugAccessPort ARMDebugAccessPort(ARMDebugPort* dp, uint8_t apnum, ARMDebugPortIDRegister id); virtual ~ARMDebugAccessPort(); + virtual void Initialize() =0; + enum dap_type { DAP_JTAG = 0, diff --git a/ARMDebugMemAccessPort.cpp b/ARMDebugMemAccessPort.cpp index 65270f3..46d8792 100644 --- a/ARMDebugMemAccessPort.cpp +++ b/ARMDebugMemAccessPort.cpp @@ -63,14 +63,21 @@ ARMDebugMemAccessPort::ARMDebugMemAccessPort(ARMDebugPort* dp, uint8_t apnum, AR "Invalid DAP type", ""); } +} +void ARMDebugMemAccessPort::Initialize() +{ //If we're enabled, try to load the ROM (if any) ARMDebugMemAPControlStatusWord csw = GetStatusRegister(); if(csw.bits.enable) { + LogDebug("Searching for debug ROMs in AP %d (%s)...\n", m_apnum, (m_daptype == DAP_AHB) ? "AHB" : "APB"); + LogIndenter li; FindRootRomTable(); if(m_hasDebugRom) LoadROMTable(m_debugBaseAddress); + else + LogDebug("No debug ROM found\n"); } //Looks like the AHB DAP for Zynq is used for main system memory access @@ -96,18 +103,20 @@ bool ARMDebugMemAccessPort::IsEnabled() void ARMDebugMemAccessPort::PrintStatusRegister() { ARMDebugMemAPControlStatusWord csw = GetStatusRegister(); - LogDebug(" Status register for AP %u:\n", m_apnum); + LogIndenter li; + LogDebug("Status register for AP %u:\n", m_apnum); + LogIndenter li2; if(csw.bits.size >= ACCESS_INVALID) - LogDebug(" Size : UNDEFINED\n"); + LogDebug("Size : UNDEFINED\n"); else - LogDebug(" Size : %s\n", g_cswLenNames[csw.bits.size]); - LogDebug(" Auto inc : %u\n", csw.bits.auto_increment); - LogDebug(" Enable : %u\n", csw.bits.enable); - LogDebug(" Busy : %u\n", csw.bits.busy); - LogDebug(" Mode : %u\n", csw.bits.mode); - LogDebug(" Secure debug : %u\n", csw.bits.secure_priv_debug); - LogDebug(" Bus protection: %u\n", csw.bits.bus_protect); - LogDebug(" Debug SW : %u\n", csw.bits.debug_sw_enable); + LogDebug("Size : %s\n", g_cswLenNames[csw.bits.size]); + LogDebug("Auto inc : %u\n", csw.bits.auto_increment); + LogDebug("Enable : %u\n", csw.bits.enable); + LogDebug("Busy : %u\n", csw.bits.busy); + LogDebug("Mode : %u\n", csw.bits.mode); + LogDebug("Secure debug : %u\n", csw.bits.secure_priv_debug); + LogDebug("Bus protection : %u\n", csw.bits.bus_protect); + LogDebug("Nonsecure transfer : %u\n", csw.bits.nonsecure_transfer); } string ARMDebugMemAccessPort::GetDescription() @@ -134,11 +143,13 @@ uint32_t ARMDebugMemAccessPort::ReadWord(uint32_t addr) return m_dp->APRegisterRead(m_apnum, ARMDebugPort::REG_MEM_DRW); } -void ARMDebugMemAccessPort::WriteWord(uint32_t /*addr*/, uint32_t /*value*/) +void ARMDebugMemAccessPort::WriteWord(uint32_t addr, uint32_t value) { - throw JtagExceptionWrapper( - "WriteWord() not yet implemented", - ""); + //Write the address + m_dp->APRegisterWrite(m_apnum, ARMDebugPort::REG_MEM_TAR, addr); + + //Write data + m_dp->APRegisterWrite(m_apnum, ARMDebugPort::REG_MEM_DRW, value); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -177,6 +188,9 @@ void ARMDebugMemAccessPort::FindRootRomTable() void ARMDebugMemAccessPort::LoadROMTable(uint32_t baseAddress) { + LogDebug("Loading ROM table at address %08x\n", baseAddress); + LogIndenter li; + //Read ROM table entries until we get to an invalid one for(int i=0; i<960; i++) { @@ -247,8 +261,11 @@ void ARMDebugMemAccessPort::LoadROMTable(uint32_t baseAddress) //Additional ROM table case CLASS_ROMTABLE: - //LogDebug("Found extra ROM table at 0x%08x, loading\n", address); - LoadROMTable(address); + { + LogDebug("Found extra ROM table at 0x%08x, loading\n", address); + LogIndenter li; + LoadROMTable(address); + } break; //Don't know what to do with anything else @@ -298,9 +315,10 @@ void ARMDebugMemAccessPort::ProcessDebugBlock(uint32_t base_address) ""); } - //unsigned int blockcount = (1 << reg.bits.log_4k_blocks); - //LogDebug("Found debug component at %08x (rev/mod/step %u/%u/%u, %u 4KB pages)\n", - // base_address, reg.bits.revnum, reg.bits.cust_mod, reg.bits.revand, blockcount); + unsigned int blockcount = (1 << reg.bits.log_4k_blocks); + LogDebug("Found debug component at %08x (rev/mod/step %u/%u/%u, %u 4KB pages)\n", + base_address, reg.bits.revnum, reg.bits.cust_mod, reg.bits.revand, blockcount); + LogIndenter li; //Check IDCODE for Xilinx if( (reg.bits.jep106_cont == 0x00) && (reg.bits.jep106_id == 0x49) ) @@ -310,12 +328,12 @@ void ARMDebugMemAccessPort::ProcessDebugBlock(uint32_t base_address) //See Xilinx UG585 page 729 table 28-5 if(reg.bits.partnum == 0x001) { - //LogDebug(" Xilinx Fabric Trace Monitor\n"); + LogDebug("Xilinx Fabric Trace Monitor\n"); } //unknown, skip it else - LogWarning(" Unknown Xilinx device (part number 0x%x)\n", reg.bits.partnum); + LogWarning("Unknown Xilinx device (part number 0x%x)\n", reg.bits.partnum); } @@ -325,37 +343,37 @@ void ARMDebugMemAccessPort::ProcessDebugBlock(uint32_t base_address) switch(reg.bits.partnum) { case 0x906: - //LogDebug(" CoreSight Cross Trigger Interface\n"); + LogDebug("CoreSight Cross Trigger Interface\n"); break; case 0x907: - //LogDebug(" CoreSight Embedded Trace Buffer\n"); + LogDebug("CoreSight Embedded Trace Buffer\n"); break; case 0x908: - //LogDebug(" CoreSight Trace Funnel\n"); + LogDebug("CoreSight Trace Funnel\n"); break; case 0x912: - //LogDebug(" CoreSight Trace Port Interface Unit\n"); + LogDebug("CoreSight Trace Port Interface Unit\n"); break; //ID is 913, not 914. CoreSight Components TRM is wrong. //See ARM #TAC650738 case 0x913: - //LogDebug(" CoreSight Instrumentation Trace Macrocell\n"); + LogDebug("CoreSight Instrumentation Trace Macrocell\n"); break; case 0x914: - //LogDebug(" CoreSight Serial Wire Output\n"); + LogDebug("CoreSight Serial Wire Output\n"); break; case 0x950: - //LogDebug(" Cortex-A9 Program Trace Macrocell\n"); + LogDebug("Cortex-A9 Program Trace Macrocell\n"); break; case 0x9A0: - //LogDebug(" Cortex-A9 Performance Monitoring Unit\n"); + LogDebug("Cortex-A9 Performance Monitoring Unit\n"); break; case 0xC09: @@ -367,7 +385,7 @@ void ARMDebugMemAccessPort::ProcessDebugBlock(uint32_t base_address) break; default: - LogWarning(" Unknown ARM device (part number 0x%x)\n", reg.bits.partnum); + LogWarning("Unknown ARM device (part number 0x%x)\n", reg.bits.partnum); break; } } @@ -375,13 +393,13 @@ void ARMDebugMemAccessPort::ProcessDebugBlock(uint32_t base_address) //Check IDCODE for Switchcore (?) else if( (reg.bits.jep106_cont == 0x03) && (reg.bits.jep106_id == 0x09) ) { - //LogWarning(" Unknown Switchcore device (part number 0x%x)\n", reg.bits.partnum); + //LogWarning("Unknown Switchcore device (part number 0x%x)\n", reg.bits.partnum); } //Unknown vendor else { - LogWarning(" Unknown device (JEP106 %u:%x, part number 0x%x)\n", + LogWarning("Unknown device (JEP106 %u:%x, part number 0x%x)\n", reg.bits.jep106_cont, reg.bits.jep106_id, reg.bits.partnum); } } diff --git a/ARMDebugMemAccessPort.h b/ARMDebugMemAccessPort.h index 581a286..9e3f5b6 100644 --- a/ARMDebugMemAccessPort.h +++ b/ARMDebugMemAccessPort.h @@ -70,10 +70,13 @@ union ARMDebugMemAPControlStatusWord unsigned int secure_priv_debug:1; ///Bus access protection (implementation defined) - unsigned int bus_protect:7; + unsigned int bus_protect:6; - ///Debug software access enable (implementation defined) - unsigned int debug_sw_enable:1; + ///Secure transfer (high=nonsecure) + unsigned int nonsecure_transfer:1; + + //Reserved, should be zero + unsigned int reserved_zero_3 : 1; } __attribute__ ((packed)) bits; @@ -97,6 +100,9 @@ class ARMDebugMemAccessPort : public ARMDebugAccessPort ARMDebugMemAccessPort(ARMDebugPort* dp, uint8_t apnum, ARMDebugPortIDRegister id); virtual ~ARMDebugMemAccessPort(); + //Called after all other Mem-APs are up + virtual void Initialize(); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Memory access diff --git a/ARMDebugPort.cpp b/ARMDebugPort.cpp index ff365d4..726c0d8 100644 --- a/ARMDebugPort.cpp +++ b/ARMDebugPort.cpp @@ -55,20 +55,38 @@ ARMDebugPort::ARMDebugPort( m_irlength = 4; //No Mem-AP for now - m_defaultMemAP = NULL; + m_defaultMemAP = NULL; + m_defaultRegisterAP = NULL; //Turn on the debug stuff EnableDebugging(); //Figure out how many APs we have + LogDebug("Searching for APs...\n"); uint8_t nap = 0; for(; nap<255; nap++) { + LogIndenter li; + ARMDebugPortIDRegister idr; idr.word = APRegisterRead(nap, REG_IDR); if(idr.word == 0) break; + /* + LogDebug("Found AP with ID 0x%08x\n", idr.word); + { + LogIndenter li; + LogDebug("Type: %x\n", idr.bits.type); + LogDebug("Variant: %x\n", idr.bits.variant); + LogDebug("Reserved: %x\n", idr.bits.reserved_zero); + LogDebug("Is mem AP: %x\n", idr.bits.is_mem_ap); + LogDebug("Identity: %x\n", idr.bits.identity); + LogDebug("Continuation: %x\n", idr.bits.continuation); + LogDebug("Revision: %x\n", idr.bits.revision); + } + */ + //Sanity check that it's a valid ARM DAP if( (idr.bits.continuation != 0x4) || (idr.bits.identity != 0x3b) ) { @@ -78,8 +96,12 @@ ARMDebugPort::ARMDebugPort( } //If it's a JTAG-AP, skip it for now + //(this seems to be fpga config?) if(!idr.bits.is_mem_ap) + { + LogDebug("Found JTAG-AP at index %d\n", nap); continue; + } //Create a new MEM-AP else @@ -87,12 +109,38 @@ ARMDebugPort::ARMDebugPort( ARMDebugMemAccessPort* ap = new ARMDebugMemAccessPort(this, nap, idr); m_aps[nap] = ap; - //If it's an AHB-AP, and we don't have a default Mem-AP, this one is probably RAM. + if(ap->GetBusType() == ARMDebugAccessPort::DAP_AHB) + LogDebug("Found AHB MEM-AP at index %d\n", nap); + else if(ap->GetBusType() == ARMDebugAccessPort::DAP_APB) + LogDebug("Found APB MEM-AP at index %d\n", nap); + + //If it's an AHB Mem-AP, and we don't have a default Mem-AP, this one is probably RAM. //Use it as our default AP. if( (ap->GetBusType() == ARMDebugAccessPort::DAP_AHB) && (m_defaultMemAP == NULL) ) + { + LogIndenter li; + LogDebug("Using as default RAM Mem-AP\n"); m_defaultMemAP = ap; + } + + //If it's an APB Mem-AP, and we don't have a default Mem-AP, this one is probably debug registers. + //Use it as our default AP. + if( (ap->GetBusType() == ARMDebugAccessPort::DAP_APB) && (m_defaultRegisterAP == NULL) ) + { + LogIndenter li; + LogDebug("Using as default register Mem-AP\n"); + m_defaultRegisterAP = ap; + } } } + + //Initialize each of the APs once they are all open + LogDebug("Initializing APs...\n"); + { + LogIndenter li; + for(auto it : m_aps) + it.second->Initialize(); + } } ARMDebugPort::~ARMDebugPort() @@ -139,6 +187,7 @@ void ARMDebugPort::EnableDebugging() //Power up the system stat.word = 0; stat.bits.sys_pwrup_req = 1; + stat.bits.debug_pwrup_req = 1; DPRegisterWrite(REG_CTRL_STAT, stat.word); //Verify it powered up OK @@ -149,14 +198,6 @@ void ARMDebugPort::EnableDebugging() "Failed to get ACK to system powerup request", ""); } - - //Power up the debug logic - stat.word = 0; - stat.bits.debug_pwrup_req = 1; - DPRegisterWrite(REG_CTRL_STAT, stat.word); - - //Verify it powered up OK - stat = GetStatusRegister(); if(!stat.bits.debug_pwrup_ack) { throw JtagExceptionWrapper( @@ -198,6 +239,35 @@ void ARMDebugPort::WriteMemory(uint32_t address, uint32_t value) m_defaultMemAP->WriteWord(address, value); } +uint32_t ARMDebugPort::ReadDebugRegister(uint32_t address) +{ + //Sanity check + if(m_defaultRegisterAP == NULL) + { + throw JtagExceptionWrapper( + "Cannot read register because there is no APB MEM-AP", + ""); + } + + //Use the default Mem-AP to read it + return m_defaultRegisterAP->ReadWord(address); +} + +///Writes a single 32-bit word of memory +void ARMDebugPort::WriteDebugRegister(uint32_t address, uint32_t value) +{ + //Sanity check + if(m_defaultRegisterAP == NULL) + { + throw JtagExceptionWrapper( + "Cannot write register because there is no APB MEM-AP", + ""); + } + + //Use the default Mem-AP to write it + m_defaultRegisterAP->WriteWord(address, value); +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Device info @@ -226,7 +296,7 @@ std::string ARMDebugPort::GetDescription() //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Chain querying -void ARMDebugPort::PrintStatusRegister(ARMDebugPortStatusRegister reg) +void ARMDebugPort::PrintStatusRegister(ARMDebugPortStatusRegister reg, bool children) { LogDebug("DAP status: %08x\n", reg.word); LogDebug(" Sys pwrup ack: %u\n", reg.bits.sys_pwrup_ack); @@ -240,14 +310,17 @@ void ARMDebugPort::PrintStatusRegister(ARMDebugPortStatusRegister reg) LogDebug(" Mask lane: %u\n", reg.bits.mask_lane); //LogDebug(" Write error: %u\n", reg.bits.wr_data_err); //LogDebug(" Read OK: %u\n", reg.bits.read_ok); - LogDebug(" Sticky error: %u\n", reg.bits.sticky_err); + LogDebug(" Sticky err: %u\n", reg.bits.sticky_err); LogDebug(" Sticky compare: %u\n", reg.bits.sticky_compare); LogDebug(" Transfer mode: %u\n", reg.bits.transfer_mode); LogDebug(" Sticky overrun: %u\n", reg.bits.sticky_overrun); LogDebug(" Sticky overrun en: %u\n", reg.bits.sticky_overrun_en); - for(auto x : m_aps) - x.second->PrintStatusRegister(); + if(children) + { + for(auto x : m_aps) + x.second->PrintStatusRegister(); + } } /** @@ -289,7 +362,7 @@ uint32_t ARMDebugPort::APRegisterRead(uint8_t ap, ApReg addr) //Poll until we get a good read back int i = 0; - int nmax = 100; + int nmax = 50; for(; iEnterShiftDR(); m_iface->ShiftData(0, &addr_flags, &ack_out, 3); if(ack_out != OK_OR_FAULT) - { - //ignore it, the previous request generated a wait or something - /* - throw JtagExceptionWrapper( - "Don't know what to do with WAIT request from DAP", - "", - JtagException::EXCEPTION_TYPE_UNIMPLEMENTED); - */ - } + LogWarning("Don't know what to do with WAIT request from DAP\n"); //Send some dummy data unsigned char unused[4] = {0}; @@ -328,8 +393,12 @@ uint32_t ARMDebugPort::APRegisterRead(uint8_t ap, ApReg addr) break; //No go? Try again after a millisecond + if(i == 0) + LogDebug("No go, trying again after 1 ms\n"); usleep(1 * 1000); } + if(i > 0) + LogDebug("Poll ended after %d ms\n", i); //Give up if we still got nothing if(i == nmax) @@ -337,7 +406,7 @@ uint32_t ARMDebugPort::APRegisterRead(uint8_t ap, ApReg addr) DebugAbort(); ClearStatusRegisterErrors(); throw JtagExceptionWrapper( - "Failed to read AP register (still waiting after way too long", + "Failed to read AP register (still waiting after way too long)", ""); } @@ -345,11 +414,18 @@ uint32_t ARMDebugPort::APRegisterRead(uint8_t ap, ApReg addr) ARMDebugPortStatusRegister stat = GetStatusRegister(); if(stat.bits.sticky_err) { + LogError("Something went wrong (sticky error bit set when reading AP %d register %d)\n", ap, addr); + PrintStatusRegister(stat, false); + DebugAbort(); ClearStatusRegisterErrors(); + + // + throw JtagExceptionWrapper( "Failed to read AP register", ""); + exit(1); } return data_out; @@ -427,6 +503,10 @@ void ARMDebugPort::APRegisterWrite(uint8_t ap, ApReg addr, uint32_t wdata) ARMDebugPortStatusRegister stat = GetStatusRegister(); if(stat.bits.sticky_err) { + LogError("Write of %08x to register %x on AP %d failed\n", + wdata, addr, ap); + m_aps[ap]->PrintStatusRegister(); + DebugAbort(); ClearStatusRegisterErrors(); throw JtagExceptionWrapper( diff --git a/ARMDebugPort.h b/ARMDebugPort.h index 4b86071..18e7aa4 100644 --- a/ARMDebugPort.h +++ b/ARMDebugPort.h @@ -147,7 +147,7 @@ class ARMDebugPort : public ARMDevice virtual std::string GetDescription(); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Memory access + // Memory access via AHB ///Read a single 32-bit word of memory (TODO support smaller sizes) virtual uint32_t ReadMemory(uint32_t address); @@ -155,6 +155,12 @@ class ARMDebugPort : public ARMDevice ///Writes a single 32-bit word of memory (TODO support smaller sizes) virtual void WriteMemory(uint32_t address, uint32_t value); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Debug register access via APB + + virtual uint32_t ReadDebugRegister(uint32_t address); + virtual void WriteDebugRegister(uint32_t address, uint32_t value); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Helpers for debug port manipulation @@ -183,18 +189,18 @@ class ARMDebugPort : public ARMDevice //Well-defined AP registers enum ApReg { - REG_MEM_CSW = 0x00, - REG_MEM_TAR = 0x04, - REG_MEM_DRW = 0x0C, - REG_MEM_BASE = 0xF8, + REG_MEM_CSW = 0x00, //Control/status word + REG_MEM_TAR = 0x04, //Transfer address register + REG_MEM_DRW = 0x0C, //Data read/write + REG_MEM_BASE = 0xF8, //Location of debug ROM - REG_IDR = 0xFC + REG_IDR = 0xFC //ID code }; protected: ARMDebugPortStatusRegister GetStatusRegister(); void ClearStatusRegisterErrors(); - void PrintStatusRegister(ARMDebugPortStatusRegister reg); + void PrintStatusRegister(ARMDebugPortStatusRegister reg, bool children = true); uint32_t DPRegisterRead(DpReg addr); void DPRegisterWrite(DpReg addr, uint32_t wdata); @@ -231,6 +237,9 @@ class ARMDebugPort : public ARMDevice ///The default Mem-AP used for memory access ARMDebugMemAccessPort* m_defaultMemAP; + + //The default Mem-AP used for debug register access + ARMDebugMemAccessPort* m_defaultRegisterAP; }; #endif