* start/start.S: Added kseg1 test to enable cache flush code
	* bsp_specs: Added -qnostartfile to disable including bsp's start.o
	* startup/bspstart.c: Made clear_cache actually work, tweaked cpu
	init to only turn on whats needed.
	* startup/gdb-support.c: Added calls to uart 2 for gdb stub I/O and
	a handy init function.
This commit is contained in:
Joel Sherrill
2002-03-01 16:21:52 +00:00
parent bd1ecb00d9
commit 0ea3293739
7 changed files with 433 additions and 124 deletions

View File

@@ -1,6 +1,11 @@
2001-02-27 Joel Sherrill <joel@OARcorp.com>
2002-02-27 Greg Menke <gregory.menke@gsfc.nasa.gov>
* startup/Makefile.am: Added rtems-stub-glue.c to C_FILES.
* start/start.S: Added kseg1 test to enable cache flush code
* bsp_specs: Added -qnostartfile to disable including bsp's start.o
* startup/bspstart.c: Made clear_cache actually work, tweaked cpu
init to only turn on whats needed.
* startup/gdb-support.c: Added calls to uart 2 for gdb stub I/O and
a handy init function.
2002-02-08 Joel Sherrill <joel@OARcorp.com>

View File

@@ -44,9 +44,10 @@ entered, else PMON jumps to the EEPROM address above, presuming a user
program is located there.
The default output of an RTEMS link is an image linked to run from
80020000, but has had its LMA shifted up to BFC40000. It is suitable
for copying to S3 records or can be burned to ROMs in whatever manner
the user desires.
0x80020000. It is suitable for copying to S3 records or can be burned
to ROMs in whatever manner the user desires. If you want to locate the
image into ROM at some other address, use mips-rtems-objcopy to shift
the LMA.
Operation
=========
@@ -67,7 +68,51 @@ linkcmds.
Before relocating the RTEMS image, the bsp startup routine attempts to
configure the processor into a rational state. During this process,
status characters are emitted at 19200N81 baud on UART port 0.
status characters are emitted at 19200N81 on UART port 0.
The default link script simply places the image at 0x8002000 with
LMA=VMA, which is conviently located in RAM on our board. You should
probably consider creating your own linkcmds, putting things where you
want and supply it as above.
The Mongoose V has a somewhat restricted cache configuration model; you
can only flush it if the code which does so executes within noncached
memory, in our case, code in kseg1. If you do so from elsewhere the
code will appear to lock up, this is caused by the cache clearing
routine making the instruction fetch always return 0, or nop- leaving
the processor in an endless loop. The default start.S code detects if
its booting from outside kseg1, it which case it disables the cache
flush code. This means you cannot flush the cache with the bsp's
functions if you boot your program from outside kseg1. A more subtle
issue is the bsp keeps a pointer to the location in kseg1 where the
bsp's cache flush code resides. This is advantageous because you can
relocate the system anywhere and still control the cache, but might
cause trouble if the boot image becomes inaccessible. If this is
possible, you should probably consider rolling your own cache control &
disabling the bsp's.
As stated above, if you boot from outside kseg1, the bsp disables the
cache flush routines. This is not desirable in the long run because the
Mongoose V remote debugger stub assumes it can flush caches when exiting
an exception so it might not be able to update code/data properly,
though it should still nominally function. However, if you're not using
the remote debugger & don't care about flushing caches, then everything
should run just fine.
Our approach has to been locate ROM in kseg1, link the code for VMA in
RAM and relocate the LMA up into kseg1 ROM. Since the start.S code is
position-independent, it will relocate the entire app down to the VMA
region before starting things up with everything in its proper place.
The cache clear code runs before relocation, so executes from ROM &
things work.
You can prevent including the default start.S by adding;
-qnostartfile
to the link command line in addition to the "nolinkcmds" options above.
Be sure to supply your replacement start.o.
Questions
@@ -84,6 +129,51 @@ when sending them fast?
somewhat faulty UART design.
Status
======
Debugging
=========
After getting Joel's initial port of the gdb stub to the Mongoose bsp, I
worked up & tested this stub on our R3000 board. It seems to work OK.
Our MIPS has 2 serial ports, the first being dedicated to the console, I
chose to arrange the 2nd one for the remote gdb protocol. While this
solution is somewhat specific to our board & bsp, I think the technique
is quite generalizable.
The following is a code snippet to be included in the user program;
/***********************************************/
extern int mg5rdbgOpenGDBuart(int);
extern void mg5rdbgCloseGDBuart(void);
void setupgdb(void)
{
printf("Configuring remote GDB stub...\n");
/* initialize remote gdb support */
if( mg5rdbgOpenGDBuart(-1) != RTEMS_SUCCESSFUL )
{
printf("Remote GDB stub is disabled.\n\n");
}
}
/***********************************************/
It allows the program to decide if it wants gdb to be ready to pick up
exceptions or not. The 2 extern functions are located in the MongooseV
bsp inside gdb-support.c. They configure & initialize the 2nd serial
port & invoke the vector initialization routine located in cpu_asm.
Note, we call directly down into the MongooseV UART driver- its quite
unfriendly to TERMIO. I chose this approach because I wanted to
minimize dependence on the I/O subsystems because they might be in a
state just short of collapsing if the program had done something bad to
cause the exception.
If user code leaves the 2nd port alone, then things will work out OK.
Greg Menke
2/27/2002
============================================================================

View File

@@ -15,8 +15,8 @@
*startfile:
%{!qrtems: %(old_startfile)} %{qrtems: \
%{!qrtems_debug: start.o%s} \
%{qrtems_debug: start_g.o%s}}
%{!qnostartfile: %{!qrtems_debug: start.o%s} \
%{qrtems_debug: start_g.o%s}}}
*link:
%(old_link) %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N -e _start}

View File

@@ -48,15 +48,6 @@
#endif
#ifdef HACKED_PMON
#define PMON_UTIL_ROUTINES 0xbfc00200
#define UTIL_WARMSTART_VECTOR 21*4
#define UTIL_CPUINIT_VECTOR 22*4
#define UTIL_CONFIGUART_VECTOR 23*4
#define UTIL_PUTCHROM_VECTOR 24*4
#endif
/*
** defined by linkcmds, pointing to the start of the relocation target
** memory, referenced in this way so we can avoid defining it
@@ -84,7 +75,6 @@
.globl putch_rom
_start:
.set noreorder
move k1,ra /* save ra so we can optionally return to caller */
$LF1 = . + 8
/*
@@ -131,6 +121,42 @@ _branch:
jal t0
nop
/*
** Print 'b'. Show that we started.
*/
move t2,a1
and t2,0xffff0000
li a0,'b'
la t0,putch_rom
and t0,0x0000ffff
or t0,t2
jal t0
nop
li k0,0
li k1,0
move t1,a1
nop
li t2,0xa0000000 /* lower limit of kseg1 */
li t3,0xbfffffff /* upper limit of kseg1 */
subu t0,t1,t2
srl t0,31 /* shift high bit down to bit 0 */
bnez t0,1f /* booting from below kseg1 */
subu t0,t3,t1
srl t0,31 /* shift high bit down to bit 0 */
bnez t0,1f /* booting from above kseg1 */
/*
** Call IcacheFlush. Masking used to call EEPROM address of IcacheFlush. Label is RAM label.
*/
@@ -139,6 +165,7 @@ _branch:
la t0,IcacheFlush
and t0,0x0000ffff
or t0,t2
move k0,t0 /* save cache flush in-prom address */
jal t0
nop
@@ -177,10 +204,12 @@ _branch:
la t0,putch_rom
and t0,0x0000ffff
or t0,t2
move k1,t0 /* save cache flush in-prom address */
jal t0
nop
1:
/*
** Print ' RTEMS b'. Show that we are booting.
*/
@@ -277,16 +306,16 @@ _branch:
la t0,putch_rom
and t0,0x0000ffff
or t0,t2
jal t0
jal t0
nop
la a3, _edata
la a3, _edata
relocate:
lw t0, (a1) /* load from EEPROM */
addu a1, 4
sw t0, (a2) /* store to RAM */
addu a2, 4
bne a2, a3, relocate /* copied all the way to edata? */
lw t0, (a1) /* load from EEPROM */
addu a1, 4
sw t0, (a2) /* store to RAM */
addu a2, 4
bne a2, a3, relocate /* copied all the way to edata? */
nop
/*
@@ -317,11 +346,11 @@ _start_in_ram:
/*
** Print 'S'. Already in RAM no need to reference EEPROM address.
*/
li a0,'S'
jal putch_rom
li a0,'S'
jal putch_rom
nop
la gp, _gp /* set the global data pointer */
la gp, _gp /* set the global data pointer */
.end _start_in_ram
@@ -341,12 +370,12 @@ zerobss:
jal putch_rom
nop
la v0, _fbss
la v1, _end
la v0, _fbss
la v1, _end
3:
sw zero,0(v0)
bltu v0,v1,3b
addiu v0,v0,4 /* executed in delay slot */
sw zero,0(v0)
bltu v0,v1,3b
addiu v0,v0,4 /* executed in delay slot */
la t0, _stack_init /* initialize stack so we */
@@ -368,8 +397,8 @@ zerobss:
/*
** Print 'Z'. Finished zeroing bss.
*/
li a0,'Z'
jal putch_rom
li a0,'Z'
jal putch_rom
nop
.end zerobss
@@ -387,12 +416,26 @@ _init:
/*
** Print 'i'. Starting to initialize RTEMS.
*/
li a0, 'i'
jal putch_rom
li a0, 'i'
jal putch_rom
nop
move a0,zero /* set argc to 0 */
jal boot_card /* call the program start function */
/*
** Save the boot-time addresses of the I & D cache flush routines.
** Note, if we're running from RAM, we cannot manipulate the cache
** so we just disable the cache flush functions.
*/
la a0,_promIcache
sw k0,0(a0)
nop
la a0,_promDcache
sw k1,0(a0)
nop
move a0,zero /* set argc to 0 */
jal boot_card /* call the program start function */
nop
/*
@@ -748,13 +791,77 @@ _cpuinit:
.end _cpuinit
/**********************************************************************
**
** Keep the boot-time address of the I & D cache reset code for
** later on. If we need to clear the I/D caches, we <must> run from
** non-cached memory. This means the relocated versions are useless,
** thankfully they are quite small.
*/
_promIcache: .word 0
_promDcache: .word 0
.globl promCopyIcacheFlush
.ent promCopyIcacheFlush
.set noreorder
promCopyIcacheFlush:
move a0,ra
la t1,_promIcache
lw t0,0(t1)
nop
beqz t0,1f
jal t0
nop
1: j a0
nop
.set reorder
.end promCopyIcacheFlush
.globl promCopyDcacheFlush
.ent promCopyDcacheFlush
.set noreorder
promCopyDcacheFlush:
move a0,ra
la t1,_promDcache
lw t0,0(t1)
nop
beqz t0,1f
jal t0
nop
1: j a0
nop
.set reorder
.end promCopyDcacheFlush
/*******************************************************************************
** Function Name: IcacheFlush
** Description: This functions flushes the on chip icache.
*/
.globl IcacheFlush
.ent IcacheFlush
.set noreorder
IcacheFlush:
1:
@@ -763,8 +870,6 @@ IcacheFlush:
li t0, M_BIU
lw t1, 0(t0)
.set noreorder
# Isolate I cache
mfc0 t3, C0_SR /* Read Status Register */
nop
@@ -778,7 +883,7 @@ IcacheFlush:
icache_write:
sw zero, 0(t8) /* Store zero to memory addres in t8 */
addu t8, 4 /* Increment t8 addres by 4 */
addu t8, 4 /* Increment t8 address by 4 */
bltu t8, t9, icache_write /* check to see if we are done */
nop
@@ -798,12 +903,12 @@ icache_write:
** Description: This functions flushes the on chip dcache.
*/
.globl DcacheFlush
.ent DcacheFlush
.set noreorder
DcacheFlush:
# isolate icache
.set noreorder
mfc0 t3,C0_SR
nop
or t0, t3, SR_ISC

View File

@@ -27,6 +27,7 @@
/*
* The original table from the application and our copy of it with
* some changes.
@@ -87,69 +88,88 @@ void bsp_pretasking_hook(void)
void bsp_start( void )
{
extern int WorkspaceBase;
extern void mips_install_isr_entries();
extern void _sys_exit(int);
extern int WorkspaceBase;
extern void mips_install_isr_entries();
extern void mips_gdb_stub_install(void);
/* Configure Number of Register Caches */
/* Configure Number of Register Caches */
Cpu_table.pretasking_hook = bsp_pretasking_hook; /* init libc, etc. */
Cpu_table.postdriver_hook = bsp_postdriver_hook;
Cpu_table.interrupt_stack_size = 4096;
Cpu_table.pretasking_hook = bsp_pretasking_hook; /* init libc, etc. */
Cpu_table.postdriver_hook = bsp_postdriver_hook;
Cpu_table.interrupt_stack_size = 4096;
/* HACK -- tied to value linkcmds */
if ( BSP_Configuration.work_space_size > (4096*1024) )
_sys_exit( 1 );
/* HACK -- tied to value linkcmds */
if ( BSP_Configuration.work_space_size > (4096*1024) )
_sys_exit( 1 );
BSP_Configuration.work_space_start = (void *) &WorkspaceBase;
BSP_Configuration.work_space_start = (void *) &WorkspaceBase;
/* mask off any interrupts */
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_FUNCTION_INTERRUPT_MASK_REGISTER, 0 );
/* mask off any interrupts */
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_FUNCTION_INTERRUPT_MASK_REGISTER, 0 );
/* reset the config register & clear any pending peripheral interrupts */
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_COMMAND_REGISTER, 0 );
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_COMMAND_REGISTER, MONGOOSEV_UART_CMD_RESET_BOTH_PORTS );
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_COMMAND_REGISTER, 0 );
MONGOOSEV_WRITE( MONGOOSEV_WATCHDOG, 0xA0 );
/* reset both timers */
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER1_BASE, MONGOOSEV_TIMER_INITIAL_COUNTER_REGISTER, 0xffffffff );
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER1_BASE, MONGOOSEV_TIMER_CONTROL_REGISTER, 0);
/* reset the config register & clear any pending peripheral interrupts */
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_COMMAND_REGISTER, 0 );
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_COMMAND_REGISTER, MONGOOSEV_UART_CMD_RESET_BOTH_PORTS );
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_COMMAND_REGISTER, 0 );
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER2_BASE, MONGOOSEV_TIMER_INITIAL_COUNTER_REGISTER, 0xffffffff );
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER2_BASE, MONGOOSEV_TIMER_CONTROL_REGISTER, 0);
/* reset both timers */
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER1_BASE, MONGOOSEV_TIMER_INITIAL_COUNTER_REGISTER, 0xffffffff );
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER1_BASE, MONGOOSEV_TIMER_CONTROL_REGISTER, 0);
/* clear any pending interrupts */
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_STATUS_REGISTER, 0xffffffff );
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER2_BASE, MONGOOSEV_TIMER_INITIAL_COUNTER_REGISTER, 0xffffffff );
MONGOOSEV_WRITE_REGISTER( MONGOOSEV_TIMER2_BASE, MONGOOSEV_TIMER_CONTROL_REGISTER, 0);
/* clear any writable bits in the cause register */
mips_set_cause( 0 );
/* clear any pending interrupts */
MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_STATUS_REGISTER, 0xffffffff );
/* set interrupt mask, but globally off. */
/* clear any writable bits in the cause register */
mips_set_cause( 0 );
/*
** Bit 15 | Bit 14 | Bit 13 | Bit 12 | Bit 11 | Bit 10 | Bit 9 | Bit 8 |
** periph | unused | FPU | unused | timer2 | timer1 | swint1 | swint2 |
** extern | | | | | | | |
**
** 1 0 1 0 0 1 0 0
**
** 0x8C00 Enable only internal Mongoose V timers.
** 0xA400 Enable Peripherial ints, FPU and timer1
** 0x0400 Timer1 only
*/
/* set interrupt mask, but globally off. */
/* mips_set_sr( (SR_CU0 | SR_CU1 | 0xA400) ); */
/*
** Bit 15 | Bit 14 | Bit 13 | Bit 12 | Bit 11 | Bit 10 | Bit 9 | Bit 8 |
** periph | unused | FPU | unused | timer2 | timer1 | swint1 | swint2 |
** extern | | | | | | | |
**
** 1 0 1 0 0 1 0 0
**
** 0x8C00 Enable only internal Mongoose V timers.
** 0xA400 Enable Peripherial ints, FPU and timer1
*/
/* to start up, only enable coprocessor 0 & timer int. per-task
** processor settings will be applied as they are created, this
** is just to configure the processor for startup
*/
mips_set_sr( (SR_CU0 | 0x400) );
mips_set_sr( (SR_CU0 | SR_CU1 | 0xA400) );
mips_install_isr_entries();
mips_install_isr_entries();
}
void clear_cache( void *address, size_t n )
void clear_cache( void )
{
extern void promCopyIcacheFlush(void); /* from start.S */
extern void promCopyDcacheFlush(void);
promCopyIcacheFlush();
promCopyDcacheFlush();
}
/* Structure filled in by get_mem_info. Only the size field is
actually used (to clear bss), so the others aren't even filled in. */
/*
//Structure filled in by get_mem_info.
struct s_mem
{
@@ -159,11 +179,14 @@ struct s_mem
};
extern unsigned32 _RamSize;
void get_mem_info ( struct s_mem *mem )
{
mem->size = (unsigned32)&_RamSize;
mem->icsize = MONGOOSEV_IC_SIZE;
mem->dcsize = MONGOOSEV_DC_SIZE;
}
*/

View File

@@ -13,16 +13,103 @@
#include <rtems.h>
#include <rtems/bspIo.h>
#include <libcpu/mongoose-v.h>
#include <rtems/libio.h>
/*
We're going to call right down into the uart driver because we're
operating within an exception. if things are broken because something
bad happened, this may be our last chance to debug before RTEMS goes
mad, so we won't rely on the I/O subsystem to be operating. This is a
little messy, but at least we're not talking right to the hardware.
*/
extern int mg5uart_set_attributes(int minor,const struct termios *t);
extern int mg5uart_open(int major,int minor, void *arg);
extern int mg5uart_close(int major,int minor, void *arg);
extern void mg5uart_write_polled(int minor, char c );
extern int mg5uart_inbyte_nonblocking_polled(int minor);
extern void mips_gdb_stub_install(void);
static int debugUartEnabled = 0;
int mg5rdbgOpenGDBuart(int breakoninit)
{
struct termios t;
memset(&t,0,sizeof(struct termios));
if( mg5uart_open(0,1,NULL) != RTEMS_SUCCESSFUL )
{
printf("gdbstub: Failed to open UART port 2\n");
return -1;
}
t.c_cflag |= B19200;
t.c_cflag |= CS8;
if( mg5uart_set_attributes(1,&t) != 0 )
{
printf("gdbstub: Failed to configure UART 2 for 19200N82\n");
return -1;
}
debugUartEnabled = -1;
/* set up vectoring for gdb */
mips_gdb_stub_install();
printf("gdbstub: Remote GDB stub listening on UART 2 at 19200N82\n");
if( breakoninit )
{
/*
break to gdb. We'll wait there for the operator to get their gdb
going, then they can 'continue' or do whatever.
*/
mips_break(0);
}
printf("gdbstub: User code running\n");
return RTEMS_SUCCESSFUL;
}
void mg5rdbgCloseGDBuart(void)
{
mg5uart_close(0,1,NULL);
debugUartEnabled = 0;
}
char getDebugChar (void)
{
return 0;
if( debugUartEnabled )
{
int rv;
while( (rv = mg5uart_inbyte_nonblocking_polled(1)) < 0 );
return (char)rv;
}
return 0;
}
void putDebugChar (char c)
{
/* big hack */
printk( "%c" );
if( debugUartEnabled )
return mg5uart_write_polled(1,c);
}

View File

@@ -21,7 +21,6 @@ ClockRate = DEFINED(ClockRate) ? ClockRate : 12000000;
MEMORY
{
romstore : ORIGIN = 0xbfc40000, LENGTH = 4M
ram : ORIGIN = 0x80020000, LENGTH = 4M
}
@@ -42,7 +41,8 @@ SECTIONS
*(.rel.dyn)
PROVIDE (__runtime_reloc_stop = .);
*(.fini)
} >ram AT>romstore
*(.gcc_except_table)
} >ram
.ctors :
{
@@ -66,7 +66,7 @@ SECTIONS
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >ram AT>romstore
} >ram
.dtors :
{
@@ -77,9 +77,9 @@ SECTIONS
etext = .;
_etext = .;
} >ram AT>romstore
} >ram
/* . = .; */
.rdata :
{
@@ -87,7 +87,7 @@ SECTIONS
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r*)
} >ram AT>romstore
} >ram
.data :
{
@@ -96,7 +96,7 @@ SECTIONS
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
} >ram AT>romstore
} >ram
.lit8 :
@@ -106,29 +106,28 @@ SECTIONS
_gp = . + 0x8000;
__global = _gp;
*(.lit8)
} >ram AT>romstore
} >ram
.lit4 :
{
*(.lit4)
} >ram AT>romstore
} >ram
.sdata :
{
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s*)
} >ram AT>romstore
} >ram
.sbss :
{
. = ALIGN(4);
edata = .;
_edata = .;
_fbss = .;
*(.sbss)
*(.scommon)
} >ram AT>romstore
} >ram
.bss :
@@ -148,7 +147,7 @@ SECTIONS
WorkspaceBase = .;
end = .;
_end = .;
} >ram AT>romstore
} >ram
/*
@@ -158,29 +157,29 @@ SECTIONS
*/
/* DWARF 1 */
.debug 0 : { *(.debug) } AT>romstore
.line 0 : { *(.line) } AT>romstore
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) } AT>romstore
.debug_sfnames 0 : { *(.debug_sfnames) } AT>romstore
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) } AT>romstore
.debug_pubnames 0 : { *(.debug_pubnames) } AT>romstore
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) } AT>romstore
.debug_abbrev 0 : { *(.debug_abbrev) } AT>romstore
.debug_line 0 : { *(.debug_line) } AT>romstore
.debug_frame 0 : { *(.debug_frame)} AT>romstore
.debug_str 0 : { *(.debug_str) } AT>romstore
.debug_loc 0 : { *(.debug_loc) } AT>romstore
.debug_macinfo 0 : { *(.debug_macinfo) } AT>romstore
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame)}
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) } AT>romstore
.debug_funcnames 0 : { *(.debug_funcnames) } AT>romstore
.debug_typenames 0 : { *(.debug_typenames) } AT>romstore
.debug_varnames 0 : { *(.debug_varnames) } AT>romstore
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}