summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2013-02-12 00:07:38 +0800
committerRonald G. Minnich <rminnich@gmail.com>2013-02-12 03:02:45 +0100
commit7635a60ca848b50ff4a0ac85a667adc7151a5abf (patch)
tree42d7db8bd1c1bcacd5d1c4d2b70ca0b8ad3a6da5 /src
parentbc64cae995ddab369289e19b41501df5dbc58751 (diff)
downloadcoreboot-7635a60ca848b50ff4a0ac85a667adc7151a5abf.tar.xz
armv7: Add emulation/qemu-armv7 board.
To simplify testing ARM implementation, we need a QEMU configuration for ARM. The qemu-armv7 provides serial output, CBFS simulation, and full boot path (bootblock, romstage, ramstage) to verify the boot loader functionality. To run with QEMU: export QEMU_AUDIO_DRV=none qemu-system-arm -M vexpress-a9 -m 1024M -nographic -kernel build/coreboot.rom Verified to boot until ramstage loaded successfully by QEMU v1.0.50. Change-Id: I1f23ffaf408199811a0756236821c7e0f2a85004 Signed-off-by: Hung-Te Lin <hungte@chromium.org> Reviewed-on: http://review.coreboot.org/2354 Reviewed-by: David Hendricks <dhendrix@chromium.org> Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/cpu/Kconfig1
-rw-r--r--src/cpu/Makefile.inc1
-rw-r--r--src/cpu/armltd/Kconfig8
-rw-r--r--src/cpu/armltd/Makefile.inc1
-rw-r--r--src/cpu/armltd/cortex-a9/Kconfig5
-rw-r--r--src/cpu/armltd/cortex-a9/Makefile.inc2
-rw-r--r--src/cpu/armltd/cortex-a9/bootblock.c17
-rw-r--r--src/cpu/armltd/cortex-a9/cache.c44
-rw-r--r--src/mainboard/emulation/Kconfig4
-rw-r--r--src/mainboard/emulation/qemu-armv7/Kconfig116
-rw-r--r--src/mainboard/emulation/qemu-armv7/Makefile.inc30
-rw-r--r--src/mainboard/emulation/qemu-armv7/bootblock.c23
-rw-r--r--src/mainboard/emulation/qemu-armv7/devicetree.cb20
-rw-r--r--src/mainboard/emulation/qemu-armv7/mainboard.c27
-rw-r--r--src/mainboard/emulation/qemu-armv7/media.c57
-rw-r--r--src/mainboard/emulation/qemu-armv7/ramstage.c24
-rw-r--r--src/mainboard/emulation/qemu-armv7/romstage.c31
-rw-r--r--src/mainboard/emulation/qemu-armv7/timer.c24
-rw-r--r--src/mainboard/emulation/qemu-armv7/uart.c56
19 files changed, 491 insertions, 0 deletions
diff --git a/src/cpu/Kconfig b/src/cpu/Kconfig
index f60ffe7cce..caf4ebc1b6 100644
--- a/src/cpu/Kconfig
+++ b/src/cpu/Kconfig
@@ -3,6 +3,7 @@
# (See also src/Kconfig)
if ARCH_ARMV7
+source src/cpu/armltd/Kconfig
source src/cpu/samsung/Kconfig
endif # ARCH_ARM
diff --git a/src/cpu/Makefile.inc b/src/cpu/Makefile.inc
index 93b16ae3bd..e1efecc7f5 100644
--- a/src/cpu/Makefile.inc
+++ b/src/cpu/Makefile.inc
@@ -2,6 +2,7 @@
## Subdirectories
################################################################################
subdirs-y += amd
+subdirs-y += armltd
subdirs-y += intel
subdirs-y += samsung
subdirs-y += via
diff --git a/src/cpu/armltd/Kconfig b/src/cpu/armltd/Kconfig
new file mode 100644
index 0000000000..b1f4c2ee4e
--- /dev/null
+++ b/src/cpu/armltd/Kconfig
@@ -0,0 +1,8 @@
+config CPU_ARMLTD_CORTEX_A9
+ depends on ARCH_ARMV7
+ bool
+ default n
+
+if CPU_ARMLTD_CORTEX_A9
+source src/cpu/armltd/cortex-a9/Kconfig
+endif
diff --git a/src/cpu/armltd/Makefile.inc b/src/cpu/armltd/Makefile.inc
new file mode 100644
index 0000000000..014742f056
--- /dev/null
+++ b/src/cpu/armltd/Makefile.inc
@@ -0,0 +1 @@
+subdirs-$(CONFIG_CPU_ARMLTD_CORTEX_A9) += cortex-a9
diff --git a/src/cpu/armltd/cortex-a9/Kconfig b/src/cpu/armltd/cortex-a9/Kconfig
new file mode 100644
index 0000000000..7f35cfd653
--- /dev/null
+++ b/src/cpu/armltd/cortex-a9/Kconfig
@@ -0,0 +1,5 @@
+config BOOTBLOCK_CPU_INIT
+ string
+ default "cpu/armltd/cortex-a9/bootblock.c"
+ help
+ CPU/SoC-specific bootblock code.
diff --git a/src/cpu/armltd/cortex-a9/Makefile.inc b/src/cpu/armltd/cortex-a9/Makefile.inc
new file mode 100644
index 0000000000..d1e7edfdee
--- /dev/null
+++ b/src/cpu/armltd/cortex-a9/Makefile.inc
@@ -0,0 +1,2 @@
+ramstage-y += cache.c
+romstage-y += cache.c
diff --git a/src/cpu/armltd/cortex-a9/bootblock.c b/src/cpu/armltd/cortex-a9/bootblock.c
new file mode 100644
index 0000000000..8925439d2a
--- /dev/null
+++ b/src/cpu/armltd/cortex-a9/bootblock.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+void bootblock_cpu_init(void);
+void bootblock_cpu_init(void)
+{
+}
diff --git a/src/cpu/armltd/cortex-a9/cache.c b/src/cpu/armltd/cortex-a9/cache.c
new file mode 100644
index 0000000000..957871dba7
--- /dev/null
+++ b/src/cpu/armltd/cortex-a9/cache.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <system.h>
+#include <armv7.h>
+
+/*
+ * Sets L2 cache related parameters before enabling data cache
+ */
+void v7_outer_cache_enable(void)
+{
+}
+
+/* stubs so we don't need weak symbols in cache_v7.c */
+void v7_outer_cache_disable(void)
+{
+}
+
+void v7_outer_cache_flush_all(void)
+{
+}
+
+void v7_outer_cache_inval_all(void)
+{
+}
+
+void v7_outer_cache_flush_range(u32 start, u32 end)
+{
+}
+
+void v7_outer_cache_inval_range(u32 start, u32 end)
+{
+}
diff --git a/src/mainboard/emulation/Kconfig b/src/mainboard/emulation/Kconfig
index 5661f0e3b1..ea6b18077b 100644
--- a/src/mainboard/emulation/Kconfig
+++ b/src/mainboard/emulation/Kconfig
@@ -6,9 +6,13 @@ choice
config BOARD_EMULATION_QEMU_X86
bool "QEMU x86"
+config BOARD_EMULATION_QEMU_ARMV7
+ bool "QEMU armv7 (vexpress-a9)"
+
endchoice
source "src/mainboard/emulation/qemu-x86/Kconfig"
+source "src/mainboard/emulation/qemu-armv7/Kconfig"
config MAINBOARD_VENDOR
string
diff --git a/src/mainboard/emulation/qemu-armv7/Kconfig b/src/mainboard/emulation/qemu-armv7/Kconfig
new file mode 100644
index 0000000000..38b1da249a
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/Kconfig
@@ -0,0 +1,116 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2013 Google Inc.
+##
+## This software is licensed under the terms of the GNU General Public
+## License version 2, as published by the Free Software Foundation, and
+## may be copied, distributed, and modified under those terms.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+# Emulation for ARM Ltd Versatile Express Cortex-A9
+# http://www.arm.com/products/tools/development-boards/versatile-express
+
+# To execute, do:
+# export QEMU_AUDIO_DRV=none
+# qemu-system-arm -M vexpress-a9 -m 1024M -nographic -kernel build/coreboot.rom
+
+if BOARD_EMULATION_QEMU_ARMV7
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+ def_bool y
+ select ARCH_ARMV7
+ select CPU_ARMLTD_CORTEX_A9
+ select DEFAULT_EARLY_CONSOLE
+ select HAVE_UART_SPECIAL
+ select BOARD_ROMSIZE_KB_4096
+
+config MAINBOARD_DIR
+ string
+ default emulation/qemu-armv7
+
+config MAINBOARD_PART_NUMBER
+ string
+ default "QEMU ARMV7"
+
+config MAX_CPUS
+ int
+ default 2
+
+config MAINBOARD_VENDOR
+ string
+ default "ARM Ltd."
+
+config BOOTBLOCK_MAINBOARD_INIT
+ string
+ default "mainboard/emulation/qemu-armv7/bootblock.c"
+
+config DRAM_SIZE_MB
+ int
+ default 1024
+
+# Memory map for qemu vexpress-a9:
+#
+# 0x0000_0000: jump instruction (by qemu)
+# 0x0001_0000: bootblock (entry of kernel / firmware)
+# 0x0002_0000: romstage, assume up to 128KB in size.
+# 0x0007_ff00: stack pointer
+# 0x0010_0000: CBFS header
+# 0x0011_0000: CBFS data
+# 0x0100_0000: reserved for ramstage
+# 0x1000_0000: I/O map address
+
+config BOOTBLOCK_BASE
+ hex
+ default 0x00010000
+
+config ID_SECTION_BASE
+ hex
+ default 0x0001f000
+
+config ROMSTAGE_BASE
+ hex
+ default 0x00020000
+
+config ROMSTAGE_SIZE
+ hex
+ default 0x20000
+
+config CBFS_HEADER_ROM_OFFSET
+ hex
+ default 0x0100000
+
+config CBFS_ROM_OFFSET
+ hex
+ default 0x0110000
+
+config IRAM_STACK
+ hex
+ default 0x0007ff00
+
+config XIP_ROM_SIZE
+ hex
+ default ROMSTAGE_SIZE
+
+config SYS_SDRAM_BASE
+ hex "SDRAM base address"
+ default 0x01000000
+
+config SYS_TEXT_BASE
+ hex "Executable code section"
+ default 0x04e00000
+
+config RAMBASE
+ hex
+ default SYS_SDRAM_BASE
+
+# according to stefan, this is RAMBASE + 1M.
+config RAMTOP
+ hex
+ default 0x01100000
+
+endif # BOARD_EMULATION_QEMU_ARMV7
diff --git a/src/mainboard/emulation/qemu-armv7/Makefile.inc b/src/mainboard/emulation/qemu-armv7/Makefile.inc
new file mode 100644
index 0000000000..cea3b15ceb
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/Makefile.inc
@@ -0,0 +1,30 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2013 Google Inc.
+##
+## This software is licensed under the terms of the GNU General Public
+## License version 2, as published by the Free Software Foundation, and
+## may be copied, distributed, and modified under those terms.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+romstage-y += romstage.c
+ramstage-y += ramstage.c
+
+bootblock-y += media.c
+romstage-y += media.c
+ramstage-y += media.c
+
+bootblock-y += timer.c
+romstage-y += timer.c
+ramstage-y += timer.c
+
+bootblock-$(CONFIG_EARLY_CONSOLE) += uart.c
+romstage-$(CONFIG_EARLY_CONSOLE) += uart.c
+ramstage-y += uart.c
+
+SRC_ROOT = $(src)/mainboard/emulation/qemu-armv7a
diff --git a/src/mainboard/emulation/qemu-armv7/bootblock.c b/src/mainboard/emulation/qemu-armv7/bootblock.c
new file mode 100644
index 0000000000..56546672c7
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/bootblock.c
@@ -0,0 +1,23 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+
+void bootblock_mainboard_init(void);
+void bootblock_mainboard_init(void)
+{
+ console_init();
+ printk(BIOS_INFO, "\n\n\n%s: ARMv7 Emulation Started.\n", __func__);
+}
diff --git a/src/mainboard/emulation/qemu-armv7/devicetree.cb b/src/mainboard/emulation/qemu-armv7/devicetree.cb
new file mode 100644
index 0000000000..91534427a9
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/devicetree.cb
@@ -0,0 +1,20 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2013 Google, Inc.
+##
+## This software is licensed under the terms of the GNU General Public
+## License version 2, as published by the Free Software Foundation, and
+## may be copied, distributed, and modified under those terms.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+# TODO fill with Versatile Express board data in QEMU.
+chip cpu/armltd/cortex-a9
+ chip drivers/generic/generic # I2C0 controller
+ device i2c 6 on end # Fake component for testing
+ end
+end
diff --git a/src/mainboard/emulation/qemu-armv7/mainboard.c b/src/mainboard/emulation/qemu-armv7/mainboard.c
new file mode 100644
index 0000000000..cbc3197569
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/mainboard.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+
+static void enable_dev(device_t dev)
+{
+ printk(BIOS_INFO, "Enable qemu/armv7 device...\n");
+}
+
+struct chip_operations mainboard_ops = {
+ .enable_dev = enable_dev,
+};
+
diff --git a/src/mainboard/emulation/qemu-armv7/media.c b/src/mainboard/emulation/qemu-armv7/media.c
new file mode 100644
index 0000000000..d024b5d340
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/media.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <cbfs.h>
+#include <string.h>
+#include <console/console.h>
+
+/* Simple memory-mapped ROM emulation. */
+
+static int emu_rom_open(struct cbfs_media *media) {
+ return 0;
+}
+
+static void *emu_rom_map(struct cbfs_media *media, size_t offset, size_t count) {
+ return (void*)(offset + CONFIG_BOOTBLOCK_BASE);
+}
+
+static void *emu_rom_unmap(struct cbfs_media *media, const void *address) {
+ return NULL;
+}
+
+static size_t emu_rom_read(struct cbfs_media *media, void *dest, size_t offset,
+ size_t count) {
+ void *ptr = emu_rom_map(media, offset, count);
+ memcpy(dest, ptr, count);
+ emu_rom_unmap(media, ptr);
+ return count;
+}
+
+static int emu_rom_close(struct cbfs_media *media) {
+ return 0;
+}
+
+int init_emu_rom_cbfs_media(struct cbfs_media *media);
+int init_emu_rom_cbfs_media(struct cbfs_media *media) {
+ media->open = emu_rom_open;
+ media->close = emu_rom_close;
+ media->map = emu_rom_map;
+ media->unmap = emu_rom_unmap;
+ media->read = emu_rom_read;
+ return 0;
+}
+
+int init_default_cbfs_media(struct cbfs_media *media) {
+ return init_emu_rom_cbfs_media(media);
+}
diff --git a/src/mainboard/emulation/qemu-armv7/ramstage.c b/src/mainboard/emulation/qemu-armv7/ramstage.c
new file mode 100644
index 0000000000..24d0d7ff8f
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/ramstage.c
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+
+void hardwaremain(int boot_complete);
+void main(void)
+{
+ console_init();
+ printk(BIOS_INFO, "hello from ramstage\n");
+ hardwaremain(0);
+}
diff --git a/src/mainboard/emulation/qemu-armv7/romstage.c b/src/mainboard/emulation/qemu-armv7/romstage.c
new file mode 100644
index 0000000000..81f62b6b83
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/romstage.c
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <cbfs.h>
+#include <common.h>
+#include <console/console.h>
+#include <arch/stages.h>
+
+void main(void)
+{
+ void *entry;
+ console_init();
+ printk(BIOS_INFO, "hello from romstage\n");
+
+ entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/coreboot_ram");
+ printk(BIOS_INFO, "entry is 0x%p, leaving romstage.\n", entry);
+
+ stage_exit(entry);
+}
diff --git a/src/mainboard/emulation/qemu-armv7/timer.c b/src/mainboard/emulation/qemu-armv7/timer.c
new file mode 100644
index 0000000000..53c378940d
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/timer.c
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+void udelay(unsigned int n);
+void udelay(unsigned int n) {
+ /* TODO provide delay here. */
+}
+
+int init_timer(void);
+int init_timer(void) {
+ return 0;
+}
diff --git a/src/mainboard/emulation/qemu-armv7/uart.c b/src/mainboard/emulation/qemu-armv7/uart.c
new file mode 100644
index 0000000000..29887777d7
--- /dev/null
+++ b/src/mainboard/emulation/qemu-armv7/uart.c
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <console/console.h>
+#include <uart.h>
+
+#define VEXPRESS_UART0_IO_ADDRESS (0x10009000)
+
+static void pl011_init_dev(void) {
+}
+
+static void pl011_uart_tx_byte(unsigned char data) {
+ static volatile unsigned int *uart0_address =
+ (unsigned int *)VEXPRESS_UART0_IO_ADDRESS;
+
+ *uart0_address = (unsigned int)data;
+}
+
+static void pl011_uart_tx_flush(void) {
+}
+
+#if !defined(__PRE_RAM__)
+
+static const struct console_driver pl011_uart_console __console = {
+ .init = pl011_init_dev,
+ .tx_byte = pl011_uart_tx_byte,
+ .tx_flush = pl011_uart_tx_flush,
+};
+
+#else
+void uart_init(void)
+{
+ pl011_init_dev();
+}
+
+void uart_tx_byte(unsigned char data)
+{
+ pl011_uart_tx_byte(data);
+}
+
+void uart_tx_flush(void) {
+ pl011_uart_tx_flush();
+}
+#endif