From patchwork Thu May 7 11:31:41 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Spyridakis X-Patchwork-Id: 469603 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 5E67114028F for ; Thu, 7 May 2015 21:33:39 +1000 (AEST) Received: from localhost ([::1]:50098 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqK3d-0006o6-Ct for incoming@patchwork.ozlabs.org; Thu, 07 May 2015 07:33:37 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44762) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqK2J-0004bi-Pu for qemu-devel@nongnu.org; Thu, 07 May 2015 07:32:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YqK2G-0000aM-Fu for qemu-devel@nongnu.org; Thu, 07 May 2015 07:32:15 -0400 Received: from mail-wi0-f173.google.com ([209.85.212.173]:34030) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YqK2G-0000aH-7F for qemu-devel@nongnu.org; Thu, 07 May 2015 07:32:12 -0400 Received: by wicmx19 with SMTP id mx19so11544794wic.1 for ; Thu, 07 May 2015 04:32:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ft244bBTPCf+GUNUUadl03D3e4ZAGulde3d/tY08tuc=; b=TOnc7JaeOT7/mexrKsPUR9D44qNQEWqnaOQnHnhpYVe59j21nw9nsaVYlpSamz+l0k Es4KuOxkBqUH1LZQacIa4TaIhm/CbTvS0TvMvD5DbcUuWuKrOXtWX+ZAS67vB46gqYsv yt/0e1n4KSG9wuD2E0HnOVhhDaP4esbQHS2Q1pXo0fuRKO0R19SO3ORFNRCwVxPj1gfr FSLoa9I3gjrmFQ/1XwoubO1I/wIRwNSRZkpX0HFzsxXMo7V7mLaNh2ID2TGcoBhO2LnP 1PRIIhpSWE6NhuPmrkxvMhxYl0rBIHTt8qbv+AHeO+DCpDWzWYuPIVQ6U4R/918RQGm5 1Wdg== X-Gm-Message-State: ALoCoQnmGvqGJiIOyLnkHrZ6PnQAOfgPIhGMDMGYQ4w8dXEC0KQtoxB3801EFtKtBDHmpBXN0rJF X-Received: by 10.180.81.104 with SMTP id z8mr5758304wix.5.1430998331664; Thu, 07 May 2015 04:32:11 -0700 (PDT) Received: from localhost.localdomain (pas38-2-82-67-73-175.fbx.proxad.net. [82.67.73.175]) by mx.google.com with ESMTPSA id e2sm6940791wix.15.2015.05.07.04.32.10 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 07 May 2015 04:32:10 -0700 (PDT) From: Alexander Spyridakis To: qemu-devel@nongnu.org Date: Thu, 7 May 2015 13:31:41 +0200 Message-Id: <1430998302-31502-2-git-send-email-a.spyridakis@virtualopensystems.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1430998302-31502-1-git-send-email-a.spyridakis@virtualopensystems.com> References: <1430998302-31502-1-git-send-email-a.spyridakis@virtualopensystems.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.212.173 Cc: mttcg@listserver.greensocs.com, jani.kokkonen@huawei.com, tech@virtualopensystems.com, claudio.fontana@huawei.com Subject: [Qemu-devel] [PATCH RFC 1/2] atomic-test: Implement ARM and AARCH64 basic bare-metal infrastructure X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Minimal payload initialization for the virt machine model. Setup a stack and jump to C code, where CPU0 will boot any discovered secondary cores through PSCI. Immediately after all cores are turned-off and the guest is powered down. Added printf functionality is based on the multiboot test. In a similar manner this test is standalone and not part of 'make check'. Suggested-by: Jani Kokkonen Suggested-by: Claudio Fontana Signed-off-by: Alexander Spyridakis --- tests/atomic-test/Makefile | 63 ++++++++++++++++++ tests/atomic-test/helpers.c | 84 ++++++++++++++++++++++++ tests/atomic-test/helpers.h | 36 +++++++++++ tests/atomic-test/link.ld.S | 19 ++++++ tests/atomic-test/main.c | 32 ++++++++++ tests/atomic-test/printf.c | 152 ++++++++++++++++++++++++++++++++++++++++++++ tests/atomic-test/start.S | 54 ++++++++++++++++ 7 files changed, 440 insertions(+) create mode 100644 tests/atomic-test/Makefile create mode 100644 tests/atomic-test/helpers.c create mode 100644 tests/atomic-test/helpers.h create mode 100644 tests/atomic-test/link.ld.S create mode 100644 tests/atomic-test/main.c create mode 100644 tests/atomic-test/printf.c create mode 100644 tests/atomic-test/start.S diff --git a/tests/atomic-test/Makefile b/tests/atomic-test/Makefile new file mode 100644 index 0000000..094e01a --- /dev/null +++ b/tests/atomic-test/Makefile @@ -0,0 +1,63 @@ +# +# Global variables, sources and tools +# +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld + +S_OBJS = start.o +C_OBJS = main.o printf.o helpers.o +H_DEPS = helpers.h +LD_SCRIPT = link.ld.S + +LIBS = $(shell $(CC) $(CCFLAGS) -print-libgcc-file-name) +CPPFLAGS += -gdwarf-2 -fno-stack-protector -nostdinc -fno-builtin + +# +# Target specific variables +# +clean: export DIRS = build-virt build-virt64 + +virt: export CPPFLAGS += -march=armv7-a +virt64: export CPPFLAGS += -march=armv8-a -mgeneral-regs-only -mstrict-align + +virt: export CROSS_COMPILE ?= arm-none-eabi- +virt64: export CROSS_COMPILE ?= aarch64-linux-gnu- + +virt: export ARCH = ARCH_ARM +virt64: export ARCH = ARCH_AARCH64 + +virt virt64: export UART_PHYS = 0x09000000 +virt virt64: export ENTRY_POINT = 0x40000000 + +virt virt64: export O_DIR = build-$@/ +virt virt64: export IMAGE = $(O_DIR)image-$@.axf + +# +# Target build rules +# +all: virt virt64 + +clean: + rm -rf $(DIRS) + +virt virt64: + mkdir -p $(O_DIR) + @$(MAKE) $(IMAGE) --no-print-directory + +$(IMAGE): $(addprefix $(O_DIR), $(S_OBJS)) \ + $(addprefix $(O_DIR), $(C_OBJS)) $(H_DEPS) $(O_DIR)link.ld Makefile + $(LD) -o $@ $(addprefix $(O_DIR), $(S_OBJS)) \ + $(addprefix $(O_DIR), $(C_OBJS)) $(LIBS) \ + --script=$(O_DIR)link.ld -Map $(O_DIR)system.map + +$(O_DIR)link.ld: $(LD_SCRIPT) + $(CC) -DENTRY_POINT=$(ENTRY_POINT) -D$(ARCH) $(CPPFLAGS) -E -P -C -o $@ $< + +$(O_DIR)%.o: %.c $(H_DEPS) + $(CC) -DENTRY_POINT=$(ENTRY_POINT) \ + -DUART_PHYS=$(UART_PHYS) -D$(ARCH) $(CPPFLAGS) -c -o $@ $< + +$(O_DIR)%.o: %.S $(H_DEPS) + $(CC) -D$(ARCH) $(CPPFLAGS) -c -o $@ $< + +.PHONY: all clean virt virt64 diff --git a/tests/atomic-test/helpers.c b/tests/atomic-test/helpers.c new file mode 100644 index 0000000..8ac8c2c --- /dev/null +++ b/tests/atomic-test/helpers.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 Virtual Open Systems SAS + * Author: Alexander Spyridakis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "helpers.h" + +#ifdef ARCH_ARM +__asm__(".arch_extension virt"); + +int get_cpuid(void) +{ + int cpu; + asm volatile ("mrc p15, 0, %0, c0, c0, 5; and %0, %0, #15\n" : "=r"(cpu)); + return cpu; +} + +int psci_call(int psci_function, int arg0, int arg1, int arg2) +{ + int ret; + asm volatile ("hvc #0; mov %0, r0\n" : "=r" (ret)); + return ret; +} +#elif ARCH_AARCH64 +int get_cpuid(void) +{ + int cpu; + asm volatile ("mrs %0, MPIDR_EL1; and %0, %0, #15\n" : "=r"(cpu)); + return cpu; +} + +int psci_call(int psci_function, int arg0, int arg1, int arg2) +{ + int ret; + asm volatile ("hvc #0; mov %0, x0\n" : "=r" (ret)); + return ret; +} +#endif + +void power_secondary(void) +{ + int ret, cpu = 1; + + /* Sequentially power-up all secondary cores, + * error means trying to wake up non existing cores */ + do { ret = psci_call(PSCI_CPU_ON, cpu++, ENTRY_POINT, 0); } while (!ret); +} + +void power_off(void) +{ + int ret, i = 1; + int cpu = get_cpuid(); + + /* Only secondary cores should power off themselves */ + if(cpu) { + psci_call(PSCI_CPU_OFF, 0, 0, 0); + return; + } + + /* Primary core should wait for all secondaries to be powered off */ + do { + ret = psci_call(PSCI_AFFINITY_INFO, i, 0, 0); + + /* If a core was powered off, wait for the next one */ + if (ret == 1) { + i++; + } + } while(ret >= 0); + + /* Shut down system */ + psci_call(PSCI_SYSTEM_OFF, 0, 0, 0); +} diff --git a/tests/atomic-test/helpers.h b/tests/atomic-test/helpers.h new file mode 100644 index 0000000..66d440e --- /dev/null +++ b/tests/atomic-test/helpers.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 Virtual Open Systems SAS + * Author: Alexander Spyridakis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef HELPERS_H +#define HELPERS_H + +#ifdef ARCH_ARM +#define PSCI_CPU_ON 0x84000003 +#define PSCI_AFFINITY_INFO 0x84000004 +#elif ARCH_AARCH64 +#define PSCI_CPU_ON 0xC4000003 +#define PSCI_AFFINITY_INFO 0xC4000004 +#endif + +#define PSCI_CPU_OFF 0x84000002 +#define PSCI_SYSTEM_OFF 0x84000008 + +int get_cpuid(void); +void power_secondary(void); +void power_off(); + +#endif diff --git a/tests/atomic-test/link.ld.S b/tests/atomic-test/link.ld.S new file mode 100644 index 0000000..e1ab018 --- /dev/null +++ b/tests/atomic-test/link.ld.S @@ -0,0 +1,19 @@ +#ifdef ARCH_ARM +OUTPUT_FORMAT("elf32-littlearm") +OUTPUT_ARCH(arm) +#elif ARCH_AARCH64 +OUTPUT_FORMAT("elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +#endif + +SECTIONS +{ + . = ENTRY_POINT; + + .text ALIGN(4096) : { *(.text) } + .data ALIGN(4096) : { *(.data) } + .bss ALIGN(4096) : { *(.bss) } + .rodata ALIGN(4096) : { *(.rodata) } + + text_end = ALIGN(8); +} diff --git a/tests/atomic-test/main.c b/tests/atomic-test/main.c new file mode 100644 index 0000000..72eaf59 --- /dev/null +++ b/tests/atomic-test/main.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 Virtual Open Systems SAS + * Author: Alexander Spyridakis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +void main(void) +{ + printf("CPU %d on\n", get_cpuid()); + power_off(); +} + +void init(void) +{ + /* Only CPU 0 should be here */ + if (get_cpuid()) { + return; + } + + power_secondary(); +} \ No newline at end of file diff --git a/tests/atomic-test/printf.c b/tests/atomic-test/printf.c new file mode 100644 index 0000000..7c40d37 --- /dev/null +++ b/tests/atomic-test/printf.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2015 Virtual Open Systems SAS + * Author: Alexander Spyridakis + * + * printf based on implementation by Kevin Wolf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define UARTDR UART_PHYS +#define UARTFR 0x18 +#define UARTFR_TXFF (1 << 5) + +typedef __builtin_va_list va_list; +#define va_start(ap, X) __builtin_va_start(ap, X) +#define va_arg(ap, type) __builtin_va_arg(ap, type) +#define va_end(ap) __builtin_va_end(ap) + +int *uart_phys = (int *)(UART_PHYS); +int *uart_busy = (int *)(UART_PHYS + UARTFR); + +static void putc(char c) +{ + /* If the FIFO is full, wait before pushing data to the UART */ + while (*uart_busy & UARTFR_TXFF); + + *uart_phys = c; + + /* Add the carriage return in case of a line feed character */ + if (c == '\n') { + putc('\r'); + } +} + +static void print_str(char *s) +{ + while (*s) { + putc(*s++); + } +} + +static void print_num(unsigned long long value, int base) +{ + char digits[] = "0123456789abcdef"; + char buf[32] = { 0 }; + int i = sizeof(buf) - 2; + + do { + buf[i--] = digits[value % base]; + value /= base; + } while (value); + + print_str(&buf[i + 1]); +} + +void printf(const char *fmt, ...) +{ + va_list ap; + char *str; + int base; + int has_long; + int alt_form; + unsigned long long val; + + va_start(ap, fmt); + + for (; *fmt; fmt++) { + if (*fmt != '%') { + putc(*fmt); + continue; + } + fmt++; + + if (*fmt == '#') { + fmt++; + alt_form = 1; + } else { + alt_form = 0; + } + + if (*fmt == 'l') { + fmt++; + if (*fmt == 'l') { + fmt++; + has_long = 2; + } else { + has_long = 1; + } + } else { + has_long = 0; + } + + switch (*fmt) { + case 'x': + case 'p': + base = 16; + goto convert_number; + case 'd': + case 'i': + case 'u': + base = 10; + goto convert_number; + case 'o': + base = 8; + goto convert_number; + + convert_number: + switch (has_long) { + case 0: + val = va_arg(ap, unsigned int); + break; + case 1: + val = va_arg(ap, unsigned long); + break; + case 2: + val = va_arg(ap, unsigned long long); + break; + } + + if (alt_form && base == 16) { + print_str("0x"); + } + + print_num(val, base); + break; + + case 's': + str = va_arg(ap, char*); + print_str(str); + break; + case '%': + putc(*fmt); + break; + default: + putc('%'); + putc(*fmt); + break; + } + } + + va_end(ap); +} diff --git a/tests/atomic-test/start.S b/tests/atomic-test/start.S new file mode 100644 index 0000000..29e483f --- /dev/null +++ b/tests/atomic-test/start.S @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Virtual Open Systems SAS + * Author: Alexander Spyridakis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * Before jumping to C code we need to setup a stack. + * This macro gets the CPU ID from MPIDR and offsets the stack + * for each CPU by 1 << 18 (256 KiB), starting after the text section. + */ +#ifdef ARCH_ARM +.macro setup_stack + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #15 + add r0, r0, #1 + + lsl r0, r0, #20 + ldr r1, =text_end + add r0, r0, r1 + mov sp, r0 +.endm +#elif ARCH_AARCH64 +.macro setup_stack + mrs x0, MPIDR_EL1 + and x0, x0, #15 + add x0, x0, #1 + + lsl x0, x0, #18 + ldr x1, =text_end + add x0, x0, x1 + mov sp, x0 +.endm +#endif + +/* Entry point */ +.section .text +.global _start +_start: + setup_stack + bl init + bl main + b .