Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 2/3] clocksource: keystone: add bindings for keystone timer
From: Ivan Khoronzhuk @ 2014-02-05 16:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAL_JsqKVc2fdg1Q+TH6ro9kpJmUYyHw8FCwhORfm2_oj6GYM2Q@mail.gmail.com>


On 02/05/2014 04:39 PM, Rob Herring wrote:
> On Wed, Feb 5, 2014 at 7:47 AM, Ivan Khoronzhuk <ivan.khoronzhuk@ti.com> wrote:
>> This patch provides bindings for the 64-bit timer in the KeyStone
>> architecture devices. The timer can be configured as a general-purpose 64-bit
>> timer, dual general-purpose 32-bit timers. When configured as dual 32-bit
>> timers, each half can operate in conjunction (chain mode) or independently
>> (unchained mode) of each other.
> This is software configurable or h/w design time configurations?
>
> Rob
>

This is h/w design time configurations

-- 
Regards,
Ivan Khoronzhuk

^ permalink raw reply

* [PATCH 1/6] i2c: bcm-kona: register with subsys_initcall
From: Matt Porter @ 2014-02-05 16:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <Pine.LNX.4.44L0.1402051028350.1312-100000@iolanthe.rowland.org>

On Wed, Feb 05, 2014 at 10:30:29AM -0500, Alan Stern wrote:
> On Wed, 5 Feb 2014, Matt Porter wrote:
> 
> > On Wed, Feb 05, 2014 at 10:08:18AM +0100, Wolfram Sang wrote:
> > > On Tue, Feb 04, 2014 at 07:19:07AM -0500, Matt Porter wrote:
> > > 
> > > > Voltage regulators are needed very early due to deferred probe
> > > > being incompatible with built-in USB gadget drivers.
> > > 
> > > What does it need to fix those instead?
> > 
> > [added Alan/Felipe for more insight]
> > 
> > Discussion on that topic came about from this submission:
> > http://www.spinics.net/lists/linux-usb/msg94217.html
> > 
> > End of it is:
> > http://www.spinics.net/lists/linux-usb/msg94731.html
> > 
> > We can either add to the many drivers that already do subsys_initcall()
> > for similar reasons...or I can drop this from the series and add gadget
> > probe ordering to my TODO list.
> > 
> > In short, it can't be a late_initcall() hack like the original post and
> > really could be solved by converting to a real bus (and letting
> > deferred probe do its job)..but Alan voiced concerns about that.
> 
> Don't worry too much about what I said.  If adding a "gadget" bus will 
> solve the problem in an appropriate way, and if nobody else objects 
> (particularly Felipe, who is on vacation now), then go for it.

Ok, I'll take a look at what can be done and restart the conversation
when Felipe returns.

Wolfram: given this, as I mentioned, I'll simply drop this patch from
the series and work around it for now. This will probably make Lee and
Mark happy to not see subsys_initcall() in the MFD/regulator drivers as
well.

-Matt

^ permalink raw reply

* [PATCH] PCI: MVEBU: Use Device ID and revision from underlying endpoint
From: Thomas Petazzoni @ 2014-02-05 16:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391597749-29807-1-git-send-email-andrew@lunn.ch>

Dear Andrew Lunn,

On Wed,  5 Feb 2014 11:55:49 +0100, Andrew Lunn wrote:
> Marvell SoCs place the SoC number into the PCIe endpoint device ID.
> The SoC stepping is placed into the PCIe revision. The old plat-orion
> PCIe driver allowed this information to be seen in user space with a
> simple lspci command.
> 
> The new driver places a virtual PCI-PCI bridge on top of these
> endpoints. It has its own hard coded PCI device ID. Thus it is no
> longer possible to see what the SoC is using lspci.
> 
> When initializing the PCI-PCI bridge, set its device ID and revision
> from the underlying endpoint, thus restoring this functionality.
> Debian would like to use this in order to aid installing the correct
> DTB file.
> 
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
> ---
>  drivers/pci/host/pci-mvebu.c | 11 ++---------
>  1 file changed, 2 insertions(+), 9 deletions(-)

Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>

I have two comments below, though.

> 
> diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
> index 13478ecd4113..0e79665afd44 100644
> --- a/drivers/pci/host/pci-mvebu.c
> +++ b/drivers/pci/host/pci-mvebu.c
> @@ -60,14 +60,6 @@
>  #define PCIE_DEBUG_CTRL         0x1a60
>  #define  PCIE_DEBUG_SOFT_RESET		BIT(20)
>  
> -/*
> - * This product ID is registered by Marvell, and used when the Marvell
> - * SoC is not the root complex, but an endpoint on the PCIe bus. It is
> - * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
> - * bridge.
> - */
> -#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
> -
>  /* PCI configuration space of a PCI-to-PCI bridge */
>  struct mvebu_sw_pci_bridge {
>  	u16 vendor;
> @@ -388,7 +380,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
>  
>  	bridge->class = PCI_CLASS_BRIDGE_PCI;
>  	bridge->vendor = PCI_VENDOR_ID_MARVELL;

This could also have been replaced by:

	bridge->vendor = mvebu_readl(port, PCIE_DEV_ID_OFF) & 0xff;

> -	bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
> +	bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
> +	bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;

On Armada 370 and XP, this field is apparently always 0x0, so not very
useful. But if it's useful on other mvebu SoCs, that's fine, it's just
an informative field anyway.

Thanks!

Thomas
-- 
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply

* [RFC/RFT 1/2] ARM: mm: introduce arch hooks for dma address translation routines
From: Dave Martin @ 2014-02-05 16:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <3284212.inOfNqnVqs@wuerfel>

On Tue, Feb 04, 2014 at 06:04:56PM +0100, Arnd Bergmann wrote:
> On Tuesday 04 February 2014 11:38:32 Santosh Shilimkar wrote:
> > On Tuesday 04 February 2014 11:15 AM, Arnd Bergmann wrote:
> > > On Tuesday 04 February 2014, Santosh Shilimkar wrote:
> 
> > > I think this is going into a wrong direction. DMA translation is not
> > > at all a platform-specific thing, but rather bus specific. The most
> > > common scenario is that you have some 64-bit capable buses and some
> > > buses that are limited to 32-bit DMA (or less if you are unfortunate).
> > >
> > I may be wrong but you could have 64 bit bus but 32 bit DMA controllers.
> > That is one of the case I am dealing with.
> 
> You are absolutely right. In fact you could have any combination of
> bus widths between a device and the RAM and the correct way to deal
> with this is probably to follow the dma-ranges properties of each
> device in-between and take the intersection (that may not be the
> right term in English, but I think you know what I mean).
> 
> > > I guess for the legacy cases (omap1, iop13xx, ks8695), we can
> > > hardcode dma_map_ops for all devices to get this right. For everything
> > > else, I'd suggest defaulting to the arm_dma_ops unless we get
> > > other information from DT. This means we have to create standardized
> > > properties to handle any combination of these:
> > > 
> > Thats the case and the $subject series doesn't change that.
> > 
> > > 1. DMA is coherent
> > > 2. DMA space is offset from phys space
> > > 3. DMA space is smaller than 32-bit
> > > 4. DMA space is larger than 32-bit
> > > 5. DMA goes through an IOMMU

As you explain above, these are properties of end-to-end paths between
a bus-mastering device and the destination.  They aren't properties
of a device, or of a bus.

For example, we can have the following system, which ePAPR can't describe
and wouldn't occur with PCI (or, at least would occur in a transparent
way so that software does not need to understand the difference between
this structure and a simple CPU->devices tree).

     C
     |
     v
     I ---+
    / \    \  
   /   \    \ 
  v     v    \
 A ----> B    \
  \            v
   +---------> D

This follows from the unidirectional and minimalistic nature of ARM SoC
buses (AMBA family, AHB, APB etc. ... and most likely many others too).

To describe A's DMA mappings correctly, the additional links must be
described, even though thay are irrelevant for direct CPU->device
transactions.


> > > 
> > > The dma-ranges property can deal with 2-4. Highbank already introduced
> > > a "dma-coherent" flag for 1, and we can decide to generalize that.
> > > I don't know what the state of IOMMU support is, but we have to come
> > > up with something better than what we had on PowerPC, because we now
> > > have to deal with a combination of different IOMMUs in the same system,
> > > whereas the most complex case on PowerPC was some devices all going
> > > through one IOMMU and the other devices being linearly mapped.
> > > 
> > Just to be clear, the patch set is not fiddling with dma_ops as such.
> > The dma_ops needs few accessors to convert addresses and these accessors
> > are different on few platforms. And hence needs to be patched.
> 
> well, iop13xx is certainly not going to be multiplatform any time
> soon, so we don't have to worry about those. ks8695 won't be multiplatform
> unless I do it I suspect. I don't know about the plans for OMAP1,
> but since only the OHCI device is special there, it would be trivial
> to do a separate dma_map_ops for that device, or to extend arm_dma_ops
> to read the offset in a per-device variable as we probably have to
> do for DT/multiplatform as well.
> 
> > We will try to look at "dma-ranges" to see if it can address my case.
> > Thanks for the pointer

dma-ranges does work for simpler cases.  In particular, it works where all
bus-mastering children of a bus node can a) access each other using the
address space of the bus node, and b) all have the same view of the rest
of the system (which may be different from the view from outside the bus:
the dma-ranges property on the bus describes the difference).

Sometimes, we may be able to describe an otherwise undescribable situation
by introducing additional fake bus nodes.  But if there are cross-links
between devices, this won't always work.


This may not be the common case, but it does happen: we need to decide
whether to describe it propertly, or to describe a fantasy in the DT
and bodge around it elsewhere when it happens.


Similarly, for IOMMU, the ARM SMMU is an independent component which is
not directly associated with a bus: nor is there guaranteed to be a 1:1
correspondence.  Simply wedging properties in a bus or device node to say
"this is associated with an IOMMU" is not always going to work:  it is
what you flow through on a given device->device path that matters, and
that can vary from path to path.


Santosh, bearing these arguments in mind, do you think that dma-ranges
is natural for your hardware?

The answer may be "yes", but if we're having to twist things to fit,
by having to describe something fake or unreal in DT and/or writing board
specific code to work around it, that motivates coming up with a better
way of describing the hardware in these cases.

I believe Jason also has examples of these issues from the Zynq family
of SoCs, which we were discussing last year.

Cheers
---Dave

^ permalink raw reply

* [PATCH v2] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Srikanth Thokala @ 2014-02-05 16:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+mB=1K8Cqe_c6_ce-fLyphvqcr90mhCjFdZ_d4BV-VkUk-gXw@mail.gmail.com>

On Fri, Jan 31, 2014 at 12:21 PM, Srikanth Thokala <sthokal@xilinx.com> wrote:
> Hi Vinod,
>
> On Tue, Jan 28, 2014 at 8:43 AM, Vinod Koul <vinod.koul@intel.com> wrote:
>> On Mon, Jan 27, 2014 at 06:42:36PM +0530, Srikanth Thokala wrote:
>>> Hi Lars/Vinod,
>>> >> The question here i think would be waht this device supports? Is the hardware
>>> >> capable of doing interleaved transfers, then would make sense.
>>> >
>>> > The hardware does 2D transfers. The parameters for a transfer are height,
>>> > width and stride. That's only a subset of what interleaved transfers can be
>>> > (xt->num_frames must be one for 2d transfers). But if I remember correctly
>>> > there has been some discussion on this in the past and the result of that
>>> > discussion was that using interleaved transfers for 2D transfers is
>>> > preferred over adding a custom API for 2D transfers.
>>>
>>> I went through the prep_interleaved_dma API and I see only one descriptor
>>> is prepared per API call (i.e. per frame).  As our IP supports upto 16 frame
>>> buffers (can be more in future), isn't it less efficient compared to the
>>> prep_slave_sg where we get a single sg list and can prepare all the descriptors
>>> (of non-contiguous buffers) in one go?  Correct me, if am wrong and let me
>>> know your opinions.
>> Well the descriptor maybe one, but that can represent multiple frames, for
>> example 16 as in your case. Can you read up the documentation of how multiple
>> frames are passed. Pls see include/linux/dmaengine.h
>>
>> /**
>>  * Interleaved Transfer Request
>>  * ----------------------------
>>  * A chunk is collection of contiguous bytes to be transfered.
>>  * The gap(in bytes) between two chunks is called inter-chunk-gap(ICG).
>>  * ICGs may or maynot change between chunks.
>>  * A FRAME is the smallest series of contiguous {chunk,icg} pairs,
>>  *  that when repeated an integral number of times, specifies the transfer.
>>  * A transfer template is specification of a Frame, the number of times
>>  *  it is to be repeated and other per-transfer attributes.
>>  *
>>  * Practically, a client driver would have ready a template for each
>>  *  type of transfer it is going to need during its lifetime and
>>  *  set only 'src_start' and 'dst_start' before submitting the requests.
>>  *
>>  *
>>  *  |      Frame-1        |       Frame-2       | ~ |       Frame-'numf'  |
>>  *  |====....==.===...=...|====....==.===...=...| ~ |====....==.===...=...|
>>  *
>>  *    ==  Chunk size
>>  *    ... ICG
>>  */
>
> Yes, it can handle multiple frames specified by 'numf' each of size
> 'frame_size * sgl[0].size'.
> But, I see it only works if all the frames' memory is contiguous and
> in this case we
> can just increment 'src_start' by the total frame size 'numf' number
> of times to fill in
> for each HW descriptor (each frame is one HW descriptor).  So, there
> is no issue when the
> memory is contiguous.  If the frames are non contiguous, we have to
> call this API for each
> frame (hence for each descriptor), as the src_start for each frame is
> different.  Is it correct?
>
> FYI: This hardware has an inbuilt Scatter-Gather engine.
>

Ping?


> Srikanth
>
>>
>> --
>> ~Vinod
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* [PATCH 5/5] ARM: tegra: cpuidle: use firmware call for power down
From: Stephen Warren @ 2014-02-05 16:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAAVeFuKLtC62+bujY4724hMV_6M8Ow0s=6zRn_M87VX4PHQgxA@mail.gmail.com>

On 01/23/2014 12:39 AM, Alexandre Courbot wrote:
> On Thu, Jan 23, 2014 at 5:45 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 01/21/2014 03:10 AM, Alexandre Courbot wrote:
>>> Invoke the do_idle() firmware call before suspending a CPU so that the
>>> underlying firmware (if any) can take necessary action.
>>
>>> diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c
>>
>>> @@ -45,6 +46,8 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev,
>>>
>>>       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
>>>
>>> +     call_firmware_op(do_idle);
>>> +
>>>       cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
>>>
>>>       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
>>
>> Don't you need to have the kernel also *not* do something when entering
>> idle; doesn't the FW op replace some of the register writes that the
>> kernel would otherwise be doing?
> 
> It seems like the operation is actually to inform the firmware that we
> are going to suspend the CPU. Downstream kernel also uses it that way.
> But you are right in that we should expect do_idle() to actually
> perform the suspend operation. Maybe a prepare_idle() operation should
> be added to the firmware interface for this purpose?

That sounds like a reasonable change. Is it easy to plumb in?

^ permalink raw reply

* [PATCH v2] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Lars-Peter Clausen @ 2014-02-05 16:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+mB=1L9XFC8h_qW_-K-cv5sYondL_0NiLr=9XCFxwWRjDHn1Q@mail.gmail.com>

On 02/05/2014 05:25 PM, Srikanth Thokala wrote:
> On Fri, Jan 31, 2014 at 12:21 PM, Srikanth Thokala <sthokal@xilinx.com> wrote:
>> Hi Vinod,
>>
>> On Tue, Jan 28, 2014 at 8:43 AM, Vinod Koul <vinod.koul@intel.com> wrote:
>>> On Mon, Jan 27, 2014 at 06:42:36PM +0530, Srikanth Thokala wrote:
>>>> Hi Lars/Vinod,
>>>>>> The question here i think would be waht this device supports? Is the hardware
>>>>>> capable of doing interleaved transfers, then would make sense.
>>>>>
>>>>> The hardware does 2D transfers. The parameters for a transfer are height,
>>>>> width and stride. That's only a subset of what interleaved transfers can be
>>>>> (xt->num_frames must be one for 2d transfers). But if I remember correctly
>>>>> there has been some discussion on this in the past and the result of that
>>>>> discussion was that using interleaved transfers for 2D transfers is
>>>>> preferred over adding a custom API for 2D transfers.
>>>>
>>>> I went through the prep_interleaved_dma API and I see only one descriptor
>>>> is prepared per API call (i.e. per frame).  As our IP supports upto 16 frame
>>>> buffers (can be more in future), isn't it less efficient compared to the
>>>> prep_slave_sg where we get a single sg list and can prepare all the descriptors
>>>> (of non-contiguous buffers) in one go?  Correct me, if am wrong and let me
>>>> know your opinions.
>>> Well the descriptor maybe one, but that can represent multiple frames, for
>>> example 16 as in your case. Can you read up the documentation of how multiple
>>> frames are passed. Pls see include/linux/dmaengine.h
>>>
>>> /**
>>>   * Interleaved Transfer Request
>>>   * ----------------------------
>>>   * A chunk is collection of contiguous bytes to be transfered.
>>>   * The gap(in bytes) between two chunks is called inter-chunk-gap(ICG).
>>>   * ICGs may or maynot change between chunks.
>>>   * A FRAME is the smallest series of contiguous {chunk,icg} pairs,
>>>   *  that when repeated an integral number of times, specifies the transfer.
>>>   * A transfer template is specification of a Frame, the number of times
>>>   *  it is to be repeated and other per-transfer attributes.
>>>   *
>>>   * Practically, a client driver would have ready a template for each
>>>   *  type of transfer it is going to need during its lifetime and
>>>   *  set only 'src_start' and 'dst_start' before submitting the requests.
>>>   *
>>>   *
>>>   *  |      Frame-1        |       Frame-2       | ~ |       Frame-'numf'  |
>>>   *  |====....==.===...=...|====....==.===...=...| ~ |====....==.===...=...|
>>>   *
>>>   *    ==  Chunk size
>>>   *    ... ICG
>>>   */
>>
>> Yes, it can handle multiple frames specified by 'numf' each of size
>> 'frame_size * sgl[0].size'.
>> But, I see it only works if all the frames' memory is contiguous and
>> in this case we
>> can just increment 'src_start' by the total frame size 'numf' number
>> of times to fill in
>> for each HW descriptor (each frame is one HW descriptor).  So, there
>> is no issue when the
>> memory is contiguous.  If the frames are non contiguous, we have to
>> call this API for each
>> frame (hence for each descriptor), as the src_start for each frame is
>> different.  Is it correct?
>>
>> FYI: This hardware has an inbuilt Scatter-Gather engine.
>>
>
> Ping?

If you want to submit multiple frames at once I think you should look at how 
the current dmaengine API can be extended to allow that. And also provide an 
explanation on how this is superior over submitting them one by one.

- Lars

^ permalink raw reply

* [PATCH 0/2] Add Ether's PHY IRQ support for Lager/Koelsh boards
From: Sergei Shtylyov @ 2014-02-05 16:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CANqRtoRj9EVVZ+0Xx+7cm8s2=iBOfgNUXXR7uS=T-fKBUkczsw@mail.gmail.com>

Hello.

On 02/05/2014 10:25 AM, Magnus Damm wrote:

>>     Here's the set of 2 patches against Simon Horman's 'renesas.git' repo,
>> 'renesas-devel-v3.14-rc1-20130204' tag. Here we add support for the Ether's PHY
>> IRQ to the R8A7790/Lager and R8A7791/Koelsch boards.

>> [1/2] ARM: shmobile: Lager: pass Ether PHY IRQ
>> [1/2] ARM: shmobile: Koelsch: pass Ether PHY IRQ

> Thanks, looking good!

    Not at all, you've already tested these patches, IIRC.

> / magnus

WBR, Sergei

^ permalink raw reply

* [PATCHv9 1/4] clk: socfpga: Add a clk-phase property to the "altr, socfpga-gate-clk"
From: Dinh Nguyen @ 2014-02-05 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140205160350.22158.37384@quantum>

On Wed, 2014-02-05 at 08:03 -0800, Mike Turquette wrote:
> Quoting Dinh Nguyen (2014-01-15 04:36:52)
> > Hi Mike,
> > 
> > Can you apply this to your clk tree?
> 
> The patch looks good to me, but I think it depends on your pending pull
> request. Can you add this to that pull request and rebase it to
> 3.14-rc1?

Yes, I will send an updated pull request shortly.

Thanks,
Dinh
> 
> Thanks,
> Mike
> 
> > 
> > Thanks,
> > Dinh
> > 
> 

^ permalink raw reply

* [PATCH] PCI: MVEBU: Use Device ID and revision from underlying endpoint
From: Andrew Lunn @ 2014-02-05 16:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140205172110.22507687@skate>

> > @@ -388,7 +380,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
> >  
> >  	bridge->class = PCI_CLASS_BRIDGE_PCI;
> >  	bridge->vendor = PCI_VENDOR_ID_MARVELL;
> 
> This could also have been replaced by:
> 
> 	bridge->vendor = mvebu_readl(port, PCIE_DEV_ID_OFF) & 0xff;

O.K, but do we ever expect it not to be PCI_VENDOR_ID_MARVELL on the
underlying hardware?

> 
> > -	bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
> > +	bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
> > +	bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
> 
> On Armada 370 and XP, this field is apparently always 0x0, so not very
> useful. But if it's useful on other mvebu SoCs, that's fine, it's just
> an informative field anyway.

Humm, that should be the stepping, unless i have made a mistake. The
code Gregory wrote for mvebu-soc-id.c does:

       /* SoC ID */
        soc_dev_id = readl(pci_base + PCIE_DEV_ID_OFF) >> 16;

        /* SoC revision */
        soc_rev = readl(pci_base + PCIE_DEV_REV_OFF) & SOC_REV_MASK;

However, the box i'm testing on has stepping 0, so it is hard to test.
Could you test this in an OpenBlocks AX3 B0, or some other B0 device?

Thanks
	Andrew

^ permalink raw reply

* [PATCH] PCI: MVEBU: Use Device ID and revision from underlying endpoint
From: Thomas Petazzoni @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140205165432.GD29860@lunn.ch>

Dear Andrew Lunn,

On Wed, 5 Feb 2014 17:54:32 +0100, Andrew Lunn wrote:
> > > @@ -388,7 +380,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
> > >  
> > >  	bridge->class = PCI_CLASS_BRIDGE_PCI;
> > >  	bridge->vendor = PCI_VENDOR_ID_MARVELL;
> > 
> > This could also have been replaced by:
> > 
> > 	bridge->vendor = mvebu_readl(port, PCIE_DEV_ID_OFF) & 0xff;
> 
> O.K, but do we ever expect it not to be PCI_VENDOR_ID_MARVELL on the
> underlying hardware?

No, I don't expect it to be different. Which is why I said it "could"
have been replaced, because I am not sure it is worth doing it.

> > > -	bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
> > > +	bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
> > > +	bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
> > 
> > On Armada 370 and XP, this field is apparently always 0x0, so not very
> > useful. But if it's useful on other mvebu SoCs, that's fine, it's just
> > an informative field anyway.
> 
> Humm, that should be the stepping, unless i have made a mistake. The
> code Gregory wrote for mvebu-soc-id.c does:
> 
>        /* SoC ID */
>         soc_dev_id = readl(pci_base + PCIE_DEV_ID_OFF) >> 16;
> 
>         /* SoC revision */
>         soc_rev = readl(pci_base + PCIE_DEV_REV_OFF) & SOC_REV_MASK;
> 
> However, the box i'm testing on has stepping 0, so it is hard to test.
> Could you test this in an OpenBlocks AX3 B0, or some other B0 device?

Tested on a B0 now, and the revision returned is indeed 0x2, so you're
correct. Seems like the datasheet that indicates the value is 0x0 is
wrong :)

Thanks!

Thomas
-- 
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH 00/22] arm/arm64: UEFI stubs + runtime services
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel

This is a combined set of patches for the arm and arm64 kernel
support for UEFI firmware.

The set depends on the following prerequisite sets:
- Laura Abbott's 'Remove ARM meminfo'
- Matt Fleming's 'Move facility flags to struct efi'
- Mark Salter's  'Generic fixmap'
- Mark Salter's  'Generic early_ioremap'
- Mark Salter's  'EFI memory map iteration helper'

All of these are held on top of 3.14-rc1, with the patches in this set,
in git://git.linaro.org/people/leif.lindholm/linux.git, rebasing branch
uefi-for-upstream.

New in this version:
- Much more stub code shared arm/arm64.
- Stub looks in configuration tables for DT.
- Stub creates empty DT if none found/specified.
- Stub ignores dtb= option when UEFI Secure Boot active.
- Stub deletes any memory nodes in DT.
- Kernel sets up available RAM for memblock from UEFI memory map.
  (So no longer need different DTs or command line parameters for
   otherwise identical platforms with different amounts of RAM.)
- arm64 now compatible with 64K pages (with 4K UEFI page size).
- Fix mapping of runtime mmio regions on arm64.
- Reworked update_sctlr asm macro.
- Various cleanup and style fixes.

---

Ard Biesheuvel (1):
  arm: efistub: ignore dtb= when UEFI SecureBoot is enabled

H. Peter Anvin (1):
  Improve cmdline conversion

Leif Lindholm (6):
  arm: break part of __soft_restart out into separate function
  arm: add new asm macro update_sctlr
  Documentation: arm: add UEFI support documentation
  arm: Add [U]EFI runtime services support
  init: efi: arm: enable (U)EFI runtime services on arm
  arm: update boot/compressed/.gitignore

Mark Salter (6):
  efi: add helper function to get UEFI params from FDT
  lib: add fdt_empty_tree.c
  arm64: Add function to create identity mappings
  arm64: add EFI stub
  doc: arm64: add description of EFI stub support
  arm64: add EFI runtime services

Roy Franz (8):
  efi-stub.txt updates for ARM
  Add shared printk wrapper for consistent prefixing
  Add helper functions used by arm/arm64
  Add shared FDT related functions for ARM/ARM64
  Add strstr to compressed string.c for ARM.
  Add shared arm/arm64 EFI stub
  Add EFI stub for ARM
  Disable stack protection for decompressor/stub

 Documentation/arm/00-INDEX             |    3 +
 Documentation/arm/uefi.txt             |   64 +++++
 Documentation/arm64/booting.txt        |    4 +
 Documentation/efi-stub.txt             |   33 ++-
 arch/arm/Kconfig                       |   27 ++
 arch/arm/boot/compressed/.gitignore    |    3 +
 arch/arm/boot/compressed/Makefile      |   19 +-
 arch/arm/boot/compressed/efi-header.S  |  117 ++++++++
 arch/arm/boot/compressed/efi-stub.c    |  118 ++++++++
 arch/arm/boot/compressed/efi-stub.h    |    5 +
 arch/arm/boot/compressed/head.S        |   83 +++++-
 arch/arm/boot/compressed/string.c      |   21 ++
 arch/arm/include/asm/assembler.h       |   14 +
 arch/arm/include/asm/idmap.h           |    1 +
 arch/arm/include/asm/uefi.h            |   28 ++
 arch/arm/kernel/Makefile               |    2 +
 arch/arm/kernel/process.c              |   12 +-
 arch/arm/kernel/setup.c                |    7 +-
 arch/arm/kernel/uefi.c                 |  413 ++++++++++++++++++++++++++++
 arch/arm/kernel/uefi_phys.S            |   69 +++++
 arch/arm/mm/idmap.c                    |   15 ++
 arch/arm64/Kconfig                     |   26 ++
 arch/arm64/include/asm/efi.h           |   12 +
 arch/arm64/include/asm/mmu.h           |    2 +
 arch/arm64/kernel/Makefile             |    4 +
 arch/arm64/kernel/efi-entry.S          |   93 +++++++
 arch/arm64/kernel/efi-stub.c           |   67 +++++
 arch/arm64/kernel/efi.c                |  462 ++++++++++++++++++++++++++++++++
 arch/arm64/kernel/head.S               |  112 ++++++++
 arch/arm64/kernel/setup.c              |    3 +
 arch/arm64/mm/mmu.c                    |   66 +++--
 arch/x86/boot/compressed/eboot.c       |    3 +-
 drivers/firmware/efi/Kconfig           |    7 +
 drivers/firmware/efi/arm-stub.c        |  146 ++++++++++
 drivers/firmware/efi/efi-stub-helper.c |  199 +++++++++++---
 drivers/firmware/efi/efi.c             |   79 ++++++
 drivers/firmware/efi/fdt.c             |  268 ++++++++++++++++++
 include/linux/efi.h                    |   12 +
 init/main.c                            |    5 +
 lib/Makefile                           |    3 +-
 lib/fdt_empty_tree.c                   |    2 +
 41 files changed, 2534 insertions(+), 95 deletions(-)
 create mode 100644 Documentation/arm/uefi.txt
 create mode 100644 arch/arm/boot/compressed/efi-header.S
 create mode 100644 arch/arm/boot/compressed/efi-stub.c
 create mode 100644 arch/arm/boot/compressed/efi-stub.h
 create mode 100644 arch/arm/include/asm/uefi.h
 create mode 100644 arch/arm/kernel/uefi.c
 create mode 100644 arch/arm/kernel/uefi_phys.S
 create mode 100644 arch/arm64/include/asm/efi.h
 create mode 100644 arch/arm64/kernel/efi-entry.S
 create mode 100644 arch/arm64/kernel/efi-stub.c
 create mode 100644 arch/arm64/kernel/efi.c
 create mode 100644 drivers/firmware/efi/arm-stub.c
 create mode 100644 drivers/firmware/efi/fdt.c
 create mode 100644 lib/fdt_empty_tree.c

-- 
1.7.10.4

^ permalink raw reply

* [PATCH 01/22] arm: break part of __soft_restart out into separate function
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

Certain operations can be considered mandatory for any piece of code
preparing to switch off the MMU. Break this out into separate function
idmap_prepare().

Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Suggested-by: Will Deacon <will.deacon@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/include/asm/idmap.h |    1 +
 arch/arm/kernel/process.c    |   12 +-----------
 arch/arm/mm/idmap.c          |   15 +++++++++++++++
 3 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/arch/arm/include/asm/idmap.h b/arch/arm/include/asm/idmap.h
index bf863ed..2e914a8 100644
--- a/arch/arm/include/asm/idmap.h
+++ b/arch/arm/include/asm/idmap.h
@@ -10,5 +10,6 @@
 extern pgd_t *idmap_pgd;
 
 void setup_mm_for_reboot(void);
+void idmap_prepare(void);
 
 #endif	/* __ASM_IDMAP_H */
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 92f7b15..91b4cec 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -75,17 +75,7 @@ static void __soft_restart(void *addr)
 {
 	phys_reset_t phys_reset;
 
-	/* Take out a flat memory mapping. */
-	setup_mm_for_reboot();
-
-	/* Clean and invalidate caches */
-	flush_cache_all();
-
-	/* Turn off caching */
-	cpu_proc_fin();
-
-	/* Push out any further dirty data, and ensure cache is empty */
-	flush_cache_all();
+	idmap_prepare();
 
 	/* Switch to the identity mapping. */
 	phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 8e0e52e..5c85779 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -122,3 +122,18 @@ void setup_mm_for_reboot(void)
 	local_flush_tlb_all();
 #endif
 }
+
+void idmap_prepare(void)
+{
+	/* Take out a flat memory mapping. */
+	setup_mm_for_reboot();
+
+	/* Clean and invalidate caches */
+	flush_cache_all();
+
+	/* Turn off caching */
+	cpu_proc_fin();
+
+	/* Push out any further dirty data, and ensure cache is empty */
+	flush_cache_all();
+}
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 02/22] arm: add new asm macro update_sctlr
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

A new macro for setting/clearing bits in the SCTLR.

Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Suggested-by: Will Deacon <will.deacon@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
---
 arch/arm/include/asm/assembler.h |   14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 5c22851..e8ca24b 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -383,4 +383,18 @@ THUMB(	orr	\reg , \reg , #PSR_T_BIT	)
 #endif
 	.endm
 
+#ifdef CONFIG_CPU_CP15
+/* Macro for setting/clearing bits in sctlr */
+	.macro	update_sctlr, tmp:req, set=, clear=
+	mrc	p15, 0, \tmp, c1, c0, 0
+	.ifnc	\set,
+	orr	\tmp, \set
+	.endif
+	.ifnc	\clear,
+	bic	\tmp, \tmp, \clear
+	.endif
+	mcr	p15, 0, \tmp, c1, c0, 0
+	.endm
+#endif
+
 #endif /* __ASM_ASSEMBLER_H__ */
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 03/22] efi: add helper function to get UEFI params from FDT
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Mark Salter <msalter@redhat.com>

ARM and ARM64 architectures use the device tree to pass UEFI parameters
from stub to kernel. These parameters are things known to the stub but
not discoverable by the kernel after the stub calls ExitBootSerives().
There is a helper function in:

   drivers/firmware/efi/fdt.c

which the stub uses to add the UEFI parameters to the device tree.
This patch adds a complimentary helper function which UEFI runtime
support may use to retrieve the parameters from the device tree.
If an architecture wants to use this helper, it should select
CONFIG_UEFI_PARAMS_FROM_FDT.

Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
 drivers/firmware/efi/Kconfig |    7 ++++
 drivers/firmware/efi/efi.c   |   79 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/efi.h          |    9 +++++
 3 files changed, 95 insertions(+)

diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 1e75f48..d3fe28d 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -47,6 +47,13 @@ config EFI_RUNTIME_MAP
 
 	  See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
 
+config UEFI_PARAMS_FROM_FDT
+	bool
+	help
+	  Select this config option from the architecture Kconfig if
+	  the EFI runtime support gets system table address, memory
+          map address, and other parameters from the device tree.
+
 endmenu
 
 config UEFI_CPER
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index b25b36b..7f6e977 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -20,6 +20,8 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/efi.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
 #include <linux/io.h>
 
 struct efi __read_mostly efi = {
@@ -318,3 +320,80 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 
 	return 0;
 }
+
+#ifdef CONFIG_UEFI_PARAMS_FROM_FDT
+
+#define UEFI_PARAM(name, prop, field)			   \
+	{						   \
+		{ name },				   \
+		{ prop },				   \
+		offsetof(struct efi_fdt_params, field),    \
+		FIELD_SIZEOF(struct efi_fdt_params, field) \
+	}
+
+static __initdata struct {
+	const char name[32];
+	const char propname[32];
+	int offset;
+	int size;
+} dt_params[] = {
+	UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
+	UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
+	UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
+	UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
+	UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
+};
+
+struct param_info {
+	int verbose;
+	void *params;
+};
+
+static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
+				       int depth, void *data)
+{
+	struct param_info *info = data;
+	void *prop, *dest;
+	unsigned long len;
+	u64 val;
+	int i;
+
+	if (depth != 1 ||
+	    (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen at 0") != 0))
+		return 0;
+
+	pr_info("Getting parameters from FDT:\n");
+
+	for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
+		prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
+		if (!prop) {
+			pr_err("Can't find %s in device tree!\n",
+			       dt_params[i].name);
+			return 0;
+		}
+		dest = info->params + dt_params[i].offset;
+
+		val = of_read_number(prop, len / sizeof(u32));
+
+		if (dt_params[i].size == sizeof(u32))
+			*(u32 *)dest = val;
+		else
+			*(u64 *)dest = val;
+
+		if (info->verbose)
+			pr_info("  %s: 0x%0*llx\n", dt_params[i].name,
+				dt_params[i].size * 2, val);
+	}
+	return 1;
+}
+
+int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
+{
+	struct param_info info;
+
+	info.verbose = verbose;
+	info.params = params;
+
+	return of_scan_flat_dt(fdt_find_uefi_params, &info);
+}
+#endif /* CONFIG_UEFI_PARAMS_FROM_FDT */
diff --git a/include/linux/efi.h b/include/linux/efi.h
index a3276da..d450673 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -483,6 +483,14 @@ struct efi_memory_map {
 	unsigned long desc_size;
 };
 
+struct efi_fdt_params {
+	u64 system_table;
+	u64 mmap;
+	u32 mmap_size;
+	u32 desc_size;
+	u32 desc_ver;
+};
+
 typedef struct {
 	u32 revision;
 	void *parent_handle;
@@ -620,6 +628,7 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource,
 extern void efi_get_time(struct timespec *now);
 extern int efi_set_rtc_mmss(const struct timespec *now);
 extern void efi_reserve_boot_services(void);
+extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
 extern struct efi_memory_map memmap;
 
 /* Iterate through an efi_memory_map */
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 04/22] efi-stub.txt updates for ARM
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

Update efi-stub.txt documentation to be more general
and not x86 specific.  Add ARM only "dtb=" command
line option description.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Grant Likely <grant.likely@linaro.org>
---
 Documentation/efi-stub.txt |   27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/Documentation/efi-stub.txt b/Documentation/efi-stub.txt
index c628788..26be7b0 100644
--- a/Documentation/efi-stub.txt
+++ b/Documentation/efi-stub.txt
@@ -1,13 +1,16 @@
 			  The EFI Boot Stub
 		     ---------------------------
 
-On the x86 platform, a bzImage can masquerade as a PE/COFF image,
-thereby convincing EFI firmware loaders to load it as an EFI
-executable. The code that modifies the bzImage header, along with the
-EFI-specific entry point that the firmware loader jumps to are
-collectively known as the "EFI boot stub", and live in
+On the x86 and ARM platforms, a kernel zImage/bzImage can masquerade
+as a PE/COFF image, thereby convincing EFI firmware loaders to load
+it as an EFI executable. The code that modifies the bzImage header,
+along with the EFI-specific entry point that the firmware loader
+jumps to are collectively known as the "EFI boot stub", and live in
 arch/x86/boot/header.S and arch/x86/boot/compressed/eboot.c,
-respectively.
+respectively. For ARM the EFI stub is implemented in
+arch/arm/boot/compressed/efi-header.S and
+arch/arm/boot/compressed/efi-stub.c. EFI stub code that is shared
+between architectures is in drivers/firmware/efi/efi-stub-helper.c.
 
 By using the EFI boot stub it's possible to boot a Linux kernel
 without the use of a conventional EFI boot loader, such as grub or
@@ -23,7 +26,9 @@ The bzImage located in arch/x86/boot/bzImage must be copied to the EFI
 System Partition (ESP) and renamed with the extension ".efi". Without
 the extension the EFI firmware loader will refuse to execute it. It's
 not possible to execute bzImage.efi from the usual Linux file systems
-because EFI firmware doesn't have support for them.
+because EFI firmware doesn't have support for them. For ARM the
+arch/arm/boot/zImage should be copied to the system partition, and it
+may not need to be renamed.
 
 
 **** Passing kernel parameters from the EFI shell
@@ -63,3 +68,11 @@ Notice how bzImage.efi can be specified with a relative path. That's
 because the image we're executing is interpreted by the EFI shell,
 which understands relative paths, whereas the rest of the command line
 is passed to bzImage.efi.
+
+
+**** The "dtb=" option
+
+For the ARM architecture, we also need to be able to provide a device
+tree to the kernel. This is done with the "dtb=" command line option,
+and is processed in the same manner as the "initrd=" option that is
+described above.
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 05/22] Add shared printk wrapper for consistent prefixing
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

Add a wrapper for printk to standardize the prefix for informational and
error messages from the EFI stub.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
 drivers/firmware/efi/efi-stub-helper.c |   25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index b6bffbf..eb5d2eb 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -45,6 +45,9 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
 	}
 }
 
+#define pr_efi(sys_table, msg)     efi_printk(sys_table, "EFI stub: "msg)
+#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg)
+
 
 static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
 				       efi_memory_desc_t **map,
@@ -324,7 +327,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 				nr_files * sizeof(*files),
 				(void **)&files);
 	if (status != EFI_SUCCESS) {
-		efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n");
+		pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n");
 		goto fail;
 	}
 
@@ -376,13 +379,13 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 					image->device_handle, &fs_proto,
 						(void **)&io);
 			if (status != EFI_SUCCESS) {
-				efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
+				pr_efi_err(sys_table_arg, "Failed to handle fs_proto\n");
 				goto free_files;
 			}
 
 			status = efi_call_phys2(io->open_volume, io, &fh);
 			if (status != EFI_SUCCESS) {
-				efi_printk(sys_table_arg, "Failed to open volume\n");
+				pr_efi_err(sys_table_arg, "Failed to open volume\n");
 				goto free_files;
 			}
 		}
@@ -390,7 +393,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 		status = efi_call_phys5(fh->open, fh, &h, filename_16,
 					EFI_FILE_MODE_READ, (u64)0);
 		if (status != EFI_SUCCESS) {
-			efi_printk(sys_table_arg, "Failed to open file: ");
+			pr_efi_err(sys_table_arg, "Failed to open file: ");
 			efi_char16_printk(sys_table_arg, filename_16);
 			efi_printk(sys_table_arg, "\n");
 			goto close_handles;
@@ -402,7 +405,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 		status = efi_call_phys4(h->get_info, h, &info_guid,
 					&info_sz, NULL);
 		if (status != EFI_BUFFER_TOO_SMALL) {
-			efi_printk(sys_table_arg, "Failed to get file info size\n");
+			pr_efi_err(sys_table_arg, "Failed to get file info size\n");
 			goto close_handles;
 		}
 
@@ -411,7 +414,7 @@ grow:
 					EFI_LOADER_DATA, info_sz,
 					(void **)&info);
 		if (status != EFI_SUCCESS) {
-			efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
+			pr_efi_err(sys_table_arg, "Failed to alloc mem for file info\n");
 			goto close_handles;
 		}
 
@@ -427,7 +430,7 @@ grow:
 		efi_call_phys1(sys_table_arg->boottime->free_pool, info);
 
 		if (status != EFI_SUCCESS) {
-			efi_printk(sys_table_arg, "Failed to get file info\n");
+			pr_efi_err(sys_table_arg, "Failed to get file info\n");
 			goto close_handles;
 		}
 
@@ -446,13 +449,13 @@ grow:
 		status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000,
 				    &file_addr, max_addr);
 		if (status != EFI_SUCCESS) {
-			efi_printk(sys_table_arg, "Failed to alloc highmem for files\n");
+			pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n");
 			goto close_handles;
 		}
 
 		/* We've run out of free low memory. */
 		if (file_addr > max_addr) {
-			efi_printk(sys_table_arg, "We've run out of free low memory\n");
+			pr_efi_err(sys_table_arg, "We've run out of free low memory\n");
 			status = EFI_INVALID_PARAMETER;
 			goto free_file_total;
 		}
@@ -473,7 +476,7 @@ grow:
 							&chunksize,
 							(void *)addr);
 				if (status != EFI_SUCCESS) {
-					efi_printk(sys_table_arg, "Failed to read file\n");
+					pr_efi_err(sys_table_arg, "Failed to read file\n");
 					goto free_file_total;
 				}
 				addr += chunksize;
@@ -558,7 +561,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
 				       &new_addr);
 	}
 	if (status != EFI_SUCCESS) {
-		efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n");
+		pr_efi_err(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n");
 		return status;
 	}
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 06/22] Add helper functions used by arm/arm64
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

Add the get_dram_base() function and efi_call_physN() macros
that are shared by arm/arm64.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
 drivers/firmware/efi/efi-stub-helper.c |   63 +++++++++++++++++++++++++-------
 1 file changed, 50 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index eb5d2eb..8477a72 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -11,6 +11,27 @@
  */
 #define EFI_READ_CHUNK_SIZE	(1024 * 1024)
 
+/* error code which can't be mistaken for valid address */
+#define EFI_ERROR	(~0UL)
+
+# if !defined(CONFIG_X86)
+/*
+ * EFI function call wrappers. These are not required for arm/arm64, but
+ * wrappers are required for X86 to convert between ABIs. These wrappers are
+ * provided to allow code sharing between X86 and other architectures. Since
+ * these wrappers directly invoke the EFI function pointer, the function
+ * pointer type must be properly defined, which is not the case for X86. One
+ * advantage of this is it allows for type checking of arguments, which is not
+ * possible with the X86 wrappers.
+ */
+#define efi_call_phys0(f)			f()
+#define efi_call_phys1(f, a1)			f(a1)
+#define efi_call_phys2(f, a1, a2)		f(a1, a2)
+#define efi_call_phys3(f, a1, a2, a3)		f(a1, a2, a3)
+#define efi_call_phys4(f, a1, a2, a3, a4)	f(a1, a2, a3, a4)
+#define efi_call_phys5(f, a1, a2, a3, a4, a5)	f(a1, a2, a3, a4, a5)
+#endif
+
 struct file_info {
 	efi_file_handle_t *handle;
 	u64 size;
@@ -92,6 +113,32 @@ fail:
 	return status;
 }
 
+
+static unsigned long __init get_dram_base(efi_system_table_t *sys_table)
+{
+	efi_status_t status;
+	unsigned long map_size;
+	unsigned long membase  = EFI_ERROR;
+	struct efi_memory_map map;
+	efi_memory_desc_t *md;
+
+	status = efi_get_memory_map(sys_table, (efi_memory_desc_t **)&map.map,
+				    &map_size, &map.desc_size, NULL, NULL);
+	if (status != EFI_SUCCESS)
+		return membase;
+
+	map.map_end = map.map + map_size;
+
+	for_each_efi_memory_desc(&map, md)
+		if (md->attribute & EFI_MEMORY_WB)
+			if (membase > md->phys_addr)
+				membase = md->phys_addr;
+
+	efi_call_phys1(sys_table->boottime->free_pool, map.map);
+
+	return membase;
+}
+
 /*
  * Allocate at the highest possible address that is not above 'max'.
  */
@@ -610,19 +657,9 @@ static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg,
 		options = &zero;
 	}
 
-	options_size++;  /* NUL termination */
-#ifdef CONFIG_ARM
-	/*
-	 * For ARM, allocate at a high address to avoid reserved
-	 * regions at low addresses that we don't know the specfics of
-	 * at the time we are processing the command line.
-	 */
-	status = efi_high_alloc(sys_table_arg, options_size, 0,
-			    &cmdline_addr, 0xfffff000);
-#else
-	status = efi_low_alloc(sys_table_arg, options_size, 0,
-			    &cmdline_addr);
-#endif
+	options_size++;  /* NULL termination */
+
+	status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
 	if (status != EFI_SUCCESS)
 		return NULL;
 
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 07/22] Add shared FDT related functions for ARM/ARM64
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

Both ARM and ARM64 stubs will update the device tree that they pass to
the kernel.  In both cases they primarily need to add the same UEFI
related information, so the function can be shared.  Create a new FDT
related file for this to avoid use of architecture #ifdefs in
efi-stub-helper.c.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Grant Likely <grant.likely@linaro.org>
---
 drivers/firmware/efi/fdt.c |  247 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/efi.h        |    3 +
 2 files changed, 250 insertions(+)
 create mode 100644 drivers/firmware/efi/fdt.c

diff --git a/drivers/firmware/efi/fdt.c b/drivers/firmware/efi/fdt.c
new file mode 100644
index 0000000..a602b0a
--- /dev/null
+++ b/drivers/firmware/efi/fdt.c
@@ -0,0 +1,247 @@
+/*
+ * FDT related Helper functions used by the EFI stub on multiple
+ * architectures. This should be #included by the EFI stub
+ * implementation files.
+ *
+ * Copyright 2013 Linaro Limited; author Roy Franz
+ *
+ * This file is part of the Linux kernel, and is made available
+ * under the terms of the GNU General Public License version 2.
+ *
+ */
+
+static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
+			       void *fdt, int new_fdt_size, char *cmdline_ptr,
+			       u64 initrd_addr, u64 initrd_size,
+			       efi_memory_desc_t *memory_map,
+			       unsigned long map_size, unsigned long desc_size,
+			       u32 desc_ver)
+{
+	int node;
+	int status;
+	u32 fdt_val32;
+	u64 fdt_val64;
+
+	/*
+	 * Copy definition of linux_banner here.  Since this code is
+	 * built as part of the decompressor for ARM v7, pulling
+	 * in version.c where linux_banner is defined for the
+	 * kernel brings other kernel dependencies with it.
+	 */
+	const char linux_banner[] =
+	    "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
+	    LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
+
+	status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
+	if (status != 0)
+		goto fdt_set_fail;
+
+	/* Delete any memory nodes present */
+	while ((node = fdt_subnode_offset(fdt, 0, "memory")) >= 0)
+		fdt_del_node(fdt, node);
+
+	node = fdt_subnode_offset(fdt, 0, "chosen");
+	if (node < 0) {
+		node = fdt_add_subnode(fdt, 0, "chosen");
+		if (node < 0) {
+			status = node; /* node is error code when negative */
+			goto fdt_set_fail;
+		}
+	}
+
+	if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
+		status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
+				     strlen(cmdline_ptr) + 1);
+		if (status)
+			goto fdt_set_fail;
+	}
+
+	/* Set initrd address/end in device tree, if present */
+	if (initrd_size != 0) {
+		u64 initrd_image_end;
+		u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
+		status = fdt_setprop(fdt, node, "linux,initrd-start",
+				     &initrd_image_start, sizeof(u64));
+		if (status)
+			goto fdt_set_fail;
+		initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
+		status = fdt_setprop(fdt, node, "linux,initrd-end",
+				     &initrd_image_end, sizeof(u64));
+		if (status)
+			goto fdt_set_fail;
+	}
+
+	/* Add FDT entries for EFI runtime services in chosen node. */
+	node = fdt_subnode_offset(fdt, 0, "chosen");
+	fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
+	status = fdt_setprop(fdt, node, "linux,uefi-system-table",
+			     &fdt_val64, sizeof(fdt_val64));
+	if (status)
+		goto fdt_set_fail;
+
+	fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
+	status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
+			     &fdt_val64,  sizeof(fdt_val64));
+	if (status)
+		goto fdt_set_fail;
+
+	fdt_val32 = cpu_to_fdt32(map_size);
+	status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
+			     &fdt_val32,  sizeof(fdt_val32));
+	if (status)
+		goto fdt_set_fail;
+
+	fdt_val32 = cpu_to_fdt32(desc_size);
+	status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
+			     &fdt_val32, sizeof(fdt_val32));
+	if (status)
+		goto fdt_set_fail;
+
+	fdt_val32 = cpu_to_fdt32(desc_ver);
+	status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
+			     &fdt_val32, sizeof(fdt_val32));
+	if (status)
+		goto fdt_set_fail;
+
+	/*
+	 * Add kernel version banner so stub/kernel match can be
+	 * verified.
+	 */
+	status = fdt_setprop_string(fdt, node, "linux,uefi-stub-kern-ver",
+			     linux_banner);
+	if (status)
+		goto fdt_set_fail;
+
+	return EFI_SUCCESS;
+
+fdt_set_fail:
+	if (status == -FDT_ERR_NOSPACE)
+		return EFI_BUFFER_TOO_SMALL;
+
+	return EFI_LOAD_ERROR;
+}
+
+#ifndef EFI_FDT_ALIGN
+#define EFI_FDT_ALIGN EFI_PAGE_SIZE
+#endif
+
+/*
+ * Allocate memory for a new FDT, then add EFI, commandline, and
+ * initrd related fields to the FDT.  This routine increases the
+ * FDT allocation size until the allocated memory is large
+ * enough.  EFI allocations are in EFI_PAGE_SIZE granules,
+ * which are fixed at 4K bytes, so in most cases the first
+ * allocation should succeed.
+ * EFI boot services are exited at the end of this function.
+ * There must be no allocations between the get_memory_map()
+ * call and the exit_boot_services() call, so the exiting of
+ * boot services is very tightly tied to the creation of the FDT
+ * with the final memory map in it.
+ */
+
+efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
+					    void *handle,
+					    unsigned long *new_fdt_addr,
+					    unsigned long max_addr,
+					    u64 initrd_addr, u64 initrd_size,
+					    char *cmdline_ptr,
+					    unsigned long fdt_addr,
+					    unsigned long fdt_size)
+{
+	unsigned long map_size, desc_size;
+	u32 desc_ver;
+	unsigned long mmap_key;
+	efi_memory_desc_t *memory_map;
+	unsigned long new_fdt_size;
+	efi_status_t status;
+
+	/*
+	 * Estimate size of new FDT, and allocate memory for it. We
+	 * will allocate a bigger buffer if this ends up being too
+	 * small, so a rough guess is OK here.
+	 */
+	new_fdt_size = fdt_size + EFI_PAGE_SIZE;
+	while (1) {
+		status = efi_high_alloc(sys_table, new_fdt_size, EFI_FDT_ALIGN,
+					new_fdt_addr, max_addr);
+		if (status != EFI_SUCCESS) {
+			pr_efi_err(sys_table, "Unable to allocate memory for new device tree.\n");
+			goto fail;
+		}
+
+		/*
+		 * Now that we have done our final memory allocation (and free)
+		 * we can get the memory map key  needed for
+		 * exit_boot_services().
+		 */
+		status = efi_get_memory_map(sys_table, &memory_map, &map_size,
+					    &desc_size, &desc_ver, &mmap_key);
+		if (status != EFI_SUCCESS)
+			goto fail_free_new_fdt;
+
+		status = update_fdt(sys_table,
+				    (void *)fdt_addr, (void *)*new_fdt_addr,
+				    new_fdt_size, cmdline_ptr, initrd_addr,
+				    initrd_size, memory_map, map_size,
+				    desc_size, desc_ver);
+
+		/* Succeeding the first time is the expected case. */
+		if (status == EFI_SUCCESS)
+			break;
+
+		if (status == EFI_BUFFER_TOO_SMALL) {
+			/*
+			 * We need to allocate more space for the new
+			 * device tree, so free existing buffer that is
+			 * too small.  Also free memory map, as we will need
+			 * to get new one that reflects the free/alloc we do
+			 * on the device tree buffer.
+			 */
+			efi_free(sys_table, new_fdt_size, *new_fdt_addr);
+			efi_call_phys1(sys_table->boottime->free_pool,
+				       memory_map);
+			new_fdt_size += EFI_PAGE_SIZE;
+		} else {
+			pr_efi_err(sys_table, "Unable to constuct new device tree.\n");
+			goto fail_free_mmap;
+		}
+	}
+
+	/* Now we are ready to exit_boot_services.*/
+	status = efi_call_phys2(sys_table->boottime->exit_boot_services,
+				handle, mmap_key);
+
+
+	if (status == EFI_SUCCESS)
+		return status;
+
+	pr_efi_err(sys_table, "Exit boot services failed.\n");
+
+fail_free_mmap:
+	efi_call_phys1(sys_table->boottime->free_pool, memory_map);
+
+fail_free_new_fdt:
+	efi_free(sys_table, new_fdt_size, *new_fdt_addr);
+
+fail:
+	return EFI_LOAD_ERROR;
+}
+
+static void *get_fdt(efi_system_table_t *sys_table)
+{
+	efi_guid_t fdt_guid = EFI_DEVICE_TREE_GUID;
+	efi_config_table_t *tables;
+	void *fdt;
+	int i;
+
+	tables = (efi_config_table_t *) sys_table->tables;
+	fdt = NULL;
+
+	for (i = 0; i < sys_table->nr_tables; i++)
+		if (efi_guidcmp(tables[i].guid, fdt_guid) == 0) {
+			fdt = (void *) tables[i].table;
+			break;
+	 }
+
+	return fdt;
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index d450673..cd112bb 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -394,6 +394,9 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long si
 #define EFI_FILE_SYSTEM_GUID \
     EFI_GUID(  0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
 
+#define EFI_DEVICE_TREE_GUID \
+    EFI_GUID(  0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 )
+
 typedef struct {
 	efi_guid_t guid;
 	u64 table;
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 08/22] Add strstr to compressed string.c for ARM.
From: Leif Lindholm @ 2014-02-05 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

The shared efi-stub-helper.c functions require a strstr implementation.
The EFI stub is part of the decompressor, so it does not use the kernel
strstr() implementation.  This patch adds a strstr() implementation to
the string.c file for the decompressor, with the implementation copied
from the arch/x86/boot/string.c file used by the x86 decompressor.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Reviewed-by: Grant Likely <grant.likely@linaro.org>
---
 arch/arm/boot/compressed/string.c |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c
index 36e53ef..5397792 100644
--- a/arch/arm/boot/compressed/string.c
+++ b/arch/arm/boot/compressed/string.c
@@ -111,6 +111,27 @@ char *strchr(const char *s, int c)
 	return (char *)s;
 }
 
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+	size_t l1, l2;
+
+	l2 = strlen(s2);
+	if (!l2)
+		return (char *)s1;
+	l1 = strlen(s1);
+	while (l1 >= l2) {
+		l1--;
+		if (!memcmp(s1, s2, l2))
+			return (char *)s1;
+		s1++;
+	}
+	return NULL;
+}
 #undef memset
 
 void *memset(void *s, int c, size_t count)
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 09/22] Add shared arm/arm64 EFI stub
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

This patch adds the EFI stub entry point that is shared
by the arm/arm64 architectures.  Each arch will implement
the handle_kernel_image() function that handles the arch
specific load address and boot protocol requirements.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
 drivers/firmware/efi/arm-stub.c |  145 +++++++++++++++++++++++++++++++++++++++
 drivers/firmware/efi/fdt.c      |   31 +++++++--
 2 files changed, 171 insertions(+), 5 deletions(-)
 create mode 100644 drivers/firmware/efi/arm-stub.c

diff --git a/drivers/firmware/efi/arm-stub.c b/drivers/firmware/efi/arm-stub.c
new file mode 100644
index 0000000..aefe963
--- /dev/null
+++ b/drivers/firmware/efi/arm-stub.c
@@ -0,0 +1,145 @@
+/*
+ * EFI stub implementation that is shared by arm and arm64 architectures.
+ * This should be #included by the EFI stub implementation files.
+ *
+ * Copyright (C) 2013,2014 Linaro Limited
+ *     Roy Franz <roy.franz at linaro.org
+ * Copyright (C) 2013 Red Hat, Inc.
+ *     Mark Salter <msalter@redhat.com>
+ *
+ * This file is part of the Linux kernel, and is made available under the
+ * terms of the GNU General Public License version 2.
+ *
+ */
+
+/*
+ * This function handles the architcture specific differences between arm and
+ * arm64 regarding where the kernel image must be loaded and any memory that
+ * must be reserved. On failure it is required to free all
+ * all allocations it has made.
+ */
+static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
+					unsigned long *image_addr,
+					unsigned long *image_size,
+					unsigned long *reserve_addr,
+					unsigned long *reserve_size,
+					unsigned long dram_base,
+					efi_loaded_image_t *image);
+/*
+ * EFI entry point for the arm/arm64 EFI stubs.  This is the entrypoint
+ * that is described in the PE/COFF header.  Most of the code is the same
+ * for both archictectures, with the arch-specific code provided in the
+ * handle_kernel_image() function.
+ */
+unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
+			       unsigned long *image_addr)
+{
+	efi_loaded_image_t *image;
+	efi_status_t status;
+	unsigned long image_size = 0;
+	unsigned long dram_base;
+	/* addr/point and size pairs for memory management*/
+	unsigned long initrd_addr;
+	u64 initrd_size = 0;
+	unsigned long fdt_addr;  /* Original DTB */
+	u64 fdt_size = 0;  /* We don't get size from configuration table */
+	char *cmdline_ptr = NULL;
+	int cmdline_size = 0;
+	unsigned long new_fdt_addr;
+	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
+	unsigned long reserve_addr = 0;
+	unsigned long reserve_size = 0;
+
+	/* Check if we were booted by the EFI firmware */
+	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+		goto fail;
+
+	pr_efi(sys_table, "Booting Linux Kernel...\n");
+
+	/*
+	 * Get a handle to the loaded image protocol.  This is used to get
+	 * information about the running image, such as size and the command
+	 * line.
+	 */
+	status = efi_call_phys3(sys_table->boottime->handle_protocol,
+				handle, &loaded_image_proto, (void *)&image);
+	if (status != EFI_SUCCESS) {
+		pr_efi_err(sys_table, "Failed to get loaded image protocol\n");
+		goto fail;
+	}
+
+	dram_base = get_dram_base(sys_table);
+	if (dram_base == EFI_ERROR) {
+		pr_efi_err(sys_table, "Failed to find DRAM base\n");
+		goto fail;
+	}
+	status = handle_kernel_image(sys_table, image_addr, &image_size,
+				     &reserve_addr,
+				     &reserve_size,
+				     dram_base, image);
+	if (status != EFI_SUCCESS) {
+		pr_efi_err(sys_table, "Failed to relocate kernel\n");
+		goto fail;
+	}
+
+	/*
+	 * Get the command line from EFI, using the LOADED_IMAGE
+	 * protocol. We are going to copy the command line into the
+	 * device tree, so this can be allocated anywhere.
+	 */
+	cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image,
+						    &cmdline_size);
+	if (!cmdline_ptr) {
+		pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n");
+		goto fail_free_image;
+	}
+
+	/* Load a device tree from the configuration table, if present. */
+	fdt_addr = (uintptr_t)get_fdt(sys_table);
+	if (!fdt_addr) {
+		status = handle_cmdline_files(sys_table, image, cmdline_ptr,
+					      "dtb=",
+					      ~0UL, (unsigned long *)&fdt_addr,
+					      (unsigned long *)&fdt_size);
+
+		if (status != EFI_SUCCESS) {
+			pr_efi_err(sys_table, "Failed to load device tree!\n");
+			goto fail_free_cmdline;
+		}
+	}
+
+	status = handle_cmdline_files(sys_table, image, cmdline_ptr,
+				      "initrd=", dram_base + SZ_512M,
+				      (unsigned long *)&initrd_addr,
+				      (unsigned long *)&initrd_size);
+	if (status != EFI_SUCCESS)
+		pr_efi_err(sys_table, "Failed initrd from command line!\n");
+
+	new_fdt_addr = fdt_addr;
+	status = allocate_new_fdt_and_exit_boot(sys_table, handle,
+				&new_fdt_addr, dram_base + MAX_FDT_OFFSET,
+				initrd_addr, initrd_size, cmdline_ptr,
+				fdt_addr, fdt_size);
+
+	/*
+	 * If all went well, we need to return the FDT address to the
+	 * calling function so it can be passed to kernel as part of
+	 * the kernel boot protocol.
+	 */
+	if (status == EFI_SUCCESS)
+		return new_fdt_addr;
+
+	pr_efi_err(sys_table, "Failed to update FDT and exit boot services\n");
+
+	efi_free(sys_table, initrd_size, initrd_addr);
+	efi_free(sys_table, fdt_size, fdt_addr);
+
+fail_free_cmdline:
+	efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
+
+fail_free_image:
+	efi_free(sys_table, image_size, *image_addr);
+	efi_free(sys_table, reserve_size, reserve_addr);
+fail:
+	return EFI_ERROR;
+}
diff --git a/drivers/firmware/efi/fdt.c b/drivers/firmware/efi/fdt.c
index a602b0a..4510f97 100644
--- a/drivers/firmware/efi/fdt.c
+++ b/drivers/firmware/efi/fdt.c
@@ -11,6 +11,7 @@
  */
 
 static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
+			       unsigned long orig_fdt_size,
 			       void *fdt, int new_fdt_size, char *cmdline_ptr,
 			       u64 initrd_addr, u64 initrd_size,
 			       efi_memory_desc_t *memory_map,
@@ -32,7 +33,27 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
 	    "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
 	    LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
 
-	status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
+	/* Do some checks on provided FDT, if it exists*/
+	if (orig_fdt) {
+		if (fdt_check_header(orig_fdt)) {
+			pr_efi_err(sys_table, "Device Tree header not valid!\n");
+			return EFI_LOAD_ERROR;
+		}
+		/*
+		 * We don't get the size of the FDT if we get if from a
+		 * configuration table.
+		 */
+		if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
+			pr_efi_err(sys_table, "Truncated device tree! foo!\n");
+			return EFI_LOAD_ERROR;
+		}
+	}
+
+	if (orig_fdt)
+		status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
+	else
+		status = fdt_create_empty_tree(fdt, new_fdt_size);
+
 	if (status != 0)
 		goto fdt_set_fail;
 
@@ -180,10 +201,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
 			goto fail_free_new_fdt;
 
 		status = update_fdt(sys_table,
-				    (void *)fdt_addr, (void *)*new_fdt_addr,
-				    new_fdt_size, cmdline_ptr, initrd_addr,
-				    initrd_size, memory_map, map_size,
-				    desc_size, desc_ver);
+				    (void *)fdt_addr, fdt_size,
+				    (void *)*new_fdt_addr, new_fdt_size,
+				    cmdline_ptr, initrd_addr, initrd_size,
+				    memory_map, map_size, desc_size, desc_ver);
 
 		/* Succeeding the first time is the expected case. */
 		if (status == EFI_SUCCESS)
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 10/22] Add EFI stub for ARM
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

This patch adds EFI stub support for the ARM Linux kernel.  The EFI stub
operates similarly to the x86 stub: it is a shim between the EFI firmware
and the normal zImage entry point, and sets up the environment that the
zImage is expecting.  This includes loading the initrd (optionaly) and
device tree from the system partition based on the kernel command line.
The stub updates the device tree as necessary, adding entries for EFI
runtime services. The PE/COFF "MZ" header at offset 0 results in the
first instruction being an add that corrupts r5, which is not used by
the zImage interface.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Grant Likely <grant.likely@linaro.org>
---
 arch/arm/Kconfig                      |   11 +++
 arch/arm/boot/compressed/Makefile     |   17 ++++-
 arch/arm/boot/compressed/efi-header.S |  117 ++++++++++++++++++++++++++++++++
 arch/arm/boot/compressed/efi-stub.c   |  118 +++++++++++++++++++++++++++++++++
 arch/arm/boot/compressed/efi-stub.h   |    5 ++
 arch/arm/boot/compressed/head.S       |   83 +++++++++++++++++++++--
 6 files changed, 342 insertions(+), 9 deletions(-)
 create mode 100644 arch/arm/boot/compressed/efi-header.S
 create mode 100644 arch/arm/boot/compressed/efi-stub.c
 create mode 100644 arch/arm/boot/compressed/efi-stub.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ef2aa77..a693921 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1885,6 +1885,17 @@ config EARLY_IOREMAP
 	  the same virtual memory range as kmap so all early mappings must
 	  be unapped before paging_init() is called.
 
+config EFI_STUB
+	bool "EFI stub support"
+	depends on EFI && !CPU_BIG_ENDIAN
+	---help---
+	  This kernel feature allows a zImage to be loaded directly by EFI
+	  firmware without the use of a bootloader.  A PE/COFF header is
+	  added to the zImage in a way that makes the binary both a Linux
+	  zImage and an PE/COFF executable that can be executed directly by
+	  EFI firmware.
+	  See Documentation/efi-stub.txt for more information.
+
 config SECCOMP
 	bool
 	prompt "Enable seccomp to safely compute untrusted bytecode"
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 68c9183..1415411 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -91,7 +91,7 @@ suffix_$(CONFIG_KERNEL_LZ4)  = lz4
 
 # Borrowed libfdt files for the ATAG compatibility mode
 
-libfdt		:= fdt_rw.c fdt_ro.c fdt_wip.c fdt.c
+libfdt		:= fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
 libfdt_hdrs	:= fdt.h libfdt.h libfdt_internal.h
 
 libfdt_objs	:= $(addsuffix .o, $(basename $(libfdt)))
@@ -99,11 +99,22 @@ libfdt_objs	:= $(addsuffix .o, $(basename $(libfdt)))
 $(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/%
 	$(call cmd,shipped)
 
-$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
+$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o efi-stub.o): \
 	$(addprefix $(obj)/,$(libfdt_hdrs))
 
 ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
-OBJS	+= $(libfdt_objs) atags_to_fdt.o
+OBJS	+= atags_to_fdt.o
+USE_LIBFDT = y
+endif
+
+ifeq ($(CONFIG_EFI_STUB),y)
+CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
+OBJS	+= efi-stub.o
+USE_LIBFDT = y
+endif
+
+ifeq ($(USE_LIBFDT),y)
+OBJS	+= $(libfdt_objs)
 endif
 
 targets       := vmlinux vmlinux.lds \
diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
new file mode 100644
index 0000000..dbb7101
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-header.S
@@ -0,0 +1,117 @@
+@ Copyright (C) 2013 Linaro Ltd;  <roy.franz@linaro.org>
+@
+@ This file contains the PE/COFF header that is part of the
+@ EFI stub.
+@
+
+	.org	0x3c
+	@
+	@ The PE header can be anywhere in the file, but for
+	@ simplicity we keep it together with the MSDOS header
+	@ The offset to the PE/COFF header needs to be at offset
+	@ 0x3C in the MSDOS header.
+	@ The only 2 fields of the MSDOS header that are used are this
+	@ PE/COFF offset, and the "MZ" bytes at offset 0x0.
+	@
+	.long	pe_header			@ Offset to the PE header.
+
+      .align 3
+pe_header:
+	.ascii	"PE"
+	.short 	0
+
+coff_header:
+	.short	0x01c2				@ ARM or Thumb
+	.short	2				@ nr_sections
+	.long	0 				@ TimeDateStamp
+	.long	0				@ PointerToSymbolTable
+	.long	1				@ NumberOfSymbols
+	.short	section_table - optional_header	@ SizeOfOptionalHeader
+	.short	0x306				@ Characteristics.
+						@ IMAGE_FILE_32BIT_MACHINE |
+						@ IMAGE_FILE_DEBUG_STRIPPED |
+						@ IMAGE_FILE_EXECUTABLE_IMAGE |
+						@ IMAGE_FILE_LINE_NUMS_STRIPPED
+
+optional_header:
+	.short	0x10b				@ PE32 format
+	.byte	0x02				@ MajorLinkerVersion
+	.byte	0x14				@ MinorLinkerVersion
+
+	.long	_edata - efi_stub_entry		@ SizeOfCode
+
+	.long	0				@ SizeOfInitializedData
+	.long	0				@ SizeOfUninitializedData
+
+	.long	efi_stub_entry			@ AddressOfEntryPoint
+	.long	efi_stub_entry			@ BaseOfCode
+	.long	0				@ data
+
+extra_header_fields:
+	.long	0				@ ImageBase
+	.long	0x20				@ SectionAlignment
+	.long	0x8				@ FileAlignment
+	.short	0				@ MajorOperatingSystemVersion
+	.short	0				@ MinorOperatingSystemVersion
+	.short	0				@ MajorImageVersion
+	.short	0				@ MinorImageVersion
+	.short	0				@ MajorSubsystemVersion
+	.short	0				@ MinorSubsystemVersion
+	.long	0				@ Win32VersionValue
+
+	.long	_edata				@ SizeOfImage
+
+	@ Everything before the entry point is considered part of the header
+	.long	efi_stub_entry			@ SizeOfHeaders
+	.long	0				@ CheckSum
+	.short	0xa				@ Subsystem (EFI application)
+	.short	0				@ DllCharacteristics
+	.long	0				@ SizeOfStackReserve
+	.long	0				@ SizeOfStackCommit
+	.long	0				@ SizeOfHeapReserve
+	.long	0				@ SizeOfHeapCommit
+	.long	0				@ LoaderFlags
+	.long	0x6				@ NumberOfRvaAndSizes
+
+	.quad   0                               @ ExportTable
+	.quad   0                               @ ImportTable
+	.quad   0                               @ ResourceTable
+	.quad   0                               @ ExceptionTable
+	.quad   0                               @ CertificationTable
+	.quad   0                               @ BaseRelocationTable
+	# Section table
+section_table:
+
+	#
+	# The EFI application loader requires a relocation section
+	# because EFI applications must be relocatable.  This is a
+	# dummy section as far as we are concerned.
+	#
+	.ascii	".reloc"
+	.byte	0
+	.byte	0			@ end of 0 padding of section name
+	.long	0
+	.long	0
+	.long	0			@ SizeOfRawData
+	.long	0			@ PointerToRawData
+	.long	0			@ PointerToRelocations
+	.long	0			@ PointerToLineNumbers
+	.short	0			@ NumberOfRelocations
+	.short	0			@ NumberOfLineNumbers
+	.long	0x42100040		@ Characteristics (section flags)
+
+
+	.ascii	".text"
+	.byte	0
+	.byte	0
+	.byte	0        		@ end of 0 padding of section name
+	.long	_edata - efi_stub_entry		@ VirtualSize
+	.long	efi_stub_entry			@ VirtualAddress
+	.long	_edata - efi_stub_entry		@ SizeOfRawData
+	.long	efi_stub_entry			@ PointerToRawData
+
+	.long	0		@ PointerToRelocations (0 for executables)
+	.long	0		@ PointerToLineNumbers (0 for executables)
+	.short	0		@ NumberOfRelocations  (0 for executables)
+	.short	0		@ NumberOfLineNumbers  (0 for executables)
+	.long	0xe0500020	@ Characteristics (section flags)
diff --git a/arch/arm/boot/compressed/efi-stub.c b/arch/arm/boot/compressed/efi-stub.c
new file mode 100644
index 0000000..dba8037
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-stub.c
@@ -0,0 +1,118 @@
+/*
+ * linux/arch/arm/boot/compressed/efi-stub.c
+ *
+ * Copyright (C) 2013 Linaro Ltd;  <roy.franz@linaro.org>
+ *
+ * This file implements the EFI boot stub for the ARM kernel
+ *
+ * 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.
+ *
+ */
+#include <linux/efi.h>
+#include <libfdt.h>
+#include <generated/compile.h>
+#include <generated/utsrelease.h>
+#include "efi-stub.h"
+
+/*
+ * The maximum uncompressed kernel size is 32 MBytes, so we will reserve
+ * that for the decompressed kernel.  We have no easy way to tell what
+ * the actuall size of code + data the uncompressed kernel will use.
+ */
+#define MAX_UNCOMP_KERNEL_SIZE	0x02000000
+
+/*
+ * The kernel zImage should be located between 32 Mbytes
+ * and 128 MBytes from the base of DRAM.  The min
+ * address leaves space for a maximal size uncompressed image,
+ * and the max address is due to how the zImage decompressor
+ * picks a destination address.
+ */
+#define ZIMAGE_OFFSET_LIMIT	0x08000000
+#define MIN_ZIMAGE_OFFSET	MAX_UNCOMP_KERNEL_SIZE
+#define MAX_FDT_OFFSET		ZIMAGE_OFFSET_LIMIT
+
+/* Include shared EFI stub code, and required headers. */
+#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
+#include "../../../../drivers/firmware/efi/fdt.c"
+#include "../../../drivers/firmware/efi/arm-stub.c"
+
+static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
+					unsigned long *image_addr,
+					unsigned long *image_size,
+					unsigned long *reserve_addr,
+					unsigned long *reserve_size,
+					unsigned long dram_base,
+					efi_loaded_image_t *image)
+{
+	unsigned long nr_pages;
+	efi_status_t status;
+	/* Use alloc_addr to tranlsate between types */
+	efi_physical_addr_t alloc_addr;
+
+	/*
+	 * Verify that the DRAM base address is compatible the the ARM
+	 * boot protocol, which determines the base of DRAM by masking
+	 * off the low 24 bits of the address at which the zImage is
+	 * loaded at.  These assumptions are made by the decompressor,
+	 * before any memory map is available.
+	 */
+	if (dram_base & (ZIMAGE_OFFSET_LIMIT - 1)) {
+		pr_efi_err(sys_table, "Invalid DRAM base address alignment.\n");
+		return EFI_ERROR;
+	}
+
+	/*
+	 * Reserve memory for the uncompressed kernel image. This is
+	 * all that prevents any future allocations from conflicting
+	 * with the kernel.  Since we can't tell from the compressed
+	 * image how much DRAM the kernel actually uses (due to BSS
+	 * size uncertainty) we allocate the maximum possible size.
+	 * Do this very early, as prints can cause memory allocations
+	 * that may conflict with this.
+	 */
+	alloc_addr = dram_base;
+	*reserve_size = MAX_UNCOMP_KERNEL_SIZE;
+	nr_pages = round_up(*reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+	status = efi_call_phys4(sys_table->boottime->allocate_pages,
+				EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
+				nr_pages, &alloc_addr);
+	if (status != EFI_SUCCESS) {
+		*reserve_size = 0;
+		pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n");
+		return status;
+	}
+	*reserve_addr = alloc_addr;
+
+	/*
+	 * Relocate the zImage, if required.  ARM doesn't have a
+	 * preferred address, so we set it to 0, as we want to allocate
+	 * as low in memory as possible.
+	 */
+	*image_size = image->image_size;
+	status = efi_relocate_kernel(sys_table, image_addr, *image_size,
+				     *image_size, 0, 0);
+	if (status != EFI_SUCCESS) {
+		pr_efi_err(sys_table, "Failed to relocate kernel.\n");
+		efi_free(sys_table, *reserve_size, *reserve_addr);
+		*reserve_size = 0;
+		return status;
+	}
+
+	/*
+	 * Check to see if we were able to allocate memory low enough
+	 * in memory.  The kernel determines the base of DRAM from the
+	 * address at which the zImage is loaded.
+	 */
+	if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) {
+		pr_efi_err(sys_table, "Failed to relocate kernel, no low memory available.\n");
+		efi_free(sys_table, *reserve_size, *reserve_addr);
+		*reserve_size = 0;
+		efi_free(sys_table, *image_size, *image_addr);
+		*image_size = 0;
+		return EFI_ERROR;
+	}
+	return EFI_SUCCESS;
+}
diff --git a/arch/arm/boot/compressed/efi-stub.h b/arch/arm/boot/compressed/efi-stub.h
new file mode 100644
index 0000000..0fe9376
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-stub.h
@@ -0,0 +1,5 @@
+#ifndef _ARM_EFI_STUB_H
+#define _ARM_EFI_STUB_H
+/* Error code returned to ASM code instead of valid FDT address. */
+#define EFI_STUB_ERROR		(~0)
+#endif
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 066b034..eeb394c 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -10,6 +10,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include "efi-stub.h"
 
 	.arch	armv7-a
 /*
@@ -120,22 +121,93 @@
  */
 		.align
 		.arm				@ Always enter in ARM state
+		.text
 start:
 		.type	start,#function
-		.rept	7
+#ifdef CONFIG_EFI_STUB
+		@ Magic MSDOS signature for PE/COFF + ADD opcode
+		@ the EFI stub only supports little endian, as the EFI functions
+		@ it invokes are little endian.
+		.word	0x62805a4d
+#else
+		mov	r0, r0
+#endif
+		.rept	5
 		mov	r0, r0
 		.endr
-   ARM(		mov	r0, r0		)
-   ARM(		b	1f		)
- THUMB(		adr	r12, BSYM(1f)	)
- THUMB(		bx	r12		)
+
+		adrl	r12, BSYM(zimage_continue)
+ ARM(		mov     pc, r12 )
+ THUMB(		bx	r12     )
+		@ zimage_continue will be in ARM or thumb mode as configured
 
 		.word	0x016f2818		@ Magic numbers to help the loader
 		.word	start			@ absolute load/run zImage address
 		.word	_edata			@ zImage end address
+
+#ifdef CONFIG_EFI_STUB
+		@ Portions of the MSDOS file header must be at offset
+		@ 0x3c from the start of the file.  All PE/COFF headers
+		@ are kept contiguous for simplicity.
+#include "efi-header.S"
+
+efi_stub_entry:
+		@ The EFI stub entry point is not at a fixed address, however
+		@ this address must be set in the PE/COFF header.
+		@ EFI entry point is in A32 mode, switch to T32 if configured.
+ THUMB(		adr	r12, BSYM(1f)	)
+ THUMB(		bx	r12		)
  THUMB(		.thumb			)
 1:
  ARM_BE8(	setend	be )			@ go BE8 if compiled for BE8
+		@ Save lr on stack for possible return to EFI firmware.
+		@ Don't care about fp, but need 64 bit alignment....
+		stmfd	sp!, {fp, lr}
+
+		@ allocate space on stack for passing current zImage address
+		@ and for the EFI stub to return of new entry point of
+		@ zImage, as EFI stub may copy the kernel.  Pointer address
+		@ is passed in r2.  r0 and r1 are passed through from the
+		@ EFI firmware to efi_entry
+		adr	r3, start
+		str	r3, [sp, #-8]!
+		mov	r2, sp			@ pass pointer in r2
+		bl	efi_entry
+		ldr	r3, [sp], #8	@ get new zImage address from stack
+
+		@ Check for error return from EFI stub.  r0 has FDT address
+		@ or EFI_STUB_ERROR error code.
+		cmp	r0, #EFI_STUB_ERROR
+		beq	efi_load_fail
+
+		@ Save return values of efi_entry
+		stmfd	sp!, {r0, r3}
+		bl	cache_clean_flush
+		bl	cache_off
+		ldmfd   sp!, {r0, r3}
+
+		@ Set parameters for booting zImage according to boot protocol
+		@ put FDT address in r2, it was returned by efi_entry()
+		@ r1 is FDT machine type, and r0 needs to be 0
+		mov	r2, r0
+		mov	r1, #0xFFFFFFFF
+		mov	r0, #0
+
+		@ Branch to (possibly) relocated zImage that is in r3
+		@ Make sure we are in A32 mode, as zImage requires
+ THUMB(		bx	r3		)
+ ARM(		mov	pc, r3		)
+
+efi_load_fail:
+		@ Return EFI_LOAD_ERROR to EFI firmware on error.
+		@ Switch back to ARM mode for EFI is done based on
+		@ return address on stack in case we are in THUMB mode
+		ldr	r0, =0x80000001
+		ldmfd	sp!, {fp, pc}		@ put lr from stack into pc
+#endif
+
+ THUMB(		.thumb			)
+zimage_continue:
 		mrs	r9, cpsr
 #ifdef CONFIG_ARM_VIRT_EXT
 		bl	__hyp_stub_install	@ get into SVC mode, reversibly
@@ -168,7 +240,6 @@ not_angel:
 		 * by the linker here, but it should preserve r7, r8, and r9.
 		 */
 
-		.text
 
 #ifdef CONFIG_AUTO_ZRELADDR
 		@ determine final kernel image address
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 11/22] Disable stack protection for decompressor/stub
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

From: Roy Franz <roy.franz@linaro.org>

The ARM decompressor/EFI stub do not implement the functions
(__stack_chk_guard_setup, etc) that are required for support of
stack protection.  The actual enablement of stack protection is
controlled by heuristics in GCC, which the code added for the EFI
stub triggers when CONFIG_STACKPROTECTOR is set.  Even with
CONFIG_STACKPROTECTOR set, the decompressor was never compiled
with stack protection actually enabled. Adding -fno-stack-protector
to the decompressor/stub build keeps it building without stack
protection as it has always been built.
The x86 decompressor/stub is also built with -fno-stack-protector.

Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
 arch/arm/boot/compressed/Makefile |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 1415411..5fc32ae 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -132,7 +132,7 @@ ORIG_CFLAGS := $(KBUILD_CFLAGS)
 KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
 endif
 
-ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj)
+ccflags-y := -fpic -mno-single-pic-base -fno-builtin -fno-stack-protector -I$(obj)
 asflags-y := -DZIMAGE
 
 # Supply kernel BSS size to the decompressor via a linker symbol.
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 12/22] Documentation: arm: add UEFI support documentation
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

This patch provides documentation of the [U]EFI runtime service and
configuration features for the arm architecture.

Changes since v1/v2:
- Complete rewrite.
- New FDT bindings.

Cc: Rob Landley <rob@landley.net>
Cc: linux-doc at vger.kernel.org

Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Grant Likely <grant.likely@linaro.org>
---
 Documentation/arm/00-INDEX |    3 +++
 Documentation/arm/uefi.txt |   64 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)
 create mode 100644 Documentation/arm/uefi.txt

diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX
index 36420e1..b3af704 100644
--- a/Documentation/arm/00-INDEX
+++ b/Documentation/arm/00-INDEX
@@ -34,3 +34,6 @@ nwfpe/
 	- NWFPE floating point emulator documentation
 swp_emulation
 	- SWP/SWPB emulation handler/logging description
+
+uefi.txt
+	- [U]EFI configuration and runtime services documentation
diff --git a/Documentation/arm/uefi.txt b/Documentation/arm/uefi.txt
new file mode 100644
index 0000000..d60030a
--- /dev/null
+++ b/Documentation/arm/uefi.txt
@@ -0,0 +1,64 @@
+UEFI, the Unified Extensible Firmware Interface, is a specification
+governing the behaviours of compatible firmware interfaces. It is
+maintained by the UEFI Forum - http://www.uefi.org/.
+
+UEFI is an evolution of its predecessor 'EFI', so the terms EFI and
+UEFI are used somewhat interchangeably in this document and associated
+source code. As a rule, anything new uses 'UEFI', whereas 'EFI' refers
+to legacy code or specifications.
+
+UEFI support in Linux
+=====================
+Booting on a platform with firmware compliant with the UEFI specification
+makes it possible for the kernel to support additional features:
+- UEFI Runtime Services
+- Retrieving various configuration information through the standardised
+  interface of UEFI configuration tables. (ACPI, SMBIOS, ...)
+
+For actually enabling [U]EFI support, enable:
+- CONFIG_EFI=y
+- CONFIG_EFI_VARS=y or m
+
+The implementation depends on receiving information about the UEFI environment
+in a Flattened Device Tree (FDT) - so is only available with CONFIG_OF.
+
+UEFI stub
+=========
+The "stub" is a feature that extends the Image/zImage into a valid UEFI
+PE/COFF executable, including a loader application that makes it possible to
+load the kernel directly from the UEFI shell, boot menu, or one of the
+lightweight bootloaders like Gummiboot or rEFInd.
+
+The kernel image built with stub support remains a valid kernel image for
+booting in non-UEFI environments.
+
+UEFI kernel support on ARM
+==========================
+UEFI kernel support on the ARM architectures (arm and arm64) is only available
+when boot is performed through the stub.
+
+When booting in UEFI mode, the stub deletes any memory nodes from a provided DT.
+Instead, the kernel reads the UEFI memory map.
+
+The stub populates the FDT /chosen node with (and the kernel scans for) the
+following parameters:
+________________________________________________________________________________
+Name                      | Size   | Description
+================================================================================
+linux,uefi-system-table   | 64-bit | Physical address of the UEFI System Table.
+--------------------------------------------------------------------------------
+linux,uefi-mmap-start     | 64-bit | Physical address of the UEFI memory map,
+                          |        | populated by the UEFI GetMemoryMap() call.
+--------------------------------------------------------------------------------
+linux,uefi-mmap-size      | 32-bit | Size in bytes of the UEFI memory map
+                          |        | pointed to in previous entry.
+--------------------------------------------------------------------------------
+linux,uefi-mmap-desc-size | 32-bit | Size in bytes of each entry in the UEFI
+                          |        | memory map.
+--------------------------------------------------------------------------------
+linux,uefi-mmap-desc-ver  | 32-bit | Version of the mmap descriptor format.
+--------------------------------------------------------------------------------
+linux,uefi-stub-kern-ver  | string | Copy of linux_banner from build.
+--------------------------------------------------------------------------------
+
+For verbose debug messages, specify 'uefi_debug' on the kernel command line.
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH 13/22] arm: Add [U]EFI runtime services support
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>

This patch implements basic support for UEFI runtime services in the
ARM architecture - a requirement for using efibootmgr to read and update
the system boot configuration.

It uses the generic configuration table scanning to populate ACPI and
SMBIOS pointers.

Changes since v2:
- Updated FDT bindings.
- Preserve regions marked RESERVED (but don't map them).
- Rename 'efi' -> 'uefi' within this new port (leaving core code as is).

Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Reviewed-by: Grant Likely <grant.likely@linaro.org>
---
 arch/arm/Kconfig            |   16 ++
 arch/arm/include/asm/uefi.h |   28 +++
 arch/arm/kernel/Makefile    |    2 +
 arch/arm/kernel/setup.c     |    7 +-
 arch/arm/kernel/uefi.c      |  413 +++++++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/uefi_phys.S |   69 ++++++++
 6 files changed, 533 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/include/asm/uefi.h
 create mode 100644 arch/arm/kernel/uefi.c
 create mode 100644 arch/arm/kernel/uefi_phys.S

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a693921..1e1273d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1885,6 +1885,20 @@ config EARLY_IOREMAP
 	  the same virtual memory range as kmap so all early mappings must
 	  be unapped before paging_init() is called.
 
+config EFI
+	bool "UEFI runtime service support"
+	depends on OF && !CPU_BIG_ENDIAN
+	select UCS2_STRING
+	select EARLY_IOREMAP
+	select UEFI_PARAMS_FROM_FDT
+	---help---
+	  This enables the kernel to use UEFI runtime services that are
+	  available (such as the UEFI variable services).
+
+	  This option is only useful on systems that have UEFI firmware.
+	  However, even with this option, the resultant kernel will
+	  continue to boot on non-UEFI platforms.
+
 config EFI_STUB
 	bool "EFI stub support"
 	depends on EFI && !CPU_BIG_ENDIAN
@@ -2304,6 +2318,8 @@ source "net/Kconfig"
 
 source "drivers/Kconfig"
 
+source "drivers/firmware/Kconfig"
+
 source "fs/Kconfig"
 
 source "arch/arm/Kconfig.debug"
diff --git a/arch/arm/include/asm/uefi.h b/arch/arm/include/asm/uefi.h
new file mode 100644
index 0000000..3bc4c60
--- /dev/null
+++ b/arch/arm/include/asm/uefi.h
@@ -0,0 +1,28 @@
+#ifndef _ASM_ARM_EFI_H
+#define _ASM_ARM_EFI_H
+
+#ifdef CONFIG_EFI
+#include <asm/mach/map.h>
+
+extern void uefi_init(void);
+
+typedef efi_status_t uefi_phys_call_t(efi_set_virtual_address_map_t *f,
+				      u32 virt_phys_offset,
+				      u32 memory_map_size,
+				      u32 descriptor_size,
+				      u32 descriptor_version,
+				      efi_memory_desc_t *dsc);
+
+extern efi_status_t uefi_phys_call(u32, u32, u32, efi_memory_desc_t *,
+				   efi_set_virtual_address_map_t *);
+
+#define uefi_remap(cookie, size) __arm_ioremap((cookie), (size), MT_MEMORY_RWX)
+#define uefi_ioremap(cookie, size) __arm_ioremap((cookie), (size), MT_DEVICE)
+#define uefi_unmap(cookie) __arm_iounmap((cookie))
+#define uefi_iounmap(cookie) __arm_iounmap((cookie))
+
+#else
+#define uefi_init()
+#endif /* CONFIG_EFI */
+
+#endif /* _ASM_ARM_EFI_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a30fc9b..736cce4 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -98,4 +98,6 @@ obj-y				+= psci.o
 obj-$(CONFIG_SMP)		+= psci_smp.o
 endif
 
+obj-$(CONFIG_EFI)		+= uefi.o uefi_phys.o
+
 extra-y := $(head-y) vmlinux.lds
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b074ef5..71b8839 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -30,6 +30,7 @@
 #include <linux/bug.h>
 #include <linux/compiler.h>
 #include <linux/sort.h>
+#include <linux/efi.h>
 
 #include <asm/unified.h>
 #include <asm/cp15.h>
@@ -57,6 +58,7 @@
 #include <asm/unwind.h>
 #include <asm/memblock.h>
 #include <asm/virt.h>
+#include <asm/uefi.h>
 
 #include "atags.h"
 
@@ -878,6 +880,9 @@ void __init setup_arch(char **cmdline_p)
 	if (mdesc->reboot_mode != REBOOT_HARD)
 		reboot_mode = mdesc->reboot_mode;
 
+	early_ioremap_init();
+	uefi_init();
+
 	init_mm.start_code = (unsigned long) _text;
 	init_mm.end_code   = (unsigned long) _etext;
 	init_mm.end_data   = (unsigned long) _edata;
@@ -889,8 +894,6 @@ void __init setup_arch(char **cmdline_p)
 
 	parse_early_param();
 
-	early_ioremap_init();
-
 	early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
 	setup_dma_zone(mdesc);
 	sanity_check_meminfo();
diff --git a/arch/arm/kernel/uefi.c b/arch/arm/kernel/uefi.c
new file mode 100644
index 0000000..77c18b6
--- /dev/null
+++ b/arch/arm/kernel/uefi.c
@@ -0,0 +1,413 @@
+/*
+ * Based on Unified Extensible Firmware Interface Specification version 2.3.1
+ *
+ * Copyright (C) 2013-2014  Linaro Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/efi.h>
+#include <linux/export.h>
+#include <linux/memblock.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/cacheflush.h>
+#include <asm/idmap.h>
+#include <asm/setup.h>
+#include <asm/tlbflush.h>
+#include <asm/uefi.h>
+
+struct efi_memory_map memmap;
+
+static efi_runtime_services_t *runtime;
+
+static phys_addr_t uefi_system_table;
+static phys_addr_t uefi_boot_mmap;
+static u32 uefi_boot_mmap_size;
+static u32 uefi_mmap_desc_size;
+static u32 uefi_mmap_desc_ver;
+
+/*
+ * If you want to wire up a debugger and debug the UEFI side, set to 0.
+ */
+#define DISCARD_UNUSED_REGIONS 1
+
+/*
+ * If you need to (temporarily) support buggy firmware, set to 0.
+ */
+#define DISCARD_BOOT_SERVICES_REGIONS 1
+
+static int uefi_debug __initdata;
+static int __init uefi_debug_setup(char *str)
+{
+	uefi_debug = 1;
+
+	return 0;
+}
+early_param("uefi_debug", uefi_debug_setup);
+
+static int __init uefi_systab_init(void)
+{
+	efi_char16_t *c16;
+	char vendor[100] = "unknown";
+	int i, retval;
+
+	efi.systab = early_memremap(uefi_system_table,
+				    sizeof(efi_system_table_t));
+
+	/*
+	 * Verify the UEFI System Table
+	 */
+	if (efi.systab == NULL)
+		panic("Whoa! Can't find UEFI system table.\n");
+	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+		panic("Whoa! UEFI system table signature incorrect\n");
+	if ((efi.systab->hdr.revision >> 16) == 0)
+		pr_warn("Warning: UEFI system table version %d.%02d, expected 2.30 or greater\n",
+			efi.systab->hdr.revision >> 16,
+			efi.systab->hdr.revision & 0xffff);
+
+	/* Show what we know for posterity */
+	c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
+	if (c16) {
+		for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
+			vendor[i] = c16[i];
+		vendor[i] = '\0';
+	}
+
+	pr_info("UEFI v%u.%.02u by %s\n",
+		efi.systab->hdr.revision >> 16,
+		efi.systab->hdr.revision & 0xffff, vendor);
+
+	retval = efi_config_init(NULL);
+	if (retval == 0)
+		set_bit(EFI_CONFIG_TABLES, &efi.flags);
+
+	early_memunmap(c16, sizeof(vendor));
+	early_memunmap(efi.systab,  sizeof(efi_system_table_t));
+
+	return retval;
+}
+
+static __init int is_discardable_region(efi_memory_desc_t *md)
+{
+	if (md->attribute & EFI_MEMORY_RUNTIME)
+		return 0;
+
+	switch (md->type) {
+	case EFI_CONVENTIONAL_MEMORY:
+		return 1;
+	case EFI_BOOT_SERVICES_CODE:
+	case EFI_BOOT_SERVICES_DATA:
+		return DISCARD_BOOT_SERVICES_REGIONS;
+	/* Keep tables around for any future kexec operations */
+	case EFI_ACPI_MEMORY_NVS:
+	case EFI_ACPI_RECLAIM_MEMORY:
+		return 0;
+	/* Preserve */
+	case EFI_RESERVED_TYPE:
+		return 0;
+	}
+
+	return DISCARD_UNUSED_REGIONS;
+}
+
+static __initdata struct {
+	u32 type;
+	const char *name;
+}  memory_type_name_map[] = {
+	{EFI_RESERVED_TYPE, "reserved"},
+	{EFI_LOADER_CODE, "loader code"},
+	{EFI_LOADER_DATA, "loader data"},
+	{EFI_BOOT_SERVICES_CODE, "boot services code"},
+	{EFI_BOOT_SERVICES_DATA, "boot services data"},
+	{EFI_RUNTIME_SERVICES_CODE, "runtime services code"},
+	{EFI_RUNTIME_SERVICES_DATA, "runtime services data"},
+	{EFI_CONVENTIONAL_MEMORY, "conventional memory"},
+	{EFI_UNUSABLE_MEMORY, "unusable memory"},
+	{EFI_ACPI_RECLAIM_MEMORY, "ACPI reclaim memory"},
+	{EFI_ACPI_MEMORY_NVS, "ACPI memory nvs"},
+	{EFI_MEMORY_MAPPED_IO, "memory mapped I/O"},
+	{EFI_MEMORY_MAPPED_IO_PORT_SPACE, "memory mapped I/O port space"},
+	{EFI_PAL_CODE, "pal code"},
+	{EFI_MAX_MEMORY_TYPE, NULL},
+};
+
+static __init void remove_sections(phys_addr_t addr, unsigned long size)
+{
+	unsigned long section_offset;
+	unsigned long num_sections;
+
+	section_offset = addr - (addr & SECTION_MASK);
+	num_sections = size / SECTION_SIZE;
+	if (size % SECTION_SIZE)
+		num_sections++;
+
+	memblock_remove(addr - section_offset, num_sections * SECTION_SIZE);
+}
+
+static void memmap_init(void)
+{
+	efi_memory_desc_t *md;
+	int i = 0;
+
+	if (uefi_debug)
+		pr_info("Processing UEFI memory map:\n");
+
+	memmap.map = early_memremap(uefi_boot_mmap, uefi_boot_mmap_size);
+	if (!memmap.map)
+		return;
+
+	memmap.map_end = memmap.map + uefi_boot_mmap_size;
+	memmap.nr_map = 0;
+
+	for_each_efi_memory_desc(&memmap, md) {
+		pr_info("  %8llu pages @ %016llx (%s)\n",
+			md->num_pages, md->phys_addr,
+			memory_type_name_map[md->type].name);
+		if (md->attribute & EFI_MEMORY_WB) {
+			if (is_discardable_region(md)) {
+				arm_add_memory(md->phys_addr,
+					       md->num_pages * EFI_PAGE_SIZE);
+				i++;
+			}
+		}
+		memmap.nr_map++;
+	}
+
+	if (uefi_debug)
+		pr_info("%d memory regions added.\n", i);
+
+	remove_sections(uefi_boot_mmap, uefi_boot_mmap_size);
+
+	early_memunmap(memmap.map, uefi_boot_mmap_size);
+
+	set_bit(EFI_MEMMAP, &efi.flags);
+}
+
+void __init uefi_init(void)
+{
+	struct efi_fdt_params params;
+
+	uefi_debug = 1;
+
+	/* Grab UEFI information placed in FDT by stub */
+	if (!efi_get_fdt_params(&params, uefi_debug))
+		return;
+
+	uefi_system_table = params.system_table;
+
+	uefi_boot_mmap = params.mmap;
+	uefi_boot_mmap_size = params.mmap_size;
+	uefi_mmap_desc_size = params.desc_size;
+	uefi_mmap_desc_ver = params.desc_ver;
+	memmap.desc_size = uefi_mmap_desc_size;
+	memmap.map_end = memmap.map + params.mmap_size;
+	if (uefi_boot_mmap > UINT_MAX) {
+		pr_err("UEFI memory map located above 4GB - unusable!");
+		return;
+	}
+
+	if (uefi_systab_init() < 0)
+		return;
+
+	memmap_init();
+
+	set_bit(EFI_BOOT, &efi.flags);
+}
+
+/*
+ * Disable instrrupts, enable idmap and disable caches.
+ */
+static void __init phys_call_prologue(void)
+{
+	local_irq_disable();
+
+	outer_disable();
+
+	idmap_prepare();
+}
+
+/*
+ * Restore original memory map and re-enable interrupts.
+ */
+static void __init phys_call_epilogue(void)
+{
+	static struct mm_struct *mm = &init_mm;
+
+	/* Restore original memory mapping */
+	cpu_switch_mm(mm->pgd, mm);
+
+	local_flush_bp_all();
+	local_flush_tlb_all();
+
+	outer_resume();
+
+	local_irq_enable();
+}
+
+static int __init remap_region(efi_memory_desc_t *md, int entry)
+{
+	efi_memory_desc_t *region;
+	u32 va;
+	u64 paddr;
+	u64 size;
+
+	region = memmap.map + entry * memmap.desc_size;
+	*region = *md;
+	paddr = region->phys_addr;
+	size = region->num_pages << EFI_PAGE_SHIFT;
+
+	/*
+	 * Map everything writeback-capable as coherent memory,
+	 * anything else as device.
+	 */
+	if (md->attribute & EFI_MEMORY_WB)
+		va = (u32)uefi_remap(paddr, size);
+	else
+		va = (u32)uefi_ioremap(paddr, size);
+	if (!va)
+		return 0;
+	region->virt_addr = va;
+
+	if (uefi_debug)
+		pr_info("  %016llx-%016llx => 0x%08x : (%s)\n",
+			paddr, paddr + size - 1, va,
+			md->attribute &  EFI_MEMORY_WB ? "WB" : "I/O");
+
+	return 1;
+}
+
+static int __init remap_regions(void)
+{
+	void *p;
+	efi_memory_desc_t *md;
+	int mapped_regions;
+
+	memmap.phys_map = uefi_remap(uefi_boot_mmap, uefi_boot_mmap_size);
+	if (!memmap.phys_map)
+		return 0;
+
+	memmap.map_end = memmap.phys_map + uefi_boot_mmap_size;
+	memmap.desc_size = uefi_mmap_desc_size;
+	memmap.desc_version = uefi_mmap_desc_ver;
+
+	/* Allocate space for the physical region map */
+	memmap.map = kzalloc(memmap.nr_map * memmap.desc_size, GFP_ATOMIC);
+	if (!memmap.map)
+		return 0;
+
+	mapped_regions = 0;
+	for (p = memmap.phys_map; p < memmap.map_end; p += memmap.desc_size) {
+		md = p;
+		if (is_discardable_region(md))
+			continue;
+
+		if (!remap_region(p, mapped_regions++))
+			return 0;
+	}
+
+	memmap.map_end = memmap.map + mapped_regions * memmap.desc_size;
+	efi.memmap = &memmap;
+
+	uefi_unmap(memmap.phys_map);
+	memmap.phys_map = efi_lookup_mapped_addr(uefi_boot_mmap);
+	efi.systab = efi_lookup_mapped_addr(uefi_system_table);
+	if (efi.systab)
+		set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+	/*
+	 * efi.systab->runtime is a 32-bit pointer to something guaranteed by
+	 * the UEFI specification to be 1:1 mapped in a 4GB address space.
+	 */
+	runtime = efi_lookup_mapped_addr((u32)efi.systab->runtime);
+
+	return 1;
+}
+
+
+/*
+ * This function switches the UEFI runtime services to virtual mode.
+ * This operation must be performed only once in the system's lifetime,
+ * including any kecec calls.
+ *
+ * This must be done with a 1:1 mapping. The current implementation
+ * resolves this by disabling the MMU.
+ */
+efi_status_t  __init phys_set_virtual_address_map(u32 memory_map_size,
+						  u32 descriptor_size,
+						  u32 descriptor_version,
+						  efi_memory_desc_t *dsc)
+{
+	uefi_phys_call_t *phys_set_map;
+	efi_status_t status;
+
+	phys_call_prologue();
+
+	phys_set_map = (void *)(unsigned long)virt_to_phys(uefi_phys_call);
+
+	/* Called with caches disabled, returns with caches enabled */
+	status = phys_set_map(efi.set_virtual_address_map,
+			      PAGE_OFFSET - PHYS_OFFSET,
+			      memory_map_size, descriptor_size,
+			      descriptor_version, dsc);
+
+	phys_call_epilogue();
+
+	return status;
+}
+
+/*
+ * Called explicitly from init/mm.c
+ */
+void __init efi_enter_virtual_mode(void)
+{
+	efi_status_t status;
+	u32 mmap_phys_addr;
+
+	if (!efi_enabled(EFI_BOOT)) {
+		pr_info("UEFI services will not be available.\n");
+		return;
+	}
+
+	pr_info("Remapping and enabling UEFI services.\n");
+
+	/* Map the regions we memblock_remove:d earlier into kernel
+	   address space */
+	if (!remap_regions()) {
+		pr_info("Failed to remap UEFI regions - runtime services will not be available.\n");
+		return;
+	}
+
+	/* Call SetVirtualAddressMap with the physical address of the map */
+	efi.set_virtual_address_map = runtime->set_virtual_address_map;
+
+	/*
+	 * __virt_to_phys() takes an unsigned long and returns a phys_addr_t
+	 * memmap.phys_map is a void *
+	 * The gymnastics below makes this compile validly with/without LPAE.
+	 */
+	mmap_phys_addr = __virt_to_phys((u32)memmap.map);
+	memmap.phys_map = (void *)mmap_phys_addr;
+
+	status = phys_set_virtual_address_map(memmap.nr_map * memmap.desc_size,
+					      memmap.desc_size,
+					      memmap.desc_version,
+					      memmap.phys_map);
+	if (status != EFI_SUCCESS) {
+		pr_info("Failed to set UEFI virtual address map!\n");
+		return;
+	}
+
+	/* Set up function pointers for efivars */
+	efi.get_variable = runtime->get_variable;
+	efi.get_next_variable = runtime->get_next_variable;
+	efi.set_variable = runtime->set_variable;
+	efi.set_virtual_address_map = NULL;
+
+	set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+}
diff --git a/arch/arm/kernel/uefi_phys.S b/arch/arm/kernel/uefi_phys.S
new file mode 100644
index 0000000..a999626
--- /dev/null
+++ b/arch/arm/kernel/uefi_phys.S
@@ -0,0 +1,69 @@
+/*
+ * arch/arm/kernel/uefi_phys.S
+ *
+ * Copyright (C) 2013  Linaro Ltd.
+ *
+ * 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.
+ */
+
+#include <asm/assembler.h>
+#include <asm/cp15.h>
+#include <linux/linkage.h>
+#define PAR_MASK 0xfff
+
+	.text
+@ uefi_phys_call(*f, virt_phys_offset, a, b, c, d, ...)
+	.align  5
+	.pushsection    .idmap.text, "ax"
+ENTRY(uefi_phys_call)
+	@ Save physical context
+	mov	r12, sp
+	ldr	sp, =tmpstack
+	stmfd	sp, {r4-r5, r12, lr}	@ push is redefined by asm/assembler.h
+
+	mov	r4, r1
+
+	@ Extract function pointer (don't write lr again before call)
+	mov	lr, r0
+
+	@ Shift arguments down
+	mov	r0, r2
+	mov	r1, r3
+	ldr	r2, [r12], #4
+	ldr	r3, [r12], #4
+
+	@ Convert sp to physical
+	sub	r12, r12, r4
+	mov	sp, r12
+
+	@ Disable MMU
+	ldr	r5, =(CR_M)
+	update_sctlr	r12, , r5
+	isb
+
+	@ Make call
+	blx	lr
+
+	@ Enable MMU + Caches
+	ldr	r4, =(CR_I | CR_C | CR_M)
+	update_sctlr	r12, r4
+	isb
+
+	ldr	sp, =tmpstack_top
+	ldmfd	sp, {r4-r5, r12, lr}
+
+	@ Restore virtual sp and return
+	mov	sp, r12
+	bx	lr
+
+	.align	3
+tmpstack_top:
+	.long	0	@ r4
+	.long	0	@ r5
+	.long	0	@ r12
+	.long	0	@ lr
+tmpstack:
+ENDPROC(uefi_phys_call)
+	.popsection
-- 
1.7.10.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox