summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:01:42 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:01:42 +0200
commitbe27e7ea088c82f9adc8347f91b21b217aaa1ce0 (patch)
tree23865dfdea6e75a7a36c2f3d81210f592354bbcd /arch
parent798de5071d2a775af8931e99560a0eb9f72dfec3 (diff)
downloadbarebox-be27e7ea088c82f9adc8347f91b21b217aaa1ce0.tar.gz
barebox-be27e7ea088c82f9adc8347f91b21b217aaa1ce0.tar.xz
svn_rev_308
add arch/linux/
Diffstat (limited to 'arch')
-rw-r--r--arch/linux/Kconfig16
-rw-r--r--arch/linux/Makefile62
-rw-r--r--arch/linux/board/Makefile3
-rw-r--r--arch/linux/board/board.c24
-rw-r--r--arch/linux/board/clock.c26
-rw-r--r--arch/linux/board/hostfile.c74
-rw-r--r--arch/linux/lib/Makefile16
-rw-r--r--arch/linux/lib/common.c249
-rw-r--r--arch/linux/lib/tap.c37
-rw-r--r--arch/linux/lib/u-boot.lds.S167
10 files changed, 674 insertions, 0 deletions
diff --git a/arch/linux/Kconfig b/arch/linux/Kconfig
new file mode 100644
index 0000000000..b5674db236
--- /dev/null
+++ b/arch/linux/Kconfig
@@ -0,0 +1,16 @@
+
+config TEXT_BASE
+ string
+ default "0x08f00000" if MACH_MX1ADS
+
+config LINUX
+ bool
+ default y
+
+config ARCH_LINUX
+ bool
+
+source common/Kconfig
+source net/Kconfig
+source drivers/Kconfig
+source fs/Kconfig
diff --git a/arch/linux/Makefile b/arch/linux/Makefile
new file mode 100644
index 0000000000..15437bef04
--- /dev/null
+++ b/arch/linux/Makefile
@@ -0,0 +1,62 @@
+
+CPPFLAGS += -fno-builtin -ffreestanding -nostdinc -Wall \
+ -isystem $(gccincdir) -pipe \
+ -fno-strict-aliasing
+
+
+machine-y := linux
+
+BOARD:= arch/linux/lib
+
+TEXT_BASE = $(CONFIG_TEXT_BASE)
+
+CPPFLAGS += -P
+CFLAGS := -fno-common -Os -Dmalloc=u_boot_malloc \
+ -Dfree=u_boot_free -Drealloc=u_boot_realloc \
+ -Dread=u_boot_read -Dwrite=u_boot_write \
+ -Dopen=u_boot_open -Dclose=u_boot_close \
+ -Dlseek=u_boot_lseek -Dperror=u_boot_perror \
+ -Derrno=u_boot_errno
+
+LDFLAGS_vmlinux :=-L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
+
+ifeq ($(incdir-y),)
+incdir-y := $(machine-y)
+endif
+INCDIR := arch-$(incdir-y)
+
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ -e s/arm.*/arm/ -e s/sa110/arm/ \
+ -e s/s390x/s390/ -e s/parisc64/parisc/ \
+ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
+
+ELF_ARCH := $(SUBARCH)
+ELF_FORMAT := elf32-$(SUBARCH)
+
+export ELF_FORMAT ELF_ARCH SUBARCH
+# Update machine arch and proc symlinks if something which affects
+# them changed. We use .arch to indicate when they were updated
+# last, otherwise make uses the target directory mtime.
+
+include/asm-linux/.arch: $(wildcard include/config/arch/*.h) include/config/auto.conf
+ @echo ' SYMLINK include/asm-linux/arch -> include/asm-linux/$(INCDIR)'
+ifneq ($(KBUILD_SRC),)
+ $(Q)mkdir -p include/asm-linux
+ $(Q)ln -fsn $(srctree)/include/asm-linux/$(INCDIR) include/asm-linux/arch
+else
+ $(Q)ln -fsn $(INCDIR) include/asm-linux/arch
+endif
+ @touch $@
+
+archprepare: maketools
+
+PHONY += maketools
+maketools: include/asm-linux/.arch
+
+cmd_vmlinux__ = $(CC) -o $@ -Wl,-T,$(vmlinux-lds) \
+ -Wl,--start-group $(vmlinux-common) -Wl,--end-group \
+ -lrt -Wl,-rpath,/lib -lrt -lpthread
+
+common-y += arch/linux/lib/ arch/linux/board/
+
+MRPROPER_FILES += include/asm-linux/arch
diff --git a/arch/linux/board/Makefile b/arch/linux/board/Makefile
new file mode 100644
index 0000000000..6c23dc7a49
--- /dev/null
+++ b/arch/linux/board/Makefile
@@ -0,0 +1,3 @@
+obj-y += board.o
+obj-y += clock.o
+obj-y += hostfile.o
diff --git a/arch/linux/board/board.c b/arch/linux/board/board.c
new file mode 100644
index 0000000000..883e6df74f
--- /dev/null
+++ b/arch/linux/board/board.c
@@ -0,0 +1,24 @@
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <asm/arch/linux.h>
+#include <init.h>
+#include <errno.h>
+#include <asm-generic/errno.h>
+
+static struct device_d tap_device = {
+ .name = "tap",
+ .id = "eth0",
+
+ .type = DEVICE_TYPE_ETHER,
+};
+
+static int devices_init(void)
+{
+ register_device(&tap_device);
+
+ return 0;
+}
+
+device_initcall(devices_init);
+
diff --git a/arch/linux/board/clock.c b/arch/linux/board/clock.c
new file mode 100644
index 0000000000..556e69e318
--- /dev/null
+++ b/arch/linux/board/clock.c
@@ -0,0 +1,26 @@
+#include <common.h>
+#include <init.h>
+#include <clock.h>
+#include <asm/arch/linux.h>
+
+uint64_t linux_clocksource_read(void)
+{
+ return linux_get_time();
+}
+
+static struct clocksource cs = {
+ .read = linux_clocksource_read,
+ .mask = 0xffffffff,
+ .shift = 10,
+};
+
+static int clocksource_init (void)
+{
+ cs.mult = clocksource_hz2mult(1000 * 1000 * 1000, cs.shift);
+
+ init_clock(&cs);
+
+ return 0;
+}
+
+core_initcall(clocksource_init);
diff --git a/arch/linux/board/hostfile.c b/arch/linux/board/hostfile.c
new file mode 100644
index 0000000000..0bfb243c99
--- /dev/null
+++ b/arch/linux/board/hostfile.c
@@ -0,0 +1,74 @@
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <asm/arch/linux.h>
+#include <init.h>
+#include <errno.h>
+#include <asm-generic/errno.h>
+#include <asm/arch/hostfile.h>
+#include <xfuncs.h>
+
+ssize_t hf_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags)
+{
+ struct hf_platform_data *hf = dev->platform_data;
+ int fd = hf->fd;
+
+ if (linux_lseek(fd, offset) != offset)
+ return -EINVAL;
+
+ return linux_read(fd, buf, count);
+}
+
+ssize_t hf_write(struct device_d *dev, const void *buf, size_t count, ulong offset, ulong flags)
+{
+ struct hf_platform_data *hf = dev->platform_data;
+ int fd = hf->fd;
+
+ if (linux_lseek(fd, offset) != offset)
+ return -EINVAL;
+
+ return linux_write(fd, buf, count);
+}
+
+static void hf_info(struct device_d *dev)
+{
+ struct hf_platform_data *hf = dev->platform_data;
+
+ printf("file: %s\n", hf->filename);
+}
+
+static struct driver_d hf_drv = {
+ .name = "hostfile",
+ .probe = dummy_probe,
+ .read = hf_read,
+ .write = hf_write,
+ .info = hf_info,
+ .type = DEVICE_TYPE_BLOCK,
+};
+
+static int hf_init(void)
+{
+ return register_driver(&hf_drv);
+}
+
+device_initcall(hf_init);
+
+int u_boot_register_filedev(struct hf_platform_data *hf, char *name_template)
+{
+ struct device_d *dev;
+
+ dev = xzalloc(sizeof(struct device_d));
+
+ dev->platform_data = hf;
+
+ hf = dev->platform_data;
+
+ strcpy(dev->name,"hostfile");
+ get_free_deviceid(dev->id, name_template);
+ dev->size = hf->size;
+ dev->map_base = hf->map_base;
+ dev->type = DEVICE_TYPE_BLOCK;
+
+ return register_device(dev);
+}
+
diff --git a/arch/linux/lib/Makefile b/arch/linux/lib/Makefile
new file mode 100644
index 0000000000..916996e557
--- /dev/null
+++ b/arch/linux/lib/Makefile
@@ -0,0 +1,16 @@
+CPPFLAGS_u-boot.lds = -DSTART=$(START) -U$(SUBARCH) -DELF_ARCH=$(ELF_ARCH) \
+ -DELF_FORMAT="$(ELF_FORMAT)" -DKERNEL_STACK_SIZE=8192
+
+extra-y += u-boot.lds
+
+START := 0x8048000
+
+export START
+
+CPPFLAGS := -I/usr/include -Iinclude -P
+CFLAGS := -Wall
+#NOSTDINC_FLAGS :=
+
+obj-y = common.o tap.o
+
+USER_OBJS := common.o
diff --git a/arch/linux/lib/common.c b/arch/linux/lib/common.c
new file mode 100644
index 0000000000..6979cfb328
--- /dev/null
+++ b/arch/linux/lib/common.c
@@ -0,0 +1,249 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <libgen.h>
+#include <sys/mman.h>
+#include <asm/arch/linux.h>
+#include <asm/arch/hostfile.h>
+#include <errno.h>
+
+static struct termios term_orig, term_vi;
+static char erase_char; // the users erase character
+
+static void rawmode(void)
+{
+ tcgetattr(0, &term_orig);
+ term_vi = term_orig;
+ term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's
+ term_vi.c_iflag &= (~IXON & ~ICRNL);
+ term_vi.c_oflag &= (~ONLCR);
+ term_vi.c_cc[VMIN] = 1;
+ term_vi.c_cc[VTIME] = 0;
+ erase_char = term_vi.c_cc[VERASE];
+ tcsetattr(0, TCSANOW, &term_vi);
+}
+
+static void cookmode(void)
+{
+ fflush(stdout);
+ tcsetattr(0, TCSANOW, &term_orig);
+}
+
+void serial_putc (const char c)
+{
+ fputc(c, stdout);
+
+ /* If \n, also do \r */
+ if (c == '\n')
+ serial_putc ('\r');
+}
+
+int serial_tstc (void)
+{
+ return 0;
+}
+
+void serial_puts (const char *s)
+{
+ while (*s) {
+ serial_putc (*s++);
+ }
+}
+
+uint64_t linux_get_time(void)
+{
+ struct timespec ts;
+ uint64_t now;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ now = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+
+ return now;
+}
+
+int do_reset (void *unused, int flag, int argc, char *argv[])
+{
+ cookmode();
+ exit(0);
+}
+
+void enable_interrupts (void)
+{
+}
+
+int serial_getc (void)
+{
+ return fgetc(stdin);
+}
+
+int linux_read(int fd, void *buf, size_t count)
+{
+ return read(fd, buf, count);
+}
+
+int linux_read_nonblock(int fd, void *buf, size_t count)
+{
+ int oldflags, ret;
+
+ oldflags = fcntl(fd, F_GETFL);
+ if (oldflags == -1)
+ goto err_out;
+
+ if (fcntl(fd, F_SETFL, oldflags | O_NONBLOCK) == -1)
+ goto err_out;
+
+ ret = read(fd, buf, count);
+
+ if (fcntl(fd, F_SETFL, oldflags) == -1)
+ goto err_out;
+
+ if (ret == -1) {
+// printf("errno\n");
+ usleep(1000);
+ }
+
+// if (ret == -1 && errno == EAGAIN) {
+// printf("delay\n");
+// }
+
+ return ret;
+
+err_out:
+ perror("fcntl");
+ return -1;
+}
+
+ssize_t linux_write(int fd, const void *buf, size_t count)
+{
+ return write(fd, buf, count);
+}
+
+off_t linux_lseek(int fildes, off_t offset)
+{
+ return lseek(fildes, offset, SEEK_SET);
+}
+
+void flush_cache (unsigned long dummy1, unsigned long dummy2)
+{
+ /* why should we? */
+}
+
+extern void start_uboot(void);
+extern void mem_malloc_init (void *start, void *end);
+
+int add_image(char *str, char *name_template)
+{
+ char *file;
+ int readonly = 0, map = 1;
+ struct stat s;
+ char *opt;
+ int fd, ret;
+ struct hf_platform_data *hf = malloc(sizeof(struct hf_platform_data));
+
+ if (!hf)
+ return -1;
+
+ file = strtok(str, ",");
+ while ((opt = strtok(NULL, ","))) {
+ if (!strcmp(opt, "ro"))
+ readonly = 1;
+ if (!strcmp(opt, "map"))
+ map = 1;
+ }
+
+ printf("add file %s(%s)\n", file, readonly ? "ro" : "");
+
+ fd = open(file, readonly ? O_RDONLY : O_RDWR);
+ hf->fd = fd;
+ hf->filename = file;
+
+ if (fd < 0) {
+ perror("open");
+ goto err_out;
+ }
+
+ if (fstat(fd, &s)) {
+ perror("fstat");
+ goto err_out;
+ }
+
+ hf->size = s.st_size;
+
+ if (map) {
+ hf->map_base = (unsigned long)mmap(0, hf->size,
+ PROT_READ | (readonly ? 0 : PROT_WRITE),
+ MAP_SHARED, fd, 0);
+ if ((void *)hf->map_base == MAP_FAILED)
+ printf("warning: mmapping %s failed\n", file);
+ }
+
+
+ ret = u_boot_register_filedev(hf, name_template);
+ if (ret)
+ goto err_out;
+ return 0;
+
+err_out:
+ if (fd > 0)
+ close(fd);
+ free(hf);
+ return -1;
+}
+
+void print_usage(const char *prgname)
+{
+ printf("usage\n");
+}
+
+int main(int argc, char *argv[])
+{
+ void *ram;
+ int opt;
+ int malloc_size = 1024 * 1024;
+ int ret;
+
+ ram = malloc(malloc_size);
+ if (!ram) {
+ printf("unable to get malloc space\n");
+ exit(1);
+ }
+ mem_malloc_init(ram, ram + malloc_size);
+
+ while ((opt = getopt(argc, argv, "hi:m:e:")) != -1) {
+ switch (opt) {
+ case 'h':
+ print_usage(basename(argv[0]));
+ exit(0);
+ case 'i':
+ ret = add_image(optarg, "fd");
+ if (ret)
+ exit(1);
+ break;
+ case 'm':
+ malloc_size = strtoul(optarg, NULL, 0);
+ break;
+ case 'e':
+ ret = add_image(optarg, "env");
+ if (ret)
+ exit(1);
+ break;
+ }
+ }
+
+ rawmode();
+ start_uboot();
+
+ /* never reached */
+ return 0;
+}
+
diff --git a/arch/linux/lib/tap.c b/arch/linux/lib/tap.c
new file mode 100644
index 0000000000..bad1c4b655
--- /dev/null
+++ b/arch/linux/lib/tap.c
@@ -0,0 +1,37 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <string.h>
+
+int tap_alloc(char *dev)
+{
+ struct ifreq ifr;
+ int fd, err;
+
+ if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ /* Flags: IFF_TUN - TUN device (no Ethernet headers)
+ * IFF_TAP - TAP device
+ *
+ * IFF_NO_PI - Do not provide packet information
+ */
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (*dev)
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+
+ if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
+ close(fd);
+ return err;
+ }
+
+ strcpy(dev, ifr.ifr_name);
+ return fd;
+}
diff --git a/arch/linux/lib/u-boot.lds.S b/arch/linux/lib/u-boot.lds.S
new file mode 100644
index 0000000000..3f8777dae8
--- /dev/null
+++ b/arch/linux/lib/u-boot.lds.S
@@ -0,0 +1,167 @@
+#include <asm-generic/u-boot.lds.h>
+
+OUTPUT_FORMAT(ELF_FORMAT)
+OUTPUT_ARCH(ELF_ARCH)
+ENTRY(_start)
+
+SECTIONS
+{
+ PROVIDE (__executable_start = START);
+ . = START + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
+ * is remapped.*/
+ __binary_start = .;
+ . = ALIGN(4096); /* Init code and data */
+ _text = .;
+ _stext = .;
+ __init_begin = .;
+ .init.text : {
+ _sinittext = .;
+ *(.init.text)
+ _einittext = .;
+ }
+
+ . = ALIGN(4096);
+
+ /* Read-only sections, merged into text segment: */
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+ .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+ .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+ .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+ .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : {
+ KEEP (*(.init))
+ } =0x90909090
+ .plt : { *(.plt) }
+ .text : {
+ *(.text)
+ *(.fixup)
+ *(.stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+
+ . = ALIGN(4096);
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ . = ALIGN(4096);
+ } =0x90909090
+ .fini : {
+ KEEP (*(.fini))
+ } =0x90909090
+
+ .kstrtab : { *(.kstrtab) }
+
+ __u_boot_initcalls_start = .;
+ __u_boot_initcalls : { INITCALLS }
+ __u_boot_initcalls_end = .;
+ __u_boot_cmd_start = .;
+ __u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end = .;
+
+ __preinit_array_start = .;
+ .preinit_array : { *(.preinit_array) }
+ __preinit_array_end = .;
+ __init_array_start = .;
+ .init_array : { *(.init_array) }
+ __init_array_end = .;
+ __fini_array_start = .;
+ .fini_array : { *(.fini_array) }
+ __fini_array_end = .;
+
+ init.data : { *(.init.data) }
+
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(32 / 8);
+ .preinit_array : { *(.preinit_array) }
+ .init_array : {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ *(.init_array)
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array : { *(.fini_array) }
+ .data : {
+ . = ALIGN(KERNEL_STACK_SIZE); /* init_task */
+ *(.data.init_task)
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .eh_frame : { KEEP (*(.eh_frame)) }
+ .gcc_except_table : { *(.gcc_except_table) }
+ .dynamic : { *(.dynamic) }
+ .ctors : {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ /* We don't want to include the .ctor section from
+ from the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors : {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .got : { *(.got.plt) *(.got) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .bss : {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ }
+ _end = .;
+ PROVIDE (end = .);
+}