fix g_dfu access from both DFU and runtime access

We need to refer to g_dfu as a pointer from all code.  In DFU mode, it
gets assigned to the address of _g_dfu, which is placed by the linker
script at the start of RAM.  In runtime mode, the pointer is statically
defined to point at the start of RAM.  The linker script for the runtime
(dfu environment) is adjusted to save the first 32 bytes for the _g_dfu
structure.
diff --git a/firmware/apps/dfu/main.c b/firmware/apps/dfu/main.c
index af595ac..5b07867 100644
--- a/firmware/apps/dfu/main.c
+++ b/firmware/apps/dfu/main.c
@@ -35,8 +35,8 @@
 	case ALTIF_RAM:
 		addr = RAM_ADDR(offset);
 		if (addr > IRAM_ADDR + IRAM_SIZE) {
-			g_dfu.state = DFU_STATE_dfuERROR;
-			g_dfu.status = DFU_STATUS_errADDRESS;
+			g_dfu->state = DFU_STATE_dfuERROR;
+			g_dfu->status = DFU_STATUS_errADDRESS;
 			return DFU_RET_STALL;
 		}
 		memcpy((void *)addr, data, len);
@@ -44,8 +44,8 @@
 	case ALTIF_FLASH:
 		addr = FLASH_ADDR(offset);
 		if (addr > IFLASH_ADDR + IFLASH_SIZE) {
-			g_dfu.state = DFU_STATE_dfuERROR;
-			g_dfu.status = DFU_STATUS_errADDRESS;
+			g_dfu->state = DFU_STATE_dfuERROR;
+			g_dfu->status = DFU_STATUS_errADDRESS;
 			return DFU_RET_STALL;
 		}
 		rc = FLASHD_Write(addr, data, len);
@@ -75,8 +75,8 @@
 	case ALTIF_RAM:
 		addr = RAM_ADDR(offset);
 		if (addr > IRAM_ADDR + IRAM_SIZE) {
-			g_dfu.state = DFU_STATE_dfuERROR;
-			g_dfu.status = DFU_STATUS_errADDRESS;
+			g_dfu->state = DFU_STATE_dfuERROR;
+			g_dfu->status = DFU_STATUS_errADDRESS;
 			return -1;
 		}
 		if ((uint8_t *)addr + req_len > IRAM_END)
@@ -86,8 +86,8 @@
 	case ALTIF_FLASH:
 		addr = FLASH_ADDR(offset);
 		if (addr > IFLASH_ADDR + IFLASH_SIZE) {
-			g_dfu.state = DFU_STATE_dfuERROR;
-			g_dfu.status = DFU_STATUS_errADDRESS;
+			g_dfu->state = DFU_STATE_dfuERROR;
+			g_dfu->status = DFU_STATUS_errADDRESS;
 			return -1;
 		}
 		if ((uint8_t *)addr + req_len > IFLASH_END)
diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
index 7776004..05e62e4 100644
--- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
+++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
@@ -1164,7 +1164,7 @@
         TRACE_INFO_WP("EoBRes ");

 

 #if defined(BOARD_USB_DFU) && defined(dfu)

-	if (g_dfu.past_manifest)

+	if (g_dfu->past_manifest)

 		USBDFU_SwitchToApp();

 #endif

 

diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
index 9033de6..b49cce0 100644
--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
@@ -98,7 +98,7 @@
 	unsigned int total_bytes;
 };
 
-extern struct dfudata g_dfu;
+extern struct dfudata *g_dfu;
 
 void set_usb_serial_str(const uint8_t *serial_usbstr);
 
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c
index 14a8469..5ba84c3 100644
--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c
@@ -42,11 +42,12 @@
 static USBDDriver usbdDriver;
 static unsigned char if_altsettings[1];
 
-__dfudata struct dfudata g_dfu = {
+__dfudata struct dfudata _g_dfu = {
   	.state = DFU_STATE_appIDLE,
 	.past_manifest = 0,
 	.total_bytes = 0,
 };
+struct dfudata *g_dfu = &_g_dfu;
 
 WEAK void dfu_drv_updstatus(void)
 {
@@ -55,8 +56,8 @@
 	/* we transition immediately from MANIFEST_SYNC to MANIFEST,
 	 * as the flash-writing is not asynchronous in this
 	 * implementation */
-	if (g_dfu.state == DFU_STATE_dfuMANIFEST_SYNC)
-		g_dfu.state = DFU_STATE_dfuMANIFEST;
+	if (g_dfu->state == DFU_STATE_dfuMANIFEST_SYNC)
+		g_dfu->state = DFU_STATE_dfuMANIFEST;
 }
 
 static __dfufunc void handle_getstatus(void)
@@ -67,8 +68,8 @@
 	dfu_drv_updstatus();
 
 	/* send status response */
-	dstat.bStatus = g_dfu.status;
-	dstat.bState = g_dfu.state;
+	dstat.bStatus = g_dfu->status;
+	dstat.bState = g_dfu->state;
 	dstat.iString = 0;
 	/* FIXME: set dstat.bwPollTimeout */
 
@@ -79,9 +80,9 @@
 
 static void __dfufunc handle_getstate(void)
 {
-	uint8_t u8 = g_dfu.state;
+	uint8_t u8 = g_dfu->state;
 
-	TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu.state);
+	TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu->state);
 
 	USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0);
 }
@@ -114,15 +115,15 @@
 		return;
 	}
 
-	rc = USBDFU_handle_dnload(if_altsettings[0], g_dfu.total_bytes, dfu_buf, transferred);
+	rc = USBDFU_handle_dnload(if_altsettings[0], g_dfu->total_bytes, dfu_buf, transferred);
 	switch (rc) {
 	case DFU_RET_ZLP:
-		g_dfu.total_bytes += transferred;
-		g_dfu.state = DFU_STATE_dfuDNLOAD_IDLE;
+		g_dfu->total_bytes += transferred;
+		g_dfu->state = DFU_STATE_dfuDNLOAD_IDLE;
 		TerminateCtrlInWithNull(0,0,0,0);
 		break;
 	case DFU_RET_STALL:
-		g_dfu.state = DFU_STATE_dfuERROR;
+		g_dfu->state = DFU_STATE_dfuERROR;
 		USBD_Stall(0);
 		break;
 	case DFU_RET_NOTHING:
@@ -137,24 +138,24 @@
 
 	if (len > BOARD_DFU_PAGE_SIZE) {
 		TRACE_ERROR("DFU length exceeds flash page size\n\r");
-		g_dfu.state = DFU_STATE_dfuERROR;
-		g_dfu.status = DFU_STATUS_errADDRESS;
+		g_dfu->state = DFU_STATE_dfuERROR;
+		g_dfu->status = DFU_STATUS_errADDRESS;
 		return DFU_RET_STALL;
 	}
 
 	if (len & 0x03) {
 		TRACE_ERROR("DFU length not four-byte-aligned\n\r");
-		g_dfu.state = DFU_STATE_dfuERROR;
-		g_dfu.status = DFU_STATUS_errADDRESS;
+		g_dfu->state = DFU_STATE_dfuERROR;
+		g_dfu->status = DFU_STATUS_errADDRESS;
 		return DFU_RET_STALL;
 	}
 
 	if (first)
-		g_dfu.total_bytes = 0;
+		g_dfu->total_bytes = 0;
 
 	if (len == 0) {
 		TRACE_DEBUG("zero-size write -> MANIFEST_SYNC\n\r");
-		g_dfu.state = DFU_STATE_dfuMANIFEST_SYNC;
+		g_dfu->state = DFU_STATE_dfuMANIFEST_SYNC;
 		return DFU_RET_ZLP;
 	}
 
@@ -180,7 +181,7 @@
 		return;
 	}
 
-	g_dfu.total_bytes += transferred;
+	g_dfu->total_bytes += transferred;
 }
 
 static int handle_upload(uint16_t val, uint16_t len, int first)
@@ -188,16 +189,16 @@
 	int rc;
 
 	if (first)
-		g_dfu.total_bytes = 0;
+		g_dfu->total_bytes = 0;
 
 	if (len > BOARD_DFU_PAGE_SIZE) {
 		TRACE_ERROR("DFU length exceeds flash page size\n\r");
-		g_dfu.state = DFU_STATE_dfuERROR;
-		g_dfu.status = DFU_STATUS_errADDRESS;
+		g_dfu->state = DFU_STATE_dfuERROR;
+		g_dfu->status = DFU_STATUS_errADDRESS;
 		return DFU_RET_STALL;
 	}
 
-	rc = USBDFU_handle_upload(if_altsettings[0], g_dfu.total_bytes, dfu_buf, len);
+	rc = USBDFU_handle_upload(if_altsettings[0], g_dfu->total_bytes, dfu_buf, len);
 	if (rc < 0) {
 		TRACE_ERROR("application handle_upload() returned %d\n\r", rc);
 		return DFU_RET_STALL;
@@ -249,7 +250,7 @@
 		USBDDriver_RequestHandler(&usbdDriver, request);
 	}
 
-	switch (g_dfu.state) {
+	switch (g_dfu->state) {
 	case DFU_STATE_appIDLE:
 	case DFU_STATE_appDETACH:
 		TRACE_ERROR("Invalid DFU State reached in DFU mode\r\n");
@@ -259,15 +260,15 @@
 		switch (req) {
 		case USB_REQ_DFU_DNLOAD:
 			if (len == 0) {
-				g_dfu.state = DFU_STATE_dfuERROR;
+				g_dfu->state = DFU_STATE_dfuERROR;
 				ret = DFU_RET_STALL;
 				goto out;
 			}
-			g_dfu.state = DFU_STATE_dfuDNLOAD_SYNC;
+			g_dfu->state = DFU_STATE_dfuDNLOAD_SYNC;
 			ret = handle_dnload(val, len, 1);
 			break;
 		case USB_REQ_DFU_UPLOAD:
-			g_dfu.state = DFU_STATE_dfuUPLOAD_IDLE;
+			g_dfu->state = DFU_STATE_dfuUPLOAD_IDLE;
 			handle_upload(val, len, 1);
 			break;
 		case USB_REQ_DFU_ABORT:
@@ -281,7 +282,7 @@
 			handle_getstate();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			goto out;
 			break;
@@ -297,7 +298,7 @@
 			handle_getstate();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			goto out;
 		}
@@ -310,7 +311,7 @@
 			handle_getstatus();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			goto out;
 		}
@@ -318,11 +319,11 @@
 	case DFU_STATE_dfuDNLOAD_IDLE:
 		switch (req) {
 		case USB_REQ_DFU_DNLOAD:
-			g_dfu.state = DFU_STATE_dfuDNLOAD_SYNC;
+			g_dfu->state = DFU_STATE_dfuDNLOAD_SYNC;
 			ret = handle_dnload(val, len, 0);
 			break;
 		case USB_REQ_DFU_ABORT:
-			g_dfu.state = DFU_STATE_dfuIDLE;
+			g_dfu->state = DFU_STATE_dfuIDLE;
 			ret = DFU_RET_ZLP;
 			break;
 		case USB_REQ_DFU_GETSTATUS:
@@ -332,7 +333,7 @@
 			handle_getstate();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			break;
 		}
@@ -346,7 +347,7 @@
 			handle_getstate();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			break;
 		}
@@ -361,16 +362,16 @@
 			 * that we've already been through MANIFST in
 			 * the global variable 'past_manifest'.
 			 */
-			//g_dfu.state = DFU_STATE_dfuMANIFEST_WAIT_RST;
-			g_dfu.state = DFU_STATE_dfuIDLE;
-			g_dfu.past_manifest = 1;
+			//g_dfu->state = DFU_STATE_dfuMANIFEST_WAIT_RST;
+			g_dfu->state = DFU_STATE_dfuIDLE;
+			g_dfu->past_manifest = 1;
 			handle_getstatus();
 			break;
 		case USB_REQ_DFU_GETSTATE:
 			handle_getstate();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			break;
 		}
@@ -384,10 +385,10 @@
 			/* state transition if less data then requested */
 			rc = handle_upload(val, len, 0);
 			if (rc >= 0 && rc < len)
-				g_dfu.state = DFU_STATE_dfuIDLE;
+				g_dfu->state = DFU_STATE_dfuIDLE;
 			break;
 		case USB_REQ_DFU_ABORT:
-			g_dfu.state = DFU_STATE_dfuIDLE;
+			g_dfu->state = DFU_STATE_dfuIDLE;
 			/* no zlp? */
 			ret = DFU_RET_ZLP;
 			break;
@@ -398,7 +399,7 @@
 			handle_getstate();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			break;
 		}
@@ -412,13 +413,13 @@
 			handle_getstate();
 			break;
 		case USB_REQ_DFU_CLRSTATUS:
-			g_dfu.state = DFU_STATE_dfuIDLE;
-			g_dfu.status = DFU_STATUS_OK;
+			g_dfu->state = DFU_STATE_dfuIDLE;
+			g_dfu->status = DFU_STATUS_OK;
 			/* no zlp? */
 			ret = DFU_RET_ZLP;
 			break;
 		default:
-			g_dfu.state = DFU_STATE_dfuERROR;
+			g_dfu->state = DFU_STATE_dfuERROR;
 			ret = DFU_RET_STALL;
 			break;
 		}
@@ -442,7 +443,7 @@
 void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors)
 {
 	/* We already start in DFU idle mode */
-	g_dfu.state = DFU_STATE_dfuIDLE;
+	g_dfu->state = DFU_STATE_dfuIDLE;
 
 	USBDDriver_Initialize(&usbdDriver, pDescriptors, if_altsettings);
 	USBD_Init();
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c
index 3bf7aa5..ba9665e 100644
--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c
@@ -35,9 +35,10 @@
 #include <usb/common/dfu/usb_dfu.h>
 #include <usb/device/dfu/dfu.h>
 
+struct dfudata *g_dfu = (struct dfudata *) IRAM_ADDR;
+
 /* FIXME: this was used for a special ELF section which then got called
  * by DFU code and Application code, across flash partitions */
-#define __dfudata
 #define __dfufunc
 
 static __dfufunc void handle_getstatus(void)
@@ -46,8 +47,8 @@
 	static struct dfu_status dstat;
 
 	/* send status response */
-	dstat.bStatus = g_dfu.status;
-	dstat.bState = g_dfu.state;
+	dstat.bStatus = g_dfu->status;
+	dstat.bState = g_dfu->state;
 	dstat.iString = 0;
 	/* FIXME: set dstat.bwPollTimeout */
 
@@ -58,9 +59,9 @@
 
 static void __dfufunc handle_getstate(void)
 {
-	uint8_t u8 = g_dfu.state;
+	uint8_t u8 = g_dfu->state;
 
-	TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu.state);
+	TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu->state);
 
 	USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0);
 }
@@ -118,7 +119,7 @@
 		USBDDriver_RequestHandler(usbdDriver, request);
 	}
 
-	switch (g_dfu.state) {
+	switch (g_dfu->state) {
 	case DFU_STATE_appIDLE:
 		switch (req) {
 		case USB_REQ_DFU_GETSTATUS:
@@ -132,7 +133,7 @@
 			 * return.  The next USB reset in this state
 			 * will then trigger DFURT_SwitchToDFU() below */
 			TRACE_DEBUG("\r\n====dfu_detach\n\r");
-			g_dfu.state = DFU_STATE_appDETACH;
+			g_dfu->state = DFU_STATE_appDETACH;
 			ret = DFU_RET_ZLP;
 			goto out;
 			break;
@@ -149,7 +150,7 @@
 			handle_getstate();
 			break;
 		default:
-			g_dfu.state = DFU_STATE_appIDLE;
+			g_dfu->state = DFU_STATE_appIDLE;
 			ret = DFU_RET_STALL;
 			goto out;
 			break;
diff --git a/firmware/libboard/common/resources/sam3s4/dfu.ld b/firmware/libboard/common/resources/sam3s4/dfu.ld
index c91c4c1..e56a435 100644
--- a/firmware/libboard/common/resources/sam3s4/dfu.ld
+++ b/firmware/libboard/common/resources/sam3s4/dfu.ld
@@ -38,8 +38,10 @@
 /* Memory Spaces Definitions */
 MEMORY
 {
+	/* reserve the first 16k (= 0x4000) for the DFU bootloader */
 	rom (rx)  : ORIGIN = 0x00404000, LENGTH = 0x0003c000 /* flash, 256K */
-	ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0000c000 /* sram, 48K */
+	/* reserve the first 32 (= 0x20) bytes for the _g_dfu struct */
+	ram (rwx) : ORIGIN = 0x20000020, LENGTH = 0x0000bfe0 /* sram, 48K */
 }
 
 /* Section Definitions */