aboutsummaryrefslogtreecommitdiff
path: root/arch/microblaze/kernel
diff options
context:
space:
mode:
authorLinus Torvalds2009-09-24 09:01:44 -0700
committerLinus Torvalds2009-09-24 09:01:44 -0700
commita6b49cb210f878709bdc0bddc16a853f18790d02 (patch)
tree6147078ef0ce584cb6a8dae7468f060ef5838d12 /arch/microblaze/kernel
parent2c9871de0ae89a0e2c365ea6e277135fe031d8b4 (diff)
parentbfc8125858d777bd5bdba03a091c07cc2e0e17c0 (diff)
Merge branch 'for-linus' of git://git.monstr.eu/linux-2.6-microblaze
* 'for-linus' of git://git.monstr.eu/linux-2.6-microblaze: (24 commits) microblaze: Disable heartbeat/enable emaclite in defconfigs microblaze: Support simpleImage.dts make target microblaze: Fix _start symbol to physical address microblaze: Use LOAD_OFFSET macro to get correct LMA for all sections microblaze: Create the LOAD_OFFSET macro used to compute VMA vs LMA offsets microblaze: Copy ppc asm-compat.h for clean handling of constants in asm and C microblaze: Actually show KiB rather than pages in "Freeing initrd memory:" microblaze: Support ptrace syscall tracing. microblaze: Updated CPU version and FPGA family codes in PVR microblaze: Generate correct signal and siginfo for integer div-by-zero microblaze: Don't be noisy when userspace causes hardware exceptions microblaze: Remove ipc.h file which points to non-existing asm-generic file microblaze: Clear sticky FSR register after generating exception signals microblaze: Ensure CPU usermode is set on new userspace processes microblaze: Use correct kbuild variable KBUILD_CFLAGS microblaze: Save and restore msr in hw exception microblaze: Add architectural support for USB EHCI host controllers microblaze: Implement include/asm/syscall.h. microblaze: Improve checking mechanism for MSR instruction microblaze: Add checking mechanism for MSR instruction ...
Diffstat (limited to 'arch/microblaze/kernel')
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c3
-rw-r--r--arch/microblaze/kernel/entry.S72
-rw-r--r--arch/microblaze/kernel/exceptions.c33
-rw-r--r--arch/microblaze/kernel/head.S14
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S10
-rw-r--r--arch/microblaze/kernel/process.c1
-rw-r--r--arch/microblaze/kernel/ptrace.c62
-rw-r--r--arch/microblaze/kernel/setup.c12
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S72
9 files changed, 205 insertions, 74 deletions
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index c411c6757deb..3539babc1c18 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -28,6 +28,7 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
{"7.10.d", 0x0b},
{"7.20.a", 0x0c},
{"7.20.b", 0x0d},
+ {"7.20.c", 0x0e},
/* FIXME There is no keycode defined in MBV for these versions */
{"2.10.a", 0x10},
{"3.00.a", 0x20},
@@ -49,6 +50,8 @@ const struct family_string_key family_string_lookup[] = {
{"spartan3a", 0xa},
{"spartan3an", 0xb},
{"spartan3adsp", 0xc},
+ {"spartan6", 0xd},
+ {"virtex6", 0xe},
/* FIXME There is no key code defined for spartan2 */
{"spartan2", 0xf0},
{NULL, 0},
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index c7353e79f4a2..acc1f05d1e2c 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -308,38 +308,69 @@ C_ENTRY(_user_exception):
swi r12, r1, PTO+PT_R0;
tovirt(r1,r1)
- la r15, r0, ret_from_trap-8
/* where the trap should return need -8 to adjust for rtsd r15, 8*/
/* Jump to the appropriate function for the system call number in r12
* (r12 is not preserved), or return an error if r12 is not valid. The LP
* register should point to the location where
* the called function should return. [note that MAKE_SYS_CALL uses label 1] */
- /* See if the system call number is valid. */
+
+ # Step into virtual mode.
+ set_vms;
+ addik r11, r0, 3f
+ rtid r11, 0
+ nop
+3:
+ add r11, r0, CURRENT_TASK /* Get current task ptr into r11 */
+ lwi r11, r11, TS_THREAD_INFO /* get thread info */
+ lwi r11, r11, TI_FLAGS /* get flags in thread info */
+ andi r11, r11, _TIF_WORK_SYSCALL_MASK
+ beqi r11, 4f
+
+ addik r3, r0, -ENOSYS
+ swi r3, r1, PTO + PT_R3
+ brlid r15, do_syscall_trace_enter
+ addik r5, r1, PTO + PT_R0
+
+ # do_syscall_trace_enter returns the new syscall nr.
+ addk r12, r0, r3
+ lwi r5, r1, PTO+PT_R5;
+ lwi r6, r1, PTO+PT_R6;
+ lwi r7, r1, PTO+PT_R7;
+ lwi r8, r1, PTO+PT_R8;
+ lwi r9, r1, PTO+PT_R9;
+ lwi r10, r1, PTO+PT_R10;
+4:
+/* Jump to the appropriate function for the system call number in r12
+ * (r12 is not preserved), or return an error if r12 is not valid.
+ * The LP register should point to the location where the called function
+ * should return. [note that MAKE_SYS_CALL uses label 1] */
+ /* See if the system call number is valid */
addi r11, r12, -__NR_syscalls;
- bgei r11,1f;
+ bgei r11,5f;
/* Figure out which function to use for this system call. */
/* Note Microblaze barrel shift is optional, so don't rely on it */
add r12, r12, r12; /* convert num -> ptr */
add r12, r12, r12;
/* Trac syscalls and stored them to r0_ram */
- lwi r3, r12, 0x400 + TOPHYS(r0_ram)
+ lwi r3, r12, 0x400 + r0_ram
addi r3, r3, 1
- swi r3, r12, 0x400 + TOPHYS(r0_ram)
+ swi r3, r12, 0x400 + r0_ram
+
+ # Find and jump into the syscall handler.
+ lwi r12, r12, sys_call_table
+ /* where the trap should return need -8 to adjust for rtsd r15, 8 */
+ la r15, r0, ret_from_trap-8
+ bra r12
- lwi r12, r12, TOPHYS(sys_call_table); /* Function ptr */
- /* Make the system call. to r12*/
- set_vms;
- rtid r12, 0;
- nop;
/* The syscall number is invalid, return an error. */
-1: VM_ON; /* RETURN() expects virtual mode*/
+5:
addi r3, r0, -ENOSYS;
rtsd r15,8; /* looks like a normal subroutine return */
or r0, r0, r0
-/* Entry point used to return from a syscall/trap. */
+/* Entry point used to return from a syscall/trap */
/* We re-enable BIP bit before state restore */
C_ENTRY(ret_from_trap):
set_bip; /* Ints masked for state restore*/
@@ -349,6 +380,23 @@ C_ENTRY(ret_from_trap):
/* We're returning to user mode, so check for various conditions that
* trigger rescheduling. */
+ # FIXME: Restructure all these flag checks.
+ add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
+ lwi r11, r11, TS_THREAD_INFO; /* get thread info */
+ lwi r11, r11, TI_FLAGS; /* get flags in thread info */
+ andi r11, r11, _TIF_WORK_SYSCALL_MASK
+ beqi r11, 1f
+
+ swi r3, r1, PTO + PT_R3
+ swi r4, r1, PTO + PT_R4
+ brlid r15, do_syscall_trace_leave
+ addik r5, r1, PTO + PT_R0
+ lwi r3, r1, PTO + PT_R3
+ lwi r4, r1, PTO + PT_R4
+1:
+
+ /* We're returning to user mode, so check for various conditions that
+ * trigger rescheduling. */
/* Get current task ptr into r11 */
add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */
lwi r11, r11, TS_THREAD_INFO; /* get thread info */
diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c
index 0cb64a31e89a..d9f70f83097f 100644
--- a/arch/microblaze/kernel/exceptions.c
+++ b/arch/microblaze/kernel/exceptions.c
@@ -72,7 +72,8 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
#endif
#if 0
- printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n",
+ printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x " \
+ "ESR=%08x\n",
type, user_mode(regs) ? "user" : "kernel", fsr,
(unsigned int) regs->pc, (unsigned int) regs->esr);
#endif
@@ -80,42 +81,50 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
switch (type & 0x1F) {
case MICROBLAZE_ILL_OPCODE_EXCEPTION:
if (user_mode(regs)) {
- printk(KERN_WARNING "Illegal opcode exception in user mode.\n");
+ pr_debug(KERN_WARNING "Illegal opcode exception " \
+ "in user mode.\n");
_exception(SIGILL, regs, ILL_ILLOPC, addr);
return;
}
- printk(KERN_WARNING "Illegal opcode exception in kernel mode.\n");
+ printk(KERN_WARNING "Illegal opcode exception " \
+ "in kernel mode.\n");
die("opcode exception", regs, SIGBUS);
break;
case MICROBLAZE_IBUS_EXCEPTION:
if (user_mode(regs)) {
- printk(KERN_WARNING "Instruction bus error exception in user mode.\n");
+ pr_debug(KERN_WARNING "Instruction bus error " \
+ "exception in user mode.\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
- printk(KERN_WARNING "Instruction bus error exception in kernel mode.\n");
+ printk(KERN_WARNING "Instruction bus error exception " \
+ "in kernel mode.\n");
die("bus exception", regs, SIGBUS);
break;
case MICROBLAZE_DBUS_EXCEPTION:
if (user_mode(regs)) {
- printk(KERN_WARNING "Data bus error exception in user mode.\n");
+ pr_debug(KERN_WARNING "Data bus error exception " \
+ "in user mode.\n");
_exception(SIGBUS, regs, BUS_ADRERR, addr);
return;
}
- printk(KERN_WARNING "Data bus error exception in kernel mode.\n");
+ printk(KERN_WARNING "Data bus error exception " \
+ "in kernel mode.\n");
die("bus exception", regs, SIGBUS);
break;
case MICROBLAZE_DIV_ZERO_EXCEPTION:
if (user_mode(regs)) {
- printk(KERN_WARNING "Divide by zero exception in user mode\n");
- _exception(SIGILL, regs, ILL_ILLOPC, addr);
+ pr_debug(KERN_WARNING "Divide by zero exception " \
+ "in user mode\n");
+ _exception(SIGILL, regs, FPE_INTDIV, addr);
return;
}
- printk(KERN_WARNING "Divide by zero exception in kernel mode.\n");
+ printk(KERN_WARNING "Divide by zero exception " \
+ "in kernel mode.\n");
die("Divide by exception", regs, SIGBUS);
break;
case MICROBLAZE_FPU_EXCEPTION:
- printk(KERN_WARNING "FPU exception\n");
+ pr_debug(KERN_WARNING "FPU exception\n");
/* IEEE FP exception */
/* I removed fsr variable and use code var for storing fsr */
if (fsr & FSR_IO)
@@ -133,7 +142,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type,
#ifdef CONFIG_MMU
case MICROBLAZE_PRIVILEGED_EXCEPTION:
- printk(KERN_WARNING "Privileged exception\n");
+ pr_debug(KERN_WARNING "Privileged exception\n");
/* "brk r0,r0" - used as debug breakpoint */
if (get_user(code, (unsigned long *)regs->pc) == 0
&& code == 0x980c0000) {
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index e41c6ce2a7be..697ce3007f30 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -54,6 +54,16 @@ ENTRY(_start)
mfs r1, rmsr
andi r1, r1, ~2
mts rmsr, r1
+/*
+ * Here is checking mechanism which check if Microblaze has msr instructions
+ * We load msr and compare it with previous r1 value - if is the same,
+ * msr instructions works if not - cpu don't have them.
+ */
+ /* r8=0 - I have msr instr, 1 - I don't have them */
+ rsubi r0, r0, 1 /* set the carry bit */
+ msrclr r0, 0x4 /* try to clear it */
+ /* read the carry bit, r8 will be '0' if msrclr exists */
+ addik r8, r0, 0
/* r7 may point to an FDT, or there may be one linked in.
if it's in r7, we've got to save it away ASAP.
@@ -209,8 +219,8 @@ start_here:
* Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
* the function.
*/
- la r8, r0, machine_early_init
- brald r15, r8
+ la r9, r0, machine_early_init
+ brald r15, r9
nop
#ifndef CONFIG_MMU
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index 3288c9737671..6b0288ebccd6 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -84,9 +84,10 @@
#define NUM_TO_REG(num) r ## num
#ifdef CONFIG_MMU
-/* FIXME you can't change first load of MSR because there is
- * hardcoded jump bri 4 */
#define RESTORE_STATE \
+ lwi r5, r1, 0; \
+ mts rmsr, r5; \
+ nop; \
lwi r3, r1, PT_R3; \
lwi r4, r1, PT_R4; \
lwi r5, r1, PT_R5; \
@@ -309,6 +310,9 @@ _hw_exception_handler:
lwi r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)) /* get saved current */
#endif
+ mfs r5, rmsr;
+ nop
+ swi r5, r1, 0;
mfs r3, resr
nop
mfs r4, rear;
@@ -380,6 +384,8 @@ handle_other_ex: /* Handle Other exceptions here */
addk r8, r17, r0; /* Load exception address */
bralid r15, full_exception; /* Branch to the handler */
nop;
+ mts r0, rfsr; /* Clear sticky fsr */
+ nop
/*
* Trigger execution of the signal handler by enabling
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 00b12c6d5326..4201c743cc9f 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -235,6 +235,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
regs->pc = pc;
regs->r1 = usp;
regs->pt_mode = 0;
+ regs->msr |= MSR_UMS;
}
#ifdef CONFIG_MMU
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
index 53ff39af6a5c..4b3ac32754de 100644
--- a/arch/microblaze/kernel/ptrace.c
+++ b/arch/microblaze/kernel/ptrace.c
@@ -29,6 +29,10 @@
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/signal.h>
+#include <linux/elf.h>
+#include <linux/audit.h>
+#include <linux/seccomp.h>
+#include <linux/tracehook.h>
#include <linux/errno.h>
#include <asm/processor.h>
@@ -174,6 +178,64 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return rval;
}
+asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
+{
+ long ret = 0;
+
+ secure_computing(regs->r12);
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ tracehook_report_syscall_entry(regs))
+ /*
+ * Tracing decided this syscall should not happen.
+ * We'll return a bogus call number to get an ENOSYS
+ * error, but leave the original number in regs->regs[0].
+ */
+ ret = -1L;
+
+ if (unlikely(current->audit_context))
+ audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12,
+ regs->r5, regs->r6,
+ regs->r7, regs->r8);
+
+ return ret ?: regs->r12;
+}
+
+asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
+{
+ int step;
+
+ if (unlikely(current->audit_context))
+ audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3);
+
+ step = test_thread_flag(TIF_SINGLESTEP);
+ if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, step);
+}
+
+#if 0
+static asmlinkage void syscall_trace(void)
+{
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ return;
+ if (!(current->ptrace & PT_PTRACED))
+ return;
+ /* The 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0));
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+}
+#endif
+
void ptrace_disable(struct task_struct *child)
{
/* nothing to do */
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 2a97bf513b64..8c1e0f4dcf18 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -94,7 +94,7 @@ inline unsigned get_romfs_len(unsigned *addr)
#endif /* CONFIG_MTD_UCLINUX_EBSS */
void __init machine_early_init(const char *cmdline, unsigned int ram,
- unsigned int fdt)
+ unsigned int fdt, unsigned int msr)
{
unsigned long *src, *dst = (unsigned long *)0x0;
@@ -157,6 +157,16 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
early_printk("New klimit: 0x%08x\n", (unsigned)klimit);
#endif
+#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
+ if (msr)
+ early_printk("!!!Your kernel has setup MSR instruction but "
+ "CPU don't have it %d\n", msr);
+#else
+ if (!msr)
+ early_printk("!!!Your kernel not setup MSR instruction but "
+ "CPU have it %d\n", msr);
+#endif
+
for (src = __ivt_start; src < __ivt_end; src++, dst++)
*dst = *src;
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index ec5fa91a48d8..e704188d7855 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -12,13 +12,16 @@ OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze")
OUTPUT_ARCH(microblaze)
ENTRY(_start)
+#include <asm/page.h>
#include <asm-generic/vmlinux.lds.h>
+#include <asm/thread_info.h>
jiffies = jiffies_64 + 4;
SECTIONS {
. = CONFIG_KERNEL_START;
- .text : {
+ _start = CONFIG_KERNEL_BASE_ADDR;
+ .text : AT(ADDR(.text) - LOAD_OFFSET) {
_text = . ;
_stext = . ;
*(.text .text.*)
@@ -33,24 +36,22 @@ SECTIONS {
}
. = ALIGN (4) ;
- _fdt_start = . ; /* place for fdt blob */
- . = . + 0x4000;
- _fdt_end = . ;
+ __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {
+ _fdt_start = . ; /* place for fdt blob */
+ *(__fdt_blob) ; /* Any link-placed DTB */
+ . = _fdt_start + 0x4000; /* Pad up to 16kbyte */
+ _fdt_end = . ;
+ }
. = ALIGN(16);
RODATA
- . = ALIGN(16);
- __ex_table : {
- __start___ex_table = .;
- *(__ex_table)
- __stop___ex_table = .;
- }
+ EXCEPTION_TABLE(16)
/*
* sdata2 section can go anywhere, but must be word aligned
* and SDA2_BASE must point to the middle of it
*/
- .sdata2 : {
+ .sdata2 : AT(ADDR(.sdata2) - LOAD_OFFSET) {
_ssrw = .;
. = ALIGN(4096); /* page aligned when MMU used - origin 0x8 */
*(.sdata2)
@@ -61,12 +62,7 @@ SECTIONS {
}
_sdata = . ;
- .data ALIGN (4096) : { /* page aligned when MMU used - origin 0x4 */
- DATA_DATA
- CONSTRUCTORS
- }
- . = ALIGN(32);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE)
_edata = . ;
/* Reserve some low RAM for r0 based memory references */
@@ -74,18 +70,14 @@ SECTIONS {
r0_ram = . ;
. = . + 4096; /* a page should be enough */
- /* The initial task */
- . = ALIGN(8192);
- .data.init_task : { *(.data.init_task) }
-
/* Under the microblaze ABI, .sdata and .sbss must be contiguous */
. = ALIGN(8);
- .sdata : {
+ .sdata : AT(ADDR(.sdata) - LOAD_OFFSET) {
_ssro = .;
*(.sdata)
}
- .sbss : {
+ .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) {
_ssbss = .;
*(.sbss)
_esbss = .;
@@ -96,47 +88,36 @@ SECTIONS {
__init_begin = .;
- . = ALIGN(4096);
- .init.text : {
- _sinittext = . ;
- INIT_TEXT
- _einittext = .;
- }
+ INIT_TEXT_SECTION(PAGE_SIZE)
- .init.data : {
+ .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
INIT_DATA
}
. = ALIGN(4);
- .init.ivt : {
+ .init.ivt : AT(ADDR(.init.ivt) - LOAD_OFFSET) {
__ivt_start = .;
*(.init.ivt)
__ivt_end = .;
}
- .init.setup : {
- __setup_start = .;
- *(.init.setup)
- __setup_end = .;
+ .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
+ INIT_SETUP(0)
}
- .initcall.init : {
- __initcall_start = .;
- INITCALLS
- __initcall_end = .;
+ .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET ) {
+ INIT_CALLS
}
- .con_initcall.init : {
- __con_initcall_start = .;
- *(.con_initcall.init)
- __con_initcall_end = .;
+ .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+ CON_INITCALL
}
SECURITY_INIT
__init_end_before_initramfs = .;
- .init.ramfs ALIGN(4096) : {
+ .init.ramfs ALIGN(4096) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
__initramfs_start = .;
*(.init.ramfs)
__initramfs_end = .;
@@ -152,7 +133,8 @@ SECTIONS {
}
__init_end = .;
- .bss ALIGN (4096) : { /* page aligned when MMU used */
+ .bss ALIGN (4096) : AT(ADDR(.bss) - LOAD_OFFSET) {
+ /* page aligned when MMU used */
__bss_start = . ;
*(.bss*)
*(COMMON)