From patchwork Fri Feb 14 16:53:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 1238214 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-109763-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha1 header.s=default header.b=fcJIcE6N; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=WVdzW4Ag; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48JzxG5Dp9zB3y5 for ; Sat, 15 Feb 2020 03:54:09 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:mime-version :content-type:content-transfer-encoding; q=dns; s=default; b=wGq KG9lYhyzg2r/m/i9EKzOLBaw8uIf+8hVdjwl+Fu4vRNfZT6AjJ2jh66HGinL2jKI e8Niyr5ZOS7UN88soK7kwd151G67fqiMu4djheo0IGONKKs5I8eVKzS8QkIZcqXp o6ZaKNmJrazfwlQnTOA6gYbvvHdtksgHAgRVIYfc= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:mime-version :content-type:content-transfer-encoding; s=default; bh=syUq0fF0p Agxk1GAa1HfheXc3/M=; b=fcJIcE6Nkqi7a94oYP/ZVqFbmi09KCT+QqONnDp0m sacvMm7UKftfLYxub3SopGszW8rXBDeqKyGN89RnTOmhE/ONlWH3m0m6hT8TZkaL vvv3i3/IF1W9FY4kMSbZEoIFhjZmx8/L6J4MpVn+WffSbN0/KzwCcWrtZOnFJojV rk= Received: (qmail 118738 invoked by alias); 14 Feb 2020 16:54:03 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 118727 invoked by uid 89); 14 Feb 2020 16:54:02 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-19.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 spammy=POWER X-HELO: us-smtp-delivery-1.mimecast.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1581699239; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=l8LqHjqe2KbNVHemxTHLmlcq38mONwbwpfpWSBDcDGE=; b=WVdzW4Agb+0RSJ8xeW/uYbISKrWWcE3QRrt8AvAFLSksP4H+ptc777pOHhv9NnGtndH07K Vq4hWfTlB809TJ8TN/EBazVkFiBudQsTqoHUtsg6jzMM/O0fRoeaHlUeicFvSgvp6JVizE nhPPf2PR35X5eZWQPaLRYum+Fr8PRMI= From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH] powerpc64: Add architecture-specific memory protection key support [BZ #23202] Date: Fri, 14 Feb 2020 17:53:49 +0100 Message-ID: <87v9o9155u.fsf@oldenburg2.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com The 32-bit protection key behavior is somewhat unclear on 32-bit powerpc, so this change is restricted to the 64-bit variants. Flag translation is needed because of hardware differences between the POWER implementation (read and write flags) and the Intel implementation (write and read+write flags). Tested on powerpc64-linux-gnu, on a system that supports memory protection keys, along with Lucas' test change. ----- .../unix/sysv/linux/powerpc/powerpc64/arch-pkey.h | 55 ++++++++++++++++++++++ .../unix/sysv/linux/powerpc/powerpc64/pkey_get.c | 42 +++++++++++++++++ .../unix/sysv/linux/powerpc/powerpc64/pkey_set.c | 48 +++++++++++++++++++ 3 files changed, 145 insertions(+) diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h new file mode 100644 index 0000000000..623b073d5a --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-pkey.h @@ -0,0 +1,55 @@ +/* Helper functions for manipulating memory protection keys, for powerpc64. + Copyright (C) 2017-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _ARCH_PKEY_H +#define _ARCH_PKEY_H + +/* Read and write access bits in the AMR register. Needs to be + translated from and to PKEY_DISABLE_* flags. */ +#define PKEY_AMR_READ 1UL +#define PKEY_AMR_WRITE 2UL + +/* Return the value of the AMR register. */ +static inline unsigned long int +pkey_read (void) +{ + unsigned long int result; + __asm__ volatile ("mfspr %0, 13" : "=r" (result)); + return result; +} + +/* Overwrite the AMR register with VALUE. */ +static inline void +pkey_write (unsigned long int value) +{ + __asm__ volatile ("mtspr 13, %0" : : "r" (value)); +} + +/* Number of the largest supported key. This depends on the width of + the AMR register. */ +#define PKEY_MAX (sizeof (unsigned long int) * 8 / 2 - 1) +_Static_assert (PKEY_MAX == 15 || PKEY_MAX == 31, "PKEY_MAX value"); + +/* Translate key number into AMR index position. */ +static inline int +pkey_index (int key) +{ + return 2 * (PKEY_MAX - key); +} + +#endif /* _ARCH_PKEY_H */ diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c new file mode 100644 index 0000000000..856ba061b9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_get.c @@ -0,0 +1,42 @@ +/* Reading the per-thread memory protection key, powerpc64 version. + Copyright (C) 2017-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +pkey_get (int key) +{ + if (key < 0 || key > PKEY_MAX) + { + __set_errno (EINVAL); + return -1; + } + unsigned int index = pkey_index (key); + unsigned long int amr = pkey_read (); + unsigned int bits = (amr >> index) & 3; + + /* Translate from AMR values. PKEY_AMR_READ standing alone is not + currently representable. */ + if (bits & PKEY_AMR_READ) + return PKEY_DISABLE_ACCESS; + else if (bits == PKEY_AMR_WRITE) + return PKEY_DISABLE_WRITE; + return 0; +} diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c new file mode 100644 index 0000000000..20b372ee29 --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/pkey_set.c @@ -0,0 +1,48 @@ +/* Changing the per-thread memory protection key, powerpc64 version. + Copyright (C) 2017-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +pkey_set (int key, unsigned int rights) +{ + if (key < 0 || key > PKEY_MAX || rights > 3) + { + __set_errno (EINVAL); + return -1; + } + + /* Translate to AMR bit values. */ + unsigned long int bits; + if (rights & PKEY_DISABLE_ACCESS) + /* The PKEY_DISABLE_WRITE bit does not matter. */ + bits = PKEY_AMR_READ | PKEY_AMR_WRITE; + else if (rights == PKEY_DISABLE_WRITE) + bits = PKEY_AMR_WRITE; + else + bits = 0; + + unsigned int index = pkey_index (key); + unsigned long int mask = 3UL << index; + unsigned long int amr = pkey_read (); + amr = (amr & ~mask) | (bits << index); + pkey_write (amr); + return 0; +}