* [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms
From: Richard Genoud @ 2016-10-27 16:04 UTC (permalink / raw)
To: linux-arm-kernel
After commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management
when hardware handshake is enabled"), the hardware handshake wasn't
functional anymore on Atmel platforms (beside SAMA5D2).
To understand why, one has to understand the flag ATMEL_US_USMODE_HWHS
first:
Before commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management
when hardware handshake is enabled"), this flag was never set.
Thus, the CTS/RTS where only handled by serial_core (and everything
worked just fine).
This commit introduced the use of the ATMEL_US_USMODE_HWHS flag,
enabling it for all boards when the user space enables flow control.
When the ATMEL_US_USMODE_HWHS is set, the Atmel USART controller
handles a part of the flow control job:
- disable the transmitter when the CTS pin gets high.
- drive the RTS pin high when the DMA buffer transfer is completed or
PDC RX buffer full or RX FIFO is beyond threshold. (depending on the
controller version).
NB: This feature is *not* mandatory for the flow control to work.
(Nevertheless, it's very useful if low latencies are needed.)
Now, the specifics of the ATMEL_US_USMODE_HWHS flag:
- For platforms with DMAC and no FIFOs (sam9x25, sam9x35, sama5D3,
sama5D4, sam9g15, sam9g25, sam9g35)* this feature simply doesn't work.
( source: https://lkml.org/lkml/2016/9/7/598 )
Tested it on sam9g35, the RTS pins always stays up, even when RXEN=1
or a new DMA transfer descriptor is set.
=> ATMEL_US_USMODE_HWHS must not be used for those platforms
- For platforms with a PDC (sam926{0,1,3}, sam9g10, sam9g20, sam9g45,
sam9g46)*, there's another kind of problem. Once the flag
ATMEL_US_USMODE_HWHS is set, the RTS pin can't be driven anymore via
RTSEN/RTSDIS in USART Control Register. The RTS pin can only be driven
by enabling/disabling the receiver or setting RCR=RNCR=0 in the PDC
(Receive (Next) Counter Register).
=> Doing this is beyond the scope of this patch and could add other
bugs, so the original (and working) behaviour should be set for those
platforms (meaning ATMEL_US_USMODE_HWHS flag should be unset).
- For platforms with a FIFO (sama5d2)*, the RTS pin is driven according
to the RX FIFO thresholds, and can be also driven by RTSEN/RTSDIS in
USART Control Register. No problem here.
(This was the use case of commit 1cf6e8fc8341 ("tty/serial: at91: fix
RTS line management when hardware handshake is enabled"))
NB: If the CTS pin declared as a GPIO in the DTS, (for instance
cts-gpios = <&pioA PIN_PB31 GPIO_ACTIVE_LOW>), the transmitter will be
disabled.
=> ATMEL_US_USMODE_HWHS flag can be set for this platform ONLY IF the
CTS pin is not a GPIO.
So, the only case when ATMEL_US_USMODE_HWHS can be enabled is when
(atmel_use_fifo(port) &&
!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
Tested on all Atmel USART controller flavours:
AT91SAM9G35-CM (DMAC flavour), AT91SAM9G20-EK (PDC flavour),
SAMA5D2xplained (FIFO flavour).
* the list may not be exhaustive
Cc: <stable@vger.kernel.org> #4.4+ (beware, missing atmel_port variable)
Fixes: 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled")
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
drivers/tty/serial/atmel_serial.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
Note for -stable:
This patch will apply on 4.4.x/4.8.x but compilation will fail due to
a missing variable atmel_port (introduced in 4.9-rc1):
static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned long flags;
unsigned int old_mode, mode, imr, quot, baud;
Changes since v5:
- fix typos
- increase commentary
Changes since v4:
- the mctrl_gpio_use_rtscts() is gone since it was atmel_serial
specific. (so patch 1 is gone)
- patches 2 and 3 have been merged together since it didn't make
a lot of sense to correct the GPIO case in one separate patch.
- ATMEL_US_USMODE_HWHS is now unset for platform with PDC
Changes since v3:
- remove superfluous #include <linux/err.h> (thanks to Uwe)
- rebase on next-20160930
Changes since v2:
- remove IS_ERR_OR_NULL() test in patch 1/3 as Uwe suggested.
- fix typos in patch 2/3
- rebase on next-20160927
- simplify the logic in patch 3/3.
Changes since v1:
- Correct patch 1 with the error found by kbuild.
- Add Alexandre's Acked-by on patch 2
- Rewrite patch 3 logic in the light of the on-going discussion
with Cyrille and Alexandre.
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index fd8aa1f4ba78..168b10cad47b 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
mode |= ATMEL_US_USMODE_RS485;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
- if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
- dev_info(port->dev, "not enabling hardware flow control because DMA is used");
- termios->c_cflag &= ~CRTSCTS;
- } else {
+ if (atmel_use_fifo(port) &&
+ !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
+ /*
+ * with ATMEL_US_USMODE_HWHS set, the controller will
+ * be able to drive the RTS pin high/low when the RX
+ * FIFO is above RXFTHRES/below RXFTHRES2.
+ * It will also disable the transmitter when the CTS
+ * pin is high.
+ * This mode is not activated if CTS pin is a GPIO
+ * because in this case, the transmitter is always
+ * disabled (there must be an internal pull-up
+ * responsible for this behaviour).
+ * If the RTS pin is a GPIO, the controller won't be
+ * able to drive it according to the FIFO thresholds,
+ * but it will be handled by the driver.
+ */
mode |= ATMEL_US_USMODE_HWHS;
+ } else {
+ /*
+ * For platforms without FIFO, the flow control is
+ * handled by the driver.
+ */
+ mode |= ATMEL_US_USMODE_NORMAL;
}
} else {
/* RS232 without hadware handshake */
^ permalink raw reply related
* [PATCH v3] drivers: psci: PSCI checker module
From: Kevin Brodsky @ 2016-10-27 16:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027145446.GJ3716@linux.vnet.ibm.com>
On 27/10/16 15:54, Paul E. McKenney wrote:
> On Thu, Oct 27, 2016 at 01:51:57PM +0100, Kevin Brodsky wrote:
> > On 27/10/16 10:13, Lorenzo Pieralisi wrote:
> >> On Wed, Oct 26, 2016 at 11:11:48AM -0700, Paul E. McKenney wrote:
> >>> On Wed, Oct 26, 2016 at 06:35:34PM +0100, Lorenzo Pieralisi wrote:
> >>>> On Wed, Oct 26, 2016 at 10:22:52AM -0700, Paul E. McKenney wrote:
> >>>>> On Wed, Oct 26, 2016 at 06:10:06PM +0100, Lorenzo Pieralisi wrote:
> >>> [ . . . ]
> >>>
> >>>>>> Thanks a lot for your feedback, thoughts appreciated.
> >>>>> Let me ask the question more directly.
> >>>>>
> >>>>> Why on earth are we trying to run these tests concurrently?
> >>>> We must prevent that, no question about that, that's why I started
> >>>> this discussion. It is not fine to enable this checker and the
> >>>> RCU/LOCK torture hotplug tests at the same time.
> >>>>
> >>>>> After all, if we just run one at a time in isolation, there is no
> >>>>> problem.
> >>>> Fine by me, it was to understand if the current assumptions we made
> >>>> are correct and they are definitely not. If we enable the PSCI checker
> >>>> we must disable the torture rcu/lock hotplug tests either statically or
> >>>> dynamically.
> >>> What rcutorture, locktorture, and rcuperf do is to invoke
> >>> torture_init_begin(), which returns false if one of these tests
> >>> is already running.
> >>>
> >>> Perhaps we should extract this torture-test-exclusion and require
> >>> than conflicting torture tests invoke it?
> >> Yes if it can be extracted as a check (but it should also prevent the
> >> torture tests from running and vice versa), either that or Kconfig
> >> dependency (which we could do as a first step, waiting to add the
> >> required interface to the torture test code ?).
> >>
> >> Thanks !
> >> Lorenzo
> >
> > That sounds like a reasonable idea, but then that would mean that the PSCI checker
> > would have to wait until the torture test is finished if it is already running (and
> > the other way around).
> >
> > I wasn't aware that torture tests were hotplugging CPUs. I think that the most
> > sensible thing to do right now is to make CONFIG_PSCI_CHECKER depend on
> > !CONFIG_TORTURE_TEST (or maybe specifically !CONFIG_RCU_TORTURE_TEST &&
> > !CONFIG_LOCK_TORTURE_TEST). We can try to make them work together afterwards, but for
> > the sake of getting this patch merged in a reasonable amount of time, I think we
> > should just exclude the conflicting tests at the build level in this patch. I'll also
> > update the comment accordingly.
>
> I suggest !CONFIG_TORTURE_TEST, given that there are a couple of other
> tests in the offing.
>
> Thanx, Paul
Fair enough. If that's fine with Lorenzo, I'll add the dependency and post v4.
Thanks,
Kevin
^ permalink raw reply
* [PATCH v6] tty/serial: at91: fix hardware handshake on Atmel platforms
From: Nicolas Ferre @ 2016-10-27 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027160406.25738-1-richard.genoud@gmail.com>
Le 27/10/2016 ? 18:04, Richard Genoud a ?crit :
> After commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management
> when hardware handshake is enabled"), the hardware handshake wasn't
> functional anymore on Atmel platforms (beside SAMA5D2).
>
> To understand why, one has to understand the flag ATMEL_US_USMODE_HWHS
> first:
> Before commit 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management
> when hardware handshake is enabled"), this flag was never set.
> Thus, the CTS/RTS where only handled by serial_core (and everything
> worked just fine).
>
> This commit introduced the use of the ATMEL_US_USMODE_HWHS flag,
> enabling it for all boards when the user space enables flow control.
>
> When the ATMEL_US_USMODE_HWHS is set, the Atmel USART controller
> handles a part of the flow control job:
> - disable the transmitter when the CTS pin gets high.
> - drive the RTS pin high when the DMA buffer transfer is completed or
> PDC RX buffer full or RX FIFO is beyond threshold. (depending on the
> controller version).
>
> NB: This feature is *not* mandatory for the flow control to work.
> (Nevertheless, it's very useful if low latencies are needed.)
>
> Now, the specifics of the ATMEL_US_USMODE_HWHS flag:
>
> - For platforms with DMAC and no FIFOs (sam9x25, sam9x35, sama5D3,
> sama5D4, sam9g15, sam9g25, sam9g35)* this feature simply doesn't work.
> ( source: https://lkml.org/lkml/2016/9/7/598 )
> Tested it on sam9g35, the RTS pins always stays up, even when RXEN=1
> or a new DMA transfer descriptor is set.
> => ATMEL_US_USMODE_HWHS must not be used for those platforms
>
> - For platforms with a PDC (sam926{0,1,3}, sam9g10, sam9g20, sam9g45,
> sam9g46)*, there's another kind of problem. Once the flag
> ATMEL_US_USMODE_HWHS is set, the RTS pin can't be driven anymore via
> RTSEN/RTSDIS in USART Control Register. The RTS pin can only be driven
> by enabling/disabling the receiver or setting RCR=RNCR=0 in the PDC
> (Receive (Next) Counter Register).
> => Doing this is beyond the scope of this patch and could add other
> bugs, so the original (and working) behaviour should be set for those
> platforms (meaning ATMEL_US_USMODE_HWHS flag should be unset).
>
> - For platforms with a FIFO (sama5d2)*, the RTS pin is driven according
> to the RX FIFO thresholds, and can be also driven by RTSEN/RTSDIS in
> USART Control Register. No problem here.
> (This was the use case of commit 1cf6e8fc8341 ("tty/serial: at91: fix
> RTS line management when hardware handshake is enabled"))
> NB: If the CTS pin declared as a GPIO in the DTS, (for instance
> cts-gpios = <&pioA PIN_PB31 GPIO_ACTIVE_LOW>), the transmitter will be
> disabled.
> => ATMEL_US_USMODE_HWHS flag can be set for this platform ONLY IF the
> CTS pin is not a GPIO.
>
> So, the only case when ATMEL_US_USMODE_HWHS can be enabled is when
> (atmel_use_fifo(port) &&
> !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
>
> Tested on all Atmel USART controller flavours:
> AT91SAM9G35-CM (DMAC flavour), AT91SAM9G20-EK (PDC flavour),
> SAMA5D2xplained (FIFO flavour).
>
> * the list may not be exhaustive
>
> Cc: <stable@vger.kernel.org> #4.4+ (beware, missing atmel_port variable)
> Fixes: 1cf6e8fc8341 ("tty/serial: at91: fix RTS line management when hardware handshake is enabled")
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Thanks
> ---
> drivers/tty/serial/atmel_serial.c | 26 ++++++++++++++++++++++----
> 1 file changed, 22 insertions(+), 4 deletions(-)
>
> Note for -stable:
> This patch will apply on 4.4.x/4.8.x but compilation will fail due to
> a missing variable atmel_port (introduced in 4.9-rc1):
>
> static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
> struct ktermios *old)
> {
> + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> unsigned long flags;
> unsigned int old_mode, mode, imr, quot, baud;
>
> Changes since v5:
> - fix typos
> - increase commentary
>
> Changes since v4:
> - the mctrl_gpio_use_rtscts() is gone since it was atmel_serial
> specific. (so patch 1 is gone)
> - patches 2 and 3 have been merged together since it didn't make
> a lot of sense to correct the GPIO case in one separate patch.
> - ATMEL_US_USMODE_HWHS is now unset for platform with PDC
>
> Changes since v3:
> - remove superfluous #include <linux/err.h> (thanks to Uwe)
> - rebase on next-20160930
>
> Changes since v2:
> - remove IS_ERR_OR_NULL() test in patch 1/3 as Uwe suggested.
> - fix typos in patch 2/3
> - rebase on next-20160927
> - simplify the logic in patch 3/3.
>
> Changes since v1:
> - Correct patch 1 with the error found by kbuild.
> - Add Alexandre's Acked-by on patch 2
> - Rewrite patch 3 logic in the light of the on-going discussion
> with Cyrille and Alexandre.
>
>
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index fd8aa1f4ba78..168b10cad47b 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -2132,11 +2132,29 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
> mode |= ATMEL_US_USMODE_RS485;
> } else if (termios->c_cflag & CRTSCTS) {
> /* RS232 with hardware handshake (RTS/CTS) */
> - if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
> - dev_info(port->dev, "not enabling hardware flow control because DMA is used");
> - termios->c_cflag &= ~CRTSCTS;
> - } else {
> + if (atmel_use_fifo(port) &&
> + !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) {
> + /*
> + * with ATMEL_US_USMODE_HWHS set, the controller will
> + * be able to drive the RTS pin high/low when the RX
> + * FIFO is above RXFTHRES/below RXFTHRES2.
> + * It will also disable the transmitter when the CTS
> + * pin is high.
> + * This mode is not activated if CTS pin is a GPIO
> + * because in this case, the transmitter is always
> + * disabled (there must be an internal pull-up
> + * responsible for this behaviour).
> + * If the RTS pin is a GPIO, the controller won't be
> + * able to drive it according to the FIFO thresholds,
> + * but it will be handled by the driver.
> + */
> mode |= ATMEL_US_USMODE_HWHS;
> + } else {
> + /*
> + * For platforms without FIFO, the flow control is
> + * handled by the driver.
> + */
> + mode |= ATMEL_US_USMODE_NORMAL;
> }
> } else {
> /* RS232 without hadware handshake */
>
--
Nicolas Ferre
^ permalink raw reply
* [RFC PATCH 0/8] arm64: Add a compat vDSO
From: Kevin Brodsky @ 2016-10-27 16:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJwJo6aexCNNVoy9L+wqMJY1i1DVJix7UP1Z7exW1hGibHzJGQ@mail.gmail.com>
On 27/10/16 16:23, Dmitry Safonov wrote:
> 2016-09-08 17:00 GMT+03:00 Kevin Brodsky <kevin.brodsky@arm.com>:
>> Hi,
>>
>> This series adds support for a compat (AArch32) vDSO, providing two
>> userspace functionalities to compat processes:
>>
>> * "Virtual" time syscalls (gettimeofday and clock_gettime). The
>> implementation is an adaptation of the arm vDSO (vgettimeofday.c),
>> sharing the data page with the 64-bit vDSO.
>>
>> * sigreturn trampolines, following the example of the 64-bit vDSO
>> (sigreturn.S), but slightly more complicated because we provide A32
>> and T32 variants for both sigreturn and rt_sigreturn.
>>
>> The first point brings the performance improvement expected of a vDSO,
>> by implementing time syscalls directly in userspace. The second point
>> allows us to get rid of the compat vector page, at the expense of the
>> kuser helpers (this is one reason for not enabling the compat vDSO by
>> default).
>>
>> Unfortunately, this time we cannot escape using a 32-bit toolchain. To
>> build the compat VDSO, CONFIG_COMPAT_VDSO must be set *and*
>> CROSS_COMPILE_ARM32 must be defined to the prefix of a 32-bit compiler.
>> Failure to do so will not prevent building the kernel, but a warning
>> will be printed and the compat vDSO will not be built.
>>
>> I have only tested the series with a 64-bit userspace (+ 32-bit glibc).
>> Testing it with a 32-bit userspace would be very welcome.
>
> Hi, what's up with these patches, are you gonna resend them or prepare
> a new version?
Absolutely, actually I was working on it just now, sending v2 very soon :-)
Kevin
>> Thanks,
>> Kevin
>>
>> Kevin Brodsky (8):
>> arm64: Refactor vDSO setup
>> arm64: compat: Add time-related syscall numbers
>> arm64: compat: Expose offset to registers in sigframes
>> arm64: compat: Add a 32-bit vDSO
>> arm64: compat: 32-bit vDSO setup
>> arm64: elf: Set AT_SYSINFO_EHDR in compat processes
>> arm64: compat: Use vDSO sigreturn trampolines if available
>> arm64: Wire up and expose the new compat vDSO
>>
>> arch/arm64/Kconfig | 20 +++
>> arch/arm64/Makefile | 20 ++-
>> arch/arm64/include/asm/elf.h | 15 +-
>> arch/arm64/include/asm/signal32.h | 46 +++++
>> arch/arm64/include/asm/unistd.h | 2 +
>> arch/arm64/include/asm/vdso.h | 3 +
>> arch/arm64/kernel/Makefile | 8 +-
>> arch/arm64/kernel/asm-offsets.c | 13 ++
>> arch/arm64/kernel/signal32.c | 61 ++-----
>> arch/arm64/kernel/vdso.c | 198 ++++++++++++---------
>> arch/arm64/kernel/vdso32/Makefile | 121 +++++++++++++
>> arch/arm64/kernel/vdso32/sigreturn.S | 86 +++++++++
>> arch/arm64/kernel/vdso32/vdso.S | 32 ++++
>> arch/arm64/kernel/vdso32/vdso.lds.S | 98 +++++++++++
>> arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
>> 15 files changed, 883 insertions(+), 134 deletions(-)
>> create mode 100644 arch/arm64/kernel/vdso32/Makefile
>> create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
>> create mode 100644 arch/arm64/kernel/vdso32/vdso.S
>> create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
>> create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
>
^ permalink raw reply
* [PATCH v4 0/3] mtd: s3c2410: add device tree support
From: Boris Brezillon @ 2016-10-27 16:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477526395-13103-1-git-send-email-sergio.prado@e-labworks.com>
On Wed, 26 Oct 2016 21:59:52 -0200
Sergio Prado <sergio.prado@e-labworks.com> wrote:
> This series adds support for configuring Samsung's s3c2410 and
> compatible flash memory controller via devicetree.
>
> Tested on FriendlyARM mini2440, based on s3c2440 SoC.
>
> Patch 3 depends on patch 1.
Applied.
Thanks,
Boris
>
> Changes since v3:
> - apply the timings in the end of ->setup_data_interface so the
> timings can be changed at runtime by the MTD core.
>
> Changes since v2:
> - conditionally assign chip->setup_data_interface to
> s3c2410_nand_setup_data_interface if booting via device tree
>
> Changes since v1:
> - automate timing selection when booting with a device tree
> - make s3c24XX_nand_devtype_data structs "static const"
> - removing samsung,s3c6400-nand compatible since it is equivalent to
> samsung,s3c2412-nand
>
> Changes since initial version:
> - patch converted to a patch series
> - read timings from nand_sdr_timings when booting with a device tree
> - naming improvements in the device tree binding
> (s/nand/nand-controller/, s/_/-, s/children/child)
> - dropped property samsung,ignore_unset_ecc
> - remove @0 from nand device node
> - checking pdev->dev.of_node instead of using ifdef CONFIG_OF_MTD
> - preventing from parsing device tree properties twice
> - increment the nand controller child node refcount, since we
> maintain a reference to it and its name field
> - using of_device_get_match_data() instead of of_match_device()
> to make the code simpler
> - remove CONFIG_MTD_NAND_S3C2410_HWECC compile option so we can
> select ECC mode using nand-ecc-mode property in the device tree
>
> Sergio Prado (3):
> mtd: s3c2410: make ecc mode configurable via platform data
> dt-bindings: mtd: add DT binding for s3c2410 flash controller
> mtd: s3c2410: parse the device configuration from OF node
>
> .../devicetree/bindings/mtd/samsung-s3c2410.txt | 56 +++++
> arch/arm/mach-s3c24xx/common-smdk.c | 1 +
> arch/arm/mach-s3c24xx/mach-anubis.c | 1 +
> arch/arm/mach-s3c24xx/mach-at2440evb.c | 1 +
> arch/arm/mach-s3c24xx/mach-bast.c | 1 +
> arch/arm/mach-s3c24xx/mach-gta02.c | 1 +
> arch/arm/mach-s3c24xx/mach-jive.c | 1 +
> arch/arm/mach-s3c24xx/mach-mini2440.c | 1 +
> arch/arm/mach-s3c24xx/mach-osiris.c | 1 +
> arch/arm/mach-s3c24xx/mach-qt2410.c | 1 +
> arch/arm/mach-s3c24xx/mach-rx1950.c | 1 +
> arch/arm/mach-s3c24xx/mach-rx3715.c | 1 +
> arch/arm/mach-s3c24xx/mach-vstms.c | 1 +
> arch/arm/mach-s3c64xx/mach-hmt.c | 1 +
> arch/arm/mach-s3c64xx/mach-mini6410.c | 1 +
> arch/arm/mach-s3c64xx/mach-real6410.c | 1 +
> drivers/mtd/nand/Kconfig | 9 -
> drivers/mtd/nand/s3c2410.c | 277 +++++++++++++++------
> include/linux/platform_data/mtd-nand-s3c2410.h | 7 +-
> 19 files changed, 278 insertions(+), 86 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/mtd/samsung-s3c2410.txt
>
^ permalink raw reply
* [PATCH 4/5] ARM: DRA7: PM: cpuidle MPU CSWR support
From: Tony Lindgren @ 2016-10-27 16:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161026151703.24730-5-tony@atomide.com>
* Tony Lindgren <tony@atomide.com> [161026 08:18]:
> From: Santosh Shilimkar <santosh.shilimkar@ti.com>
>
> Add DRA74/72 CPUIDLE support.
And as Nishnath noted, that hardware does not support deeper
idle states properly. So below is patches 4 and 5 updated and
squashed together into a single patche to enable cpuidle only
for omap5.
Regards,
Tony
8< -------------------------
>From tony Mon Sep 17 00:00:00 2001
From: Santosh Shilimkar <santosh.shilimkar@ti.com>
Date: Tue, 25 Oct 2016 08:33:32 -0700
Subject: [PATCH] ARM: OMAP5: Add basic cpuidle MPU CSWR support
Add OMAP5 CPUIDLE support.
This patch adds MPUSS low power states in cpuidle.
C1 - CPU0 WFI + CPU1 WFI + MPU ON
C2 - CPU0 RET + CPU1 RET + MPU CSWR
Modified from TI kernel tree commit 605967fd2205 ("ARM: DRA7: PM:
cpuidle MPU CSWR support") except enable cpuidle for omap5 instead
of dra7.
According to Nishanth Menon <nm@ti.com>, cpuidle on dra7 is not
supported properly in the hardware so we don't want to enable it.
However, for omap5 this adds some nice power savings. Note that
the TI 3.8 based tree has other cpuidle states that we may be able
to enable later on.
On omap5-uevm, the power consumption eventually settles down to about
920mW with ehci-omap and ohci-omap3 unloaded compared to about 1.7W
without these patches. Note that it seems to take few minutes after
booting for the idle power to go down to 920mW from 1.3W, no idea so
far what might be causing that.
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
[ j-keerthy at ti.com rework on 3.14]
Signed-off-by: Keerthy <j-keerthy@ti.com>
[nm at ti.com: updates based on profiling]
[tony at atomide.com: dropped CPUIDLE_FLAG_TIME_VALID no longer used,
changed for omap5 only as requested by Nishanth, updated comments]
Signed-off-by: Nishanth Menon <nm@ti.com>
---
arch/arm/mach-omap2/cpuidle44xx.c | 80 ++++++++++++++++++++++++++++++++++++++-
arch/arm/mach-omap2/pm44xx.c | 2 +-
2 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -21,6 +21,7 @@
#include "common.h"
#include "pm.h"
#include "prm.h"
+#include "soc.h"
#include "clockdomain.h"
#define MAX_CPUS 2
@@ -30,6 +31,7 @@ struct idle_statedata {
u32 cpu_state;
u32 mpu_logic_state;
u32 mpu_state;
+ u32 mpu_state_vote;
};
static struct idle_statedata omap4_idle_data[] = {
@@ -50,12 +52,26 @@ static struct idle_statedata omap4_idle_data[] = {
},
};
+static struct idle_statedata omap5_idle_data[] = {
+ {
+ .cpu_state = PWRDM_POWER_ON,
+ .mpu_state = PWRDM_POWER_ON,
+ .mpu_logic_state = PWRDM_POWER_ON,
+ },
+ {
+ .cpu_state = PWRDM_POWER_RET,
+ .mpu_state = PWRDM_POWER_RET,
+ .mpu_logic_state = PWRDM_POWER_RET,
+ },
+};
+
static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
static struct clockdomain *cpu_clkdm[MAX_CPUS];
static atomic_t abort_barrier;
static bool cpu_done[MAX_CPUS];
static struct idle_statedata *state_ptr = &omap4_idle_data[0];
+static DEFINE_RAW_SPINLOCK(mpu_lock);
/* Private functions */
@@ -77,6 +93,32 @@ static int omap_enter_idle_simple(struct cpuidle_device *dev,
return index;
}
+static int omap_enter_idle_smp(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ struct idle_statedata *cx = state_ptr + index;
+ unsigned long flag;
+
+ raw_spin_lock_irqsave(&mpu_lock, flag);
+ cx->mpu_state_vote++;
+ if (cx->mpu_state_vote == num_online_cpus()) {
+ pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
+ omap_set_pwrdm_state(mpu_pd, cx->mpu_state);
+ }
+ raw_spin_unlock_irqrestore(&mpu_lock, flag);
+
+ omap4_enter_lowpower(dev->cpu, cx->cpu_state);
+
+ raw_spin_lock_irqsave(&mpu_lock, flag);
+ if (cx->mpu_state_vote == num_online_cpus())
+ omap_set_pwrdm_state(mpu_pd, PWRDM_POWER_ON);
+ cx->mpu_state_vote--;
+ raw_spin_unlock_irqrestore(&mpu_lock, flag);
+
+ return index;
+}
+
static int omap_enter_idle_coupled(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
@@ -220,6 +262,32 @@ static struct cpuidle_driver omap4_idle_driver = {
.safe_state_index = 0,
};
+static struct cpuidle_driver omap5_idle_driver = {
+ .name = "omap5_idle",
+ .owner = THIS_MODULE,
+ .states = {
+ {
+ /* C1 - CPU0 ON + CPU1 ON + MPU ON */
+ .exit_latency = 2 + 2,
+ .target_residency = 5,
+ .enter = omap_enter_idle_simple,
+ .name = "C1",
+ .desc = "CPUx WFI, MPUSS ON"
+ },
+ {
+ /* C2 - CPU0 RET + CPU1 RET + MPU CSWR */
+ .exit_latency = 48 + 60,
+ .target_residency = 100,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
+ .enter = omap_enter_idle_smp,
+ .name = "C2",
+ .desc = "CPUx CSWR, MPUSS CSWR",
+ },
+ },
+ .state_count = ARRAY_SIZE(omap5_idle_data),
+ .safe_state_index = 0,
+};
+
/* Public functions */
/**
@@ -230,6 +298,16 @@ static struct cpuidle_driver omap4_idle_driver = {
*/
int __init omap4_idle_init(void)
{
+ struct cpuidle_driver *idle_driver;
+
+ if (soc_is_omap54xx()) {
+ state_ptr = &omap5_idle_data[0];
+ idle_driver = &omap5_idle_driver;
+ } else {
+ state_ptr = &omap4_idle_data[0];
+ idle_driver = &omap4_idle_driver;
+ }
+
mpu_pd = pwrdm_lookup("mpu_pwrdm");
cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm");
cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm");
@@ -244,5 +322,5 @@ int __init omap4_idle_init(void)
/* Configure the broadcast timer on each cpu */
on_each_cpu(omap_setup_broadcast_timer, NULL, 1);
- return cpuidle_register(&omap4_idle_driver, cpu_online_mask);
+ return cpuidle_register(idle_driver, cpu_online_mask);
}
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -287,7 +287,7 @@ int __init omap4_pm_init(void)
/* Overwrite the default cpu_do_idle() */
arm_pm_idle = omap_default_idle;
- if (cpu_is_omap44xx())
+ if (cpu_is_omap44xx() || soc_is_omap54xx())
omap4_idle_init();
err2:
--
2.9.3
^ permalink raw reply
* [PATCH v3 0/3] modversions: Fix CRC mangling under CONFIG_RELOCATABLE=y
From: Ard Biesheuvel @ 2016-10-27 16:26 UTC (permalink / raw)
To: linux-arm-kernel
This series is a followup to the single patch 'modversions: treat symbol
CRCs as 32 bit quantities on 64 bit archs', of which two versions have
been sent out so far [0][1]
As pointed out by Michael, GNU ld behaves a bit differently between arm64
and PowerPC64, and where the former gets rid of all runtime relocations
related to CRCs, the latter is not as easily convinced.
Patch #1 fixes the issue where CRCs are corrupted by the runtime relocation
routines for 32-bit PowerPC, for which the original fix was effectively
reverted by commit 0e0ed6406e61 ("powerpc/modules: Module CRC relocation fix
causes perf issues")
Patch #2 adds handling of R_PPC64_ADDR32 relocations against the NULL .dynsym
symbol entry to the PPC64 runtime relocation routines, so it is prepared to
deal with CRCs being emitted as 32-bit quantities.
Patch #3 is the original patch from the v1 and v2 submissions.
Changes since v2:
- added #1 and #2
- updated #3 to deal with CRC entries being emitted from assembler
- added Rusty's ack (#3)
[0] http://marc.info/?l=linux-kernel&m=147652300207369&w=2
[1] http://marc.info/?l=linux-kernel&m=147695629614409&w=2
Ard Biesheuvel (3):
powerpc/reloc32: fix corrupted modversion CRCs
powerpc/reloc64: add support for 32-bit CRC pseudo-symbols
modversions: treat symbol CRCs as 32 bit quantities on 64 bit archs
arch/powerpc/include/asm/module.h | 4 --
arch/powerpc/kernel/module_64.c | 8 ----
arch/powerpc/kernel/reloc_32.S | 36 +++++++++++++--
arch/powerpc/kernel/reloc_64.S | 22 +++++++--
arch/powerpc/relocs_check.sh | 3 +-
include/asm-generic/export.h | 7 +--
include/linux/export.h | 8 ++++
include/linux/module.h | 14 +++---
kernel/module.c | 47 +++++++-------------
9 files changed, 85 insertions(+), 64 deletions(-)
--
2.7.4
^ permalink raw reply
* Add Allwinner Q8 tablets hardware manager
From: Pantelis Antoniou @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4cfdd415-1965-7be9-b204-86a9931683a6@redhat.com>
Hi Hans,
Nice to see other people coming up with similar problems.
It?s not a new thing at all, hacks like this have been around
since for ever (but safely tucked away in product specific areas).
> On Oct 27, 2016, at 17:53 , Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 27-10-16 14:57, Pierre-Hugues Husson wrote:
>> 2016-10-27 11:14 GMT+02:00 Hans de Goede <hdegoede@redhat.com>:
>>> In my experience with these cheap boards, there is a mix of auto-probing +
>>> device / revision specific os-image modifications. I keep coming back to
>>> the touchscreen controller firmware (but also the orientation), for the
>>> gsl1680 controller I need at least 2 different firmware files (per gsl1680
>>> revision) to make all q8 tablets I have working. This is simply not solved
>>> by the vendor android code, they just shove the right firmware into the
>>> os-image. Likewise for the touchscreen orientation (x-mirored, y-mirored,
>>> etc) too is just a hard-coded setting in the os-image.
>> Reading your patch, it looks like to handle the two different firmware
>> files, you're simply adding a command-line switch, there is no
>> detection involved.
>> Am I understanding correctly?
>
> No, the firmware-name (and matching resolution as different firmwares
> report different axis-ranges for the same digitizer) is selected
> primarily by the touchscreen_variant which sets: touchscreen_fw_name,
> touchscreen_width and touchscreen_height.
>
> The touchscreen_variant module option defaults to -1 which means "auto",
> when it is auto it gets set based on the touchscreen / accelerometer
> combination (which more or less uniquely identifies boards sofar),
> likewise all the other touchscreen module options default to -1,
> but can be overridden from the commandline.
>
> The intention is for things to just work, the commandline options are
> there as a fallback.
>
>> If this is the case, two things:
>> 1. I'm not too sure having the user choose this via cmdline is the
>> right way. I think I'd rather have it set by userspace. (though that's
>> not a strong opinion).
>> Or if cmdline is being changed... how about having DTS (or just an
>> overlay on top of it) being changed instead?
>>
>> 2. This could still be declared by DTS. For instance, assuming your
>> i2c-probe-stop-at-first-match:
>> &i2c0 {
>> touchscreen1: gsl1680 at 40 {
>> reg = <0x40>;
>> compatible = "silead,gsl1680";
>> enable-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
>> touchscreen-size = <1024 600>;
>> touchscreen-fw = "gsl1680-a082-q8-700.fw";
>> filter-names = "touchscreen_variant";
>> filter-0 = "none", "gsl1680-a082-q8-700";
>> id = <0xa0820000>;
>> status = "disabled";
>> };
>> touchscreen2: gsl1680 at 40 {
>> reg = <0x40>;
>> compatible = "silead,gsl1680";
>> enable-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
>> touchscreen-size = <480 800>;
>> touchscreen-fw = "gsl1680-a082-q8-a70.fw";
>> filter-names = "touchscreen_variant";
>> filter-0 = "gsl1680-a082-q8-a70";
>> id = <0xa0820000>;
>> status = "disabled";
>> };
>> touchscreen2: gsl1680 at 40 {
>> reg = <0x40>;
>> compatible = "silead,gsl1680";
>> enable-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
>> touchscreen-size = <960 640>;
>> touchscreen-fw = "gsl1680-b482-q8-d702.fw";
>> filter-names = "touchscreen_variant";
>> filter-0 = "gsl1680-b482-q8-d702";
>> id = <0xb4820000>;
>> status = "disabled";
>> };
>> i2c-probe-stop-at-first-match = <&touchscreen1>,
>> <&touchscreen2>, <&touchscreen3>;
>> }
>>
>> With "none" value being the value when the "touchscreen_variant"
>> option is not defined in cmdline.
>>
>> Please note that I'm not too sure whether SILEAD_REG_ID represents an
>> OTP which can be changed by OEM, or if it's more of a hardware
>> revision. Depending on this, this would either fit into a id =
>> <0xa0820000> DTS line, or a compatible = "silead,gsl1680_a082",
>> "silead,gsl1680"; DTS line.
>>
>>> Sofar I've only seen this with one type of touchscreen so an easy cop-out
>>> would be to add an "optional-vddio-supply" to the the bindings for the
>>> specific touchscreen use and put all the necessary logic in the driver.
>>>
>>> This does require propagating the learned need for the regulator
>>> from the drivers detect() callback to probe() or alternatively I'm
>>> thinking we should just use probe() instead of detect()to begin with,
>>> that will save a lot of duplication with things
>>> like code for enable gpio-s and regulators.
>>>
>>> So assuming we go for the cop-out option for 3. (I'm ok with that),
>>> this would be a pretty clean solution adding just the 2 new:
>>> i2c-probe-stop-at-first-match and i2c-probe-all properties to
>>> the i2c-bus bindings. One problem here is that we may want to have
>>> multiple i2c-probe-stop-at-first-match phandle lists on a single bus
>>> (e.g. try 3 touchscreens + 6 accelerometers on the same bus, stop at
>>> first touchscreen / first accelerometer), anyone have any ideas for
>>> that?
>> How about something like:
>>
>> &i2c1 {
>> touchscreen1....
>> touchscreen2....
>> touchscreen3....
>> accelerometer1....
>> accelerometer2....
>> accelerometer3....
>> accelerometer4....
>>
>> select-one {
>> compatible = "i2c-select;
>> group-names = "touchscreen", "accelerometer";
>> group-0 = <&touchscreen1>, <&touchscreen2>, <&touchscreen3>;
>> group-1 = <&accelerometer1>, <&accelerometer2>,
>> <&accelerometer3>, <&accelerometer4>;
>> };
>> };
>
> We could just have:
>
> i2c-probe-stop-at-first-match-0 = <&touchscreen1>, <&touchscreen2>, <&touchscreen3>;
> i2c-probe-stop-at-first-match-1 = <&accelerometer1>, <&accelerometer2>;
>
> And have the i2c bus code look for an i2c-probe-stop-at-first-match-[i++] property
> until it is not found. Having a child-node with its own compatible for this
> feels wrong, as it uses a hierarchy where there really is none.
>
>>>> When it comes to detection, I've witnessed various things.
>>>> It can be kernel-side or bootloader-side "global setting" reading (like an
>>>> ADC/resistor value, or an OTP), it can be bootloader doing the
>>>> "brute-force", or it can be the kernel doing all the probes.
>>>>
>>>> For instance, as of today, on a Spreadtrum ODM tree, the bootloader will
>>>> detect the screen by testing all knowns screens, the screen-drivers declare
>>>> a get_id function, and the bootloader probes until the get_id matches the id
>>>> declared by the screen driver.
>>>> And then the bootloader tells the kernel, via cmdline, which screen is
>>>> actually there (but auto-detection is also coded in kernel).
>>>> Finally all possible sensors/touchscreen/camera are declared in DTS, and
>>>> probe will filter-out N/C ones in the kernel.
>>>>
>>>> Now the big difference between my experience and what Hans is trying to
>>>> do, is that I've always worked with devices with "safely" queriable IDs,
>>>> either on i2c or dsi. I've never encountered SPI. This makes probing
>>>> inherently more dangerous, but I believe the question roughly remains the
>>>> same.
>>>
>>>
>>> I'm dealing with i2c too, Mark mistakenly used SPI in his reply,
>>> which I think is what got you thinking I've SPI.
>> Right, so let's concentrate on reasonable bus-es first then. (I can
>> think of I2C and DSI)
>>
>>> See above, I think that we can make this work by delegating the actual
>>> detection to the driver (so each compatible can have a different detect
>>> method / code).
>>> So with this we can remove a big part of drivers/misc/q8-hardwaremgr.c, but
>>> not all
>>> of it. We still need board specific code somewhere to deal with things like
>>> picking
>>> the right touchscreen firmware and touchscreen orientation. This is all
>>> somewhat
>>> gsl1680 specific.
>>> I actually have the same problem on x86 where the ACPI description of the
>>> device
>>> basically says: "There is a gsl1680 at this bus at this address" and does
>>> not say
>>> anything about firmware / orientation (again this is simply hardcoded
>>> in the os-image these devices ship with).
>>>
>>> For x86 my plan is to have an array of configs in the driver and select the
>>> right
>>> one based on DMI strings, which is in essence putting board specific info in
>>> the
>>> driver.
>>>
>>> I can imagine mirroring this for ARM, and have an array of configs in the
>>> driver
>>> there too (for cases where cannot simply hardcode everything in dt only) and
>>> have
>>> some board specific code (activated by of_machine_is_compatible()) to select
>>> the
>>> right config.
>> I do believe this can all be done in DTS
>
> Well x86 does not have DTS.
>
Says who? :)
x86 _can_ have DT and there?s no problem using it at all.
For custom boards no one wants to go through the insane ACPI limitations.
FWIW all the x86 mobile parts used it (but are now RIP).
>> and at the moment, what
>> you're describing seem to happen often enough to be worth writing
>> generic code for.
>
> Let me quote some of the auto-code currently in q8-hardwaremgr.c :
>
> /*
> * These accelerometer based heuristics select the best
> * default based on known q8 tablets.
> */
> switch (data->accelerometer.model) {
> case da280:
> if (data->accelerometer.addr == 0x27)
> ; /* No-op */
> else if (data->has_rda599x)
> data->touchscreen_invert_x = 1;
> else
> data->touchscreen_invert_y = 1;
> break;
> case dmard09:
> data->touchscreen_invert_x = 1;
> break;
> case mxc6225:
> data->touchscreen_variant = 1;
> break;
> }
>
> (Non set data->touchscreen_foo are left at 0).
>
> So this would require us to be able to filter (to use your example)
> on if another i2c device is found and on which address it is found,
> that does not even take the rda559x check into account and is
> going to cause interesting ordering issues, how do we know when
> we can actually do the filtering if some of the variables we are
> filtering on are set by other auto-detected paths. Which auto-detect /
> i2c-probe-stop-at-first-match list do we execute first ? Worse
> actually for accelerometer orientation I will likely need to
> set the mount-matrix based on the detected touchscreen ...
>
> The rda559x here is a sdio wifi chip, which is also connected to the
> i2c, and currently is detected through i2c to be able to separately
> identify 2 q8 boards which share the same touchscreen + accelerometer
> combination and who knows what other checks I or other people can
> come up with to differentiate board variants which do not have
> a simple eeprom to uniquely id them.
>
> So as said before, no this cannot be all done in dt without
> adding a turing complete language to dt, and that is just to
> select which touchscreen_variant to use.
>
> Then there also the probem of the combinatorial explosion having
> not only 2 firmware files but also invert-x and invert-y flags causes:
> We have 2 revisions with each 2 different firmware-files (more actually
> but I've reduced the set since some firmwares are compatible) with each
> both the x- and / or y axis as normal or inverted, for a total of:
> 2 (revision) * 2 (firmware-files) * 2 (x-inverted or not) * 2 (y...) = 16
> touchscreen variants, which means dt nodes for touchscreen1 to touchscreen16
> and that is just the silead gsl1680, some of these tablets also have
> elan or zeitec touchscreen controllers.
>
There is a combinatorial explosion, but only a finite number of _known_
board versions.
> Now imagine what happens if a new board comes out which needs a 3th firmware
> file... I hope you can understand this is not a route I want to go.
>
> Another problem is that if a user encounters the need for a new firmware
> variant he can now not easily try this (where as before we had
> module options to separately override firmware-name, the size, etc.
>
> As written in my previous mail, this is all rather gsl1680 specific,
> and esp. being able to override the firmware-name, the size, etc.
> through module options is going to be useful (to ask endusers to test
> stuff without recompiling) on x86 too. So we will likely want to add
> most of the necessary stuff to the silead driver anyways.
>
>> But then, I can't really tell which makes the most sense between
>> source-based and devicetree-based.
>> I prefer doing it in device-tree, since it means that any OEM can have
>> his device supported by only providing DTB, and won't need to provide
>> kernel patches.
>
> If the OEM provides a DTB the OEM can just directly have the right
> parameters in there without relying on any auto-detection, this is
> already supported and the e.g. gsl1680 driver already happily
> works on several tablets where there is not so much hardware
> variance.
>
> Even if the OEM needs to deal with e.g. different touchscreens on
> different board revisions, hopefully the simple auto-detect code will
> be enough, and he does not need e.g. different firmware-name settings
> for otherwise the same touchscreen controller. If that is not the
> case then he the OEM will have to provide a separate static
> (non probing) DTB per variant.
>
>>> 2) miscellaneous extra config on top of figuring out which ICs are
>>> connected,
>>> basically the kind of stuff many vendors simply hard-code in their device
>>> specific os-image. This one is much more difficult to deal with and I think
>>> we need to figure this out on a case by case basis. This will require board
>>> specific code (just like the kernel has tons of DMI string activated board
>>> specific code on x86) and what is the best code for this place to live will
>>> be a case by case thing too.
>>
>> With things like mount-matrix devicetree property, the goal is to have
>> such informations in the DTS.
>
> Right and all the info I'm talking about can already be in the DTS and
> is already specified this way for various existing boards, this is
> obviously how we want things to work, this is the normal case /
> the straight code path.
>
> Now lets get back to your mount-matrix example, the problem here is 2 board
> variants where the same accelerometer is used, but on a newer revision
> of the board it is mounted with a different orientation and otherwise
> almost nothing is changed on the board, certainly not something as
> useful as an id eeprom.
>
> Lets assume that we can however still somehow differ the 2 revisions,
> then try to imagine how many different ways there are to differ
> between 2 board revisions if there is no easy way to do so,
> some crazy examples:
> -The 2nd revision has an external loopback on unused audio out / in
> pins for testing purposes, we could play + record sound and do
> a (rough) waveform match to see if the loopback is present
> -On the 2nd revision a pin from a pin compatible part which
> allows putting it in fully compatible mode, or allow new features
> mode, is now hooked up to a gpio instead of hardwired to compatible
> mode, we could change the device to new features mode and try
> to read/modify/write some register bit on the chip which is only
> writable in this mode
> -Etc.
>
> Now try to design a way to express this in dt and we're back to
> needing a turing complete language (with a library for accessing
> various busses) again.
>
No, not turing complete. This is going to require a little bit more
digging up but I think we can handle this with the method I described.
> Regards,
>
> Hans
Regards
? Pantelis
P.S. Damn too much content to read.
^ permalink raw reply
* [PATCH v3 0/3] modversions: Fix CRC mangling under CONFIG_RELOCATABLE=y
From: Ard Biesheuvel @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
This series is a followup to the single patch 'modversions: treat symbol
CRCs as 32 bit quantities on 64 bit archs', of which two versions have
been sent out so far [0][1]
As pointed out by Michael, GNU ld behaves a bit differently between arm64
and PowerPC64, and where the former gets rid of all runtime relocations
related to CRCs, the latter is not as easily convinced.
Patch #1 fixes the issue where CRCs are corrupted by the runtime relocation
routines for 32-bit PowerPC, for which the original fix was effectively
reverted by commit 0e0ed6406e61 ("powerpc/modules: Module CRC relocation fix
causes perf issues")
Patch #2 adds handling of R_PPC64_ADDR32 relocations against the NULL .dynsym
symbol entry to the PPC64 runtime relocation routines, so it is prepared to
deal with CRCs being emitted as 32-bit quantities.
Patch #3 is the original patch from the v1 and v2 submissions.
Changes since v2:
- added #1 and #2
- updated #3 to deal with CRC entries being emitted from assembler
- added Rusty's ack (#3)
Branch can be found here:
https://git.kernel.org/cgit/linux/kernel/git/ardb/linux.git/log/?h=kcrctab-reloc
[0] http://marc.info/?l=linux-kernel&m=147652300207369&w=2
[1] http://marc.info/?l=linux-kernel&m=147695629614409&w=2
Ard Biesheuvel (3):
powerpc/reloc32: fix corrupted modversion CRCs
powerpc/reloc64: add support for 32-bit CRC pseudo-symbols
modversions: treat symbol CRCs as 32 bit quantities on 64 bit archs
arch/powerpc/include/asm/module.h | 4 --
arch/powerpc/kernel/module_64.c | 8 ----
arch/powerpc/kernel/reloc_32.S | 36 +++++++++++++--
arch/powerpc/kernel/reloc_64.S | 22 +++++++--
arch/powerpc/relocs_check.sh | 3 +-
include/asm-generic/export.h | 7 +--
include/linux/export.h | 8 ++++
include/linux/module.h | 14 +++---
kernel/module.c | 47 +++++++-------------
9 files changed, 85 insertions(+), 64 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH v3 1/3] powerpc/reloc32: fix corrupted modversion CRCs
From: Ard Biesheuvel @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477585631-18574-1-git-send-email-ard.biesheuvel@linaro.org>
Commit 0e0ed6406e61 ("powerpc/modules: Module CRC relocation fix causes
perf issues") fixed an issue with relocatable PIE kernels in a way that
essentially reintroduced the issue again for 32-bit builds.
Since the chosen approach does is not applicable to 32-bit, fix the
issue by updating the runtime relocation routine to ignore the load
offset for the interval [__start___kcrctab, __stop___kcrctab_gpl_future),
which is where the CRCs reside. This ensures that the values of the CRC
pseudo-symbols are no longer made dependent on the runtime load offset.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/powerpc/kernel/reloc_32.S | 36 +++++++++++++++++---
1 file changed, 32 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/reloc_32.S b/arch/powerpc/kernel/reloc_32.S
index f366fedb0872..150686b9febb 100644
--- a/arch/powerpc/kernel/reloc_32.S
+++ b/arch/powerpc/kernel/reloc_32.S
@@ -87,12 +87,12 @@ eodyn: /* End of Dyn Table scan */
* Work out the current offset from the link time address of .rela
* section.
* cur_offset[r7] = rela.run[r9] - rela.link [r7]
- * _stext.link[r12] = _stext.run[r10] - cur_offset[r7]
- * final_offset[r3] = _stext.final[r3] - _stext.link[r12]
+ * _stext.link[r11] = _stext.run[r10] - cur_offset[r7]
+ * final_offset[r3] = _stext.final[r3] - _stext.link[r11]
*/
subf r7, r7, r9 /* cur_offset */
- subf r12, r7, r10
- subf r3, r12, r3 /* final_offset */
+ subf r11, r7, r10
+ subf r3, r11, r3 /* final_offset */
subf r8, r6, r8 /* relaz -= relaent */
/*
@@ -101,6 +101,21 @@ eodyn: /* End of Dyn Table scan */
* r13 - points to the symbol table
*/
+#ifdef CONFIG_MODVERSIONS
+ /*
+ * Treat R_PPC_RELATIVE relocations differently when they target the
+ * interval [__start___kcrctab, __stop___kcrctab_gpl_future): in this
+ * case, the relocated quantities are CRC pseudo-symbols, which should
+ * be preserved as-is, rather than be modified to take the runtime
+ * offset into account.
+ */
+ lwz r10, (p_kcrc_start - 0b)(r12)
+ lwz r11, (p_kcrc_stop - 0b)(r12)
+ subf r12, r7, r12 /* link time addr of 0b */
+ add r10, r10, r12
+ add r11, r11, r12
+#endif
+
/*
* Check if we have a relocation based on symbol
* r5 will hold the value of the symbol.
@@ -135,7 +150,15 @@ get_type:
bne hi16
lwz r4, 0(r9) /* r_offset */
lwz r0, 8(r9) /* r_addend */
+#ifdef CONFIG_MODVERSIONS
+ cmplw r4, r10
+ blt do_add
+ cmplw r4, r11
+ blt skip_add
+do_add:
+#endif
add r0, r0, r3 /* final addend */
+skip_add:
stwx r0, r4, r7 /* memory[r4+r7]) = (u32)r0 */
b nxtrela /* continue */
@@ -207,3 +230,8 @@ p_dyn: .long __dynamic_start - 0b
p_rela: .long __rela_dyn_start - 0b
p_sym: .long __dynamic_symtab - 0b
p_st: .long _stext - 0b
+
+#ifdef CONFIG_MODVERSIONS
+p_kcrc_start: .long __start___kcrctab - 0b
+p_kcrc_stop: .long __stop___kcrctab_gpl_future - 0b
+#endif
--
2.7.4
^ permalink raw reply related
* [PATCH v3 2/3] powerpc/reloc64: add support for 32-bit CRC pseudo-symbols
From: Ard Biesheuvel @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477585631-18574-1-git-send-email-ard.biesheuvel@linaro.org>
In preparation of modifying the core modversions code to emit the CRCs
as 32-bit quantities, ensure that 64-bit PowerPC will be able to deal
with this when CONFIG_RELOCATABLE=y, in which case the CRCs will be
emitted into the final ELF binary as R_PPC64_ADDR32 relocations.
Since 32-bit relocations cannot be used to relocate memory addresses on
64-bit architectures, and since the CRC pseudo-symbol references are
emitted as anonymous relocations (i.e., against the NULL symbol in the
.dynsym section) with the final value recorded in the addend (*), we
can disregard any relocations where the symbol index != 0.
* Note that unsatisfied CRC pseudo-symbol references are emitted as
R_PPC64_ADDR32 relocations against named symbols that are typed as
weak undefined in the .dynsym symbol table. These can simply be
ignored (as before), considering that zero CRCs are interpreted as
missing, and the module code deals with that accordingly.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/powerpc/kernel/reloc_64.S | 22 ++++++++++++++++----
arch/powerpc/relocs_check.sh | 3 ++-
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S
index d88736fbece6..7927e00be746 100644
--- a/arch/powerpc/kernel/reloc_64.S
+++ b/arch/powerpc/kernel/reloc_64.S
@@ -14,6 +14,7 @@
RELA = 7
RELACOUNT = 0x6ffffff9
R_PPC64_RELATIVE = 22
+R_PPC64_ADDR32 = 1
/*
* r3 = desired final address of kernel
@@ -66,10 +67,10 @@ _GLOBAL(relocate)
/*
* Run through the list of relocations and process the
- * R_PPC64_RELATIVE ones.
+ * R_PPC64_RELATIVE and R_PPC64_ADDR32 ones.
*/
mtctr r8
-5: ld r0,8(9) /* ELF64_R_TYPE(reloc->r_info) */
+5: ld r0,8(9) /* reloc->r_info (type *and* symbol index) */
cmpdi r0,R_PPC64_RELATIVE
bne 6f
ld r6,0(r9) /* reloc->r_offset */
@@ -77,9 +78,22 @@ _GLOBAL(relocate)
add r0,r0,r3
stdx r0,r7,r6
addi r9,r9,24
- bdnz 5b
+ b 7f
+
+ /*
+ * CRCs of exported symbols are emitted as 32-bit relocations against
+ * the NULL .dynsym entry, with the CRC value recorded in the addend.
+ */
+6: cmpdi r0,R_PPC64_ADDR32
+ bne 7f
+ ld r6,0(r9) /* reloc->r_offset */
+ ld r0,16(r9) /* reloc->r_addend */
+ stwx r0,r7,r6
+ addi r9,r9,24
+
+7: bdnz 5b
+ blr
-6: blr
.balign 8
p_dyn: .llong __dynamic_start - 0b
diff --git a/arch/powerpc/relocs_check.sh b/arch/powerpc/relocs_check.sh
index ec2d5c835170..2f510fbc87da 100755
--- a/arch/powerpc/relocs_check.sh
+++ b/arch/powerpc/relocs_check.sh
@@ -43,7 +43,8 @@ R_PPC_ADDR16_HA
R_PPC_RELATIVE
R_PPC_NONE' |
grep -E -v '\<R_PPC64_ADDR64[[:space:]]+mach_' |
- grep -E -v '\<R_PPC64_ADDR64[[:space:]]+__crc_'
+ grep -E -v '\<R_PPC64_ADDR64[[:space:]]+__crc_' |
+ grep -E -v '\<R_PPC64_ADDR32[[:space:]]+\*ABS\*'
)
if [ -z "$bad_relocs" ]; then
--
2.7.4
^ permalink raw reply related
* [PATCH v3 3/3] modversions: treat symbol CRCs as 32 bit quantities on 64 bit archs
From: Ard Biesheuvel @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477585631-18574-1-git-send-email-ard.biesheuvel@linaro.org>
The modversion symbol CRCs are emitted as ELF symbols, which allows us to
easily populate the kcrctab sections by relying on the linker to associate
each kcrctab slot with the correct value.
This has a couple of downsides:
- Given that the CRCs are treated as memory addresses, we waste 4 bytes
for each CRC on 64 bit architectures,
- On architectures that support runtime relocation, a R_<arch>_RELATIVE
relocation entry is emitted for each CRC value, which identifies it as
a quantity that requires fixing up based on the actual runtime load
offset of the kernel. This results in corrupted CRCs unless we
explicitly undo the fixup (and this is currently being handled in the
core module code)
- Such runtime relocation entries take up 24 bytes of __init space each,
resulting in a x8 overhead in [uncompressed] kernel size for CRCs.
Switching to explicit 32 bit values on 64 bit architectures fixes most
of these issues, given that 32 bit values are not treated as quantities
that require fixing up based on the actual runtime load offset. Note that
on some ELF64 architectures [such as PPC64], these 32-bit values are still
emitted as runtime relocatable quantities, even if the value resolves to
a build time constant. However, these can easily be distinguished from
variables that do need fixing up, and the CRCs can be emitted correctly
in the arch specific runtime relocation routines right off the bat.
So redefine all CRC fields and variables as u32, and redefine the
__CRC_SYMBOL() macro for 64 bit builds to emit the CRC reference using
inline assembler (which is necessary since 64-bit C code cannot use
32-bit types to hold memory addresses, even if they are ultimately
resolved using values that do not exceed 0xffffffff.
Note that this mostly reverts commit d4703aefdbc8 ("module: handle ppc64
relocating kcrctabs when CONFIG_RELOCATABLE=y")
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/powerpc/include/asm/module.h | 4 --
arch/powerpc/kernel/module_64.c | 8 ----
include/asm-generic/export.h | 7 +--
include/linux/export.h | 8 ++++
include/linux/module.h | 14 +++---
kernel/module.c | 47 +++++++-------------
6 files changed, 33 insertions(+), 55 deletions(-)
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index cd4ffd86765f..94a7f7aa3ae8 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -94,9 +94,5 @@ struct exception_table_entry;
void sort_ex_table(struct exception_table_entry *start,
struct exception_table_entry *finish);
-#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
-#define ARCH_RELOCATES_KCRCTAB
-#define reloc_start PHYSICAL_START
-#endif
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MODULE_H */
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 183368e008cf..be9b2d5ff846 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -286,14 +286,6 @@ static void dedotify_versions(struct modversion_info *vers,
for (end = (void *)vers + size; vers < end; vers++)
if (vers->name[0] == '.') {
memmove(vers->name, vers->name+1, strlen(vers->name));
-#ifdef ARCH_RELOCATES_KCRCTAB
- /* The TOC symbol has no CRC computed. To avoid CRC
- * check failing, we must force it to the expected
- * value (see CRC check in module.c).
- */
- if (!strcmp(vers->name, "TOC."))
- vers->crc = -(unsigned long)reloc_start;
-#endif
}
}
diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h
index 43199a049da5..d245910d026b 100644
--- a/include/asm-generic/export.h
+++ b/include/asm-generic/export.h
@@ -9,18 +9,15 @@
#ifndef KSYM_ALIGN
#define KSYM_ALIGN 8
#endif
-#ifndef KCRC_ALIGN
-#define KCRC_ALIGN 8
-#endif
#else
#define __put .long
#ifndef KSYM_ALIGN
#define KSYM_ALIGN 4
#endif
+#endif
#ifndef KCRC_ALIGN
#define KCRC_ALIGN 4
#endif
-#endif
#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
#define KSYM(name) _##name
@@ -52,7 +49,7 @@ KSYM(__kstrtab_\name):
.section ___kcrctab\sec+\name,"a"
.balign KCRC_ALIGN
KSYM(__kcrctab_\name):
- __put KSYM(__crc_\name)
+ .long KSYM(__crc_\name)
.weak KSYM(__crc_\name)
.previous
#endif
diff --git a/include/linux/export.h b/include/linux/export.h
index 2a0f61fbc731..a000d421526d 100644
--- a/include/linux/export.h
+++ b/include/linux/export.h
@@ -41,6 +41,7 @@ extern struct module __this_module;
#if defined(__KERNEL__) && !defined(__GENKSYMS__)
#ifdef CONFIG_MODVERSIONS
+#ifndef CONFIG_64BIT
/* Mark the CRC weak since genksyms apparently decides not to
* generate a checksums for some symbols */
#define __CRC_SYMBOL(sym, sec) \
@@ -50,6 +51,13 @@ extern struct module __this_module;
__attribute__((section("___kcrctab" sec "+" #sym), used)) \
= (unsigned long) &__crc_##sym;
#else
+#define __CRC_SYMBOL(sym, sec) \
+ asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
+ " .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
+ " .long " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
+ " .previous \n");
+#endif
+#else
#define __CRC_SYMBOL(sym, sec)
#endif
diff --git a/include/linux/module.h b/include/linux/module.h
index 0c3207d26ac0..e0067673f5e5 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -346,7 +346,7 @@ struct module {
/* Exported symbols */
const struct kernel_symbol *syms;
- const unsigned long *crcs;
+ const u32 *crcs;
unsigned int num_syms;
/* Kernel parameters. */
@@ -359,18 +359,18 @@ struct module {
/* GPL-only exported symbols. */
unsigned int num_gpl_syms;
const struct kernel_symbol *gpl_syms;
- const unsigned long *gpl_crcs;
+ const u32 *gpl_crcs;
#ifdef CONFIG_UNUSED_SYMBOLS
/* unused exported symbols. */
const struct kernel_symbol *unused_syms;
- const unsigned long *unused_crcs;
+ const u32 *unused_crcs;
unsigned int num_unused_syms;
/* GPL-only, unused exported symbols. */
unsigned int num_unused_gpl_syms;
const struct kernel_symbol *unused_gpl_syms;
- const unsigned long *unused_gpl_crcs;
+ const u32 *unused_gpl_crcs;
#endif
#ifdef CONFIG_MODULE_SIG
@@ -382,7 +382,7 @@ struct module {
/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
- const unsigned long *gpl_future_crcs;
+ const u32 *gpl_future_crcs;
unsigned int num_gpl_future_syms;
/* Exception table */
@@ -523,7 +523,7 @@ struct module *find_module(const char *name);
struct symsearch {
const struct kernel_symbol *start, *stop;
- const unsigned long *crcs;
+ const u32 *crcs;
enum {
NOT_GPL_ONLY,
GPL_ONLY,
@@ -539,7 +539,7 @@ struct symsearch {
*/
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
- const unsigned long **crc,
+ const u32 **crc,
bool gplok,
bool warn);
diff --git a/kernel/module.c b/kernel/module.c
index f57dd63186e6..18d92e710a13 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -386,16 +386,16 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
-extern const unsigned long __start___kcrctab[];
-extern const unsigned long __start___kcrctab_gpl[];
-extern const unsigned long __start___kcrctab_gpl_future[];
+extern const u32 __start___kcrctab[];
+extern const u32 __start___kcrctab_gpl[];
+extern const u32 __start___kcrctab_gpl_future[];
#ifdef CONFIG_UNUSED_SYMBOLS
extern const struct kernel_symbol __start___ksymtab_unused[];
extern const struct kernel_symbol __stop___ksymtab_unused[];
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
-extern const unsigned long __start___kcrctab_unused[];
-extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const u32 __start___kcrctab_unused[];
+extern const u32 __start___kcrctab_unused_gpl[];
#endif
#ifndef CONFIG_MODVERSIONS
@@ -494,7 +494,7 @@ struct find_symbol_arg {
/* Output */
struct module *owner;
- const unsigned long *crc;
+ const u32 *crc;
const struct kernel_symbol *sym;
};
@@ -560,7 +560,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
- const unsigned long **crc,
+ const u32 **crc,
bool gplok,
bool warn)
{
@@ -1257,23 +1257,11 @@ static int try_to_force_load(struct module *mod, const char *reason)
}
#ifdef CONFIG_MODVERSIONS
-/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
-static unsigned long maybe_relocated(unsigned long crc,
- const struct module *crc_owner)
-{
-#ifdef ARCH_RELOCATES_KCRCTAB
- if (crc_owner == NULL)
- return crc - (unsigned long)reloc_start;
-#endif
- return crc;
-}
-
static int check_version(Elf_Shdr *sechdrs,
unsigned int versindex,
const char *symname,
struct module *mod,
- const unsigned long *crc,
- const struct module *crc_owner)
+ const u32 *crc)
{
unsigned int i, num_versions;
struct modversion_info *versions;
@@ -1294,10 +1282,10 @@ static int check_version(Elf_Shdr *sechdrs,
if (strcmp(versions[i].name, symname) != 0)
continue;
- if (versions[i].crc == maybe_relocated(*crc, crc_owner))
+ if (versions[i].crc == *crc)
return 1;
- pr_debug("Found checksum %lX vs module %lX\n",
- maybe_relocated(*crc, crc_owner), versions[i].crc);
+ pr_debug("Found checksum %X vs module %lX\n",
+ *crc, versions[i].crc);
goto bad_version;
}
@@ -1314,7 +1302,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
unsigned int versindex,
struct module *mod)
{
- const unsigned long *crc;
+ const u32 *crc;
/*
* Since this should be found in kernel (which can't be removed), no
@@ -1328,8 +1316,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
}
preempt_enable();
return check_version(sechdrs, versindex,
- VMLINUX_SYMBOL_STR(module_layout), mod, crc,
- NULL);
+ VMLINUX_SYMBOL_STR(module_layout), mod, crc);
}
/* First part is kernel version, which we ignore if module has crcs. */
@@ -1347,8 +1334,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
unsigned int versindex,
const char *symname,
struct module *mod,
- const unsigned long *crc,
- const struct module *crc_owner)
+ const u32 *crc)
{
return 1;
}
@@ -1375,7 +1361,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
{
struct module *owner;
const struct kernel_symbol *sym;
- const unsigned long *crc;
+ const u32 *crc;
int err;
/*
@@ -1390,8 +1376,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
if (!sym)
goto unlock;
- if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
- owner)) {
+ if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
sym = ERR_PTR(-EINVAL);
goto getname;
}
--
2.7.4
^ permalink raw reply related
* [PATCHv4 0/4] WX checking for arm64
From: Laura Abbott @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This is v4 of the implementation to check for writable and executable pages on
arm64. This version contains a review from Ard and makes the UXN page count
a separate variable. Overall, minor changes.
Thanks,
Laura
Laura Abbott (4):
arm64: dump: Make ptdump debugfs a separate option
arm64: dump: Make the page table dumping seq_file optional
arm64: dump: Remove max_addr
arm64: dump: Add checking for writable and exectuable pages
arch/arm64/Kconfig.debug | 35 ++++++++++++-
arch/arm64/include/asm/ptdump.h | 22 +++++---
arch/arm64/mm/Makefile | 3 +-
arch/arm64/mm/dump.c | 105 +++++++++++++++++++++++++++----------
arch/arm64/mm/mmu.c | 2 +
arch/arm64/mm/ptdump_debugfs.c | 31 +++++++++++
drivers/firmware/efi/arm-runtime.c | 4 +-
7 files changed, 164 insertions(+), 38 deletions(-)
create mode 100644 arch/arm64/mm/ptdump_debugfs.c
--
2.7.4
^ permalink raw reply
* [PATCHv4 1/4] arm64: dump: Make ptdump debugfs a separate option
From: Laura Abbott @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477585654-8908-1-git-send-email-labbott@redhat.com>
ptdump_register currently initializes a set of page table information and
registers debugfs. There are uses for the ptdump option without wanting the
debugfs options. Split this out to make it a separate option.
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v4: Reviewed-by from Ard
---
arch/arm64/Kconfig.debug | 6 +++++-
arch/arm64/include/asm/ptdump.h | 15 +++++++++------
arch/arm64/mm/Makefile | 3 ++-
arch/arm64/mm/dump.c | 26 +++++---------------------
arch/arm64/mm/ptdump_debugfs.c | 31 +++++++++++++++++++++++++++++++
drivers/firmware/efi/arm-runtime.c | 4 ++--
6 files changed, 54 insertions(+), 31 deletions(-)
create mode 100644 arch/arm64/mm/ptdump_debugfs.c
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index b661fe7..21a5b74 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -2,9 +2,13 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config ARM64_PTDUMP
+config ARM64_PTDUMP_CORE
+ def_bool n
+
+config ARM64_PTDUMP_DEBUGFS
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
+ select ARM64_PTDUMP_CORE
select DEBUG_FS
help
Say Y here if you want to show the kernel pagetable layout in a
diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index 07b8ed0..16335da 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -16,9 +16,10 @@
#ifndef __ASM_PTDUMP_H
#define __ASM_PTDUMP_H
-#ifdef CONFIG_ARM64_PTDUMP
+#ifdef CONFIG_ARM64_PTDUMP_CORE
#include <linux/mm_types.h>
+#include <linux/seq_file.h>
struct addr_marker {
unsigned long start_address;
@@ -32,13 +33,15 @@ struct ptdump_info {
unsigned long max_addr;
};
-int ptdump_register(struct ptdump_info *info, const char *name);
-
+void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
+#ifdef CONFIG_ARM64_PTDUMP_DEBUGFS
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name);
#else
-static inline int ptdump_register(struct ptdump_info *info, const char *name)
+static inline int ptdump_debugfs_register(struct ptdump_info *info,
+ const char *name)
{
return 0;
}
-#endif /* CONFIG_ARM64_PTDUMP */
-
+#endif
+#endif /* CONFIG_ARM64_PTDUMP_CORE */
#endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 54bb209..e703fb9 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -3,7 +3,8 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
ioremap.o mmap.o pgd.o mmu.o \
context.o proc.o pageattr.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-obj-$(CONFIG_ARM64_PTDUMP) += dump.o
+obj-$(CONFIG_ARM64_PTDUMP_CORE) += dump.o
+obj-$(CONFIG_ARM64_PTDUMP_DEBUGFS) += ptdump_debugfs.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_KASAN) += kasan_init.o
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index 9c3e75d..f0f0be7 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -304,9 +304,8 @@ static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
}
}
-static int ptdump_show(struct seq_file *m, void *v)
+void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)
{
- struct ptdump_info *info = m->private;
struct pg_state st = {
.seq = m,
.marker = info->markers,
@@ -315,33 +314,16 @@ static int ptdump_show(struct seq_file *m, void *v)
walk_pgd(&st, info->mm, info->base_addr);
note_page(&st, 0, 0, 0);
- return 0;
}
-static int ptdump_open(struct inode *inode, struct file *file)
+static void ptdump_initialize(void)
{
- return single_open(file, ptdump_show, inode->i_private);
-}
-
-static const struct file_operations ptdump_fops = {
- .open = ptdump_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-int ptdump_register(struct ptdump_info *info, const char *name)
-{
- struct dentry *pe;
unsigned i, j;
for (i = 0; i < ARRAY_SIZE(pg_level); i++)
if (pg_level[i].bits)
for (j = 0; j < pg_level[i].num; j++)
pg_level[i].mask |= pg_level[i].bits[j].mask;
-
- pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
- return pe ? 0 : -ENOMEM;
}
static struct ptdump_info kernel_ptdump_info = {
@@ -352,6 +334,8 @@ static struct ptdump_info kernel_ptdump_info = {
static int ptdump_init(void)
{
- return ptdump_register(&kernel_ptdump_info, "kernel_page_tables");
+ ptdump_initialize();
+ return ptdump_debugfs_register(&kernel_ptdump_info,
+ "kernel_page_tables");
}
device_initcall(ptdump_init);
diff --git a/arch/arm64/mm/ptdump_debugfs.c b/arch/arm64/mm/ptdump_debugfs.c
new file mode 100644
index 0000000..eee4d86
--- /dev/null
+++ b/arch/arm64/mm/ptdump_debugfs.c
@@ -0,0 +1,31 @@
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/ptdump.h>
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+ struct ptdump_info *info = m->private;
+ ptdump_walk_pgd(m, info);
+ return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ptdump_show, inode->i_private);
+}
+
+static const struct file_operations ptdump_fops = {
+ .open = ptdump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name)
+{
+ struct dentry *pe;
+ pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
+ return pe ? 0 : -ENOMEM;
+
+}
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
index 7c75a8d..349dc3e 100644
--- a/drivers/firmware/efi/arm-runtime.c
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -39,7 +39,7 @@ static struct mm_struct efi_mm = {
.mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
};
-#ifdef CONFIG_ARM64_PTDUMP
+#ifdef CONFIG_ARM64_PTDUMP_DEBUGFS
#include <asm/ptdump.h>
static struct ptdump_info efi_ptdump_info = {
@@ -53,7 +53,7 @@ static struct ptdump_info efi_ptdump_info = {
static int __init ptdump_init(void)
{
- return ptdump_register(&efi_ptdump_info, "efi_page_tables");
+ return ptdump_debugfs_register(&efi_ptdump_info, "efi_page_tables");
}
device_initcall(ptdump_init);
--
2.7.4
^ permalink raw reply related
* [PATCHv4 2/4] arm64: dump: Make the page table dumping seq_file optional
From: Laura Abbott @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477585654-8908-1-git-send-email-labbott@redhat.com>
The page table dumping code always assumes it will be dumping to a
seq_file to userspace. Future code will be taking advantage of
the page table dumping code but will not need the seq_file. Make
the seq_file optional for these cases.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v4: No changes
---
arch/arm64/mm/dump.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index f0f0be7..bb36649 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -50,6 +50,18 @@ static const struct addr_marker address_markers[] = {
{ -1, NULL },
};
+#define pt_dump_seq_printf(m, fmt, args...) \
+({ \
+ if (m) \
+ seq_printf(m, fmt, ##args); \
+})
+
+#define pt_dump_seq_puts(m, fmt) \
+({ \
+ if (m) \
+ seq_printf(m, fmt); \
+})
+
/*
* The page dumper groups page table entries of the same type into a single
* description. It uses pg_state to track the range information while
@@ -186,7 +198,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
s = bits->clear;
if (s)
- seq_printf(st->seq, " %s", s);
+ pt_dump_seq_printf(st->seq, " %s", s);
}
}
@@ -200,14 +212,14 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
st->level = level;
st->current_prot = prot;
st->start_address = addr;
- seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
} else if (prot != st->current_prot || level != st->level ||
addr >= st->marker[1].start_address) {
const char *unit = units;
unsigned long delta;
if (st->current_prot) {
- seq_printf(st->seq, "0x%016lx-0x%016lx ",
+ pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx ",
st->start_address, addr);
delta = (addr - st->start_address) >> 10;
@@ -215,17 +227,17 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
delta >>= 10;
unit++;
}
- seq_printf(st->seq, "%9lu%c %s", delta, *unit,
+ pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
pg_level[st->level].name);
if (pg_level[st->level].bits)
dump_prot(st, pg_level[st->level].bits,
pg_level[st->level].num);
- seq_puts(st->seq, "\n");
+ pt_dump_seq_puts(st->seq, "\n");
}
if (addr >= st->marker[1].start_address) {
st->marker++;
- seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
}
st->start_address = addr;
@@ -235,7 +247,7 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
if (addr >= st->marker[1].start_address) {
st->marker++;
- seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
}
}
--
2.7.4
^ permalink raw reply related
* [PATCHv4 3/4] arm64: dump: Remove max_addr
From: Laura Abbott @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477585654-8908-1-git-send-email-labbott@redhat.com>
max_addr was added as part of struct ptdump_info but has never actually
been used. Remove it.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v4: No changes
---
arch/arm64/include/asm/ptdump.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index 16335da..f72ee69 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -30,7 +30,6 @@ struct ptdump_info {
struct mm_struct *mm;
const struct addr_marker *markers;
unsigned long base_addr;
- unsigned long max_addr;
};
void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
--
2.7.4
^ permalink raw reply related
* [PATCHv4 4/4] arm64: dump: Add checking for writable and exectuable pages
From: Laura Abbott @ 2016-10-27 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477585654-8908-1-git-send-email-labbott@redhat.com>
Page mappings with full RWX permissions are a security risk. x86
has an option to walk the page tables and dump any bad pages.
(See e1a58320a38d ("x86/mm: Warn on W^X mappings")). Add a similar
implementation for arm64.
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Laura Abbott <labbott@redhat.com>
---
v4: Changed pr_info -> pr_warn. Added a separate count variable for uxn to avoid
double counting.
---
arch/arm64/Kconfig.debug | 29 ++++++++++++++++++++++
arch/arm64/include/asm/ptdump.h | 8 +++++++
arch/arm64/mm/dump.c | 53 +++++++++++++++++++++++++++++++++++++++++
arch/arm64/mm/mmu.c | 2 ++
4 files changed, 92 insertions(+)
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index 21a5b74..d1ebd46 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -42,6 +42,35 @@ config ARM64_RANDOMIZE_TEXT_OFFSET
of TEXT_OFFSET and platforms must not require a specific
value.
+config DEBUG_WX
+ bool "Warn on W+X mappings at boot"
+ select ARM64_PTDUMP_CORE
+ ---help---
+ Generate a warning if any W+X mappings are found at boot.
+
+ This is useful for discovering cases where the kernel is leaving
+ W+X mappings after applying NX, as such mappings are a security risk.
+ This check also includes UXN, which should be set on all kernel
+ mappings.
+
+ Look for a message in dmesg output like this:
+
+ arm64/mm: Checked W+X mappings: passed, no W+X pages found.
+
+ or like this, if the check failed:
+
+ arm64/mm: Checked W+X mappings: FAILED, <N> W+X pages found.
+
+ Note that even if the check fails, your kernel is possibly
+ still fine, as W+X mappings are not a security hole in
+ themselves, what they do is that they make the exploitation
+ of other unfixed kernel bugs easier.
+
+ There is no runtime or memory usage effect of this option
+ once the kernel has booted up - it's a one time check.
+
+ If in doubt, say "Y".
+
config DEBUG_SET_MODULE_RONX
bool "Set loadable kernel module data as NX and text as RO"
depends on MODULES
diff --git a/arch/arm64/include/asm/ptdump.h b/arch/arm64/include/asm/ptdump.h
index f72ee69..6afd847 100644
--- a/arch/arm64/include/asm/ptdump.h
+++ b/arch/arm64/include/asm/ptdump.h
@@ -42,5 +42,13 @@ static inline int ptdump_debugfs_register(struct ptdump_info *info,
return 0;
}
#endif
+void ptdump_check_wx(void);
#endif /* CONFIG_ARM64_PTDUMP_CORE */
+
+#ifdef CONFIG_DEBUG_WX
+#define debug_checkwx() ptdump_check_wx()
+#else
+#define debug_checkwx() do { } while (0)
+#endif
+
#endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
index bb36649..ef8aca8 100644
--- a/arch/arm64/mm/dump.c
+++ b/arch/arm64/mm/dump.c
@@ -74,6 +74,9 @@ struct pg_state {
unsigned long start_address;
unsigned level;
u64 current_prot;
+ bool check_wx;
+ unsigned long wx_pages;
+ unsigned long uxn_pages;
};
struct prot_bits {
@@ -202,6 +205,35 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
}
}
+static void note_prot_uxn(struct pg_state *st, unsigned long addr)
+{
+ if (!st->check_wx)
+ return;
+
+ if ((st->current_prot & PTE_UXN) == PTE_UXN)
+ return;
+
+ WARN_ONCE(1, "arm64/mm: Found non-UXN mapping at address %p/%pS\n",
+ (void *)st->start_address, (void *)st->start_address);
+
+ st->uxn_pages += (addr - st->start_address) / PAGE_SIZE;
+}
+
+static void note_prot_wx(struct pg_state *st, unsigned long addr)
+{
+ if (!st->check_wx)
+ return;
+ if ((st->current_prot & PTE_RDONLY) == PTE_RDONLY)
+ return;
+ if ((st->current_prot & PTE_PXN) == PTE_PXN)
+ return;
+
+ WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n",
+ (void *)st->start_address, (void *)st->start_address);
+
+ st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
+}
+
static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
u64 val)
{
@@ -219,6 +251,8 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
unsigned long delta;
if (st->current_prot) {
+ note_prot_uxn(st, addr);
+ note_prot_wx(st, addr);
pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx ",
st->start_address, addr);
@@ -344,6 +378,25 @@ static struct ptdump_info kernel_ptdump_info = {
.base_addr = VA_START,
};
+void ptdump_check_wx(void)
+{
+ struct pg_state st = {
+ .seq = NULL,
+ .marker = (struct addr_marker[]) {
+ { -1, NULL},
+ },
+ .check_wx = true,
+ };
+
+ walk_pgd(&st, &init_mm, 0);
+ note_page(&st, 0, 0, 0);
+ if (st.wx_pages || st.uxn_pages)
+ pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
+ st.wx_pages, st.uxn_pages);
+ else
+ pr_info("Checked W+X mappings: passed, no W+X pages found\n");
+}
+
static int ptdump_init(void)
{
ptdump_initialize();
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 05615a3..2cbe2fe 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -42,6 +42,7 @@
#include <asm/tlb.h>
#include <asm/memblock.h>
#include <asm/mmu_context.h>
+#include <asm/ptdump.h>
u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
@@ -396,6 +397,7 @@ void mark_rodata_ro(void)
section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
create_mapping_late(__pa(__start_rodata), (unsigned long)__start_rodata,
section_size, PAGE_KERNEL_RO);
+ debug_checkwx();
}
static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
--
2.7.4
^ permalink raw reply related
* [RFC PATCH v2 0/8] arm64: Add a compat vDSO
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series adds support for a compat (AArch32) vDSO, providing two
userspace functionalities to compat processes:
* "Virtual" time syscalls (gettimeofday and clock_gettime). The
implementation is an adaptation of the arm vDSO (vgettimeofday.c),
sharing the data page with the 64-bit vDSO.
* sigreturn trampolines, following the example of the 64-bit vDSO
(sigreturn.S), but slightly more complicated because we provide A32
and T32 variants for both sigreturn and rt_sigreturn.
The first point brings the performance improvement expected of a vDSO,
by implementing time syscalls directly in userspace. The second point
allows us to get rid of the compat vector page, at the expense of the
kuser helpers (this is one reason for not enabling the compat vDSO by
default).
Unfortunately, this time we cannot escape using a 32-bit toolchain. To
build the compat VDSO, CONFIG_COMPAT_VDSO must be set *and*
CROSS_COMPILE_ARM32 must be defined to the prefix of a 32-bit compiler.
Failure to do so will not prevent building the kernel, but a warning
will be printed and the compat vDSO will not be built.
Thanks,
Kevin
Changelog v1..v2:
* Rebased on 4.9-rc2. I preserved the spirit of 5a9e3e156ec1 ("arm64:
apply __ro_after_init to some objects") by making the new
vdso{,32}_mappings static variables __ro_after_init, and removing
pages from struct vdso_mappings.
* Added CONFIG_CROSS_COMPILE_ARM32, on the same principle as
CONFIG_CROSS_COMPILE. That may help avoid forgetting to set the
variable when building the kernel with CONFIG_COMPAT_VDSO.
Kevin Brodsky (8):
arm64: Refactor vDSO setup
arm64: compat: Add time-related syscall numbers
arm64: compat: Expose offset to registers in sigframes
arm64: compat: Add a 32-bit vDSO
arm64: compat: 32-bit vDSO setup
arm64: elf: Set AT_SYSINFO_EHDR in compat processes
arm64: compat: Use vDSO sigreturn trampolines if available
arm64: Wire up and expose the new compat vDSO
arch/arm64/Kconfig | 26 +++
arch/arm64/Makefile | 28 ++-
arch/arm64/include/asm/elf.h | 15 +-
arch/arm64/include/asm/signal32.h | 46 +++++
arch/arm64/include/asm/unistd.h | 2 +
arch/arm64/include/asm/vdso.h | 3 +
arch/arm64/kernel/Makefile | 8 +-
arch/arm64/kernel/asm-offsets.c | 13 ++
arch/arm64/kernel/signal32.c | 61 ++-----
arch/arm64/kernel/vdso.c | 199 ++++++++++++---------
arch/arm64/kernel/vdso32/Makefile | 121 +++++++++++++
arch/arm64/kernel/vdso32/sigreturn.S | 86 +++++++++
arch/arm64/kernel/vdso32/vdso.S | 32 ++++
arch/arm64/kernel/vdso32/vdso.lds.S | 98 +++++++++++
arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
15 files changed, 897 insertions(+), 135 deletions(-)
create mode 100644 arch/arm64/kernel/vdso32/Makefile
create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
create mode 100644 arch/arm64/kernel/vdso32/vdso.S
create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
--
2.10.0
^ permalink raw reply
* [RFC PATCH v2 1/8] arm64: Refactor vDSO setup
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027163058.12156-1-kevin.brodsky@arm.com>
Move the logic for setting up mappings and pages for the vDSO into
static functions with a clear interface. This will allow to reuse the
setup code for the future compat vDSO.
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
arch/arm64/kernel/vdso.c | 177 ++++++++++++++++++++++++++---------------------
1 file changed, 98 insertions(+), 79 deletions(-)
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index a2c2478e7d78..c239b1c15eb3 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -37,8 +37,10 @@
#include <asm/vdso.h>
#include <asm/vdso_datapage.h>
-extern char vdso_start, vdso_end;
-static unsigned long vdso_pages __ro_after_init;
+struct vdso_mappings {
+ unsigned long num_pages;
+ struct vm_special_mapping data_mapping, code_mapping;
+};
/*
* The vDSO data page.
@@ -49,6 +51,92 @@ static union {
} vdso_data_store __page_aligned_data;
struct vdso_data *vdso_data = &vdso_data_store.data;
+static int __init setup_vdso_mappings(const char *name,
+ const char *code_start,
+ const char *code_end,
+ struct vdso_mappings *mappings)
+{
+ unsigned long i, num_pages;
+ struct page **pages;
+
+ if (memcmp(code_start, "\177ELF", 4)) {
+ pr_err("%s is not a valid ELF object!\n", name);
+ return -EINVAL;
+ }
+
+ num_pages = (code_end - code_start) >> PAGE_SHIFT;
+ pr_info("%s: %ld pages (%ld code @ %p, %ld data @ %p)\n",
+ name, num_pages + 1, num_pages, code_start, 1L, vdso_data);
+
+ /* Allocate the vDSO code pages, plus a page for the data. */
+ pages = kcalloc(num_pages + 1, sizeof(struct page *), GFP_KERNEL);
+ if (pages == NULL)
+ return -ENOMEM;
+
+ /* Grab the vDSO data page. */
+ pages[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
+
+ /* Grab the vDSO code pages. */
+ for (i = 0; i < num_pages; i++)
+ pages[i + 1] = pfn_to_page(PHYS_PFN(__pa(code_start)) + i);
+
+ /* Populate the special mapping structures */
+ mappings->data_mapping = (struct vm_special_mapping) {
+ .name = "[vvar]",
+ .pages = &pages[0],
+ };
+
+ mappings->code_mapping = (struct vm_special_mapping) {
+ .name = "[vdso]",
+ .pages = &pages[1],
+ };
+
+ mappings->num_pages = num_pages;
+ return 0;
+}
+
+static int setup_vdso_pages(const struct vdso_mappings *mappings)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
+ void *ret;
+
+ vdso_text_len = mappings->num_pages << PAGE_SHIFT;
+ /* Be sure to map the data page */
+ vdso_mapping_len = vdso_text_len + PAGE_SIZE;
+
+ if (down_write_killable(&mm->mmap_sem))
+ return -EINTR;
+ vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+ if (IS_ERR_VALUE(vdso_base)) {
+ ret = ERR_PTR(vdso_base);
+ goto up_fail;
+ }
+ ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
+ VM_READ|VM_MAYREAD,
+ &mappings->data_mapping);
+ if (IS_ERR(ret))
+ goto up_fail;
+
+ vdso_base += PAGE_SIZE;
+ mm->context.vdso = (void *)vdso_base;
+ ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+ &mappings->code_mapping);
+ if (IS_ERR(ret))
+ goto up_fail;
+
+
+ up_write(&mm->mmap_sem);
+ return 0;
+
+up_fail:
+ mm->context.vdso = NULL;
+ up_write(&mm->mmap_sem);
+ return PTR_ERR(ret);
+}
+
#ifdef CONFIG_COMPAT
/*
* Create and map the vectors page for AArch32 tasks.
@@ -71,11 +159,11 @@ static int __init alloc_vectors_page(void)
/* kuser helpers */
memcpy((void *)vpage + 0x1000 - kuser_sz, __kuser_helper_start,
- kuser_sz);
+ kuser_sz);
/* sigreturn code */
memcpy((void *)vpage + AARCH32_KERN_SIGRET_CODE_OFFSET,
- __aarch32_sigret_code_start, sigret_sz);
+ __aarch32_sigret_code_start, sigret_sz);
flush_icache_range(vpage, vpage + PAGE_SIZE);
vectors_page[0] = virt_to_page(vpage);
@@ -110,90 +198,21 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
}
#endif /* CONFIG_COMPAT */
-static struct vm_special_mapping vdso_spec[2] __ro_after_init = {
- {
- .name = "[vvar]",
- },
- {
- .name = "[vdso]",
- },
-};
+extern char vdso_start, vdso_end;
+
+static struct vdso_mappings vdso_mappings __ro_after_init;
static int __init vdso_init(void)
{
- int i;
- struct page **vdso_pagelist;
-
- if (memcmp(&vdso_start, "\177ELF", 4)) {
- pr_err("vDSO is not a valid ELF object!\n");
- return -EINVAL;
- }
-
- vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
- pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
- vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
-
- /* Allocate the vDSO pagelist, plus a page for the data. */
- vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
- GFP_KERNEL);
- if (vdso_pagelist == NULL)
- return -ENOMEM;
-
- /* Grab the vDSO data page. */
- vdso_pagelist[0] = pfn_to_page(PHYS_PFN(__pa(vdso_data)));
-
- /* Grab the vDSO code pages. */
- for (i = 0; i < vdso_pages; i++)
- vdso_pagelist[i + 1] = pfn_to_page(PHYS_PFN(__pa(&vdso_start)) + i);
-
- vdso_spec[0].pages = &vdso_pagelist[0];
- vdso_spec[1].pages = &vdso_pagelist[1];
-
- return 0;
+ return setup_vdso_mappings("vdso", &vdso_start, &vdso_end,
+ &vdso_mappings);
}
arch_initcall(vdso_init);
int arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp)
{
- struct mm_struct *mm = current->mm;
- unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
- void *ret;
-
- vdso_text_len = vdso_pages << PAGE_SHIFT;
- /* Be sure to map the data page */
- vdso_mapping_len = vdso_text_len + PAGE_SIZE;
-
- if (down_write_killable(&mm->mmap_sem))
- return -EINTR;
- vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
- if (IS_ERR_VALUE(vdso_base)) {
- ret = ERR_PTR(vdso_base);
- goto up_fail;
- }
- ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
- VM_READ|VM_MAYREAD,
- &vdso_spec[0]);
- if (IS_ERR(ret))
- goto up_fail;
-
- vdso_base += PAGE_SIZE;
- mm->context.vdso = (void *)vdso_base;
- ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
- VM_READ|VM_EXEC|
- VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- &vdso_spec[1]);
- if (IS_ERR(ret))
- goto up_fail;
-
-
- up_write(&mm->mmap_sem);
- return 0;
-
-up_fail:
- mm->context.vdso = NULL;
- up_write(&mm->mmap_sem);
- return PTR_ERR(ret);
+ return setup_vdso_pages(&vdso_mappings);
}
/*
--
2.10.0
^ permalink raw reply related
* [RFC PATCH v2 2/8] arm64: compat: Add time-related syscall numbers
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027163058.12156-1-kevin.brodsky@arm.com>
They will be used by the future compat vDSO.
The compat syscall numbers correspond to the arm syscall numbers, see
arch/arm/include/uapi/asm/unistd.h.
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
arch/arm64/include/asm/unistd.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index e78ac26324bd..8d1c5f5e58f3 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -34,8 +34,10 @@
#define __NR_compat_exit 1
#define __NR_compat_read 3
#define __NR_compat_write 4
+#define __NR_compat_gettimeofday 78
#define __NR_compat_sigreturn 119
#define __NR_compat_rt_sigreturn 173
+#define __NR_compat_clock_gettime 263
/*
* The following SVCs are ARM private.
--
2.10.0
^ permalink raw reply related
* [RFC PATCH v2 3/8] arm64: compat: Expose offset to registers in sigframes
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027163058.12156-1-kevin.brodsky@arm.com>
This will be needed to provide debug information (CFI/unwind tables)
in compat sigreturn trampolines, part of the future compat vDSO.
Also fix minor style issues reported by checkpatch.
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
arch/arm64/include/asm/signal32.h | 46 +++++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/asm-offsets.c | 13 +++++++++++
arch/arm64/kernel/signal32.c | 46 ---------------------------------------
3 files changed, 59 insertions(+), 46 deletions(-)
diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
index eeaa97559bab..9b1bcd3abd83 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -20,6 +20,52 @@
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
+struct compat_sigcontext {
+ /* We always set these two fields to 0 */
+ compat_ulong_t trap_no;
+ compat_ulong_t error_code;
+
+ compat_ulong_t oldmask;
+ compat_ulong_t arm_r0;
+ compat_ulong_t arm_r1;
+ compat_ulong_t arm_r2;
+ compat_ulong_t arm_r3;
+ compat_ulong_t arm_r4;
+ compat_ulong_t arm_r5;
+ compat_ulong_t arm_r6;
+ compat_ulong_t arm_r7;
+ compat_ulong_t arm_r8;
+ compat_ulong_t arm_r9;
+ compat_ulong_t arm_r10;
+ compat_ulong_t arm_fp;
+ compat_ulong_t arm_ip;
+ compat_ulong_t arm_sp;
+ compat_ulong_t arm_lr;
+ compat_ulong_t arm_pc;
+ compat_ulong_t arm_cpsr;
+ compat_ulong_t fault_address;
+};
+
+struct compat_ucontext {
+ compat_ulong_t uc_flags;
+ compat_uptr_t uc_link;
+ compat_stack_t uc_stack;
+ struct compat_sigcontext uc_mcontext;
+ compat_sigset_t uc_sigmask;
+ int __unused[32 - (sizeof(compat_sigset_t) / sizeof(int))];
+ compat_ulong_t uc_regspace[128] __aligned(8);
+};
+
+struct compat_sigframe {
+ struct compat_ucontext uc;
+ compat_ulong_t retcode[2];
+};
+
+struct compat_rt_sigframe {
+ struct compat_siginfo info;
+ struct compat_sigframe sig;
+};
+
#define AARCH32_KERN_SIGRET_CODE_OFFSET 0x500
extern const compat_ulong_t aarch32_sigret_code[6];
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 4a2f0f0fef32..965371186a5a 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -26,6 +26,7 @@
#include <asm/cpufeature.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
+#include <asm/signal32.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include <asm/vdso_datapage.h>
@@ -75,6 +76,18 @@ int main(void)
DEFINE(S_ORIG_ADDR_LIMIT, offsetof(struct pt_regs, orig_addr_limit));
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
BLANK();
+#ifdef CONFIG_COMPAT
+ DEFINE(COMPAT_SIGFRAME_REGS_OFFSET,
+ offsetof(struct compat_sigframe, uc) +
+ offsetof(struct compat_ucontext, uc_mcontext) +
+ offsetof(struct compat_sigcontext, arm_r0));
+ DEFINE(COMPAT_RT_SIGFRAME_REGS_OFFSET,
+ offsetof(struct compat_rt_sigframe, sig) +
+ offsetof(struct compat_sigframe, uc) +
+ offsetof(struct compat_ucontext, uc_mcontext) +
+ offsetof(struct compat_sigcontext, arm_r0));
+ BLANK();
+#endif
DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter));
BLANK();
DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm));
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index b7063de792f7..9de7d128e0e0 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -29,42 +29,6 @@
#include <asm/uaccess.h>
#include <asm/unistd.h>
-struct compat_sigcontext {
- /* We always set these two fields to 0 */
- compat_ulong_t trap_no;
- compat_ulong_t error_code;
-
- compat_ulong_t oldmask;
- compat_ulong_t arm_r0;
- compat_ulong_t arm_r1;
- compat_ulong_t arm_r2;
- compat_ulong_t arm_r3;
- compat_ulong_t arm_r4;
- compat_ulong_t arm_r5;
- compat_ulong_t arm_r6;
- compat_ulong_t arm_r7;
- compat_ulong_t arm_r8;
- compat_ulong_t arm_r9;
- compat_ulong_t arm_r10;
- compat_ulong_t arm_fp;
- compat_ulong_t arm_ip;
- compat_ulong_t arm_sp;
- compat_ulong_t arm_lr;
- compat_ulong_t arm_pc;
- compat_ulong_t arm_cpsr;
- compat_ulong_t fault_address;
-};
-
-struct compat_ucontext {
- compat_ulong_t uc_flags;
- compat_uptr_t uc_link;
- compat_stack_t uc_stack;
- struct compat_sigcontext uc_mcontext;
- compat_sigset_t uc_sigmask;
- int __unused[32 - (sizeof (compat_sigset_t) / sizeof (int))];
- compat_ulong_t uc_regspace[128] __attribute__((__aligned__(8)));
-};
-
struct compat_vfp_sigframe {
compat_ulong_t magic;
compat_ulong_t size;
@@ -91,16 +55,6 @@ struct compat_aux_sigframe {
unsigned long end_magic;
} __attribute__((__aligned__(8)));
-struct compat_sigframe {
- struct compat_ucontext uc;
- compat_ulong_t retcode[2];
-};
-
-struct compat_rt_sigframe {
- struct compat_siginfo info;
- struct compat_sigframe sig;
-};
-
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
--
2.10.0
^ permalink raw reply related
* [RFC PATCH v2 4/8] arm64: compat: Add a 32-bit vDSO
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027163058.12156-1-kevin.brodsky@arm.com>
Provide the files necessary for building a compat (AArch32) vDSO in
kernel/vdso32.
This is mostly an adaptation of the arm vDSO. The most significant
change in vgettimeofday.c is the use of the arm64 vdso_data struct,
allowing the vDSO data page to be shared between the 32 and 64-bit
vDSOs.
In addition to the time functions, sigreturn trampolines are also
provided, aiming at replacing those in the vector page. To improve
debugging, CFI and unwinding directives are used, based on glibc's
implementation. Symbol offsets are made available to the kernel using
the same method as the 64-bit vDSO.
There is unfortunately an important caveat to all this: we cannot get
away with hand-coding 32-bit instructions like in kernel/kuser32.S,
this time we really need a 32-bit compiler. The compat vDSO Makefile
relies on CROSS_COMPILE_ARM32 to provide a 32-bit compiler,
appropriate logic will be added to the arm64 Makefile later on to
ensure that an attempt to build the compat vDSO is made only if this
variable has been set properly.
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
arch/arm64/kernel/vdso32/Makefile | 121 +++++++++++++
arch/arm64/kernel/vdso32/sigreturn.S | 86 +++++++++
arch/arm64/kernel/vdso32/vdso.S | 32 ++++
arch/arm64/kernel/vdso32/vdso.lds.S | 98 +++++++++++
arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
5 files changed, 631 insertions(+)
create mode 100644 arch/arm64/kernel/vdso32/Makefile
create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
create mode 100644 arch/arm64/kernel/vdso32/vdso.S
create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
new file mode 100644
index 000000000000..38facc870f6e
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -0,0 +1,121 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <kevin.brodsky@arm.com>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+# Same as cc-ldoption, but using CC_ARM32 instead of CC
+cc32-ldoption = $(call try-run,\
+ $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2
+# Import some useful flags from arch/arm/Makefile
+VDSO_CFLAGS += -mabi=aapcs-linux -mfloat-abi=soft -funwind-tables
+# The 32-bit compiler does not provide 128-bit integers, which are used in
+# some headers that are indirectly included from the vDSO code.
+# This hack makes the compiler happy and should trigger a warning/error if
+# variables of such type are referenced.
+VDSO_CFLAGS += -D__uint128_t='void*'
+# Silence some warnings coming from headers that operate on long's
+VDSO_CFLAGS += -Wno-shift-count-overflow -Wno-int-to-pointer-cast
+
+# We need to use the global flags to compile the vDSO files. However some flags
+# inherited from either the top-level or the arm64 Makefile are not appropriate
+# for the 32-bit compiler, this function takes care of changing them as
+# appropriate.
+sanitize_flags = \
+ $(subst $(shell $(CC) -print-file-name=include), \
+ $(shell $(CC_ARM32) -print-file-name=include), \
+ $(filter-out -pg -mgeneral-regs-only -mpc-relative-literal-loads \
+ -fno-asynchronous-unwind-tables, \
+ $(1)))
+
+VDSO_LDFLAGS := -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1
+VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+VDSO_LDFLAGS += -nostdlib -shared -mfloat-abi=soft
+VDSO_LDFLAGS += $(call cc32-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS += $(call cc32-ldoption, -Wl$(comma)--build-id)
+VDSO_LDFLAGS += $(call cc32-ldoption, -fuse-ld=bfd)
+
+obj-y += vdso.o
+extra-y += vdso.lds
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+CFLAGS_REMOVE_vdso.o = -pg
+
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
+# Force dependency (incbin is bad)
+$(obj)/vdso.o: $(obj)/vdso.so
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE
+ $(call if_changed,vdsold)
+
+$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(objtree)/$(munge) FORCE
+ $(call if_changed,vdsomunge)
+
+# Strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+ $(call if_changed,objcopy)
+
+# Generate vDSO offsets using helper script (borrowed from the 64-bit vDSO)
+gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+# The AArch64 nm should be able to read an AArch32 binary
+define cmd_vdsosym
+ $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+endef
+
+include/generated/vdso32-offsets.h: $(obj)/vdso.so.dbg FORCE
+ $(call if_changed,vdsosym)
+
+# Compilation rules for the vDSO sources
+$(c-obj-vdso): %.o: %.c FORCE
+ $(call if_changed_dep,vdsocc)
+$(asm-obj-vdso): %.o: %.S FORCE
+ $(call if_changed_dep,vdsoas)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL $@
+ cmd_vdsold = $(CC_ARM32) $(call sanitize_flags,$(c_flags)) \
+ $(VDSO_LDFLAGS) -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
+quiet_cmd_vdsocc = VDSOC $@
+ cmd_vdsocc = $(CC_ARM32) $(call sanitize_flags,$(c_flags)) \
+ $(VDSO_CFLAGS) -c -o $@ $<
+quiet_cmd_vdsoas = VDSOA $@
+ cmd_vdsoas = $(CC_ARM32) $(call sanitize_flags, $(a_flags)) -c -o $@ $<
+
+quiet_cmd_vdsomunge = MUNGE $@
+ cmd_vdsomunge = $(objtree)/$(munge) $< $@
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+ cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so
+
+vdso.so: $(obj)/vdso.so.dbg
+ @mkdir -p $(MODLIB)/vdso
+ $(call cmd,vdso_install)
+
+vdso_install: vdso.so
diff --git a/arch/arm64/kernel/vdso32/sigreturn.S b/arch/arm64/kernel/vdso32/sigreturn.S
new file mode 100644
index 000000000000..a203140ec491
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/sigreturn.S
@@ -0,0 +1,86 @@
+/*
+ * Sigreturn trampolines for returning from a signal when the SA_RESTORER
+ * flag is not set.
+ *
+ * Copyright (C) 2016 ARM Limited
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Based on glibc's arm sa_restorer. While this is not strictly necessary, we
+ * provide both A32 and T32 versions, in accordance with the arm sigreturn
+ * code.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+.macro cfi_regs offset
+ .cfi_def_cfa sp, 0
+ .cfi_offset r0, \offset + 0 * 4
+ .cfi_offset r1, \offset + 1 * 4
+ .cfi_offset r2, \offset + 2 * 4
+ .cfi_offset r3, \offset + 3 * 4
+ .cfi_offset r4, \offset + 4 * 4
+ .cfi_offset r5, \offset + 5 * 4
+ .cfi_offset r6, \offset + 6 * 4
+ .cfi_offset r7, \offset + 7 * 4
+ .cfi_offset r8, \offset + 8 * 4
+ .cfi_offset r9, \offset + 9 * 4
+ .cfi_offset r10, \offset + 10 * 4
+ .cfi_offset r11, \offset + 11 * 4
+ .cfi_offset r12, \offset + 12 * 4
+ .cfi_offset r13, \offset + 13 * 4
+ .cfi_offset r14, \offset + 14 * 4
+ .cfi_offset r15, \offset + 15 * 4
+.endm
+
+.macro sigreturn_trampoline name, syscall, regs_offset
+ .fnstart
+ .save {r0-r15}
+ .pad #\regs_offset
+ENTRY(\name)
+ .cfi_startproc
+ .cfi_signal_frame
+ cfi_regs \regs_offset
+ mov r7, #\syscall
+ svc #0
+ .fnend
+ .cfi_endproc
+/*
+ * We would like to use ENDPROC, but the macro uses @ which is a comment symbol
+ * for arm assemblers, so directly use .type with % instead.
+ */
+ .type \name, %function
+END(\name)
+.endm
+
+ .text
+
+ .arm
+ sigreturn_trampoline __kernel_sigreturn_arm, \
+ __NR_compat_sigreturn, \
+ COMPAT_SIGFRAME_REGS_OFFSET
+
+ sigreturn_trampoline __kernel_rt_sigreturn_arm, \
+ __NR_compat_rt_sigreturn, \
+ COMPAT_RT_SIGFRAME_REGS_OFFSET
+
+ .thumb
+ sigreturn_trampoline __kernel_sigreturn_thumb, \
+ __NR_compat_sigreturn, \
+ COMPAT_SIGFRAME_REGS_OFFSET
+
+ sigreturn_trampoline __kernel_rt_sigreturn_thumb, \
+ __NR_compat_rt_sigreturn, \
+ COMPAT_RT_SIGFRAME_REGS_OFFSET
diff --git a/arch/arm64/kernel/vdso32/vdso.S b/arch/arm64/kernel/vdso32/vdso.S
new file mode 100644
index 000000000000..fe19ff70eb76
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vdso.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+ .globl vdso32_start, vdso32_end
+ .section .rodata
+ .balign PAGE_SIZE
+vdso32_start:
+ .incbin "arch/arm64/kernel/vdso32/vdso.so"
+ .balign PAGE_SIZE
+vdso32_end:
+
+ .previous
diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
new file mode 100644
index 000000000000..95abcc0dd37e
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -0,0 +1,98 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * GNU linker script for the VDSO library.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+SECTIONS
+{
+ HIDDEN(_vdso_data = . - PAGE_SIZE);
+ . = VDSO_LBASE + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+
+ .text : { *(.text*) } :text =0xe7f001f2
+
+ .got : { *(.got) }
+ .rel.plt : { *(.rel.plt) }
+
+ /DISCARD/ : {
+ *(.note.GNU-stack)
+ *(.data .data.* .gnu.linkonce.d.* .sdata*)
+ *(.bss .sbss .dynbss .dynsbss)
+ }
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+VERSION
+{
+ LINUX_2.6 {
+ global:
+ __vdso_clock_gettime;
+ __vdso_gettimeofday;
+ __kernel_sigreturn_arm;
+ __kernel_sigreturn_thumb;
+ __kernel_rt_sigreturn_arm;
+ __kernel_rt_sigreturn_thumb;
+ local: *;
+ };
+}
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_compat_sigreturn_arm = __kernel_sigreturn_arm;
+VDSO_compat_sigreturn_thumb = __kernel_sigreturn_thumb;
+VDSO_compat_rt_sigreturn_arm = __kernel_rt_sigreturn_arm;
+VDSO_compat_rt_sigreturn_thumb = __kernel_rt_sigreturn_thumb;
diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c
new file mode 100644
index 000000000000..3591fd56f8a6
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vgettimeofday.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2015 Mentor Graphics Corporation.
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/compiler.h>
+#include <linux/time.h>
+#include <asm/barrier.h>
+#include <asm/unistd.h>
+#include <asm/vdso_datapage.h>
+
+/*
+ * We use the hidden visibility to prevent the compiler from generating a GOT
+ * relocation. Not only is going through a GOT useless (the entry couldn't and
+ * musn't be overridden by another library), it does not even work: the linker
+ * cannot generate an absolute address to the data page.
+ *
+ * With the hidden visibility, the compiler simply generates a PC-relative
+ * relocation (R_ARM_REL32), and this is what we need.
+ */
+extern const struct vdso_data _vdso_data __attribute__((visibility("hidden")));
+
+static inline const struct vdso_data *get_vdso_data(void)
+{
+ const struct vdso_data *ret;
+ /*
+ * This simply puts &_vdso_data into ret. The reason why we don't use
+ * "ret = &_vdso_data" is that the compiler tends to optimise this in a
+ * very suboptimal way: instead of keeping &_vdso_data in a register,
+ * it goes through a relocation almost every time _vdso_data must be
+ * accessed (even in subfunctions). This is both time and space
+ * consuming: each relocation uses a word in the code section, and it
+ * has to be loaded at runtime.
+ *
+ * This trick hides the assignment from the compiler. Since it cannot
+ * track where the pointer comes from, it will only use one relocation
+ * where get_vdso_data() is called, and then keep the result in a
+ * register.
+ */
+ asm("mov %0, %1" : "=r"(ret) : "r"(&_vdso_data));
+ return ret;
+}
+
+static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
+{
+ u32 seq;
+repeat:
+ seq = ACCESS_ONCE(vdata->tb_seq_count);
+ if (seq & 1) {
+ cpu_relax();
+ goto repeat;
+ }
+ return seq;
+}
+
+static notrace u32 vdso_read_begin(const struct vdso_data *vdata)
+{
+ u32 seq;
+
+ seq = __vdso_read_begin(vdata);
+
+ smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
+ return seq;
+}
+
+static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
+{
+ smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
+ return vdata->tb_seq_count != start;
+}
+
+/*
+ * Note: only AEABI is supported by the compat layer, we can assume AEABI
+ * syscall conventions are used.
+ */
+static notrace long clock_gettime_fallback(clockid_t _clkid,
+ struct timespec *_ts)
+{
+ register struct timespec *ts asm("r1") = _ts;
+ register clockid_t clkid asm("r0") = _clkid;
+ register long ret asm ("r0");
+ register long nr asm("r7") = __NR_compat_clock_gettime;
+
+ asm volatile(
+ " svc #0\n"
+ : "=r" (ret)
+ : "r" (clkid), "r" (ts), "r" (nr)
+ : "memory");
+
+ return ret;
+}
+
+static notrace int do_realtime_coarse(struct timespec *ts,
+ const struct vdso_data *vdata)
+{
+ u32 seq;
+
+ do {
+ seq = vdso_read_begin(vdata);
+
+ ts->tv_sec = vdata->xtime_coarse_sec;
+ ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+ } while (vdso_read_retry(vdata, seq));
+
+ return 0;
+}
+
+static notrace int do_monotonic_coarse(struct timespec *ts,
+ const struct vdso_data *vdata)
+{
+ struct timespec tomono;
+ u32 seq;
+
+ do {
+ seq = vdso_read_begin(vdata);
+
+ ts->tv_sec = vdata->xtime_coarse_sec;
+ ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+ tomono.tv_sec = vdata->wtm_clock_sec;
+ tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+ } while (vdso_read_retry(vdata, seq));
+
+ ts->tv_sec += tomono.tv_sec;
+ timespec_add_ns(ts, tomono.tv_nsec);
+
+ return 0;
+}
+
+static notrace u64 get_ns(const struct vdso_data *vdata)
+{
+ u64 cycle_delta;
+ u64 cycle_now;
+ u64 nsec;
+
+ /* AArch32 implementation of arch_counter_get_cntvct() */
+ isb();
+ asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cycle_now));
+
+ /* The virtual counter provides 56 significant bits. */
+ cycle_delta = (cycle_now - vdata->cs_cycle_last) & CLOCKSOURCE_MASK(56);
+
+ nsec = (cycle_delta * vdata->cs_mono_mult) + vdata->xtime_clock_nsec;
+ nsec >>= vdata->cs_shift;
+
+ return nsec;
+}
+
+static notrace int do_realtime(struct timespec *ts,
+ const struct vdso_data *vdata)
+{
+ u64 nsecs;
+ u32 seq;
+
+ do {
+ seq = vdso_read_begin(vdata);
+
+ if (vdata->use_syscall)
+ return -1;
+
+ ts->tv_sec = vdata->xtime_clock_sec;
+ nsecs = get_ns(vdata);
+
+ } while (vdso_read_retry(vdata, seq));
+
+ ts->tv_nsec = 0;
+ timespec_add_ns(ts, nsecs);
+
+ return 0;
+}
+
+static notrace int do_monotonic(struct timespec *ts,
+ const struct vdso_data *vdata)
+{
+ struct timespec tomono;
+ u64 nsecs;
+ u32 seq;
+
+ do {
+ seq = vdso_read_begin(vdata);
+
+ if (vdata->use_syscall)
+ return -1;
+
+ ts->tv_sec = vdata->xtime_clock_sec;
+ nsecs = get_ns(vdata);
+
+ tomono.tv_sec = vdata->wtm_clock_sec;
+ tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+ } while (vdso_read_retry(vdata, seq));
+
+ ts->tv_sec += tomono.tv_sec;
+ ts->tv_nsec = 0;
+ timespec_add_ns(ts, nsecs + tomono.tv_nsec);
+
+ return 0;
+}
+
+notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+ const struct vdso_data *vdata = get_vdso_data();
+ int ret = -1;
+
+ switch (clkid) {
+ case CLOCK_REALTIME_COARSE:
+ ret = do_realtime_coarse(ts, vdata);
+ break;
+ case CLOCK_MONOTONIC_COARSE:
+ ret = do_monotonic_coarse(ts, vdata);
+ break;
+ case CLOCK_REALTIME:
+ ret = do_realtime(ts, vdata);
+ break;
+ case CLOCK_MONOTONIC:
+ ret = do_monotonic(ts, vdata);
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ ret = clock_gettime_fallback(clkid, ts);
+
+ return ret;
+}
+
+static notrace long gettimeofday_fallback(struct timeval *_tv,
+ struct timezone *_tz)
+{
+ register struct timezone *tz asm("r1") = _tz;
+ register struct timeval *tv asm("r0") = _tv;
+ register long ret asm ("r0");
+ register long nr asm("r7") = __NR_compat_gettimeofday;
+
+ asm volatile(
+ " svc #0\n"
+ : "=r" (ret)
+ : "r" (tv), "r" (tz), "r" (nr)
+ : "memory");
+
+ return ret;
+}
+
+notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ struct timespec ts;
+ const struct vdso_data *vdata = get_vdso_data();
+ int ret;
+
+ ret = do_realtime(&ts, vdata);
+ if (ret)
+ return gettimeofday_fallback(tv, tz);
+
+ if (tv) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+ if (tz) {
+ tz->tz_minuteswest = vdata->tz_minuteswest;
+ tz->tz_dsttime = vdata->tz_dsttime;
+ }
+
+ return ret;
+}
+
+/* Avoid unresolved references emitted by GCC */
+
+void __aeabi_unwind_cpp_pr0(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr1(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr2(void)
+{
+}
--
2.10.0
^ permalink raw reply related
* [RFC PATCH v2 5/8] arm64: compat: 32-bit vDSO setup
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027163058.12156-1-kevin.brodsky@arm.com>
If the compat vDSO is enabled, install it in compat processes. In this
case, the compat vDSO replaces the vector page.
aarch32_setup_vectors_page has also been renamed to the more generic
aarch32_setup_additional_pages to reflect both use cases.
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
arch/arm64/include/asm/elf.h | 6 +++---
arch/arm64/kernel/vdso.c | 22 +++++++++++++++++++++-
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index a55384f4a5d7..7da9452596ad 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -185,10 +185,10 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
#define compat_start_thread compat_start_thread
#define COMPAT_SET_PERSONALITY(ex) set_thread_flag(TIF_32BIT);
#define COMPAT_ARCH_DLINFO
-extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
- int uses_interp);
+extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
+ int uses_interp);
#define compat_arch_setup_additional_pages \
- aarch32_setup_vectors_page
+ aarch32_setup_additional_pages
#endif /* CONFIG_COMPAT */
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index c239b1c15eb3..76fb5e9ca521 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -138,6 +138,25 @@ static int setup_vdso_pages(const struct vdso_mappings *mappings)
}
#ifdef CONFIG_COMPAT
+#ifdef CONFIG_VDSO32
+extern char vdso32_start, vdso32_end;
+
+static struct vdso_mappings vdso32_mappings __ro_after_init;
+
+static int __init vdso32_init(void)
+{
+ return setup_vdso_mappings("vdso32", &vdso32_start, &vdso32_end,
+ &vdso32_mappings);
+}
+arch_initcall(vdso32_init);
+
+int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+ return setup_vdso_pages(&vdso32_mappings);
+}
+
+#else /* CONFIG_VDSO32 */
+
/*
* Create and map the vectors page for AArch32 tasks.
*/
@@ -172,7 +191,7 @@ static int __init alloc_vectors_page(void)
}
arch_initcall(alloc_vectors_page);
-int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
+int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
{
struct mm_struct *mm = current->mm;
unsigned long addr = AARCH32_VECTORS_BASE;
@@ -196,6 +215,7 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
return PTR_ERR_OR_ZERO(ret);
}
+#endif /* CONFIG_VDSO32 */
#endif /* CONFIG_COMPAT */
extern char vdso_start, vdso_end;
--
2.10.0
^ permalink raw reply related
* [RFC PATCH v2 6/8] arm64: elf: Set AT_SYSINFO_EHDR in compat processes
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027163058.12156-1-kevin.brodsky@arm.com>
If the compat vDSO is enabled, we need to set AT_SYSINFO_EHDR in the
auxiliary vector of compat processes to the address of the vDSO code
page, so that the dynamic linker can find it (just like the regular vDSO).
Note that we cast context.vdso to unsigned long, instead of elf_addr_t,
because elf_addr_t is 32-bit in compat_binfmt_elf.c, and casting to u32
would trigger a pointer narrowing warning.
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
arch/arm64/include/asm/elf.h | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 7da9452596ad..765c633950b7 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -141,11 +141,12 @@ typedef struct user_fpsimd_state elf_fpregset_t;
#define SET_PERSONALITY(ex) clear_thread_flag(TIF_32BIT);
/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
-#define ARCH_DLINFO \
+#define _SET_AUX_ENT_VDSO \
do { \
NEW_AUX_ENT(AT_SYSINFO_EHDR, \
- (elf_addr_t)current->mm->context.vdso); \
+ (unsigned long)current->mm->context.vdso); \
} while (0)
+#define ARCH_DLINFO _SET_AUX_ENT_VDSO
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
struct linux_binprm;
@@ -184,7 +185,11 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
#define compat_start_thread compat_start_thread
#define COMPAT_SET_PERSONALITY(ex) set_thread_flag(TIF_32BIT);
+#ifdef CONFIG_VDSO32
+#define COMPAT_ARCH_DLINFO _SET_AUX_ENT_VDSO
+#else
#define COMPAT_ARCH_DLINFO
+#endif
extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp);
#define compat_arch_setup_additional_pages \
--
2.10.0
^ permalink raw reply related
* [RFC PATCH v2 7/8] arm64: compat: Use vDSO sigreturn trampolines if available
From: Kevin Brodsky @ 2016-10-27 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161027163058.12156-1-kevin.brodsky@arm.com>
If the compat vDSO is enabled, it replaces the vector page. Therefore,
we use the sigreturn trampolines it provides instead of those in the
vector page.
Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
arch/arm64/include/asm/vdso.h | 3 +++
arch/arm64/kernel/signal32.c | 15 +++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 839ce0031bd5..f2a952338f1e 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -28,6 +28,9 @@
#ifndef __ASSEMBLY__
#include <generated/vdso-offsets.h>
+#ifdef CONFIG_VDSO32
+#include <generated/vdso32-offsets.h>
+#endif
#define VDSO_SYMBOL(base, name) \
({ \
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 9de7d128e0e0..b72a4180a531 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -28,6 +28,7 @@
#include <asm/signal32.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
+#include <asm/vdso.h>
struct compat_vfp_sigframe {
compat_ulong_t magic;
@@ -438,6 +439,19 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
retcode = ptr_to_compat(ka->sa.sa_restorer);
} else {
/* Set up sigreturn pointer */
+#ifdef CONFIG_VDSO32
+ void *vdso_page = current->mm->context.vdso;
+ void *trampoline =
+ (ka->sa.sa_flags & SA_SIGINFO
+ ? (thumb
+ ? VDSO_SYMBOL(vdso_page, compat_rt_sigreturn_thumb)
+ : VDSO_SYMBOL(vdso_page, compat_rt_sigreturn_arm))
+ : (thumb
+ ? VDSO_SYMBOL(vdso_page, compat_sigreturn_thumb)
+ : VDSO_SYMBOL(vdso_page, compat_sigreturn_arm)));
+
+ retcode = ptr_to_compat(trampoline) + thumb;
+#else
unsigned int idx = thumb << 1;
if (ka->sa.sa_flags & SA_SIGINFO)
@@ -446,6 +460,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
retcode = AARCH32_VECTORS_BASE +
AARCH32_KERN_SIGRET_CODE_OFFSET +
(idx << 2) + thumb;
+#endif
}
regs->regs[0] = usig;
--
2.10.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox