* [PATCH v5 01/12] dt-bindings: panel: lvds: Document power-supply property
From: Maxime Ripard @ 2018-01-04 19:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2493504.1OPucrC18r@avalon>
Hi Laurent,
On Fri, Dec 22, 2017 at 02:08:20PM +0200, Laurent Pinchart wrote:
> Hi Maxime,
>
> Thank you for the patch.
>
> On Thursday, 21 December 2017 13:02:27 EET Maxime Ripard wrote:
> > The power-supply property is used by a vast majority of panels, including
> > panel-simple. Let's document it as a common property
> >
> > Reviewed-by: Rob Herring <robh@kernel.org>
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> > Documentation/devicetree/bindings/display/panel/panel-common.txt | 6 ++++++
> > Documentation/devicetree/bindings/display/panel/panel-lvds.txt | 1 +
> > Documentation/devicetree/bindings/display/panel/simple-panel.txt | 2 +- 3
> > files changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git
> > a/Documentation/devicetree/bindings/display/panel/panel-common.txt
> > b/Documentation/devicetree/bindings/display/panel/panel-common.txt index
> > ec52c472c845..125ea68052af 100644
> > --- a/Documentation/devicetree/bindings/display/panel/panel-common.txt
> > +++ b/Documentation/devicetree/bindings/display/panel/panel-common.txt
> > @@ -78,6 +78,12 @@ used for panels that implement compatible control
> > signals. while active. Active high reset signals can be supported by
> > inverting the GPIO specifier polarity flag.
> >
> > +Power
> > +-----
> > +
> > +- power-supply: many display panels need an additional power supply in
> > + order to be fully powered-up. For such panels, power-supply contains
> > + a phandle to the regulator powering the panel.
>
> I think we should give more details here about the limitations of this
> property. How about the following explanation ?
>
> - power-supply: display panels require power to be supplied. While several
> panels need more than one power supply with panel-specific constraints
> governing the order and timings of the power supplies, in many cases a single
> power supply is sufficient, either because the panel has a single power rail,
> or because all its power rails can be driven by the same supply. In that case
> the power-supply property specifies the supply powering the panel as a phandle
> to a regulator.
That works for me. Do you want me to resend it with that text, or
should I merge it (and if so, with your Reviewed-by or Acked-by?)?
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/ddaee006/attachment-0001.sig>
^ permalink raw reply
* [PATCH 2/4] dt-bindings: gpio: add raspberry pi GPIO expander binding
From: Baruch Siach @ 2018-01-04 19:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <860502005.181510.1514917560724@email.1und1.de>
Hi Stefan,
On Tue, Jan 02, 2018 at 07:26:00PM +0100, Stefan Wahren wrote:
> > Baruch Siach <baruch@tkos.co.il> hat am 2. Januar 2018 um 14:19 geschrieben:
> >
> >
> > The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware over
> > I2C. The firmware mailbox interface allows the ARM core to control the
> > GPIO lines.
> >
> > Signed-off-by: Baruch Siach <baruch@tkos.co.il>
> > ---
> > .../bindings/gpio/brcm,bcm2835-expgpio.txt | 24 ++++++++++++++++++++++
> > 1 file changed, 24 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/gpio/brcm,bcm2835-expgpio.txt
> >
> > diff --git a/Documentation/devicetree/bindings/gpio/brcm,bcm2835-expgpio.txt b/Documentation/devicetree/bindings/gpio/brcm,bcm2835-expgpio.txt
> > new file mode 100644
> > index 000000000000..55257f31a9be
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/gpio/brcm,bcm2835-expgpio.txt
> > @@ -0,0 +1,24 @@
> > +Raspberry Pi GPIO expander
> > +
> > +The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware. The
> > +firmware exposes a mailbox interface that allows the ARM core to control the
> > +GPIO lines on the expander.
> > +
> > +Required properties:
> > +
> > +- compatible : Should be "brcm,bcm2835-expgpio"
>
> from my understand this driver is specific to the Raspberry Pi and it's
> vendor is the Raspberry Pi Foundation. So i prefer Eric's suggestion of
> "raspberrypi,firmware-gpio", which also applies to the filename.
That was my inclination as well. But I thought that keeping DT compatibility
with downstream is desirable.
I'll change compatible/file/driver names to raspberry something.
baruch
> > +- gpio-controller : Marks the device node as a gpio controller
> > +- #gpio-cells : Should be two. The first cell is the pin number, and
> > + the second cell is used to specify the gpio polarity:
> > + 0 = active high
> > + 1 = active low
> > +- firmware : Reference to the RPi firmware device node
> > +
> > +Example:
> > +
> > +expgpio: expgpio {
> > + compatible = "brcm,bcm2835-expgpio";
> > + gpio-controller;
> > + #gpio-cells = <2>;
> > + firmware = <&firmware>;
> > +};
--
http://baruch.siach.name/blog/ ~. .~ Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
- baruch at tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -
^ permalink raw reply
* [PATCH 1/8] ARM: dts: keystone: Move keystone_irq to under device-state-control
From: Andrew F. Davis @ 2018-01-04 19:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cce1676d-8e91-c3d4-be79-7896011a8f26@ti.com>
On 01/02/2018 05:30 PM, Suman Anna wrote:
> Hi Andrew,
>
> On 01/02/2018 11:01 AM, Andrew F. Davis wrote:
>> The keystone_irq node describes a device that is a component of the device
>> state control module.
>
> I would prefer 'address space' to be added to this statement as this
> module is really not a single IP but really a collection of different
> register sets providing different functionalities. Some of these
> comments apply to the following patches as well.
>
Works for me, will re-word.
> As such, it should not be a member of soc0 bus
>> but instead a sub-node of device-state-control.
>>
>> This move also fixes a warning about not having a reg property. Now
>> that this is a sub-node of device-state-control, a syscon type node,
>> we add this reg property but relative to the syscon base, this way
>> when the dt-binding/driver are updated we can drop the non-standard
>> ti,syscon-dev property completely and simply use get_resource() in
>> the driver.
>
> Please add an appropriate 'ranges' property in the parent node following
> the parent-child node convention, it's upto individual drivers to use
> the appropriate API for whether they want to deal with the offset or the
> actual bus addresses. You should not tie this into forcing to use a
> get_resource() without ranges to get the offset.
>
Will add.
>>
>> Signed-off-by: Andrew F. Davis <afd@ti.com>
>> Acked-by: Nishanth Menon <nm@ti.com>
>> ---
>> arch/arm/boot/dts/keystone.dtsi | 21 ++++++++++++---------
>> 1 file changed, 12 insertions(+), 9 deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi
>> index 93ea5c69ea77..158e0a903f7e 100644
>> --- a/arch/arm/boot/dts/keystone.dtsi
>> +++ b/arch/arm/boot/dts/keystone.dtsi
>> @@ -87,8 +87,19 @@
>> };
>>
>> devctrl: device-state-control at 2620000 {
>> - compatible = "ti,keystone-devctrl", "syscon";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + compatible = "ti,keystone-devctrl", "syscon", "simple-mfd";
>
> nit, can you please maintain the current order of compatible and reg,
> and add the new properties after them.
>
#address/size-cells are the first properties in many other nodes,
including the top level soc0, I have no real preference, so I'll change
it around if you prefer.
> regards
> Suman
>
>> reg = <0x02620000 0x1000>;
>> +
>> + kirq0: keystone_irq at 2a0 {
>> + compatible = "ti,keystone-irq";
>> + reg = <0x2a0 0x4>;
>> + interrupts = <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
>> + interrupt-controller;
>> + #interrupt-cells = <1>;
>> + ti,syscon-dev = <&devctrl 0x2a0>;
>> + };
>> };
>>
>> rstctrl: reset-controller {
>> @@ -282,14 +293,6 @@
>> 1 0 0x21000A00 0x00000100>;
>> };
>>
>> - kirq0: keystone_irq at 26202a0 {
>> - compatible = "ti,keystone-irq";
>> - interrupts = <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
>> - interrupt-controller;
>> - #interrupt-cells = <1>;
>> - ti,syscon-dev = <&devctrl 0x2a0>;
>> - };
>> -
>> pcie0: pcie at 21800000 {
>> compatible = "ti,keystone-pcie", "snps,dw-pcie";
>> clocks = <&clkpcie>;
>>
>
^ permalink raw reply
* [PATCH 01/11] clk: sunxi-ng: Don't set k if width is 0 for nkmp plls
From: Jernej Škrabec @ 2018-01-04 19:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v67B23yUdACijKxosfFG_os5WndiBKX02DGA4PFUkxDx9g@mail.gmail.com>
Hi,
Dne ?etrtek, 04. januar 2018 ob 15:45:18 CET je Chen-Yu Tsai napisal(a):
> On Sun, Dec 31, 2017 at 5:01 AM, Jernej Skrabec <jernej.skrabec@siol.net>
wrote:
> > For example, A83T have nmp plls which are modelled as nkmp plls. Since k
> > is not specified, it has offset 0, shift 0 and lowest value 1. This
> > means that LSB bit is always set to 1, which may change clock rate.
> >
> > Fix that by applying k factor only if k width is greater than 0.
> >
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > ---
> >
> > drivers/clk/sunxi-ng/ccu_nkmp.c | 21 +++++++++++++--------
> > 1 file changed, 13 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c
> > b/drivers/clk/sunxi-ng/ccu_nkmp.c index e58c95787f94..709f528af2b3 100644
> > --- a/drivers/clk/sunxi-ng/ccu_nkmp.c
> > +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
> > @@ -81,7 +81,7 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw
> > *hw,>
> > unsigned long parent_rate)
> >
> > {
> >
> > struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
> >
> > - unsigned long n, m, k, p;
> > + unsigned long n, m, k = 1, p;
> >
> > u32 reg;
> >
> > reg = readl(nkmp->common.base + nkmp->common.reg);
> >
> > @@ -92,11 +92,13 @@ static unsigned long ccu_nkmp_recalc_rate(struct
> > clk_hw *hw,>
> > if (!n)
> >
> > n++;
> >
> > - k = reg >> nkmp->k.shift;
> > - k &= (1 << nkmp->k.width) - 1;
> > - k += nkmp->k.offset;
> > - if (!k)
> > - k++;
> > + if (nkmp->k.width) {
> > + k = reg >> nkmp->k.shift;
> > + k &= (1 << nkmp->k.width) - 1;
> > + k += nkmp->k.offset;
> > + if (!k)
> > + k++;
> > + }
>
> The conditional shouldn't be necessary. With nkmp->k.width = 0,
> you'd simply get k & 0, which is 0, which then gets bumped up to 1,
> unless k.offset > 1, which would be a bug.
>
> > m = reg >> nkmp->m.shift;
> > m &= (1 << nkmp->m.width) - 1;
> >
> > @@ -153,12 +155,15 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw,
> > unsigned long rate,>
> > reg = readl(nkmp->common.base + nkmp->common.reg);
> > reg &= ~GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift);
> >
> > - reg &= ~GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift);
> > + if (nkmp->k.width)
> > + reg &= ~GENMASK(nkmp->k.width + nkmp->k.shift - 1,
> > + nkmp->k.shift);
> >
> > reg &= ~GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
> > reg &= ~GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
> >
> > reg |= (_nkmp.n - nkmp->n.offset) << nkmp->n.shift;
> >
> > - reg |= (_nkmp.k - nkmp->k.offset) << nkmp->k.shift;
> > + if (nkmp->k.width)
> > + reg |= (_nkmp.k - nkmp->k.offset) << nkmp->k.shift;
>
> I think a better way would be
>
> reg |= ((_nkmp.k - nkmp->k.offset) << nkmp->k.shift) &
> GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift);
>
> And do this for all the factors, not just k. This pattern is what
> regmap_update_bits does, which seems much safer. I wonder what
> GENMASK() with a negative value would do though...
You're right, GENMASK(-1, 0) equals 0 (calculated by hand, not tested). This
seems much more elegant solution.
Semi-related question: All nmp PLLs have much wider N range than real nkmp
PLLs. This causes integer overflow when using nkmp formula from datasheet.
Usually, N is 1-256 for nmp PLLs, which means that for very high N factors, it
overflows. This also causes issue that M factor is never higher than 1.
I was wondering, if patch would be acceptable which would change this formula:
RATE = (24MHz * N * K) / (M * P)
to this:
RATE ((24MHz / M) * N * K) / P
I checked all M factors and are all in 1-4 or 1-2 range, which means it
wouldn't have any impact for real nkmp PLLs when parent is 24 MHz clock which
is probably always.
What do you think?
I discovered that when I tried to set A83T PLL_VIDEO to 346.5 MHz which is
possible only when above formula is changed.
Best regards,
Jernej
>
> ChenYu
>
> > reg |= (_nkmp.m - nkmp->m.offset) << nkmp->m.shift;
> > reg |= ilog2(_nkmp.p) << nkmp->p.shift;
> >
> > --
> > 2.15.1
^ permalink raw reply
* [PATCH v4 6/7] ARM: davinci: convert to common clock framework
From: Adam Ford @ 2018-01-04 19:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f09641b7-a9e9-24d1-ce13-1b627d077ce5@lechnology.com>
On Thu, Jan 4, 2018 at 11:50 AM, David Lechner <david@lechnology.com> wrote:
>
>
> On 1/4/18 6:39 AM, Sekhar Nori wrote:
>>
>> On Monday 01 January 2018 05:09 AM, David Lechner wrote:
>>>
>>> This converts all of arch/arm/mach-davinci to the common clock framework.
>>> The clock drivers from clock.c and psc.c have been moved to drivers/clk,
>>> so these files are removed.
>>>
>>> There is one subtle change in the clock trees. AUX, BPDIV and OSCDIV
>>> clocks now have "ref_clk" as a parent instead of the PLL clock. These
>>> clocks are part of the PLL's MMIO block, but they bypass the PLL and
>>> therefore it makes more sense to have "ref_clk" as their parent since
>>> "ref_clk" is the input clock of the PLL.
>>>
>>> CONFIG_DAVINCI_RESET_CLOCKS is removed since the common clock frameworks
>>> takes care of disabling unused clocks.
>>>
>>> Known issue: This breaks CPU frequency scaling on da850.
>>
>>
>> This functionality needs to be restored as part of this series since we
>> cannot commit anything with regressions.
>>
>
> Do you have a suggestion on how to accomplish this? I don't have a board for
> testing, so I don't have a way of knowing if my changes will work or not.
I work for Logic PD who makes the original da850-evm. I can help if
you want to send me patches. It would be better if you had a git repo
setup where I could just clone the repo and tests.
Having a larger collection of smaller the patches would also give me
the ability to bisect down to help determine what actually breaks the
da850-evm vs a few large patches.
Do you still need me to run the board with some of the extra debugging
enabled, or should I wait for the next round of patches?
adam
>
>>>
>>> Also, the order of #includes are cleaned up in files while we are
>>> touching
>>> this code.
>>>
>>> Signed-off-by: David Lechner <david@lechnology.com>
>>
>>
>> This is a pretty huge patch again and I hope it can be broken down.
>> Ideally one per SoC converted and then the unused code removal.
>>
>
> Will do.
^ permalink raw reply
* [PATCH v5 03/20] firmware: arm_scmi: add basic driver infrastructure for SCMI
From: Alexey Klimov @ 2018-01-04 19:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1514904162-11201-4-git-send-email-sudeep.holla@arm.com>
Hi Sudeep,
thank you for working on this.
On Tue, Jan 2, 2018 at 2:42 PM, Sudeep Holla <sudeep.holla@arm.com> wrote:
[...]
> diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
> new file mode 100644
> index 000000000000..58d8f88893e6
> --- /dev/null
> +++ b/drivers/firmware/arm_scmi/driver.c
[..]
> + * Return: 0 is successfully released
> + * if null was passed, it returns -EINVAL;
> + */
> +int scmi_handle_put(const struct scmi_handle *handle)
> +{
> + struct scmi_info *info;
> +
> + if (!handle)
> + return -EINVAL;
> +
> + info = handle_to_scmi_info(handle);
> + mutex_lock(&scmi_list_mutex);
> + if (!WARN_ON(!info->users))
> + info->users--;
> + mutex_unlock(&scmi_list_mutex);
> +
> + return 0;
> +}
> +
> +static const struct scmi_desc scmi_generic_desc = {
> + .max_rx_timeout_ms = 30, /* we may increase this if required */
What are your thoughts about making it a module parameter?
IIRC, this may required to be increased when someone uses debugging
version of firmware, for example.
In such case someone might need to recompile the kernel in order to
boot with enabled and initialized scmi.
Also, there can be a chance that another transport will be used that
will require larger than 5 * 30 ms delay (such kind of transport can
be kinda useless, I know, but can help with development).
With module parameter you can still boot passing the larger timeout
parameter to the module from cmdline.
> + .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */
> + .max_msg_size = 128,
> +};
Best regards,
Alexey
^ permalink raw reply
* [PATCH 0/8] ARM: dts: keystone*: Continued warnings cleanups
From: Santosh Shilimkar @ 2018-01-04 19:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180102170202.15045-1-afd@ti.com>
On 1/2/2018 9:01 AM, Andrew F. Davis wrote:
> Hello all,
>
> Just a couple cleanups for DT warnings when compiling with W=1.
>
> This clears up 51 more warnings when building keystone_defconfig.
>
> Based on Santosh's "for_4.16/keystone-dts" branch.
>
Will see if this can be queued up post merge window as 'non-critical'
fixes o.w it waits for 4.17. Please repost it after addressing
Suman's comments.
Regards,
Santosh
^ permalink raw reply
* [PATCH v5 1/2] PCI: mediatek: Clear IRQ status after IRQ dispatched to avoid reentry
From: Marc Zyngier @ 2018-01-04 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184040.GE12239@red-moon>
On 04/01/18 18:40, Lorenzo Pieralisi wrote:
> [+Marc]
>
> On Wed, Dec 27, 2017 at 08:59:53AM +0800, honghui.zhang at mediatek.com wrote:
>> From: Honghui Zhang <honghui.zhang@mediatek.com>
>>
>> There maybe a same IRQ reentry scenario after IRQ received in current
>> IRQ handle flow:
>> EP device PCIe host driver EP driver
>> 1. issue an IRQ
>> 2. received IRQ
>> 3. clear IRQ status
>> 4. dispatch IRQ
>> 5. clear IRQ source
>> The IRQ status was not successfully cleared at step 2 since the IRQ
>> source was not cleared yet. So the PCIe host driver may receive the
>> same IRQ after step 5. Then there's an IRQ reentry occurred.
>> Even worse, if the reentry IRQ was not an IRQ that EP driver expected,
>> it may not handle the IRQ. Then we may run into the infinite loop from
>> step 2 to step 4.
>> Clear the IRQ status after IRQ have been dispatched to avoid the IRQ
>> reentry.
>> This patch also fix another INTx IRQ issue by initialize the iterate
>> before the loop. If an INTx IRQ re-occurred while we are dispatching
>> the INTx IRQ, then iterate may start from PCI_NUM_INTX + INTX_SHIFT
>> instead of INTX_SHIFT for the second time entering the
>> for_each_set_bit_from() loop.
>
> This looks like two different issues that should be fixed with two
> patches.
>
>> Signed-off-by: Honghui Zhang <honghui.zhang@mediatek.com>
>> Acked-by: Ryder Lee <ryder.lee@mediatek.com>
>> ---
>> drivers/pci/host/pcie-mediatek.c | 11 ++++++-----
>> 1 file changed, 6 insertions(+), 5 deletions(-)
>
> For the sake of uniformity, I first want to understand why this
> driver does not call:
>
> chained_irq_enter/exit()
>
> in the primary handler (mtk_pcie_intr_handler()).
>
> With the GIC as a primary interrupt controller we have not
> even figured out how current code can actually work without
> calling the chained_* API.
>
> I want to come up with a consistent handling of IRQ domains for
> all host bridges and any discrepancy should be explained.
That's because this driver is a huge hack, see below:
>
>> diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c
>> index db93efd..fc29a9a 100644
>> --- a/drivers/pci/host/pcie-mediatek.c
>> +++ b/drivers/pci/host/pcie-mediatek.c
>> @@ -601,15 +601,16 @@ static irqreturn_t mtk_pcie_intr_handler(int irq, void *data)
This function is not a chained irqchip, but an interrupt handler...
>> struct mtk_pcie_port *port = (struct mtk_pcie_port *)data;
>> unsigned long status;
>> u32 virq;
>> - u32 bit = INTX_SHIFT;
>> + u32 bit;
>>
>> while ((status = readl(port->base + PCIE_INT_STATUS)) & INTX_MASK) {
>> + bit = INTX_SHIFT;
>> for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) {
>> - /* Clear the INTx */
>> - writel(1 << bit, port->base + PCIE_INT_STATUS);
>> virq = irq_find_mapping(port->irq_domain,
>> bit - INTX_SHIFT);
>> generic_handle_irq(virq);
and nonetheless, this calls into generic_handle_irq(). That's a complete
violation of the interrupt layering. Maybe there is a good reason for
it, but I'd like to know which one.
Which means that all of the ack/mask has to be done outside of the
irqchip framework too... Disgusting.
>> + /* Clear the INTx */
>> + writel(1 << bit, port->base + PCIE_INT_STATUS);
>
> I think that these masking/acking should actually be done through
> the irq_chip hooks (see for instance pci-ftpci100.c) - that would
> make this kind of bugs much easier to prevent (because the IRQ
> layer does the sequencing for you).
+1.
> Marc (CC'ed) has a more comprehensive view on this than me - I would
> like to get to a point where all host bridges uses a consistent
> approach for chained IRQ handling and I hope this bug fix can be
> a starting point.
+1 again. We definitely need to come up with some form of common
approach for all these host drivers, and maybe turn that into a library...
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH v5 03/12] dt-bindings: display: sun4i-drm: Add LVDS properties
From: Maxime Ripard @ 2018-01-04 19:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1927811.df6406f6u0@jernej-laptop>
Hi,
On Sat, Dec 30, 2017 at 12:45:19PM +0100, Jernej ?krabec wrote:
> Hi Maxime,
>
> Dne ?etrtek, 21. december 2017 ob 12:02:29 CET je Maxime Ripard napisal(a):
> > Some clocks and resets supposed to drive the LVDS logic in the display
> > engine have been overlooked when the driver was first introduced.
> >
> > Add those additional resources to the binding, and we'll deal with the ABI
> > stability in the code.
> >
> > Reviewed-by: Chen-Yu Tsai <wens@csie.org>
> > Reviewed-by: Rob Herring <robh@kernel.org>
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> > Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 9 +++++++-
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index
> > 50cc72ee1168..1e21cfaac9e2 100644
> > --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > @@ -121,6 +121,15 @@ Required properties:
> > On SoCs other than the A33 and V3s, there is one more clock required:
> > - 'tcon-ch1': The clock driving the TCON channel 1
> >
> > +On SoCs that support LVDS (all SoCs but the A13, H3, H5 and V3s), you
> > +need one more reset line:
> > + - 'lvds': The reset line driving the LVDS logic
> > +
> > +And on the SoCs newer than the A31 (sun6i and sun8i families), you
> > +need one more clock line:
> > + - 'lvds-alt': An alternative clock source, separate from the TCON
> > channel 0 + clock, that can be used to drive the LVDS clock
>
> I think this wording is imprecise, since A83T is part of the sun8i family, but
> from the code (patch 7) and DT changes (patch 9) you do, it doesn't need this
> property.
>
> Maybe it would be just easier to enumerate all compatibles which needs this
> property?
You're right, but the rest of the document uses the SoC name
instead. In order to remain consistent, I listed the (currently
supported) SoCs that need that property and applied that patch.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/024c3533/attachment.sig>
^ permalink raw reply
* [PATCH 06/11] dt-bindings: display: sun4i-drm: Add A83T HDMI pipeline
From: Maxime Ripard @ 2018-01-04 18:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1645801.yZU0HLsLbk@jernej-laptop>
On Wed, Jan 03, 2018 at 10:32:26PM +0100, Jernej ?krabec wrote:
> Hi Rob,
>
> Dne sreda, 03. januar 2018 ob 21:21:54 CET je Rob Herring napisal(a):
> > On Sat, Dec 30, 2017 at 10:01:58PM +0100, Jernej Skrabec wrote:
> > > This commit adds all necessary compatibles and descriptions needed to
> > > implement A83T HDMI pipeline.
> > >
> > > Mixer is already properly described, so only compatible is added.
> > >
> > > However, A83T TCON1, which is connected to HDMI, doesn't have channel 0,
> > > contrary to all TCONs currently described. Because of that, TCON
> > > documentation is extended.
> > >
> > > A83T features Synopsys DW HDMI controller with a custom PHY which looks
> > > like Synopsys Gen2 PHY with few additions. Since there is no
> > > documentation, needed properties were found out through experimentation
> > > and reading BSP code.
> > >
> > > At the end, example is added for newer SoCs, which features DE2 and DW
> > > HDMI.
> > >
> > > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > > ---
> > >
> > > .../bindings/display/sunxi/sun4i-drm.txt | 188
> > > ++++++++++++++++++++- 1 file changed, 181 insertions(+), 7 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > > b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index
> > > 9f073af4c711..3eca258096a5 100644
> > > --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > > +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > >
> > > @@ -64,6 +64,40 @@ Required properties:
> > > first port should be the input endpoint. The second should be the
> > > output, usually to an HDMI connector.
> > >
> > > +DWC HDMI TX Encoder
> > > +-----------------------------
> > > +
> > > +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
> > > +with Allwinner's own PHY IP. It supports audio and video outputs and CEC.
> > > +
> > > +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
> > > +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
> > > +following device-specific properties.
> > > +
> > > +Required properties:
> > > +
> > > + - compatible: value must be one of:
> > > + * "allwinner,sun8i-a83t-dw-hdmi"
> > > + - reg: two pairs of base address and size of memory-mapped region,
> > > first
> > > + for controller and second for PHY
> > > + registers.
> >
> > Seems like the phy should be a separate node and use the phy binding.
> > You can use the phy binding even if you don't use the kernel phy
> > framework...
>
> Unfortunately, it's not so straighforward. Phy is actually accessed through
> I2C implemented in HDMI controller. Second memory region in this case has
> small influence on phy. However, it has big influence on controller. For
> example, magic number has to be written in one register in second memory
> region in order to unlock read access to any register from first memory region
> (controller). However, they shouldn't be merged to one region, because first
> memory region requires byte access while second memory region can be accessed
> per byte or word.
>
> To complicate things more, later I want to add support for another SoC which
> has same glue layer (unlocking read access, etc.) and uses memory mapped phy
> registers in second memory region.
>
> I think current binding is the least complicated way to represent this.
I agree with Rob here. I did a similar thing for the DSI patches I've
sent a few monthes ago and it turned out to not be that difficult, so
I'm sure you can come up with something :)
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [kernel-hardening] [PATCH] arm: Always use REFCOUNT_FULL
From: Russell King - ARM Linux @ 2018-01-04 18:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGXu5jKkw7aCN7N8P-UkoFH2xF8Szy-UsL5tJBYUQKaW2a38yA@mail.gmail.com>
On Thu, Jan 04, 2018 at 10:42:21AM -0800, Kees Cook wrote:
> On Thu, Jan 4, 2018 at 10:35 AM, Russell King - ARM Linux
> <linux@armlinux.org.uk> wrote:
> > On Thu, Jan 04, 2018 at 10:32:46AM -0800, Kees Cook wrote:
> >> On Thu, Jan 4, 2018 at 4:28 AM, Jinbum Park <jinb.park7@gmail.com> wrote:
> >> > arm prefers to use REFCOUNT_FULL by default.
> >> > This enables it for arm.
> >> >
> >> > Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
> >>
> >> Acked-by: Kees Cook <keescook@chromium.org>
> >
> > I'd help if there was some kind of explanation about this. Not
> > everyone knows what REFCOUNT_FULL is.
> >
> > Also, why does "arm" "prefer" to use this? Where does the preference
> > come from - and why is it a preference but being enforced by the
> > Kconfig ?
>
> This came from discussions with Will Deacon (and others) during the
> Linux Security Summit. The arm64 side of this is in commit
> 4adcec1164de ("arm64: Always use REFCOUNT_FULL"). AIUI, Will said he
> didn't want the specialized "fast but technically incomplete"
> refcounting as seen with x86's fast refcount infrastructure, but
> rather to keep refcounts always fully protected by default because no
> one could point to real-world performance impacts with REFCOUNT_FULL
> vs unprotected atomic_t infrastructure.
>
> I'm fine leaving this choice up to the end user, but I think it makes
> sense to be always-on. If that's no okay, maybe make it default-y for
> arm32, and still let people turn it off if they want?
I'm not really asking for changes.
I'm basically asking for the commit message to do a better job of
explaining this - in years to come, the currently proposed commit
message contains very little information about why this commit exists.
Commit messages need to say what they're doing and why, and not assume
that someone's been to some conference and knows all the inside details
that were discussed there. It's also best to avoid referencing papers -
conferences and their websites come and go, and links break, at which
point information gets lost. If it's all properly explained in the
commit message, then it's there forever.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up
^ permalink raw reply
* [PATCH v4 19/19] arm64: Update the KVM memory map documentation
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
Update the documentation to reflect the new tricks we play on the
EL2 mappings...
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
Documentation/arm64/memory.txt | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt
index 671bc0639262..ea64e20037f6 100644
--- a/Documentation/arm64/memory.txt
+++ b/Documentation/arm64/memory.txt
@@ -86,9 +86,11 @@ Translation table lookup with 64KB pages:
+-------------------------------------------------> [63] TTBR0/1
-When using KVM without the Virtualization Host Extensions, the hypervisor
-maps kernel pages in EL2 at a fixed offset from the kernel VA. See the
-kern_hyp_va macro for more details.
+When using KVM without the Virtualization Host Extensions, the
+hypervisor maps kernel pages in EL2 at a fixed offset (modulo a random
+offset) from the linear mapping. See the kern_hyp_va macro and
+kvm_update_va_mask function for more details. MMIO devices such as
+GICv2 gets mapped next to the HYP idmap page.
When using KVM with the Virtualization Host Extensions, no additional
mappings are created, since the host kernel runs directly in EL2.
--
2.14.2
^ permalink raw reply related
* [PATCH v4 18/19] arm64: KVM: Introduce EL2 VA randomisation
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
The main idea behind randomising the EL2 VA is that we usually have
a few spare bits between the most significant bit of the VA mask
and the most significant bit of the linear mapping.
Those bits could be a bunch of zeroes, and could be useful
to move things around a bit. Of course, the more memory you have,
the less randomisation you get...
Alternatively, these bits could be the result of KASLR, in which
case they are already random. But it would be nice to have a
*different* randomization, just to make the job of a potential
attacker a bit more difficult.
Inserting these random bits is a bit involved. We don't have a spare
register (short of rewriting all the kern_hyp_va call sites), and
the immediate we want to insert is too random to be used with the
ORR instruction. The best option I could come up with is the following
sequence:
and x0, x0, #va_mask
ror x0, x0, #first_random_bit
add x0, x0, #(random & 0xfff)
add x0, x0, #(random >> 12), lsl #12
ror x0, x0, #(63 - first_random_bit)
making it a fairly long sequence, but one that a decent CPU should
be able to execute without breaking a sweat. It is of course NOPed
out on VHE. The last 4 instructions can also be turned into NOPs
if it appears that there is no free bits to use.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/kvm_mmu.h | 10 +++++-
arch/arm64/kvm/va_layout.c | 68 +++++++++++++++++++++++++++++++++++++---
virt/kvm/arm/mmu.c | 2 +-
3 files changed, 73 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index cc882e890bb1..4fca6ddadccc 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -85,6 +85,10 @@
.macro kern_hyp_va reg
alternative_cb kvm_update_va_mask
and \reg, \reg, #1
+ ror \reg, \reg, #1
+ add \reg, \reg, #0
+ add \reg, \reg, #0
+ ror \reg, \reg, #63
alternative_cb_end
.endm
@@ -101,7 +105,11 @@ void kvm_update_va_mask(struct alt_instr *alt,
static inline unsigned long __kern_hyp_va(unsigned long v)
{
- asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n",
+ asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n"
+ "ror %0, %0, #1\n"
+ "add %0, %0, #0\n"
+ "add %0, %0, #0\n"
+ "ror %0, %0, #63\n",
kvm_update_va_mask)
: "+r" (v));
return v;
diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c
index 75bb1c6772b0..bf0d6bdf5f14 100644
--- a/arch/arm64/kvm/va_layout.c
+++ b/arch/arm64/kvm/va_layout.c
@@ -16,11 +16,15 @@
*/
#include <linux/kvm_host.h>
+#include <linux/random.h>
+#include <linux/memblock.h>
#include <asm/alternative.h>
#include <asm/debug-monitors.h>
#include <asm/insn.h>
#include <asm/kvm_mmu.h>
+static u8 tag_lsb;
+static u64 tag_val;
static u64 va_mask;
static void compute_layout(void)
@@ -32,8 +36,31 @@ static void compute_layout(void)
region = idmap_addr & BIT(VA_BITS - 1);
region ^= BIT(VA_BITS - 1);
- va_mask = BIT(VA_BITS - 1) - 1;
- va_mask |= region;
+ tag_lsb = fls64((u64)phys_to_virt(memblock_start_of_DRAM()) ^
+ (u64)(high_memory - 1));
+
+ if (tag_lsb == (VA_BITS - 1)) {
+ /*
+ * No space in the address, let's compute the mask so
+ * that it covers (VA_BITS - 1) bits, and the region
+ * bit. The tag is set to zero.
+ */
+ tag_lsb = tag_val = 0;
+ va_mask = BIT(VA_BITS - 1) - 1;
+ va_mask |= region;
+ } else {
+ /*
+ * We do have some free bits. Let's have the mask to
+ * cover the low bits of the VA, and the tag to
+ * contain the random stuff plus the region bit.
+ */
+ u64 mask = GENMASK_ULL(VA_BITS - 2, tag_lsb);
+
+ va_mask = BIT(tag_lsb) - 1;
+ tag_val = get_random_long() & mask;
+ tag_val |= region;
+ tag_val >>= tag_lsb;
+ }
}
static u32 compute_instruction(int n, u32 rd, u32 rn)
@@ -46,6 +73,33 @@ static u32 compute_instruction(int n, u32 rd, u32 rn)
AARCH64_INSN_VARIANT_64BIT,
rn, rd, va_mask);
break;
+
+ case 1:
+ /* ROR is a variant of EXTR with Rm = Rn */
+ insn = aarch64_insn_gen_extr(AARCH64_INSN_VARIANT_64BIT,
+ rn, rn, rd,
+ tag_lsb);
+ break;
+
+ case 2:
+ insn = aarch64_insn_gen_add_sub_imm(rd, rn,
+ tag_val & (SZ_4K - 1),
+ AARCH64_INSN_VARIANT_64BIT,
+ AARCH64_INSN_ADSB_ADD);
+ break;
+
+ case 3:
+ insn = aarch64_insn_gen_add_sub_imm(rd, rn,
+ tag_val & GENMASK(23, 12),
+ AARCH64_INSN_VARIANT_64BIT,
+ AARCH64_INSN_ADSB_ADD);
+ break;
+
+ case 4:
+ /* ROR is a variant of EXTR with Rm = Rn */
+ insn = aarch64_insn_gen_extr(AARCH64_INSN_VARIANT_64BIT,
+ rn, rn, rd, 64 - tag_lsb);
+ break;
}
return insn;
@@ -56,8 +110,8 @@ void __init kvm_update_va_mask(struct alt_instr *alt,
{
int i;
- /* We only expect a 1 instruction sequence */
- BUG_ON(nr_inst != 1);
+ /* We only expect a 5 instruction sequence */
+ BUG_ON(nr_inst != 5);
if (!has_vhe() && !va_mask)
compute_layout();
@@ -68,8 +122,12 @@ void __init kvm_update_va_mask(struct alt_instr *alt,
/*
* VHE doesn't need any address translation, let's NOP
* everything.
+ *
+ * Alternatively, if we don't have any spare bits in
+ * the address, NOP everything after masking tha
+ * kernel VA.
*/
- if (has_vhe()) {
+ if (has_vhe() || (!tag_lsb && i > 1)) {
updptr[i] = aarch64_insn_gen_nop();
continue;
}
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 14c5e5534f2f..d01c7111b1f7 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -1811,7 +1811,7 @@ int kvm_mmu_init(void)
kern_hyp_va((unsigned long)high_memory - 1));
if (hyp_idmap_start >= kern_hyp_va(PAGE_OFFSET) &&
- hyp_idmap_start < kern_hyp_va(~0UL) &&
+ hyp_idmap_start < kern_hyp_va((unsigned long)high_memory - 1) &&
hyp_idmap_start != (unsigned long)__hyp_idmap_text_start) {
/*
* The idmap page is intersecting with the VA space,
--
2.14.2
^ permalink raw reply related
* [PATCH v4 17/19] arm64: KVM: Dynamically compute the HYP VA mask
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
As we're moving towards a much more dynamic way to compute our
HYP VA, let's express the mask in a slightly different way.
Instead of comparing the idmap position to the "low" VA mask,
we directly compute the mask by taking into account the idmap's
(VA_BIT-1) bit.
No functionnal change.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/kvm/va_layout.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c
index aee758574e61..75bb1c6772b0 100644
--- a/arch/arm64/kvm/va_layout.c
+++ b/arch/arm64/kvm/va_layout.c
@@ -21,24 +21,19 @@
#include <asm/insn.h>
#include <asm/kvm_mmu.h>
-#define HYP_PAGE_OFFSET_HIGH_MASK ((UL(1) << VA_BITS) - 1)
-#define HYP_PAGE_OFFSET_LOW_MASK ((UL(1) << (VA_BITS - 1)) - 1)
-
static u64 va_mask;
static void compute_layout(void)
{
phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
- unsigned long mask = HYP_PAGE_OFFSET_HIGH_MASK;
+ u64 region;
- /*
- * Activate the lower HYP offset only if the idmap doesn't
- * clash with it,
- */
- if (idmap_addr > HYP_PAGE_OFFSET_LOW_MASK)
- mask = HYP_PAGE_OFFSET_HIGH_MASK;
+ /* Where is my RAM region? */
+ region = idmap_addr & BIT(VA_BITS - 1);
+ region ^= BIT(VA_BITS - 1);
- va_mask = mask;
+ va_mask = BIT(VA_BITS - 1) - 1;
+ va_mask |= region;
}
static u32 compute_instruction(int n, u32 rd, u32 rn)
--
2.14.2
^ permalink raw reply related
* [PATCH v4 16/19] arm64: insn: Allow ADD/SUB (immediate) with LSL #12
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
The encoder for ADD/SUB (immediate) can only cope with 12bit
immediates, while there is an encoding for a 12bit immediate shifted
by 12 bits to the left.
Let's fix this small oversight by allowing the LSL_12 bit to be set.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/kernel/insn.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 59669d7d4383..20655537cdd1 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -35,6 +35,7 @@
#define AARCH64_INSN_SF_BIT BIT(31)
#define AARCH64_INSN_N_BIT BIT(22)
+#define AARCH64_INSN_LSL_12 BIT(22)
static int aarch64_insn_encoding_class[] = {
AARCH64_INSN_CLS_UNKNOWN,
@@ -903,9 +904,18 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
return AARCH64_BREAK_FAULT;
}
+ /* We can't encode more than a 24bit value (12bit + 12bit shift) */
+ if (imm & ~(BIT(24) - 1))
+ goto out;
+
+ /* If we have something in the top 12 bits... */
if (imm & ~(SZ_4K - 1)) {
- pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
- return AARCH64_BREAK_FAULT;
+ /* ... and in the low 12 bits -> error */
+ if (imm & (SZ_4K - 1))
+ goto out;
+
+ imm >>= 12;
+ insn |= AARCH64_INSN_LSL_12;
}
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, dst);
@@ -913,6 +923,10 @@ u32 aarch64_insn_gen_add_sub_imm(enum aarch64_insn_register dst,
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, src);
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_12, insn, imm);
+
+out:
+ pr_err("%s: invalid immediate encoding %d\n", __func__, imm);
+ return AARCH64_BREAK_FAULT;
}
u32 aarch64_insn_gen_bitfield(enum aarch64_insn_register dst,
--
2.14.2
^ permalink raw reply related
* [PATCH v4 15/19] arm64; insn: Add encoder for the EXTR instruction
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
Add an encoder for the EXTR instruction, which also implements the ROR
variant (where Rn == Rm).
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/insn.h | 6 ++++++
arch/arm64/kernel/insn.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 815b35bc53ed..f62c56b1793f 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -319,6 +319,7 @@ __AARCH64_INSN_FUNCS(and_imm, 0x7F800000, 0x12000000)
__AARCH64_INSN_FUNCS(orr_imm, 0x7F800000, 0x32000000)
__AARCH64_INSN_FUNCS(eor_imm, 0x7F800000, 0x52000000)
__AARCH64_INSN_FUNCS(ands_imm, 0x7F800000, 0x72000000)
+__AARCH64_INSN_FUNCS(extr, 0x7FA00000, 0x13800000)
__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000)
__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000)
__AARCH64_INSN_FUNCS(cbz, 0x7F000000, 0x34000000)
@@ -433,6 +434,11 @@ u32 aarch64_insn_gen_logical_immediate(enum aarch64_insn_logic_type type,
enum aarch64_insn_register Rn,
enum aarch64_insn_register Rd,
u64 imm);
+u32 aarch64_insn_gen_extr(enum aarch64_insn_variant variant,
+ enum aarch64_insn_register Rm,
+ enum aarch64_insn_register Rn,
+ enum aarch64_insn_register Rd,
+ u8 lsb);
u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
enum aarch64_insn_prfm_type type,
enum aarch64_insn_prfm_target target,
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 72cb1721c63f..59669d7d4383 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -1621,3 +1621,35 @@ u32 aarch64_insn_gen_logical_immediate(enum aarch64_insn_logic_type type,
insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, Rn);
return aarch64_encode_immediate(imm, variant, insn);
}
+
+u32 aarch64_insn_gen_extr(enum aarch64_insn_variant variant,
+ enum aarch64_insn_register Rm,
+ enum aarch64_insn_register Rn,
+ enum aarch64_insn_register Rd,
+ u8 lsb)
+{
+ u32 insn;
+
+ insn = aarch64_insn_get_extr_value();
+
+ switch (variant) {
+ case AARCH64_INSN_VARIANT_32BIT:
+ if (lsb > 31)
+ return AARCH64_BREAK_FAULT;
+ break;
+ case AARCH64_INSN_VARIANT_64BIT:
+ if (lsb > 63)
+ return AARCH64_BREAK_FAULT;
+ insn |= AARCH64_INSN_SF_BIT;
+ insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_N, insn, 1);
+ break;
+ default:
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
+ return AARCH64_BREAK_FAULT;
+ }
+
+ insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_S, insn, lsb);
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, Rd);
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, Rn);
+ return aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RM, insn, Rm);
+}
--
2.14.2
^ permalink raw reply related
* [PATCH v4 14/19] KVM: arm/arm64: Move HYP IO VAs to the "idmap" range
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
We so far mapped our HYP IO (which is essencially the GICv2 control
registers) using the same method as for memory. It recently appeared
that is a bit unsafe:
We compute the HYP VA using the kern_hyp_va helper, but that helper
is only designed to deal with kernel VAs coming from the linear map,
and not from the vmalloc region... This could in turn cause some bad
aliasing between the two, amplified by the upcoming VA randomisation.
A solution is to come up with our very own basic VA allocator for
MMIO. Since half of the HYP address space only contains a single
page (the idmap), we have plenty to borrow from. Let's use the idmap
as a base, and allocate downwards from it. GICv2 now lives on the
other side of the great VA barrier.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/mmu.c | 56 +++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 43 insertions(+), 13 deletions(-)
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 6192d45d1e1a..14c5e5534f2f 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -43,6 +43,9 @@ static unsigned long hyp_idmap_start;
static unsigned long hyp_idmap_end;
static phys_addr_t hyp_idmap_vector;
+static DEFINE_MUTEX(io_map_lock);
+static unsigned long io_map_base;
+
#define S2_PGD_SIZE (PTRS_PER_S2_PGD * sizeof(pgd_t))
#define hyp_pgd_order get_order(PTRS_PER_PGD * sizeof(pgd_t))
@@ -502,27 +505,31 @@ static void unmap_hyp_range(pgd_t *pgdp, phys_addr_t start, u64 size)
*
* Assumes hyp_pgd is a page table used strictly in Hyp-mode and
* therefore contains either mappings in the kernel memory area (above
- * PAGE_OFFSET), or device mappings in the vmalloc range (from
- * VMALLOC_START to VMALLOC_END).
+ * PAGE_OFFSET), or device mappings in the idmap range.
*
- * boot_hyp_pgd should only map two pages for the init code.
+ * boot_hyp_pgd should only map the idmap range, and is only used in
+ * the extended idmap case.
*/
void free_hyp_pgds(void)
{
+ pgd_t *id_pgd;
+
mutex_lock(&kvm_hyp_pgd_mutex);
+ id_pgd = boot_hyp_pgd ? boot_hyp_pgd : hyp_pgd;
+
+ if (id_pgd)
+ unmap_hyp_range(id_pgd, io_map_base,
+ hyp_idmap_start + PAGE_SIZE - io_map_base);
+
if (boot_hyp_pgd) {
- unmap_hyp_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
free_pages((unsigned long)boot_hyp_pgd, hyp_pgd_order);
boot_hyp_pgd = NULL;
}
if (hyp_pgd) {
- unmap_hyp_range(hyp_pgd, hyp_idmap_start, PAGE_SIZE);
unmap_hyp_range(hyp_pgd, kern_hyp_va(PAGE_OFFSET),
(uintptr_t)high_memory - PAGE_OFFSET);
- unmap_hyp_range(hyp_pgd, kern_hyp_va(VMALLOC_START),
- VMALLOC_END - VMALLOC_START);
free_pages((unsigned long)hyp_pgd, hyp_pgd_order);
hyp_pgd = NULL;
@@ -721,7 +728,8 @@ int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
void __iomem **kaddr,
void __iomem **haddr)
{
- unsigned long start, end;
+ pgd_t *pgd = hyp_pgd;
+ unsigned long base;
int ret;
*kaddr = ioremap(phys_addr, size);
@@ -733,17 +741,38 @@ int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
return 0;
}
+ mutex_lock(&io_map_lock);
+
+ base = io_map_base - size;
+ base &= ~(size - 1);
- start = kern_hyp_va((unsigned long)*kaddr);
- end = kern_hyp_va((unsigned long)*kaddr + size);
- ret = __create_hyp_mappings(hyp_pgd, start, end,
+ /*
+ * Verify that BIT(VA_BITS - 1) hasn't been flipped by
+ * allocating the new area, as it would indicate we've
+ * overflowed the idmap/IO address range.
+ */
+ if ((base ^ io_map_base) & BIT(VA_BITS - 1)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (__kvm_cpu_uses_extended_idmap())
+ pgd = boot_hyp_pgd;
+
+ ret = __create_hyp_mappings(pgd, base, base + size,
__phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
+ if (!ret) {
+ *haddr = (void __iomem *)base;
+ io_map_base = base;
+ }
+
+out:
+ mutex_unlock(&io_map_lock);
+
if (ret) {
iounmap(*kaddr);
*kaddr = NULL;
- } else {
- *haddr = (void __iomem *)start;
}
return ret;
@@ -1826,6 +1855,7 @@ int kvm_mmu_init(void)
goto out;
}
+ io_map_base = hyp_idmap_start;
return 0;
out:
free_hyp_pgds();
--
2.14.2
^ permalink raw reply related
* [PATCH v4 13/19] KVM: arm/arm64: Keep GICv2 HYP VAs in kvm_vgic_global_state
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
As we're about to change the way we map devices at HYP, we need
to move away from kern_hyp_va on an IO address.
One way of achieving this is to store the VAs in kvm_vgic_global_state,
and use that directly from the HYP code. This requires a small change
to create_hyp_io_mappings so that it can also return a HYP VA.
We take this opportunity to nuke the vctrl_base field in the emulated
distributor, as it is not used anymore.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/include/asm/kvm_mmu.h | 3 ++-
arch/arm64/include/asm/kvm_mmu.h | 3 ++-
include/kvm/arm_vgic.h | 12 ++++++------
virt/kvm/arm/hyp/vgic-v2-sr.c | 10 +++-------
virt/kvm/arm/mmu.c | 20 ++++++++++++++++----
virt/kvm/arm/vgic/vgic-init.c | 6 ------
virt/kvm/arm/vgic/vgic-v2.c | 13 +++++++------
7 files changed, 36 insertions(+), 31 deletions(-)
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index cb3bef71ec9b..feff24b34506 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -42,7 +42,8 @@
int create_hyp_mappings(void *from, void *to, pgprot_t prot);
int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
- void __iomem **kaddr);
+ void __iomem **kaddr,
+ void __iomem **haddr);
void free_hyp_pgds(void);
void stage2_unmap_vm(struct kvm *kvm);
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 09a208014457..cc882e890bb1 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -120,7 +120,8 @@ static inline unsigned long __kern_hyp_va(unsigned long v)
int create_hyp_mappings(void *from, void *to, pgprot_t prot);
int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
- void __iomem **kaddr);
+ void __iomem **kaddr,
+ void __iomem **haddr);
void free_hyp_pgds(void);
void stage2_unmap_vm(struct kvm *kvm);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 8c896540a72c..8b3fbc03293b 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -57,11 +57,15 @@ struct vgic_global {
/* Physical address of vgic virtual cpu interface */
phys_addr_t vcpu_base;
- /* GICV mapping */
+ /* GICV mapping, kernel VA */
void __iomem *vcpu_base_va;
+ /* GICV mapping, HYP VA */
+ void __iomem *vcpu_hyp_va;
- /* virtual control interface mapping */
+ /* virtual control interface mapping, kernel VA */
void __iomem *vctrl_base;
+ /* virtual control interface mapping, HYP VA */
+ void __iomem *vctrl_hyp;
/* Number of implemented list registers */
int nr_lr;
@@ -198,10 +202,6 @@ struct vgic_dist {
int nr_spis;
- /* TODO: Consider moving to global state */
- /* Virtual control interface mapping */
- void __iomem *vctrl_base;
-
/* base addresses in guest physical address space: */
gpa_t vgic_dist_base; /* distributor */
union {
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 4573d0552af3..dbd109f3a4ab 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -56,10 +56,8 @@ static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
/* vcpu is already in the HYP VA space */
void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
{
- struct kvm *kvm = kern_hyp_va(vcpu->kvm);
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- struct vgic_dist *vgic = &kvm->arch.vgic;
- void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+ void __iomem *base = hyp_symbol_addr(kvm_vgic_global_state)->vctrl_hyp;
u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
if (!base)
@@ -81,10 +79,8 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
/* vcpu is already in the HYP VA space */
void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
{
- struct kvm *kvm = kern_hyp_va(vcpu->kvm);
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- struct vgic_dist *vgic = &kvm->arch.vgic;
- void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+ void __iomem *base = hyp_symbol_addr(kvm_vgic_global_state)->vctrl_hyp;
int i;
u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
@@ -139,7 +135,7 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
return -1;
rd = kvm_vcpu_dabt_get_rd(vcpu);
- addr = kern_hyp_va(hyp_symbol_addr(kvm_vgic_global_state)->vcpu_base_va);
+ addr = hyp_symbol_addr(kvm_vgic_global_state)->vcpu_hyp_va;
addr += fault_ipa - vgic->vgic_cpu_base;
if (kvm_vcpu_dabt_iswrite(vcpu)) {
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 38adbe0a016c..6192d45d1e1a 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -713,28 +713,40 @@ int create_hyp_mappings(void *from, void *to, pgprot_t prot)
* @phys_addr: The physical start address which gets mapped
* @size: Size of the region being mapped
* @kaddr: Kernel VA for this mapping
+ * @haddr: HYP VA for this mapping
*
- * The resulting HYP VA is the same as the kernel VA, modulo
- * HYP_PAGE_OFFSET.
+ * The resulting HYP VA is completely unrelated to the kernel VA.
*/
int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
- void __iomem **kaddr)
+ void __iomem **kaddr,
+ void __iomem **haddr)
{
unsigned long start, end;
+ int ret;
*kaddr = ioremap(phys_addr, size);
if (!*kaddr)
return -ENOMEM;
if (is_kernel_in_hyp_mode()) {
+ *haddr = *kaddr;
return 0;
}
start = kern_hyp_va((unsigned long)*kaddr);
end = kern_hyp_va((unsigned long)*kaddr + size);
- return __create_hyp_mappings(hyp_pgd, start, end,
+ ret = __create_hyp_mappings(hyp_pgd, start, end,
__phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
+
+ if (ret) {
+ iounmap(*kaddr);
+ *kaddr = NULL;
+ } else {
+ *haddr = (void __iomem *)start;
+ }
+
+ return ret;
}
/**
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c
index 62310122ee78..3f01b5975055 100644
--- a/virt/kvm/arm/vgic/vgic-init.c
+++ b/virt/kvm/arm/vgic/vgic-init.c
@@ -166,12 +166,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
kvm->arch.vgic.in_kernel = true;
kvm->arch.vgic.vgic_model = type;
- /*
- * kvm_vgic_global_state.vctrl_base is set on vgic probe (kvm_arch_init)
- * it is stored in distributor struct for asm save/restore purpose
- */
- kvm->arch.vgic.vctrl_base = kvm_vgic_global_state.vctrl_base;
-
kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
kvm->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index bc49d702f9f0..f0f566e4494e 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -335,7 +335,8 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
ret = create_hyp_io_mappings(info->vcpu.start,
resource_size(&info->vcpu),
- &kvm_vgic_global_state.vcpu_base_va);
+ &kvm_vgic_global_state.vcpu_base_va,
+ &kvm_vgic_global_state.vcpu_hyp_va);
if (ret) {
kvm_err("Cannot map GICV into hyp\n");
goto out;
@@ -346,7 +347,8 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
ret = create_hyp_io_mappings(info->vctrl.start,
resource_size(&info->vctrl),
- &kvm_vgic_global_state.vctrl_base);
+ &kvm_vgic_global_state.vctrl_base,
+ &kvm_vgic_global_state.vctrl_hyp);
if (ret) {
kvm_err("Cannot map VCTRL into hyp\n");
goto out;
@@ -381,15 +383,14 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
void vgic_v2_load(struct kvm_vcpu *vcpu)
{
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
- writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
+ writel_relaxed(cpu_if->vgic_vmcr,
+ kvm_vgic_global_state.vctrl_base + GICH_VMCR);
}
void vgic_v2_put(struct kvm_vcpu *vcpu)
{
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
- cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
+ cpu_if->vgic_vmcr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VMCR);
}
--
2.14.2
^ permalink raw reply related
* [PATCH v4 12/19] KVM: arm/arm64: Move ioremap calls to create_hyp_io_mappings
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
Both HYP io mappings call ioremap, followed by create_hyp_io_mappings.
Let's move the ioremap call into create_hyp_io_mappings itself, which
simplifies the code a bit and allows for further refactoring.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/include/asm/kvm_mmu.h | 3 ++-
arch/arm64/include/asm/kvm_mmu.h | 3 ++-
virt/kvm/arm/mmu.c | 24 ++++++++++++++----------
virt/kvm/arm/vgic/vgic-v2.c | 31 ++++++++-----------------------
4 files changed, 26 insertions(+), 35 deletions(-)
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index fa6f2174276b..cb3bef71ec9b 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -41,7 +41,8 @@
#include <asm/stage2_pgtable.h>
int create_hyp_mappings(void *from, void *to, pgprot_t prot);
-int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
+int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
+ void __iomem **kaddr);
void free_hyp_pgds(void);
void stage2_unmap_vm(struct kvm *kvm);
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index b0c3cbe9b513..09a208014457 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -119,7 +119,8 @@ static inline unsigned long __kern_hyp_va(unsigned long v)
#include <asm/stage2_pgtable.h>
int create_hyp_mappings(void *from, void *to, pgprot_t prot);
-int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
+int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
+ void __iomem **kaddr);
void free_hyp_pgds(void);
void stage2_unmap_vm(struct kvm *kvm);
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 84d09f1a44d4..38adbe0a016c 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -709,26 +709,30 @@ int create_hyp_mappings(void *from, void *to, pgprot_t prot)
}
/**
- * create_hyp_io_mappings - duplicate a kernel IO mapping into Hyp mode
- * @from: The kernel start VA of the range
- * @to: The kernel end VA of the range (exclusive)
+ * create_hyp_io_mappings - Map IO into both kernel and HYP
* @phys_addr: The physical start address which gets mapped
+ * @size: Size of the region being mapped
+ * @kaddr: Kernel VA for this mapping
*
* The resulting HYP VA is the same as the kernel VA, modulo
* HYP_PAGE_OFFSET.
*/
-int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr)
+int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
+ void __iomem **kaddr)
{
- unsigned long start = kern_hyp_va((unsigned long)from);
- unsigned long end = kern_hyp_va((unsigned long)to);
+ unsigned long start, end;
- if (is_kernel_in_hyp_mode())
+ *kaddr = ioremap(phys_addr, size);
+ if (!*kaddr)
+ return -ENOMEM;
+
+ if (is_kernel_in_hyp_mode()) {
return 0;
+ }
- /* Check for a valid kernel IO mapping */
- if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1))
- return -EINVAL;
+ start = kern_hyp_va((unsigned long)*kaddr);
+ end = kern_hyp_va((unsigned long)*kaddr + size);
return __create_hyp_mappings(hyp_pgd, start, end,
__phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
}
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index 80897102da26..bc49d702f9f0 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -332,16 +332,10 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
if (!PAGE_ALIGNED(info->vcpu.start) ||
!PAGE_ALIGNED(resource_size(&info->vcpu))) {
kvm_info("GICV region size/alignment is unsafe, using trapping (reduced performance)\n");
- kvm_vgic_global_state.vcpu_base_va = ioremap(info->vcpu.start,
- resource_size(&info->vcpu));
- if (!kvm_vgic_global_state.vcpu_base_va) {
- kvm_err("Cannot ioremap GICV\n");
- return -ENOMEM;
- }
- ret = create_hyp_io_mappings(kvm_vgic_global_state.vcpu_base_va,
- kvm_vgic_global_state.vcpu_base_va + resource_size(&info->vcpu),
- info->vcpu.start);
+ ret = create_hyp_io_mappings(info->vcpu.start,
+ resource_size(&info->vcpu),
+ &kvm_vgic_global_state.vcpu_base_va);
if (ret) {
kvm_err("Cannot map GICV into hyp\n");
goto out;
@@ -350,26 +344,17 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
static_branch_enable(&vgic_v2_cpuif_trap);
}
- kvm_vgic_global_state.vctrl_base = ioremap(info->vctrl.start,
- resource_size(&info->vctrl));
- if (!kvm_vgic_global_state.vctrl_base) {
- kvm_err("Cannot ioremap GICH\n");
- ret = -ENOMEM;
+ ret = create_hyp_io_mappings(info->vctrl.start,
+ resource_size(&info->vctrl),
+ &kvm_vgic_global_state.vctrl_base);
+ if (ret) {
+ kvm_err("Cannot map VCTRL into hyp\n");
goto out;
}
vtr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR);
kvm_vgic_global_state.nr_lr = (vtr & 0x3f) + 1;
- ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base,
- kvm_vgic_global_state.vctrl_base +
- resource_size(&info->vctrl),
- info->vctrl.start);
- if (ret) {
- kvm_err("Cannot map VCTRL into hyp\n");
- goto out;
- }
-
ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2);
if (ret) {
kvm_err("Cannot register GICv2 KVM device\n");
--
2.14.2
^ permalink raw reply related
* [PATCH v4 11/19] KVM: arm/arm64: Demote HYP VA range display to being a debug feature
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
Displaying the HYP VA information is slightly counterproductive when
using VA randomization. Turn it into a debug feature only, and adjust
the last displayed value to reflect the top of RAM instead of ~0.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/mmu.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index b4b69c2d1012..84d09f1a44d4 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -1760,9 +1760,10 @@ int kvm_mmu_init(void)
*/
BUG_ON((hyp_idmap_start ^ (hyp_idmap_end - 1)) & PAGE_MASK);
- kvm_info("IDMAP page: %lx\n", hyp_idmap_start);
- kvm_info("HYP VA range: %lx:%lx\n",
- kern_hyp_va(PAGE_OFFSET), kern_hyp_va(~0UL));
+ kvm_debug("IDMAP page: %lx\n", hyp_idmap_start);
+ kvm_debug("HYP VA range: %lx:%lx\n",
+ kern_hyp_va(PAGE_OFFSET),
+ kern_hyp_va((unsigned long)high_memory - 1));
if (hyp_idmap_start >= kern_hyp_va(PAGE_OFFSET) &&
hyp_idmap_start < kern_hyp_va(~0UL) &&
--
2.14.2
^ permalink raw reply related
* [PATCH v4 10/19] KVM: arm/arm64: Do not use kern_hyp_va() with kvm_vgic_global_state
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
kvm_vgic_global_state is part of the read-only section, and is
usually accessed using a PC-relative address generation (adrp + add).
It is thus useless to use kern_hyp_va() on it, and actively problematic
if kern_hyp_va() becomes non-idempotent. On the other hand, there is
no way that the compiler is going to guarantee that such access is
always be PC relative.
So let's bite the bullet and provide our own accessor.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/include/asm/kvm_hyp.h | 6 ++++++
arch/arm64/include/asm/kvm_hyp.h | 9 +++++++++
virt/kvm/arm/hyp/vgic-v2-sr.c | 4 ++--
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
index ab20ffa8b9e7..1d42d0aa2feb 100644
--- a/arch/arm/include/asm/kvm_hyp.h
+++ b/arch/arm/include/asm/kvm_hyp.h
@@ -26,6 +26,12 @@
#define __hyp_text __section(.hyp.text) notrace
+#define hyp_symbol_addr(s) \
+ ({ \
+ typeof(s) *addr = &(s); \
+ addr; \
+ })
+
#define __ACCESS_VFP(CRn) \
"mrc", "mcr", __stringify(p10, 7, %0, CRn, cr0, 0), u32
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 08d3bb66c8b7..a2d98c539023 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -25,6 +25,15 @@
#define __hyp_text __section(.hyp.text) notrace
+#define hyp_symbol_addr(s) \
+ ({ \
+ typeof(s) *addr; \
+ asm volatile("adrp %0, %1\n" \
+ "add %0, %0, :lo12:%1\n" \
+ : "=r" (addr) : "S" (&s)); \
+ addr; \
+ })
+
#define read_sysreg_elx(r,nvh,vh) \
({ \
u64 reg; \
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index d7fd46fe9efb..4573d0552af3 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -25,7 +25,7 @@
static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
{
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
- int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
+ int nr_lr = hyp_symbol_addr(kvm_vgic_global_state)->nr_lr;
u32 elrsr0, elrsr1;
elrsr0 = readl_relaxed(base + GICH_ELRSR0);
@@ -139,7 +139,7 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
return -1;
rd = kvm_vcpu_dabt_get_rd(vcpu);
- addr = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va);
+ addr = kern_hyp_va(hyp_symbol_addr(kvm_vgic_global_state)->vcpu_base_va);
addr += fault_ipa - vgic->vgic_cpu_base;
if (kvm_vcpu_dabt_iswrite(vcpu)) {
--
2.14.2
^ permalink raw reply related
* [PATCH v4 09/19] arm64: cpufeatures: Drop the ARM64_HYP_OFFSET_LOW feature flag
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
Now that we can dynamically compute the kernek/hyp VA mask, there
is need for a feature flag to trigger the alternative patching.
Let's drop the flag and everything that depends on it.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/cpucaps.h | 2 +-
arch/arm64/kernel/cpufeature.c | 19 -------------------
2 files changed, 1 insertion(+), 20 deletions(-)
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 2ff7c5e8efab..f130f35dca3c 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -32,7 +32,7 @@
#define ARM64_HAS_VIRT_HOST_EXTN 11
#define ARM64_WORKAROUND_CAVIUM_27456 12
#define ARM64_HAS_32BIT_EL0 13
-#define ARM64_HYP_OFFSET_LOW 14
+/* #define ARM64_UNALLOCATED_ENTRY 14 */
#define ARM64_MISMATCHED_CACHE_LINE_SIZE 15
#define ARM64_HAS_NO_FPSIMD 16
#define ARM64_WORKAROUND_REPEAT_TLBI 17
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index a73a5928f09b..b99f8b1688c3 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -825,19 +825,6 @@ static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused
return is_kernel_in_hyp_mode();
}
-static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry,
- int __unused)
-{
- phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
-
- /*
- * Activate the lower HYP offset only if:
- * - the idmap doesn't clash with it,
- * - the kernel is not running at EL2.
- */
- return idmap_addr > GENMASK(VA_BITS - 2, 0) && !is_kernel_in_hyp_mode();
-}
-
static bool has_no_fpsimd(const struct arm64_cpu_capabilities *entry, int __unused)
{
u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
@@ -926,12 +913,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.field_pos = ID_AA64PFR0_EL0_SHIFT,
.min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT,
},
- {
- .desc = "Reduced HYP mapping offset",
- .capability = ARM64_HYP_OFFSET_LOW,
- .def_scope = SCOPE_SYSTEM,
- .matches = hyp_offset_low,
- },
{
/* FP/SIMD is not implemented */
.capability = ARM64_HAS_NO_FPSIMD,
--
2.14.2
^ permalink raw reply related
* [PATCH v4 08/19] arm64: KVM: Dynamically patch the kernel/hyp VA mask
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
So far, we're using a complicated sequence of alternatives to
patch the kernel/hyp VA mask on non-VHE, and NOP out the
masking altogether when on VHE.
THe newly introduced dynamic patching gives us the opportunity
to simplify that code by patching a single instruction with
the correct mask (instead of the mind bending cummulative masking
we have at the moment) or even a single NOP on VHE.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/kvm_mmu.h | 45 ++++++--------------
arch/arm64/kvm/Makefile | 2 +-
arch/arm64/kvm/va_layout.c | 91 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 104 insertions(+), 34 deletions(-)
create mode 100644 arch/arm64/kvm/va_layout.c
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 672c8684d5c2..b0c3cbe9b513 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -69,9 +69,6 @@
* mappings, and none of this applies in that case.
*/
-#define HYP_PAGE_OFFSET_HIGH_MASK ((UL(1) << VA_BITS) - 1)
-#define HYP_PAGE_OFFSET_LOW_MASK ((UL(1) << (VA_BITS - 1)) - 1)
-
#ifdef __ASSEMBLY__
#include <asm/alternative.h>
@@ -81,28 +78,14 @@
* Convert a kernel VA into a HYP VA.
* reg: VA to be converted.
*
- * This generates the following sequences:
- * - High mask:
- * and x0, x0, #HYP_PAGE_OFFSET_HIGH_MASK
- * nop
- * - Low mask:
- * and x0, x0, #HYP_PAGE_OFFSET_HIGH_MASK
- * and x0, x0, #HYP_PAGE_OFFSET_LOW_MASK
- * - VHE:
- * nop
- * nop
- *
- * The "low mask" version works because the mask is a strict subset of
- * the "high mask", hence performing the first mask for nothing.
- * Should be completely invisible on any viable CPU.
+ * The actual code generation takes place in kvm_update_va_mask, and
+ * the instructions below are only there to reserve the space and
+ * perform the register allocation.
*/
.macro kern_hyp_va reg
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
- and \reg, \reg, #HYP_PAGE_OFFSET_HIGH_MASK
-alternative_else_nop_endif
-alternative_if ARM64_HYP_OFFSET_LOW
- and \reg, \reg, #HYP_PAGE_OFFSET_LOW_MASK
-alternative_else_nop_endif
+alternative_cb kvm_update_va_mask
+ and \reg, \reg, #1
+alternative_cb_end
.endm
#else
@@ -113,18 +96,14 @@ alternative_else_nop_endif
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
+void kvm_update_va_mask(struct alt_instr *alt,
+ __le32 *origptr, __le32 *updptr, int nr_inst);
+
static inline unsigned long __kern_hyp_va(unsigned long v)
{
- asm volatile(ALTERNATIVE("and %0, %0, %1",
- "nop",
- ARM64_HAS_VIRT_HOST_EXTN)
- : "+r" (v)
- : "i" (HYP_PAGE_OFFSET_HIGH_MASK));
- asm volatile(ALTERNATIVE("nop",
- "and %0, %0, %1",
- ARM64_HYP_OFFSET_LOW)
- : "+r" (v)
- : "i" (HYP_PAGE_OFFSET_LOW_MASK));
+ asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n",
+ kvm_update_va_mask)
+ : "+r" (v));
return v;
}
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 87c4f7ae24de..93afff91cb7c 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -16,7 +16,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/e
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arm.o $(KVM)/arm/mmu.o $(KVM)/arm/mmio.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/psci.o $(KVM)/arm/perf.o
-kvm-$(CONFIG_KVM_ARM_HOST) += inject_fault.o regmap.o
+kvm-$(CONFIG_KVM_ARM_HOST) += inject_fault.o regmap.o va_layout.o
kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
kvm-$(CONFIG_KVM_ARM_HOST) += vgic-sys-reg-v3.o
diff --git a/arch/arm64/kvm/va_layout.c b/arch/arm64/kvm/va_layout.c
new file mode 100644
index 000000000000..aee758574e61
--- /dev/null
+++ b/arch/arm64/kvm/va_layout.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 ARM Ltd.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * 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/>.
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/alternative.h>
+#include <asm/debug-monitors.h>
+#include <asm/insn.h>
+#include <asm/kvm_mmu.h>
+
+#define HYP_PAGE_OFFSET_HIGH_MASK ((UL(1) << VA_BITS) - 1)
+#define HYP_PAGE_OFFSET_LOW_MASK ((UL(1) << (VA_BITS - 1)) - 1)
+
+static u64 va_mask;
+
+static void compute_layout(void)
+{
+ phys_addr_t idmap_addr = __pa_symbol(__hyp_idmap_text_start);
+ unsigned long mask = HYP_PAGE_OFFSET_HIGH_MASK;
+
+ /*
+ * Activate the lower HYP offset only if the idmap doesn't
+ * clash with it,
+ */
+ if (idmap_addr > HYP_PAGE_OFFSET_LOW_MASK)
+ mask = HYP_PAGE_OFFSET_HIGH_MASK;
+
+ va_mask = mask;
+}
+
+static u32 compute_instruction(int n, u32 rd, u32 rn)
+{
+ u32 insn = AARCH64_BREAK_FAULT;
+
+ switch (n) {
+ case 0:
+ insn = aarch64_insn_gen_logical_immediate(AARCH64_INSN_LOGIC_AND,
+ AARCH64_INSN_VARIANT_64BIT,
+ rn, rd, va_mask);
+ break;
+ }
+
+ return insn;
+}
+
+void __init kvm_update_va_mask(struct alt_instr *alt,
+ __le32 *origptr, __le32 *updptr, int nr_inst)
+{
+ int i;
+
+ /* We only expect a 1 instruction sequence */
+ BUG_ON(nr_inst != 1);
+
+ if (!has_vhe() && !va_mask)
+ compute_layout();
+
+ for (i = 0; i < nr_inst; i++) {
+ u32 rd, rn, insn, oinsn;
+
+ /*
+ * VHE doesn't need any address translation, let's NOP
+ * everything.
+ */
+ if (has_vhe()) {
+ updptr[i] = aarch64_insn_gen_nop();
+ continue;
+ }
+
+ oinsn = le32_to_cpu(origptr[i]);
+ rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, oinsn);
+ rn = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RN, oinsn);
+
+ insn = compute_instruction(i, rd, rn);
+ BUG_ON(insn == AARCH64_BREAK_FAULT);
+
+ updptr[i] = cpu_to_le32(insn);
+ }
+}
--
2.14.2
^ permalink raw reply related
* [PATCH v4 07/19] arm64: insn: Add encoder for bitwise operations using literals
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
We lack a way to encode operations such as AND, ORR, EOR that take
an immediate value. Doing so is quite involved, and is all about
reverse engineering the decoding algorithm described in the
pseudocode function DecodeBitMasks().
This has been tested by feeding it all the possible literal values
and comparing the output with that of GAS.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/insn.h | 9 +++
arch/arm64/kernel/insn.c | 136 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 145 insertions(+)
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 21fffdd290a3..815b35bc53ed 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -315,6 +315,10 @@ __AARCH64_INSN_FUNCS(eor, 0x7F200000, 0x4A000000)
__AARCH64_INSN_FUNCS(eon, 0x7F200000, 0x4A200000)
__AARCH64_INSN_FUNCS(ands, 0x7F200000, 0x6A000000)
__AARCH64_INSN_FUNCS(bics, 0x7F200000, 0x6A200000)
+__AARCH64_INSN_FUNCS(and_imm, 0x7F800000, 0x12000000)
+__AARCH64_INSN_FUNCS(orr_imm, 0x7F800000, 0x32000000)
+__AARCH64_INSN_FUNCS(eor_imm, 0x7F800000, 0x52000000)
+__AARCH64_INSN_FUNCS(ands_imm, 0x7F800000, 0x72000000)
__AARCH64_INSN_FUNCS(b, 0xFC000000, 0x14000000)
__AARCH64_INSN_FUNCS(bl, 0xFC000000, 0x94000000)
__AARCH64_INSN_FUNCS(cbz, 0x7F000000, 0x34000000)
@@ -424,6 +428,11 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
int shift,
enum aarch64_insn_variant variant,
enum aarch64_insn_logic_type type);
+u32 aarch64_insn_gen_logical_immediate(enum aarch64_insn_logic_type type,
+ enum aarch64_insn_variant variant,
+ enum aarch64_insn_register Rn,
+ enum aarch64_insn_register Rd,
+ u64 imm);
u32 aarch64_insn_gen_prefetch(enum aarch64_insn_register base,
enum aarch64_insn_prfm_type type,
enum aarch64_insn_prfm_target target,
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 7e432662d454..72cb1721c63f 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -1485,3 +1485,139 @@ pstate_check_t * const aarch32_opcode_cond_checks[16] = {
__check_hi, __check_ls, __check_ge, __check_lt,
__check_gt, __check_le, __check_al, __check_al
};
+
+static bool range_of_ones(u64 val)
+{
+ /* Doesn't handle full ones or full zeroes */
+ u64 sval = val >> __ffs64(val);
+
+ /* One of Sean Eron Anderson's bithack tricks */
+ return ((sval + 1) & (sval)) == 0;
+}
+
+static u32 aarch64_encode_immediate(u64 imm,
+ enum aarch64_insn_variant variant,
+ u32 insn)
+{
+ unsigned int immr, imms, n, ones, ror, esz, tmp;
+ u64 mask = ~0UL;
+
+ /* Can't encode full zeroes or full ones */
+ if (!imm || !~imm)
+ return AARCH64_BREAK_FAULT;
+
+ switch (variant) {
+ case AARCH64_INSN_VARIANT_32BIT:
+ if (upper_32_bits(imm))
+ return AARCH64_BREAK_FAULT;
+ esz = 32;
+ break;
+ case AARCH64_INSN_VARIANT_64BIT:
+ insn |= AARCH64_INSN_SF_BIT;
+ esz = 64;
+ break;
+ default:
+ pr_err("%s: unknown variant encoding %d\n", __func__, variant);
+ return AARCH64_BREAK_FAULT;
+ }
+
+ /*
+ * Inverse of Replicate(). Try to spot a repeating pattern
+ * with a pow2 stride.
+ */
+ for (tmp = esz / 2; tmp >= 2; tmp /= 2) {
+ u64 emask = BIT(tmp) - 1;
+
+ if ((imm & emask) != ((imm >> (tmp / 2)) & emask))
+ break;
+
+ esz = tmp;
+ mask = emask;
+ }
+
+ /* N is only set if we're encoding a 64bit value */
+ n = esz == 64;
+
+ /* Trim imm to the element size */
+ imm &= mask;
+
+ /* That's how many ones we need to encode */
+ ones = hweight64(imm);
+
+ /*
+ * imms is set to (ones - 1), prefixed with a string of ones
+ * and a zero if they fit. Cap it to 6 bits.
+ */
+ imms = ones - 1;
+ imms |= 0xf << ffs(esz);
+ imms &= BIT(6) - 1;
+
+ /* Compute the rotation */
+ if (range_of_ones(imm)) {
+ /*
+ * Pattern: 0..01..10..0
+ *
+ * Compute how many rotate we need to align it right
+ */
+ ror = __ffs64(imm);
+ } else {
+ /*
+ * Pattern: 0..01..10..01..1
+ *
+ * Fill the unused top bits with ones, and check if
+ * the result is a valid immediate (all ones with a
+ * contiguous ranges of zeroes).
+ */
+ imm |= ~mask;
+ if (!range_of_ones(~imm))
+ return AARCH64_BREAK_FAULT;
+
+ /*
+ * Compute the rotation to get a continuous set of
+ * ones, with the first bit set@position 0
+ */
+ ror = fls(~imm);
+ }
+
+ /*
+ * immr is the number of bits we need to rotate back to the
+ * original set of ones. Note that this is relative to the
+ * element size...
+ */
+ immr = (esz - ror) % esz;
+
+ insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_N, insn, n);
+ insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_R, insn, immr);
+ return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_S, insn, imms);
+}
+
+u32 aarch64_insn_gen_logical_immediate(enum aarch64_insn_logic_type type,
+ enum aarch64_insn_variant variant,
+ enum aarch64_insn_register Rn,
+ enum aarch64_insn_register Rd,
+ u64 imm)
+{
+ u32 insn;
+
+ switch (type) {
+ case AARCH64_INSN_LOGIC_AND:
+ insn = aarch64_insn_get_and_imm_value();
+ break;
+ case AARCH64_INSN_LOGIC_ORR:
+ insn = aarch64_insn_get_orr_imm_value();
+ break;
+ case AARCH64_INSN_LOGIC_EOR:
+ insn = aarch64_insn_get_eor_imm_value();
+ break;
+ case AARCH64_INSN_LOGIC_AND_SETFLAGS:
+ insn = aarch64_insn_get_ands_imm_value();
+ break;
+ default:
+ pr_err("%s: unknown logical encoding %d\n", __func__, type);
+ return AARCH64_BREAK_FAULT;
+ }
+
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RD, insn, Rd);
+ insn = aarch64_insn_encode_register(AARCH64_INSN_REGTYPE_RN, insn, Rn);
+ return aarch64_encode_immediate(imm, variant, insn);
+}
--
2.14.2
^ permalink raw reply related
* [PATCH v4 06/19] arm64: insn: Add N immediate encoding
From: Marc Zyngier @ 2018-01-04 18:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104184334.16571-1-marc.zyngier@arm.com>
We're missing the a way to generate the encoding of the N immediate,
which is only a single bit used in a number of instruction that take
an immediate.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm64/include/asm/insn.h | 1 +
arch/arm64/kernel/insn.c | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 4214c38d016b..21fffdd290a3 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -70,6 +70,7 @@ enum aarch64_insn_imm_type {
AARCH64_INSN_IMM_6,
AARCH64_INSN_IMM_S,
AARCH64_INSN_IMM_R,
+ AARCH64_INSN_IMM_N,
AARCH64_INSN_IMM_MAX
};
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 2718a77da165..7e432662d454 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -343,6 +343,10 @@ static int __kprobes aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type,
mask = BIT(6) - 1;
shift = 16;
break;
+ case AARCH64_INSN_IMM_N:
+ mask = 1;
+ shift = 22;
+ break;
default:
return -EINVAL;
}
--
2.14.2
^ 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