From patchwork Wed Jan 23 01:02:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 10776465 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E8DF7746 for ; Wed, 23 Jan 2019 01:03:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D6E99284A3 for ; Wed, 23 Jan 2019 01:03:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CAD142858F; Wed, 23 Jan 2019 01:03:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E5CD0284A3 for ; Wed, 23 Jan 2019 01:03:53 +0000 (UTC) Received: from localhost ([127.0.0.1]:53117 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gm6xN-0008NS-5w for patchwork-qemu-devel@patchwork.kernel.org; Tue, 22 Jan 2019 20:03:53 -0500 Received: from eggs.gnu.org ([209.51.188.92]:50736) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gm6vk-0007Bu-CI for qemu-devel@nongnu.org; Tue, 22 Jan 2019 20:02:14 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gm6vh-0002T3-JR for qemu-devel@nongnu.org; Tue, 22 Jan 2019 20:02:12 -0500 Received: from mail-wm1-x32e.google.com ([2a00:1450:4864:20::32e]:35706) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gm6vh-0002Nb-AX for qemu-devel@nongnu.org; Tue, 22 Jan 2019 20:02:09 -0500 Received: by mail-wm1-x32e.google.com with SMTP id t200so403643wmt.0 for ; Tue, 22 Jan 2019 17:02:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QirMGIyyJ8mPyffeQaMAhYCCUiHPI3baaFNQ4whC7Y4=; b=YQ3hqgCoo/8xDDLuWW/2EHFQRdbdYxSPW4/K8VIK9ckqhmYWpnMYSvwicj6bIFkksq ciF3kCVviyFUn6IlcROBVDDaREz1u0d/e3xbox8npkODmmMgN4Y8q6gOnfdTvSBq8ZHa auWheOk0lG46PDdshWI5PJMksBkDWXpD2QCm4kxUBYKq0N8blwBmC7zncpbjdfnxCgsg GHY3bFXu1gPlbXQQ6c2riORTkfOHrkCa/EiuMHMXb4DS95gjadmV+rNxjp9T9zmpf+ne o7XvtRZWbBcuIrZPVwlZ8iZMLa+7upX6CmLF51tFYR4Gmlld4Cru2v5JVW0oalsSkmYn wgAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=QirMGIyyJ8mPyffeQaMAhYCCUiHPI3baaFNQ4whC7Y4=; b=cL94qkjmijlDrWqQMw1Z8azDwnnFQHiCd3ncVZW72LYAw38CZu3mqaTlklazfNTQ5j mjA9g2cRw7E1pmPcq8gjlcJYtXlS2R+Cy8PciCzhl5Gny+riP0ckqJr7K2wMW9f1d1Zd UtOa1JM5PsweuJwotV/GBf/NhzGCW/h1Ugjoc4E0LRNGdoKAmrkrIlBQd7vblAIgya3k hvn2UB6uarp0sAK8J2CQM9YKxHvyAF2jbc5Tz/hD01+idXjO1d30J/xQt3WakB6YOhSO 7s7ZUP3KQ6pkuNc7wzT1zz4FE6grQ4/TeI/VFvvHdRib4lX6Sc2YgXrR18/sEpaVjtC5 U4ZQ== X-Gm-Message-State: AJcUukfc6Jwd7R0gHNBN3XrrIiNEM/CHKpDxEuxIWql7srgNuD+T98yf 32zR3VXkqkx5ziYUVLW6pQFis9ja X-Google-Smtp-Source: ALg8bN4QAbCeY7hTey6rkmo6t4be/UB4DyE/ojoxuPwa0Gr5USxIpfFhEY3KrABgyhWEsZqfexArkA== X-Received: by 2002:a1c:7409:: with SMTP id p9mr606096wmc.136.1548205325321; Tue, 22 Jan 2019 17:02:05 -0800 (PST) Received: from 640k.lan ([93.56.166.5]) by smtp.gmail.com with ESMTPSA id e17sm155062376wri.36.2019.01.22.17.02.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Jan 2019 17:02:03 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Wed, 23 Jan 2019 02:02:00 +0100 Message-Id: <1548205322-36101-2-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1548205322-36101-1-git-send-email-pbonzini@redhat.com> References: <1548205322-36101-1-git-send-email-pbonzini@redhat.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::32e Subject: [Qemu-devel] [PULL 29/51] linuxboot_dma: move common functions in a new header X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stefano Garzarella Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Stefano Garzarella In order to allow other option roms to use these common useful functions and definitions, this patch put them in two new C header files called optrom.h and optrom_fw_cfg.h. We also add useful out*() in*() functions for different size, and new fw_cfg functions to use when DMA feature is not available. Signed-off-by: Stefano Garzarella Reviewed-by: Stefan Hajnoczi Reviewed-by: Liam Merwick --- pc-bios/optionrom/linuxboot_dma.c | 102 +++++++---------------------------- pc-bios/optionrom/optrom.h | 110 ++++++++++++++++++++++++++++++++++++++ pc-bios/optionrom/optrom_fw_cfg.h | 92 +++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+), 83 deletions(-) create mode 100644 pc-bios/optionrom/optrom.h create mode 100644 pc-bios/optionrom/optrom_fw_cfg.h diff --git a/pc-bios/optionrom/linuxboot_dma.c b/pc-bios/optionrom/linuxboot_dma.c index f728dc8..cbcf667 100644 --- a/pc-bios/optionrom/linuxboot_dma.c +++ b/pc-bios/optionrom/linuxboot_dma.c @@ -58,21 +58,13 @@ asm( " jmp load_kernel\n" ); -#define BIOS_CFG_DMA_ADDR_HIGH 0x514 -#define BIOS_CFG_DMA_ADDR_LOW 0x518 - -#define uint64_t unsigned long long -#define uint32_t unsigned int -#define uint16_t unsigned short - -#include "../../include/standard-headers/linux/qemu_fw_cfg.h" - -#define barrier() asm("" : : : "memory") - -static inline void outl(uint32_t value, uint16_t port) -{ - asm("outl %0, %w1" : : "a"(value), "Nd"(port)); -} +/* + * The includes of C headers must be after the asm block to avoid compiler + * errors. + */ +#include +#include "optrom.h" +#include "optrom_fw_cfg.h" static inline void set_es(void *addr) { @@ -80,12 +72,6 @@ static inline void set_es(void *addr) asm("movl %0, %%es" : : "r"(seg)); } -#ifdef __clang__ -#define ADDR32 -#else -#define ADDR32 "addr32 " -#endif - static inline uint16_t readw_es(uint16_t offset) { uint16_t val; @@ -108,56 +94,6 @@ static inline void writel_es(uint16_t offset, uint32_t val) asm(ADDR32 "movl %0, %%es:(%1)" : : "r"(val), "r"((uint32_t)offset)); } -static inline uint32_t bswap32(uint32_t x) -{ - asm("bswapl %0" : "=r" (x) : "0" (x)); - return x; -} - -static inline uint64_t bswap64(uint64_t x) -{ - asm("bswapl %%eax; bswapl %%edx; xchg %%eax, %%edx" : "=A" (x) : "0" (x)); - return x; -} - -static inline uint64_t cpu_to_be64(uint64_t x) -{ - return bswap64(x); -} - -static inline uint32_t cpu_to_be32(uint32_t x) -{ - return bswap32(x); -} - -static inline uint32_t be32_to_cpu(uint32_t x) -{ - return bswap32(x); -} - -/* clang is happy to inline this function, and bloats the - * ROM. - */ -static __attribute__((__noinline__)) -void bios_cfg_read_entry(void *buf, uint16_t entry, uint32_t len) -{ - struct fw_cfg_dma_access access; - uint32_t control = (entry << 16) | FW_CFG_DMA_CTL_SELECT - | FW_CFG_DMA_CTL_READ; - - access.address = cpu_to_be64((uint64_t)(uint32_t)buf); - access.length = cpu_to_be32(len); - access.control = cpu_to_be32(control); - - barrier(); - - outl(cpu_to_be32((uint32_t)&access), BIOS_CFG_DMA_ADDR_LOW); - - while (be32_to_cpu(access.control) & ~FW_CFG_DMA_CTL_ERROR) { - barrier(); - } -} - /* Return top of memory using BIOS function E801. */ static uint32_t get_e801_addr(void) { @@ -211,9 +147,9 @@ void load_kernel(void) uint32_t initrd_end_page, max_allowed_page; uint32_t segment_addr, stack_addr; - bios_cfg_read_entry(&setup_addr, FW_CFG_SETUP_ADDR, 4); - bios_cfg_read_entry(&setup_size, FW_CFG_SETUP_SIZE, 4); - bios_cfg_read_entry(setup_addr, FW_CFG_SETUP_DATA, setup_size); + bios_cfg_read_entry_dma(&setup_addr, FW_CFG_SETUP_ADDR, 4); + bios_cfg_read_entry_dma(&setup_size, FW_CFG_SETUP_SIZE, 4); + bios_cfg_read_entry_dma(setup_addr, FW_CFG_SETUP_DATA, setup_size); set_es(setup_addr); @@ -223,8 +159,8 @@ void load_kernel(void) writel_es(0x22c, 0x37ffffff); } - bios_cfg_read_entry(&initrd_addr, FW_CFG_INITRD_ADDR, 4); - bios_cfg_read_entry(&initrd_size, FW_CFG_INITRD_SIZE, 4); + bios_cfg_read_entry_dma(&initrd_addr, FW_CFG_INITRD_ADDR, 4); + bios_cfg_read_entry_dma(&initrd_size, FW_CFG_INITRD_SIZE, 4); initrd_end_page = ((uint32_t)(initrd_addr + initrd_size) & -4096); max_allowed_page = (readl_es(0x22c) & -4096); @@ -239,15 +175,15 @@ void load_kernel(void) } - bios_cfg_read_entry(initrd_addr, FW_CFG_INITRD_DATA, initrd_size); + bios_cfg_read_entry_dma(initrd_addr, FW_CFG_INITRD_DATA, initrd_size); - bios_cfg_read_entry(&kernel_addr, FW_CFG_KERNEL_ADDR, 4); - bios_cfg_read_entry(&kernel_size, FW_CFG_KERNEL_SIZE, 4); - bios_cfg_read_entry(kernel_addr, FW_CFG_KERNEL_DATA, kernel_size); + bios_cfg_read_entry_dma(&kernel_addr, FW_CFG_KERNEL_ADDR, 4); + bios_cfg_read_entry_dma(&kernel_size, FW_CFG_KERNEL_SIZE, 4); + bios_cfg_read_entry_dma(kernel_addr, FW_CFG_KERNEL_DATA, kernel_size); - bios_cfg_read_entry(&cmdline_addr, FW_CFG_CMDLINE_ADDR, 4); - bios_cfg_read_entry(&cmdline_size, FW_CFG_CMDLINE_SIZE, 4); - bios_cfg_read_entry(cmdline_addr, FW_CFG_CMDLINE_DATA, cmdline_size); + bios_cfg_read_entry_dma(&cmdline_addr, FW_CFG_CMDLINE_ADDR, 4); + bios_cfg_read_entry_dma(&cmdline_size, FW_CFG_CMDLINE_SIZE, 4); + bios_cfg_read_entry_dma(cmdline_addr, FW_CFG_CMDLINE_DATA, cmdline_size); /* Boot linux */ segment_addr = ((uint32_t)setup_addr >> 4); diff --git a/pc-bios/optionrom/optrom.h b/pc-bios/optionrom/optrom.h new file mode 100644 index 0000000..3578192 --- /dev/null +++ b/pc-bios/optionrom/optrom.h @@ -0,0 +1,110 @@ +/* + * Common Option ROM Functions for C code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 . + * + * Copyright (c) 2015-2019 Red Hat Inc. + * Authors: + * Marc MarĂ­ + * Richard W.M. Jones + * Stefano Garzarella + */ + +#ifndef OPTROM_H +#define OPTROM_H + +#include +#include "../../include/standard-headers/linux/qemu_fw_cfg.h" + +#define barrier() asm("" : : : "memory") + +#ifdef __clang__ +#define ADDR32 +#else +#define ADDR32 "addr32 " +#endif + +static inline void outb(uint8_t value, uint16_t port) +{ + asm volatile("outb %0, %w1" : : "a"(value), "Nd"(port)); +} + +static inline void outw(uint16_t value, uint16_t port) +{ + asm volatile("outw %0, %w1" : : "a"(value), "Nd"(port)); +} + +static inline void outl(uint32_t value, uint16_t port) +{ + asm volatile("outl %0, %w1" : : "a"(value), "Nd"(port)); +} + +static inline uint8_t inb(uint16_t port) +{ + uint8_t value; + + asm volatile("inb %w1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +static inline uint16_t inw(uint16_t port) +{ + uint16_t value; + + asm volatile("inw %w1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +static inline uint32_t inl(uint16_t port) +{ + uint32_t value; + + asm volatile("inl %w1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +static inline void insb(uint16_t port, uint8_t *buf, uint32_t len) +{ + asm volatile("rep insb %%dx, %%es:(%%edi)" + : "+c"(len), "+D"(buf) : "d"(port) : "memory"); +} + +static inline uint32_t bswap32(uint32_t x) +{ + asm("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +static inline uint64_t bswap64(uint64_t x) +{ + asm("bswapl %%eax; bswapl %%edx; xchg %%eax, %%edx" : "=A" (x) : "0" (x)); + return x; +} + +static inline uint64_t cpu_to_be64(uint64_t x) +{ + return bswap64(x); +} + +static inline uint32_t cpu_to_be32(uint32_t x) +{ + return bswap32(x); +} + +static inline uint32_t be32_to_cpu(uint32_t x) +{ + return bswap32(x); +} + +#endif /* OPTROM_H */ diff --git a/pc-bios/optionrom/optrom_fw_cfg.h b/pc-bios/optionrom/optrom_fw_cfg.h new file mode 100644 index 0000000..a3660a5 --- /dev/null +++ b/pc-bios/optionrom/optrom_fw_cfg.h @@ -0,0 +1,92 @@ +/* + * Common Option ROM Functions for fw_cfg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 . + * + * Copyright (c) 2015-2019 Red Hat Inc. + * Authors: + * Marc MarĂ­ + * Richard W.M. Jones + * Stefano Garzarella + */ + +#ifndef OPTROM_FW_CFG_H +#define OPTROM_FW_CFG_H + +#include "../../include/standard-headers/linux/qemu_fw_cfg.h" + +#define BIOS_CFG_IOPORT_CFG 0x510 +#define BIOS_CFG_IOPORT_DATA 0x511 +#define BIOS_CFG_DMA_ADDR_HIGH 0x514 +#define BIOS_CFG_DMA_ADDR_LOW 0x518 + +static __attribute__((unused)) +void bios_cfg_select(uint16_t key) +{ + outw(key, BIOS_CFG_IOPORT_CFG); +} + +static __attribute__((unused)) +void bios_cfg_read_entry_io(void *buf, uint16_t entry, uint32_t len) +{ + bios_cfg_select(entry); + insb(BIOS_CFG_IOPORT_DATA, buf, len); +} + +/* + * clang is happy to inline this function, and bloats the + * ROM. + */ +static __attribute__((__noinline__)) __attribute__((unused)) +void bios_cfg_read_entry_dma(void *buf, uint16_t entry, uint32_t len) +{ + struct fw_cfg_dma_access access; + uint32_t control = (entry << 16) | FW_CFG_DMA_CTL_SELECT + | FW_CFG_DMA_CTL_READ; + + access.address = cpu_to_be64((uint64_t)(uint32_t)buf); + access.length = cpu_to_be32(len); + access.control = cpu_to_be32(control); + + barrier(); + + outl(cpu_to_be32((uint32_t)&access), BIOS_CFG_DMA_ADDR_LOW); + + while (be32_to_cpu(access.control) & ~FW_CFG_DMA_CTL_ERROR) { + barrier(); + } +} + +static __attribute__((unused)) +void bios_cfg_read_entry(void *buf, uint16_t entry, uint32_t len, + uint32_t version) +{ + if (version & FW_CFG_VERSION_DMA) { + bios_cfg_read_entry_dma(buf, entry, len); + } else { + bios_cfg_read_entry_io(buf, entry, len); + } +} + +static __attribute__((unused)) +uint32_t bios_cfg_version(void) +{ + uint32_t version; + + bios_cfg_read_entry_io(&version, FW_CFG_ID, sizeof(version)); + + return version; +} + +#endif /* OPTROM_FW_CFG_H */