diff --git a/.gitignore b/.gitignore index c74ee06e8..ae76f2f66 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ cscope.* *.rej *.[1-9].gz *.o +*.elf *.[psS]o *.pico lib*.so* diff --git a/minix/drivers/storage/ramdisk/rc b/minix/drivers/storage/ramdisk/rc index de2a3a6a8..47bd3ea1f 100644 --- a/minix/drivers/storage/ramdisk/rc +++ b/minix/drivers/storage/ramdisk/rc @@ -3,7 +3,7 @@ set -e exec >/dev/log exec 2>/dev/log -exec /dev/null fi +# XXX: We don't have anything better to do on Raspberry Pi yet +if [ "$(/bin/sysenv board_name)" = "RPI_2_B" ] || [ "$(/bin/sysenv board_name)" = "RPI_3_B" ] +then + exec /bin/sh < /dev/console +fi + if [ X`/bin/sysenv arch` = Xearm ] then echo Starting the mmc driver /bin/service -c up /service/mmc -dev /dev/c0d0 @@ -88,7 +94,7 @@ fi echo "Root device name is $rootdevname" -if ! sysenv cdproberoot >/dev/null +if (! sysenv cdproberoot) && (! sysenv bootramdisk) >/dev/null then if [ -e $FSCK ] then $FSCK -p $rootdevname diff --git a/minix/include/arch/earm/include/interrupt.h b/minix/include/arch/earm/include/interrupt.h index 0cc92491e..06df12ce9 100644 --- a/minix/include/arch/earm/include/interrupt.h +++ b/minix/include/arch/earm/include/interrupt.h @@ -3,6 +3,6 @@ #ifndef _INTERRUPT_H #define _INTERRUPT_H -#define NR_IRQ_VECTORS 125 +#define NR_IRQ_VECTORS 128 #endif /* _INTERRUPT_H */ diff --git a/minix/include/minix/board.h b/minix/include/minix/board.h index 1a6bfb55e..10374682c 100644 --- a/minix/include/minix/board.h +++ b/minix/include/minix/board.h @@ -67,12 +67,15 @@ #define MINIX_BOARD_VENDOR_INTEL MINIX_MK_BOARD_VENDOR(1<<0) #define MINIX_BOARD_VENDOR_TI MINIX_MK_BOARD_VENDOR(1<<1) +#define MINIX_BOARD_VENDOR_RPI MINIX_MK_BOARD_VENDOR(1<<2) #define MINIX_BOARD_GENERIC MINIX_MK_BOARD(1<<0) /* BeagleBoard XM */ #define MINIX_BOARD_BBXM MINIX_MK_BOARD(1<<1) /* BeagleBone (Black and* white) */ #define MINIX_BOARD_BB MINIX_MK_BOARD(1<<2) +/* Raspberry Pi */ +#define MINIX_BOARD_RPI MINIX_MK_BOARD(1<<3) /* Only one of a kind */ #define MINIX_BOARD_VARIANT_GENERIC MINIX_MK_BOARD_VARIANT(1<<0) @@ -81,6 +84,10 @@ /* BeagleBone Black */ #define MINIX_BOARD_VARIANT_BBB MINIX_MK_BOARD_VARIANT(1<<2) +/* Rasberry Pi */ +#define MINIX_BOARD_VARIANT_RPI_2_B MINIX_MK_BOARD_VARIANT(1<<1) +#define MINIX_BOARD_VARIANT_RPI_3_B MINIX_MK_BOARD_VARIANT(1<<2) + #define BOARD_ID_INTEL \ ( MINIX_BOARD_ARCH_X86 \ | MINIX_BOARD_ARCH_VARIANT_X86_GENERIC \ @@ -113,6 +120,22 @@ | MINIX_BOARD_VARIANT_BBB\ ) +#define BOARD_ID_RPI_2_B \ + ( MINIX_BOARD_ARCH_ARM \ + | MINIX_BOARD_ARCH_VARIANT_ARM_ARMV7 \ + | MINIX_BOARD_VENDOR_RPI \ + | MINIX_BOARD_RPI \ + | MINIX_BOARD_VARIANT_RPI_2_B \ + ) + +#define BOARD_ID_RPI_3_B \ + ( MINIX_BOARD_ARCH_ARM \ + | MINIX_BOARD_ARCH_VARIANT_ARM_ARMV7 \ + | MINIX_BOARD_VENDOR_RPI \ + | MINIX_BOARD_RPI \ + | MINIX_BOARD_VARIANT_RPI_3_B \ + ) + #define BOARD_IS_BBXM(v) \ ( (BOARD_ID_BBXM & ~MINIX_BOARD_VARIANT_MASK) == (v & ~MINIX_BOARD_VARIANT_MASK)) /* Either one of the known BeagleBones */ @@ -121,6 +144,9 @@ #define BOARD_IS_BBW(v) ( v == BOARD_ID_BBW) #define BOARD_IS_BBB(v) ( v == BOARD_ID_BBB) +#define BOARD_IS_RPI_2_B(v) ( v == BOARD_ID_RPI_2_B) +#define BOARD_IS_RPI_3_B(v) ( v == BOARD_ID_RPI_3_B) + #define BOARD_FILTER_BBXM_VALUE (BOARD_ID_BBXM) #define BOARD_FILTER_BBXM_MASK \ (MINIX_BOARD_ARCH_MASK \ @@ -148,6 +174,8 @@ static struct shortname2id shortname2id[] = { {.name = "BBXM",.id = BOARD_ID_BBXM}, {.name = "A335BONE",.id = BOARD_ID_BBW}, {.name = "A335BNLT",.id = BOARD_ID_BBB}, + {.name = "RPI_2_B",.id = BOARD_ID_RPI_2_B}, + {.name = "RPI_3_B",.id = BOARD_ID_RPI_3_B}, }; struct board_id2name @@ -162,6 +190,8 @@ static struct board_id2name board_id2name[] = { {.id = BOARD_ID_BBXM,.name = "ARM-ARMV7-TI-BBXM-GENERIC"}, {.id = BOARD_ID_BBW,.name = "ARM-ARMV7-TI-BB-WHITE"}, {.id = BOARD_ID_BBB,.name = "ARM-ARMV7-TI-BB-BLACK"}, + {.id = BOARD_ID_RPI_2_B,.name = "ARM-ARMV7-RPI-RPI_2_B"}, + {.id = BOARD_ID_RPI_3_B,.name = "ARM-ARMV7-RPI-RPI_3_B"}, }; struct board_arch2arch diff --git a/minix/include/minix/padconf.h b/minix/include/minix/padconf.h index c1d07f956..5192a0296 100644 --- a/minix/include/minix/padconf.h +++ b/minix/include/minix/padconf.h @@ -319,4 +319,9 @@ #define CONTROL_CONF_PUDEN (1<<3) #define CONTROL_CONF_MUXMODE(X) (X&0x7) +/* Raspberry Pi specific registers */ +#define PADCONF_RPI2_REGISTERS_BASE 0x3F200000 +#define PADCONF_RPI2_REGISTERS_OFFSET 0x0000 +#define PADCONF_RPI2_REGISTERS_SIZE 0x1000 + #endif /* __MINIX_PADCONF_H */ diff --git a/minix/kernel/arch/earm/arch_clock.c b/minix/kernel/arch/earm/arch_clock.c index ead7b6725..f26370c37 100644 --- a/minix/kernel/arch/earm/arch_clock.c +++ b/minix/kernel/arch/earm/arch_clock.c @@ -24,6 +24,7 @@ #include "bsp_timer.h" #include "bsp_intr.h" +#include "cpufunc_timer.h" static unsigned tsc_per_ms[CONFIG_MAX_CPUS]; static unsigned tsc_per_tick[CONFIG_MAX_CPUS]; @@ -37,7 +38,11 @@ int init_local_timer(unsigned freq) tsc_per_ms[0] = 16250; } else if (BOARD_IS_BB(machine.board_id)) { tsc_per_ms[0] = 15000; - } else { + } else if (BOARD_IS_RPI_2_B(machine.board_id) || + BOARD_IS_RPI_3_B(machine.board_id)) { + tsc_per_ms[0] = read_cntfrq() / 1000; + } + else { panic("Can not do the clock setup. machine (0x%08x) is unknown\n",machine.board_id); }; diff --git a/minix/kernel/arch/earm/bsp/rpi/Makefile.inc b/minix/kernel/arch/earm/bsp/rpi/Makefile.inc new file mode 100644 index 000000000..1f8a2f3b1 --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/Makefile.inc @@ -0,0 +1,12 @@ +# +# BSP for RPI hardware +# + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/bsp/${BSP_NAME} + +.for unpaged_obj in rpi_serial.o rpi_reset.o +BSP_OBJS_UNPAGED += ${unpaged_obj} +.endfor + +SRCS+= rpi_init.c rpi_serial.c rpi_timer.c rpi_padconf.c rpi_intr.c \ + rpi_reset.c diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_init.c b/minix/kernel/arch/earm/bsp/rpi/rpi_init.c new file mode 100644 index 000000000..044975e82 --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_init.c @@ -0,0 +1,17 @@ +#include +#include "bsp_init.h" +#include "bsp_padconf.h" +#include "bsp_reset.h" + +void +bsp_init() +{ + /* map memory for padconf */ + bsp_padconf_init(); + + /* map memory for reset control */ + bsp_reset_init(); + + /* disable watchdog */ + bsp_disable_watchdog(); +} diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_intr.c b/minix/kernel/arch/earm/bsp/rpi/rpi_intr.c new file mode 100644 index 000000000..53e85c09a --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_intr.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include + +#include "kernel/kernel.h" +#include "kernel/proc.h" +#include "kernel/vm.h" +#include "kernel/proto.h" +#include "arch_proto.h" +#include "hw_intr.h" + +#include "rpi_intr_registers.h" +#include "rpi_timer_registers.h" + +static struct rpi2_intr +{ + vir_bytes base; + vir_bytes core_base; + int size; +} rpi2_intr; + +static kern_phys_map intr_phys_map; +static kern_phys_map timer_phys_map; + +static irq_hook_t dummy8_irq_hook; +static irq_hook_t dummy41_irq_hook; +static irq_hook_t dummy51_irq_hook; + +int +dummy_irq_handler() +{ + /* + * The Raspberry Pi has a bunch of cascaded interrupts that are useless + * for MINIX. This handler catches them so as not to pollute the console + * with spurious interrupts messages. + */ + return 0; +} + +int +intr_init(const int auto_eoi) +{ + if (BOARD_IS_RPI_2_B(machine.board_id) || + BOARD_IS_RPI_3_B(machine.board_id)) { + rpi2_intr.base = RPI2_INTR_BASE; + rpi2_intr.core_base = RPI2_QA7_BASE; + } else { + panic + ("Can not do the interrupt setup. machine (0x%08x) is unknown\n", + machine.board_id); + } + + rpi2_intr.size = 0x1000; /* 4K */ + + kern_phys_map_ptr(rpi2_intr.base, rpi2_intr.size, + VMMF_UNCACHED | VMMF_WRITE, + &intr_phys_map, (vir_bytes) & rpi2_intr.base); + kern_phys_map_ptr(rpi2_intr.core_base, rpi2_intr.size, + VMMF_UNCACHED | VMMF_WRITE, + &timer_phys_map, (vir_bytes) & rpi2_intr.core_base); + + /* Disable FIQ and all interrupts */ + mmio_write(rpi2_intr.base + RPI2_INTR_FIQ_CTRL, 0); + mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE_BASIC, 0xFFFFFFFF); + mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE1, 0xFFFFFFFF); + mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE2, 0xFFFFFFFF); + + /* Enable ARM timer routing to IRQ here */ + mmio_write(rpi2_intr.core_base + QA7_CORE0TIMER, 0x8); + + /* Register dummy irq handlers */ + put_irq_handler(&dummy8_irq_hook, 8, (irq_handler_t)dummy_irq_handler); + put_irq_handler(&dummy41_irq_hook, 41, (irq_handler_t)dummy_irq_handler); + put_irq_handler(&dummy51_irq_hook, 51, (irq_handler_t)dummy_irq_handler); + + return 0; +} + +void +bsp_irq_handle(void) +{ + /* Function called from assembly to handle interrupts */ + uint32_t irq_0_31 = mmio_read(rpi2_intr.core_base + QA7_CORE0INT); + uint32_t irq_32_63 = mmio_read(rpi2_intr.base + RPI2_INTR_BASIC_PENDING); + uint32_t irq_64_95 = mmio_read(rpi2_intr.base + RPI2_INTR_PENDING1); + uint64_t irq_96_128 = mmio_read(rpi2_intr.base + RPI2_INTR_PENDING2); + + int irq = 0; + + /* Scan all interrupts bits */ + for (irq = 0; irq < 128; irq++) { + int is_pending = 0; + if (irq < 32) + is_pending = irq_0_31 & (1 << irq); + else if (irq < 64) + is_pending = irq_32_63 & (1 << (irq-32)); + else if (irq < 96) + is_pending = irq_64_95 & (1 << (irq-64)); + else + is_pending = irq_96_128 & (1 << (irq-96)); + + if (is_pending) + irq_handle(irq); + } + + /* Clear all pending interrupts */ + mmio_write(rpi2_intr.base + RPI2_INTR_BASIC_PENDING, irq_32_63); + mmio_write(rpi2_intr.base + RPI2_INTR_PENDING1, irq_64_95); + mmio_write(rpi2_intr.base + RPI2_INTR_PENDING2, irq_96_128); +} + +void +bsp_irq_unmask(int irq) +{ + if (irq < 32) + /* Nothing to do */ + ; + else if (irq < 64) + mmio_write(rpi2_intr.base + RPI2_INTR_ENABLE_BASIC, 1 << (irq-32)); + else if (irq < 96) + mmio_write(rpi2_intr.base + RPI2_INTR_ENABLE1, 1 << (irq-64)); + else if (irq < 128) + mmio_write(rpi2_intr.base + RPI2_INTR_ENABLE2, 1 << (irq-96)); +} + +void +bsp_irq_mask(const int irq) +{ + if (irq < 32) + /* Nothing to do */ + ; + else if (irq < 64) + mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE_BASIC, 1 << (irq-32)); + else if (irq < 96) + mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE1, 1 << (irq-64)); + else if (irq < 128) + mmio_write(rpi2_intr.base + RPI2_INTR_DISABLE2, 1 << (irq-96)); +} diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_intr_registers.h b/minix/kernel/arch/earm/bsp/rpi/rpi_intr_registers.h new file mode 100644 index 000000000..67a207bbd --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_intr_registers.h @@ -0,0 +1,17 @@ +#ifndef _RPI_INTR_H +#define _RPI_INTR_H + +#define RPI2_INTR_BASE 0x3f00B000 + +#define RPI2_INTR_BASIC_PENDING 0x200 +#define RPI2_INTR_PENDING1 0x204 +#define RPI2_INTR_PENDING2 0x208 +#define RPI2_INTR_FIQ_CTRL 0x20c +#define RPI2_INTR_ENABLE1 0x210 +#define RPI2_INTR_ENABLE2 0x214 +#define RPI2_INTR_ENABLE_BASIC 0x218 +#define RPI2_INTR_DISABLE1 0x21c +#define RPI2_INTR_DISABLE2 0x220 +#define RPI2_INTR_DISABLE_BASIC 0x224 + +#endif /* _RPI_INTR_H */ diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_padconf.c b/minix/kernel/arch/earm/bsp/rpi/rpi_padconf.c new file mode 100644 index 000000000..a30defda5 --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_padconf.c @@ -0,0 +1,58 @@ +/* Implements sys_padconf() for the Raspberry Pi. */ + +#include "kernel/kernel.h" +#include "arch_proto.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bsp_padconf.h" + +struct rpi2_padconf +{ + vir_bytes base; + vir_bytes offset; + vir_bytes size; +}; + +static struct rpi2_padconf rpi2_padconf; + +static kern_phys_map padconf_phys_map; + +int +bsp_padconf_set(u32_t padconf, u32_t mask, u32_t value) +{ + /* check that the value will be inside the padconf memory range */ + if (padconf >= (rpi2_padconf.size - rpi2_padconf.offset)) { + return EINVAL; /* outside of valid range */ + } + + set32(padconf + rpi2_padconf.base + rpi2_padconf.offset, mask, + value); + + return OK; +} + +void +bsp_padconf_init(void) +{ + if (BOARD_IS_RPI_2_B(machine.board_id) || + BOARD_IS_RPI_3_B(machine.board_id)) { + rpi2_padconf.base = PADCONF_RPI2_REGISTERS_BASE; + rpi2_padconf.offset = PADCONF_RPI2_REGISTERS_OFFSET; + rpi2_padconf.size = PADCONF_RPI2_REGISTERS_SIZE; + } + + kern_phys_map_ptr(rpi2_padconf.base, rpi2_padconf.size, + VMMF_UNCACHED | VMMF_WRITE, + &padconf_phys_map, (vir_bytes) & rpi2_padconf.base); + + return; +} diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_reset.c b/minix/kernel/arch/earm/bsp/rpi/rpi_reset.c new file mode 100644 index 000000000..4236ec327 --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_reset.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +#include "kernel/kernel.h" +#include "kernel/proc.h" +#include "kernel/vm.h" +#include "kernel/proto.h" +#include "arch_proto.h" +#include "bsp_reset.h" + +void +bsp_reset_init(void) +{ +} + +void +bsp_reset(void) +{ +} + +void +bsp_poweroff(void) +{ +} + +void bsp_disable_watchdog(void) +{ +} + diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_serial.c b/minix/kernel/arch/earm/bsp/rpi/rpi_serial.c new file mode 100644 index 000000000..53bde5703 --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_serial.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include + +#include "kernel/kernel.h" +#include "kernel/proc.h" +#include "kernel/vm.h" +#include "kernel/proto.h" +#include "arch_proto.h" + +#include "rpi_serial.h" + +struct pl011_serial +{ + vir_bytes base; + vir_bytes size; +}; + +static struct pl011_serial pl011_serial = { + .base = 0, +}; + +static kern_phys_map serial_phys_map; + +/* + * In kernel serial for the RPi. The serial driver like most other + * drivers needs to be started early and even before the MMU is turned on. + * We start by directly accessing the hardware memory address. Later on + * when the MMU is turned on we still use a 1:1 mapping for these addresses. + * + * Pretty soon we are going to remap these addresses at later stage. And this + * requires us to use a dynamic base address. The idea is to receive a callback + * from VM with the new address to use. + * + * The serial driver also gets used in the "pre_init" stage before the kernel is loaded + * in high memory so keep in mind there are two copies of this code in the kernel. + */ +void +bsp_ser_init() +{ + if (BOARD_IS_RPI_2_B(machine.board_id) || + BOARD_IS_RPI_3_B(machine.board_id)) { + pl011_serial.base = RPI2_PL011_DEBUG_UART_BASE; + } + + pl011_serial.size = 0x1000; /* 4k */ + + kern_phys_map_ptr(pl011_serial.base, pl011_serial.size, + VMMF_UNCACHED | VMMF_WRITE, &serial_phys_map, + (vir_bytes) & pl011_serial.base); + + assert(pl011_serial.base); + + /* Set UART to 115200 bauds */ + if (BOARD_IS_RPI_2_B(machine.board_id)) { + /* UARTCLK=48MHz */ + mmio_write(pl011_serial.base + PL011_IBRD, 1); + mmio_write(pl011_serial.base + PL011_FBRD, 40); + } + else if (BOARD_IS_RPI_3_B(machine.board_id)) { + /* UARTCLK=3MHz */ + mmio_write(pl011_serial.base + PL011_IBRD, 26); + mmio_write(pl011_serial.base + PL011_FBRD, 3); + } + + mmio_write(pl011_serial.base + PL011_LCRH, 0x70); + mmio_write(pl011_serial.base + PL011_CR, 0x301); +} + +void +bsp_ser_putc(char c) +{ + int i; + assert(pl011_serial.base); + + /* Wait until FIFO's not full */ + for (i = 0; i < 100000; i++) { + if ((mmio_read(pl011_serial.base + PL011_FR) & PL011_FR_TXFF) == 0) { + break; + } + } + + /* Write character */ + mmio_write(pl011_serial.base + PL011_DR, c); + + /* And wait again until FIFO's empty to prevent TTY from overwriting */ + for (i = 0; i < 100000; i++) { + if (mmio_read(pl011_serial.base + PL011_FR) & PL011_FR_TXFE) { + break; + } + } +} diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_serial.h b/minix/kernel/arch/earm/bsp/rpi/rpi_serial.h new file mode 100644 index 000000000..f77b04887 --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_serial.h @@ -0,0 +1,23 @@ +#ifndef _RPI_SERIAL_H +#define _RPI_SERIAL_H + +#define RPI2_PL011_DEBUG_UART_BASE 0x3f201000 + +#define PL011_DR 0x0 +#define PL011_FR 0x18 +#define PL011_IBRD 0x24 +#define PL011_FBRD 0x28 +#define PL011_LCRH 0x2c +#define PL011_CR 0x30 + +#define PL011_FR_TXFF (1<<5) +#define PL011_FR_TXFE (1<<7) + +#ifndef __ASSEMBLY__ + +void bsp_ser_init(); +void bsp_ser_putc(char c); + +#endif /* __ASSEMBLY__ */ + +#endif /* _RPI_SERIAL_H */ diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_timer.c b/minix/kernel/arch/earm/bsp/rpi/rpi_timer.c new file mode 100644 index 000000000..1b400450a --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_timer.c @@ -0,0 +1,85 @@ +#include "kernel/kernel.h" +#include "kernel/clock.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "arch_proto.h" +#include "bsp_timer.h" +#include "rpi_timer_registers.h" +#include "rpi_intr_registers.h" +#include "bsp_intr.h" + +#include "cpufunc_timer.h" + +static irq_hook_t arm_timer_hook; + +struct arm_timer +{ + int irq_nr; + u32_t freq; +}; + +static struct arm_timer arm_timer = { + .irq_nr = RPI2_IRQ_ARMTIMER, + .freq = 0, +}; + +static kern_phys_map stc_timer_phys_map; + +int +bsp_register_timer_handler(const irq_handler_t handler) +{ + /* Initialize the CLOCK's interrupt hook. */ + arm_timer_hook.proc_nr_e = NONE; + arm_timer_hook.irq = arm_timer.irq_nr; + + put_irq_handler(&arm_timer_hook, arm_timer.irq_nr, handler); + + /* Prepare next firing of timer */ + bsp_timer_int_handler(); + + /* only unmask interrupts after registering */ + bsp_irq_unmask(arm_timer.irq_nr); + + return 0; +} + +/* callback for when the free running clock gets mapped */ +int +kern_phys_fr_user_mapped(vir_bytes id, phys_bytes address) +{ + return 0; +} + +void +bsp_timer_init(unsigned freq) +{ + arm_timer.freq = freq; +} + +void +bsp_timer_stop() +{ + bsp_irq_mask(arm_timer.irq_nr); +} + +void +bsp_timer_int_handler() +{ + /* Arm next timer countdown and enable timer */ + write_cntv_cval(-1); + write_cntv_tval(read_cntfrq() / arm_timer.freq); + write_cntv_ctl(ARMTIMER_ENABLE); +} + +/* Use the free running clock as TSC */ +void +read_tsc_64(u64_t * t) +{ + *t = read_cntv_cval(); +} diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_timer_registers.h b/minix/kernel/arch/earm/bsp/rpi/rpi_timer_registers.h new file mode 100644 index 000000000..351f99901 --- /dev/null +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_timer_registers.h @@ -0,0 +1,11 @@ +#ifndef _RPI_TIMER_REGISTERS_H +#define _RPI_TIMER_REGISTERS_H + +#define RPI2_QA7_BASE 0x40000000 + +#define QA7_CORE0TIMER 0x40 +#define QA7_CORE0INT 0x60 + +#define RPI2_IRQ_ARMTIMER 3 + +#endif /* _RPI_TIMER_REGISTERS_H */ diff --git a/minix/kernel/arch/earm/include/cpufunc_timer.h b/minix/kernel/arch/earm/include/cpufunc_timer.h new file mode 100644 index 000000000..49f24500f --- /dev/null +++ b/minix/kernel/arch/earm/include/cpufunc_timer.h @@ -0,0 +1,67 @@ +#ifndef _ARM_CPUFUNC_TIMER_H +#define _ARM_CPUFUNC_TIMER_H + +/* Read CNTFRQ */ +static inline u32_t read_cntfrq() { + u32_t cntfrq; + asm volatile("mrc p15, 0, %[cntfrq], c14, c0 , 0 @ READ CNTFRQ\n\t" + : [cntfrq] "=r" (cntfrq)); + return cntfrq; +} + +/* Read CNTV_TVAL, virtual timer value register */ +static inline i32_t read_cntv_tval() { + i32_t cntv_tval; + asm volatile("mrc p15, 0, %[cntv_tval], c14, c3 , 0 @ READ CNTV_TVAL\n\t" + : [cntv_tval] "=r" (cntv_tval)); + return cntv_tval; +} + +/* write CNTV_TVAL, virtual timer control register */ +static inline void write_cntv_tval(i32_t val) { + asm volatile("mcr p15, 0, %[val], c14, c3 , 0 @ WRITE CNTV_CTL\n\t" + : : [val] "r" (val)); +} + +/* Read CNTV_CTL, virtual timer control register */ +static inline u32_t read_cntv_ctl() { + u32_t cntv_ctl; + asm volatile("mrc p15, 0, %[cntv_ctl], c14, c3 , 1 @ READ CNTV_CTL\n\t" + : [cntv_ctl] "=r" (cntv_ctl)); + return cntv_ctl; +} + +/* write CNTV_CTL, virtual timer control register */ +static inline void write_cntv_ctl(u32_t val) { + asm volatile("mcr p15, 0, %[val], c14, c3 , 1 @ WRITE CNTV_CTL\n\t" + : : [val] "r" (val)); +} + +/* Read CNTV_CVAL, virtual timer compare value register */ +static inline u64_t read_cntv_cval() { + u32_t cntv_cval_lo, cntv_cval_hi; + asm volatile("mrrc p15, 3, %[cntv_cval_lo], %[cntv_cval_hi], c14 @ READ CNTV_CVAL\n\t" + : [cntv_cval_lo] "=r" (cntv_cval_lo), [cntv_cval_hi] "=r" (cntv_cval_hi)); + return ((u64_t)cntv_cval_hi) << 32 | cntv_cval_lo; +} + +/* Write CNTV_CVAL, virtual timer compare value register */ +static inline void write_cntv_cval(u64_t val) { + u32_t cntv_cval_lo = val & 0xFFFFFFFF, cntv_cval_hi = val >> 32; + asm volatile("mcrr p15, 3, %[cntv_cval_lo], %[cntv_cval_hi], c14 @ WRITE CNTV_CVAL\n\t" + : : [cntv_cval_lo] "r" (cntv_cval_lo), [cntv_cval_hi] "r" (cntv_cval_hi)); +} + +/* Read CNTVCT, virtual count register */ +static inline u64_t read_cntvct() { + u32_t cntvct_lo, cntvct_hi; + asm volatile("mrrc p15, 1, %[cntvct_lo], %[cntvct_hi], c14 @ READ CNTVCT\n\t" + : [cntvct_lo] "=r" (cntvct_lo), [cntvct_hi] "=r" (cntvct_hi)); + return ((u64_t)cntvct_hi) << 32 | cntvct_lo; +} + +#define ARMTIMER_ENABLE 0x1 +#define ARMTIMER_IMASK 0x2 +#define ARMTIMER_ISTATUS 0x4 + +#endif /* _ARM_CPUFUNC_TIMER_H */ diff --git a/minix/kernel/arch/earm/kernel-rpi.lds b/minix/kernel/arch/earm/kernel-rpi.lds new file mode 100644 index 000000000..03f47b5ea --- /dev/null +++ b/minix/kernel/arch/earm/kernel-rpi.lds @@ -0,0 +1,50 @@ +OUTPUT_ARCH("arm") +ENTRY(__k_unpaged_MINIX) + +_kern_phys_base = 0x00200000; /* phys 4MB aligned for convenient remapping */ +_kern_vir_base = 0xF0400000; /* map kernel high for max. user vir space */ +_kern_offset = (_kern_vir_base - _kern_phys_base); + +__k_unpaged__kern_offset = _kern_offset; +__k_unpaged__kern_vir_base = _kern_vir_base; +__k_unpaged__kern_phys_base = _kern_phys_base; + +SECTIONS +{ + . = _kern_phys_base; + __k_unpaged__kern_unpaged_start = .; + + .unpaged_text ALIGN(4096) : { unpaged_*.o(.startup); unpaged_*.o(.text) } + .unpaged_data ALIGN(4096) : { unpaged_*.o(.data .rodata*) } + __k_unpaged__kern_unpaged_edata = .; + + .unpaged_bss ALIGN(4096) : { unpaged_*.o(.bss COMMON) } + __k_unpaged__kern_unpaged_end = .; + + . += _kern_offset; + + . = ALIGN(4096); usermapped_start = .; + .usermapped_glo : AT(ADDR(.usermapped_glo) - _kern_offset) { *(.usermapped_glo) } + . = ALIGN(4096); usermapped_nonglo_start = .; + .usermapped : AT(ADDR(.usermapped) - _kern_offset) { *(.usermapped) } + . = ALIGN(4096); usermapped_end = .; + .text : AT(ADDR(.text) - _kern_offset) { *(.text*) } + _etext = .; + .data ALIGN(4096) : AT(ADDR(.data) - _kern_offset) { *(.data .rodata* ) } + . = ALIGN(4096); + _edata = .; + __k_unpaged__edata = . - _kern_offset; + .bss ALIGN(4096) : AT(ADDR(.bss) - _kern_offset) { *(.bss* COMMON) + __k_unpaged__kern_size = . - _kern_vir_base; + _kern_size = __k_unpaged__kern_size; + + . += 4096; + } + _end = .; + __k_unpaged__end = . - _kern_offset; + + /DISCARD/ : + { + *(.ARM.exidx*) + } +} diff --git a/minix/kernel/arch/earm/pg_utils.c b/minix/kernel/arch/earm/pg_utils.c index 902c2ea8d..3fcbf8c89 100644 --- a/minix/kernel/arch/earm/pg_utils.c +++ b/minix/kernel/arch/earm/pg_utils.c @@ -31,6 +31,10 @@ void get_phys_mem_map(phys_bytes *start, phys_bytes *end) *start = 0x80000000; *end = 0xbfffffff; } + else if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)) { + *start = 0x00000000; + *end = 0x3effffff; + } } void print_memmap(kinfo_t *cbi) diff --git a/minix/kernel/arch/earm/pre_init.c b/minix/kernel/arch/earm/pre_init.c index 902af5a71..7be837cff 100644 --- a/minix/kernel/arch/earm/pre_init.c +++ b/minix/kernel/arch/earm/pre_init.c @@ -211,6 +211,11 @@ void setup_mbi(multiboot_info_t *mbi, char *bootargs) mb_mmap_start = 0x80000000; mb_mmap_size = 0x10000000; /* 256 MB */ } + else if (BOARD_IS_RPI_2_B(machine.board_id) || BOARD_IS_RPI_3_B(machine.board_id)) { + mb_mods_base = 0x02000000; + mb_mmap_start = 0x00008000; /* Don't overwrite bootcode for secondary CPUs */ + mb_mmap_size = 0x3C000000 - 0x00008000; /* 960 MB */ + } else POORMANS_FAILURE_NOTIFICATION; diff --git a/releasetools/arm_sdimage_rpi.sh b/releasetools/arm_sdimage_rpi.sh new file mode 100755 index 000000000..13616ce5e --- /dev/null +++ b/releasetools/arm_sdimage_rpi.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +set -e + +# +# This script creates a bootable image and should at some point in the future +# be replaced by the proper NetBSD infrastructure. +# + +# +# Source settings if present +# +: ${SETTINGS_MINIX=.settings} +if [ -f "${SETTINGS_MINIX}" ] +then + echo "Sourcing settings from ${SETTINGS_MINIX}" + # Display the content (so we can check in the build logs + # what the settings contain. + cat ${SETTINGS_MINIX} | sed "s,^,CONTENT ,g" + . ${SETTINGS_MINIX} +fi + +BSP_NAME=rpi +: ${ARCH=evbearm-el} +: ${TOOLCHAIN_TRIPLET=arm-elf32-minix-} +: ${BUILDSH=build.sh} + +: ${SETS="minix-base"} +: ${IMG=minix_arm_sd_rpi.img} + +# ARM definitions: +: ${BUILDVARS=-V MKGCCCMDS=yes -V MKLLVM=no} +# These BUILDVARS are for building with LLVM: +#: ${BUILDVARS=-V MKLIBCXX=no -V MKKYUA=no -V MKATF=no -V MKLLVMCMDS=no} + +if [ ! -f ${BUILDSH} ] +then + echo "Please invoke me from the root source dir, where ${BUILDSH} is." + exit 1 +fi + +# we create a disk image of about 2 gig's +# for alignment reasons, prefer sizes which are multiples of 4096 bytes +: ${FAT_START=4096} +: ${FAT_SIZE=$(( 64*(2**20) - ${FAT_START} ))} +: ${ROOT_SIZE=$(( 64*(2**20) ))} +: ${HOME_SIZE=$(( 128*(2**20) ))} +: ${USR_SIZE=$(( 1792*(2**20) ))} +#: ${IMG_SIZE=$(( 2*(2**30) ))} # no need to build an image that big for now +: ${IMG_SIZE=$(( 64*(2**20) ))} + +# set up disk creation environment +. releasetools/image.defaults +. releasetools/image.functions + +${RELEASETOOLSDIR}/checkout_repo.sh -o ${RELEASETOOLSDIR}/rpi-firmware -b ${RPI_FIRMWARE_BRANCH} -n ${RPI_FIRMWARE_REVISION} ${RPI_FIRMWARE_URL} + +# where the kernel & boot modules will be +MODDIR=${DESTDIR}/boot/minix/.temp + +echo "Building work directory..." +build_workdir "$SETS" + +# IMG might be a block device +if [ -f ${IMG} ] +then + rm -f ${IMG} +fi +dd if=/dev/zero of=${IMG} bs=512 count=1 seek=$((($IMG_SIZE / 512) -1)) 2>/dev/null + +# +# Generate /root, /usr and /home partition images. +# +echo "Writing disk image..." + +# +# Write FAT bootloader partition +# +echo " * BOOT" +rm -rf ${ROOT_DIR}/* +# copy over all modules +for i in ${MODDIR}/* +do + cp $i ${ROOT_DIR}/$(basename $i).elf +done +${CROSS_PREFIX}objcopy ${OBJ}/minix/kernel/kernel -O binary ${ROOT_DIR}/kernel.bin +# create packer +${CROSS_PREFIX}as ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.S -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.o +${CROSS_PREFIX}as ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.S -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.o +${CROSS_PREFIX}ld ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.o -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.elf -Ttext=0x8000 2> /dev/null +${CROSS_PREFIX}ld ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.o -o ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.elf -Ttext=0x8000 2> /dev/null +${CROSS_PREFIX}objcopy -O binary ${RELEASETOOLSDIR}/rpi-bootloader/bootloader2.elf ${ROOT_DIR}/minix_rpi2.bin +${CROSS_PREFIX}objcopy -O binary ${RELEASETOOLSDIR}/rpi-bootloader/bootloader3.elf ${ROOT_DIR}/minix_rpi3.bin +# pack modules +(cd ${ROOT_DIR} && cat <> ${ROOT_DIR}/minix_rpi2.bin 2>/dev/null +kernel.bin +mod01_ds.elf +mod02_rs.elf +mod03_pm.elf +mod04_sched.elf +mod05_vfs.elf +mod06_memory.elf +mod07_tty.elf +mod08_mib.elf +mod09_vm.elf +mod10_pfs.elf +mod11_mfs.elf +mod12_init.elf +EOF +) +(cd ${ROOT_DIR} && cat <> ${ROOT_DIR}/minix_rpi3.bin 2>/dev/null +kernel.bin +mod01_ds.elf +mod02_rs.elf +mod03_pm.elf +mod04_sched.elf +mod05_vfs.elf +mod06_memory.elf +mod07_tty.elf +mod08_mib.elf +mod09_vm.elf +mod10_pfs.elf +mod11_mfs.elf +mod12_init.elf +EOF +) +cp -r releasetools/rpi-firmware/* ${ROOT_DIR} + +# Write GPU config file +cat <${ROOT_DIR}/config.txt +[pi3] +kernel=minix_rpi3.bin +enable_uart=1 +dtoverlay=pi3-disable-bt + +[pi2] +kernel=minix_rpi2.bin +EOF + +${CROSS_TOOLS}/nbmakefs -t msdos -s $FAT_SIZE -O $FAT_START -o "F=32,c=1" ${IMG} ${ROOT_DIR} >/dev/null + +# +# Write the partition table using the natively compiled +# minix partition utility +# +${CROSS_TOOLS}/nbpartition -f -m ${IMG} $((${FAT_START}/512)) "c:$((${FAT_SIZE}/512))*" + +echo "" +echo "Disk image at `pwd`/${IMG}" +echo "" +echo "To boot this image on kvm:" +echo "qemu-system-arm -M raspi2 -drive if=sd,cache=writeback,format=raw,file=$(pwd)/${IMG} -bios ${ROOT_DIR}/minix_rpi2.bin" diff --git a/releasetools/image.defaults b/releasetools/image.defaults index 5872b5855..259bf535c 100644 --- a/releasetools/image.defaults +++ b/releasetools/image.defaults @@ -33,3 +33,7 @@ MODDIR=${DESTDIR}/boot/minix/.temp : ${U_BOOT_URL=git://git.minix3.org/u-boot} : ${U_BOOT_BRANCH=minix} : ${U_BOOT_REVISION=cb5178f12787c690cb1c888d88733137e5a47b15} + +: ${RPI_FIRMWARE_URL=https://github.com/boricj/rpi-firmware.git} +: ${RPI_FIRMWARE_BRANCH=master} +: ${RPI_FIRMWARE_REVISION=ccbca2eadd09dc550968839f227ecd0323cdbf22} diff --git a/releasetools/rpi-bootloader/bootloader2.S b/releasetools/rpi-bootloader/bootloader2.S new file mode 100644 index 000000000..367ecff3d --- /dev/null +++ b/releasetools/rpi-bootloader/bootloader2.S @@ -0,0 +1,18 @@ +.text + +.include "releasetools/rpi-bootloader/bootloader_common.S" + +.align 4 +argv: + .word argv0 + .word argv1 + .word 0x0 +argv0: + .asciz "0x00200000" +argv1: + .asciz "board_name=RPI_2_B console=tty00" + +.data +.align 4 + .space 256 +stack_top: diff --git a/releasetools/rpi-bootloader/bootloader3.S b/releasetools/rpi-bootloader/bootloader3.S new file mode 100644 index 000000000..1b3ae2cab --- /dev/null +++ b/releasetools/rpi-bootloader/bootloader3.S @@ -0,0 +1,18 @@ +.text + +.include "releasetools/rpi-bootloader/bootloader_common.S" + +.align 4 +argv: + .word argv0 + .word argv1 + .word 0x0 +argv0: + .asciz "0x00200000" +argv1: + .asciz "board_name=RPI_3_B console=tty00" + +.data +.align 4 + .space 256 +stack_top: diff --git a/releasetools/rpi-bootloader/bootloader_common.S b/releasetools/rpi-bootloader/bootloader_common.S new file mode 100644 index 000000000..613fa9314 --- /dev/null +++ b/releasetools/rpi-bootloader/bootloader_common.S @@ -0,0 +1,332 @@ +_start: + ldr sp, =stack_top + + /* Print banner */ + ldr r0, =msg_empty + bl puts + ldr r0, =msg_empty + bl puts + ldr r0, =msg_banner + bl puts + + /* Check if in hypervisor mode */ + mrs r0, cpsr + and r1, r0, #0x1f + cmp r1, #0x1a + bne mode_svc + +mode_hyp: + /* In hypervisor mode */ + ldr r0, =msg_hypmode + bl puts + + movw r0, #0x1d3 + ldr r1, =mode_svc + msr ELR_hyp, r1 + msr SPSR_hyp, r0 + eret + nop + +mode_svc: + nop + ldr sp, =stack_top + + /* In supervisor mode */ + ldr r0, =msg_svcmode + bl puts + + /* Move CPIO archive out of the way */ + ldr r0, =0xA000000 + ldr r1, =stack_top + mov r2, #0x2000000 + bl memcpy + +load_files: + ldr r0, =msg_extract + bl puts + /* Load kernel */ + ldr r0, =0x0A000000 + ldr r1, =0x00200000 + bl load_file + /* Load module */ + ldr r4, =0x02000000 + ldr r5, =0x00800000 +load_files_loop: + mov r1, r4 + bl load_file + cmp r0, #0 + beq final_preparations + add r4, r4, r5 + b load_files_loop +final_preparations: + /* Set up args and jump */ + ldr r0, =msg_launch + bl print + mov r0, #0x22 + bl putc + ldr r0, =argv1 + bl print + mov r0, #0x22 + bl putc + ldr r0, =msg_empty + bl puts + mov r0, #2 + ldr r1, =argv + b 0x00200000 + +/* + * Load a file from CPIO archive. + * r0: address of CPIO archive + * r1: address to copy the file to + * Return: address of next entry, or 0 if loading failed + */ +load_file: + push {r4-r8,lr} + mov r4, r0 + mov r5, r1 + mov r6, r2 + + /* Check header : either 070701 or 070702 */ + ldr r0, [r4] + ldr r1, =0x37303730 + cmp r0, r1 + bne load_file_failed + ldr r0, [r4, #4] + ldr r1, =0xFFFF + and r1, r1, r0 + ldr r2, =0x3130 + cmp r1, r2 + beq load_file_header_ok + ldr r2, =0x3230 + cmp r1, r2 + bne load_file_failed +load_file_header_ok: + /* Check for trailer */ + ldrh r0, [r4, #0x6e] + ldr r1, =0x5254 + cmp r1, r0 + beq load_file_failed + ldrh r0, [r4, #0x6e] + ldr r1, =0x4941 + cmp r1, r0 + beq load_file_failed + + /* Get data size */ + add r0, r4, #0x36 + bl hex2bin + mov r7, r0 + /* Get filename size */ + add r0, r4, #0x5e + bl hex2bin + mov r8, r0 + + /* Print file, size and offset */ + add r0, r4, #0x6e + bl print + + mov r0, r8 +load_file_name_padding_loop: + cmp r0, #24 + bgt load_file_name_padding_loop_end + push {r0} + mov r0, #0x20 + bl putc + pop {r0} + add r0, r0, #1 + b load_file_name_padding_loop + +load_file_name_padding_loop_end: + ldr r0, =msg_size + bl print + mov r0, r7 + bl print_hex + ldr r0, =msg_addr + bl print + mov r0, r5 + bl print_hex + /* Add CR/LF */ + mov r0, #0xd + bl putc + mov r0, #0xa + bl putc + + /* Get pointer to data source */ + add r1, r4, #0x6e + add r1, r1, r8 + /* Align to 4 bytes */ + and r2, r1, #0x3 + cmp r2, #0 + mov r0, #4 + subne r2, r0, r2 + addne r1, r1, r2 + + mov r0, r5 + mov r2, r7 + push {r1} + bl memcpy + + pop {r0} + add r0, r7 + /* Align to 4 bytes */ + and r2, r0, #0x3 + cmp r2, #0 + mov r1, #4 + subne r2, r1, r2 + addne r0, r0, r2 + + pop {r4-r8,lr} + bx lr +load_file_failed: + mov r0, #0 + pop {r4-r8,lr} + bx lr + +/* + * Send one character to the PL011 UART. + * r0: character to send + */ +putc: + /* Loop as long as FIFO isn't empty */ + ldr r1, =0x3f201018 + ldr r1, [r1] + and r1, #0x80 + tst r1, #0x80 + beq putc + + # Write character + ldr r1, =0x3f201000 + str r0, [r1] + + bx lr + +/* + * Print an ASCIIZ string to the PL011 UART. + * r0: address of string to print + */ +print: + push {lr} + /* If end of string, add newline */ +print_loop: + ldrb r1, [r0] + cmp r1, #0 + beq print_end + + /* Send character */ + push {r0} + mov r0, r1 + bl putc + pop {r0} + /* Advance to next character */ + add r0, r0, #1 + b print_loop + +print_end: + pop {lr} + bx lr +/* + * Print an ASCIIZ string to the PL011 UART, followed by CR/LF. + * r0: address of string to print + */ +puts: + push {lr} + bl print + + /* Add CR/LF */ + mov r0, #0xd + bl putc + mov r0, #0xa + bl putc + + pop {lr} + bx lr + + +/* + * Convert 8 hexadecimal characters to binary. + * r0: address of string to convert + * Return: the converted value + */ +hex2bin: + mov r1, #0 + mov r2, #0 +hex2bin_loop: + ldrb r3, [r0, r2] + cmp r3, #0x40 + sublt r3, r3, #0x30 + blt hex2bin_add_digit + cmp r3, #0x60 + sublt r3, r3, #0x37 + blt hex2bin_add_digit + sub r3, r3, #0x57 +hex2bin_add_digit: + lsl r1, r1, #4 + add r1, r1, r3 + add r2, r2, #1 + cmp r2, #8 + blt hex2bin_loop + mov r0, r1 + bx lr + +/* + * Print a value as hexadecimal. + * r0: value to print + */ +print_hex: + push {lr} + mov r1, #8 +print_hex_loop: + cmp r1, #0 + ble print_hex_end + + lsr r2, r0, #28 + cmp r2, #10 + addlt r2, r2, #0x30 + addge r2, r2, #0x37 + + push {r0-r2} + mov r0, r2 + bl putc + pop {r0-r2} + + sub r1, r1, #1 + lsl r0, r0, #4 + b print_hex_loop +print_hex_end: + pop {lr} + bx lr + +/* + * Quickly copy a memory area to another. + * r0: destination + * r1: source + * r2: length + */ +memcpy: + push {r5-r11} + add r2, r0, r2 +memcpy_loop: + cmp r0, r2 + bge memcpy_done + ldm r1!, {r3-r11} + stm r0!, {r3-r11} + b memcpy_loop +memcpy_done: + pop {r5-r11} + bx lr + +msg_empty: + .asciz "" +msg_banner: + .asciz "MINIX 3 unpacker for Raspberry Pi" +msg_svcmode: + .asciz "Current mode: supervisor" +msg_hypmode: + .asciz "Current mode: hypervisor. Switching to supervisor mode..." +msg_extract: + .asciz "Extracting modules..." +msg_launch: + .asciz "Jumping into kernel, argv[1]=" +msg_size: + .asciz " size:0x" +msg_addr: + .asciz " address:0x"