From myselfdushyantbehl at gmail.com  Thu May  5 03:47:08 2016
From: myselfdushyantbehl at gmail.com (Dushyant Behl)
Date: Thu, 5 May 2016 16:17:08 +0530
Subject: Query regarding Linux Arm pagetable setup
Message-ID: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>

Hi,

I am trying to understand the linux arm memory management and
I have some questions regarding the linux's arm pagetables.

I am looking at the kernel 4.1.0 execution with Arm-v7 architecture
and LPAE enabled.

I am not able to understand what is the use of TTBR1 page table mappings.
The settings in TTBCR register are T0SZ - 0 and T1SZ - 2, which indicate a
3G-1G split but if I look at the TTBR1 page table then it doesn't
contains some of the
actual required high address (1G range) mappings while they are
present in the TTBR0 page table.

Can someone explain how the kernel is using both the TTBR0 and TTBR1
and how some
mappings which should've been present in TTBR1 are actually used
through the TTBR0 register?

Also, another thing which I noticed is that kernel is mapping the high
interrupt vectors (addr 0xFFFF0000)
in the user process's page table with read only permissions and user
bit enabled.
Can you also explain why kernel is mapping the kernel's pages with the
user bit? Also are there any other
kernel pages which are marked with similar user bit and read only
permissions in the pagetables
with possible aliasing in the kernel's address space too?

Thanks,
Dushyant


From linux at armlinux.org.uk  Thu May  5 09:04:57 2016
From: linux at armlinux.org.uk (Russell King - ARM Linux)
Date: Thu, 5 May 2016 17:04:57 +0100
Subject: Query regarding Linux Arm pagetable setup
In-Reply-To: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
References: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
Message-ID: <20160505160457.GX19428@n2100.arm.linux.org.uk>

On Thu, May 05, 2016 at 04:17:08PM +0530, Dushyant Behl wrote:
> I am looking at the kernel 4.1.0 execution with Arm-v7 architecture
> and LPAE enabled.
> 
> I am not able to understand what is the use of TTBR1 page table mappings.
> The settings in TTBCR register are T0SZ - 0 and T1SZ - 2, which indicate a
> 3G-1G split but if I look at the TTBR1 page table then it doesn't
> contains some of the
> actual required high address (1G range) mappings while they are
> present in the TTBR0 page table.
> 
> Can someone explain how the kernel is using both the TTBR0 and TTBR1
> and how some
> mappings which should've been present in TTBR1 are actually used
> through the TTBR0 register?

Those who know LPAE (or have the documentation to hand) may be able to
answer that better than I can at the moment.

> Also, another thing which I noticed is that kernel is mapping the high
> interrupt vectors (addr 0xFFFF0000) in the user process's page table
> with read only permissions and user bit enabled.
> Can you also explain why kernel is mapping the kernel's pages with the
> user bit?

The vector page is used to provide a set of userspace helpers so that
userspace can be more independent of the CPU than it otherwise would
be - things like a cmpxchg implementation, memory barrier, and a TLS
helper.  You can turn this off, provided you know for certain that
your userspace does not make use of these facilities.

> Also are there any other kernel pages which are marked with similar
> user bit and read only permissions in the pagetables with possible
> aliasing in the kernel's address space too?

No.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.


From catalin.marinas at arm.com  Thu May  5 09:54:55 2016
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Thu, 5 May 2016 17:54:55 +0100
Subject: Query regarding Linux Arm pagetable setup
In-Reply-To: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
References: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
Message-ID: <20160505165455.GB3703@e104818-lin.cambridge.arm.com>

On Thu, May 05, 2016 at 04:17:08PM +0530, Dushyant Behl wrote:
> I am looking at the kernel 4.1.0 execution with Arm-v7 architecture
> and LPAE enabled.
> 
> I am not able to understand what is the use of TTBR1 page table mappings.
> The settings in TTBCR register are T0SZ - 0 and T1SZ - 2, which indicate a
> 3G-1G split but if I look at the TTBR1 page table then it doesn't
> contains some of the actual required high address (1G range) mappings
> while they are present in the TTBR0 page table.
> 
> Can someone explain how the kernel is using both the TTBR0 and TTBR1
> and how some mappings which should've been present in TTBR1 are
> actually used through the TTBR0 register?

With the 3-1 split, TTBR1 only needs to cover 1GB of virtual memory.
This means that Level 1 page table is disabled (pgd/pud) and the first 3
pmd pages are also skipped. The architecture does not allow TTBRx sizes
with a single entry at the top level, meaning that the number of levels
must be reduced.

To recap: with LPAE, 1 pgd/pud entry covers 1GB of VA, the same as a
full pmd page (4K/8 entries * 2MB per entry). So for 1GB kernel mapping
in TTBR1 we only need 512 pmd entries == 1 4KB page for the pmd. The
v7_ttb_setup macro in arch/arm/mm/proc-v7-3level.S adjusts the TTBR1
value (initially pointing at swapper_pg_dir) with TTBR1_OFFSET (defined
in pgtable-3level-hwdef.h).

So I think you may just be mis-reading the page table pointed at by
TTBR1.

-- 
Catalin


From catalin.marinas at arm.com  Thu May  5 09:59:01 2016
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Thu, 5 May 2016 17:59:01 +0100
Subject: Query regarding Linux Arm pagetable setup
In-Reply-To: <20160505160457.GX19428@n2100.arm.linux.org.uk>
References: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
 <20160505160457.GX19428@n2100.arm.linux.org.uk>
Message-ID: <20160505165901.GC3703@e104818-lin.cambridge.arm.com>

On Thu, May 05, 2016 at 05:04:57PM +0100, Russell King - ARM Linux wrote:
> On Thu, May 05, 2016 at 04:17:08PM +0530, Dushyant Behl wrote:
> > Also, another thing which I noticed is that kernel is mapping the high
> > interrupt vectors (addr 0xFFFF0000) in the user process's page table
> > with read only permissions and user bit enabled.
> > Can you also explain why kernel is mapping the kernel's pages with the
> > user bit?
> 
> The vector page is used to provide a set of userspace helpers so that
> userspace can be more independent of the CPU than it otherwise would
> be - things like a cmpxchg implementation, memory barrier, and a TLS
> helper.  You can turn this off, provided you know for certain that
> your userspace does not make use of these facilities.
> 
> > Also are there any other kernel pages which are marked with similar
> > user bit and read only permissions in the pagetables with possible
> > aliasing in the kernel's address space too?
> 
> No.

Actually, most read-only user pages (e.g. mmap'ed code) have an alias in
the kernel linear mapping or temporarily in highmem (after kmap).

-- 
Catalin


From linux at armlinux.org.uk  Thu May  5 10:00:38 2016
From: linux at armlinux.org.uk (Russell King - ARM Linux)
Date: Thu, 5 May 2016 18:00:38 +0100
Subject: Query regarding Linux Arm pagetable setup
In-Reply-To: <20160505165901.GC3703@e104818-lin.cambridge.arm.com>
References: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
 <20160505160457.GX19428@n2100.arm.linux.org.uk>
 <20160505165901.GC3703@e104818-lin.cambridge.arm.com>
Message-ID: <20160505170038.GZ19428@n2100.arm.linux.org.uk>

On Thu, May 05, 2016 at 05:59:01PM +0100, Catalin Marinas wrote:
> On Thu, May 05, 2016 at 05:04:57PM +0100, Russell King - ARM Linux wrote:
> > On Thu, May 05, 2016 at 04:17:08PM +0530, Dushyant Behl wrote:
> > > Also are there any other kernel pages which are marked with similar
> > > user bit and read only permissions in the pagetables with possible
> > > aliasing in the kernel's address space too?
> > 
> > No.
> 
> Actually, most read-only user pages (e.g. mmap'ed code) have an alias in
> the kernel linear mapping or temporarily in highmem (after kmap).

If you want to be strict about it, all pages can end up in that state.

I assumed, however, that the OP was asking about pages similar to the
special vector page.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.


From catalin.marinas at arm.com  Thu May  5 10:13:48 2016
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Thu, 5 May 2016 18:13:48 +0100
Subject: Query regarding Linux Arm pagetable setup
In-Reply-To: <20160505170038.GZ19428@n2100.arm.linux.org.uk>
References: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
 <20160505160457.GX19428@n2100.arm.linux.org.uk>
 <20160505165901.GC3703@e104818-lin.cambridge.arm.com>
 <20160505170038.GZ19428@n2100.arm.linux.org.uk>
Message-ID: <20160505171348.GE3703@e104818-lin.cambridge.arm.com>

On Thu, May 05, 2016 at 06:00:38PM +0100, Russell King - ARM Linux wrote:
> On Thu, May 05, 2016 at 05:59:01PM +0100, Catalin Marinas wrote:
> > On Thu, May 05, 2016 at 05:04:57PM +0100, Russell King - ARM Linux wrote:
> > > On Thu, May 05, 2016 at 04:17:08PM +0530, Dushyant Behl wrote:
> > > > Also are there any other kernel pages which are marked with similar
> > > > user bit and read only permissions in the pagetables with possible
> > > > aliasing in the kernel's address space too?
> > > 
> > > No.
> > 
> > Actually, most read-only user pages (e.g. mmap'ed code) have an alias in
> > the kernel linear mapping or temporarily in highmem (after kmap).
> 
> If you want to be strict about it, all pages can end up in that state.
> 
> I assumed, however, that the OP was asking about pages similar to the
> special vector page.

That was my first thought as well but given that we don't know the
background to this question, I think it's better to state the other
cases (maybe OP is trying to work around a hardware bug affecting page
permission, you never know; I hope not).

-- 
Catalin


From myselfdushyantbehl at gmail.com  Fri May  6 12:41:25 2016
From: myselfdushyantbehl at gmail.com (Dushyant Behl)
Date: Sat, 7 May 2016 01:11:25 +0530
Subject: Query regarding Linux Arm pagetable setup
In-Reply-To: <20160505171348.GE3703@e104818-lin.cambridge.arm.com>
References: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
 <20160505160457.GX19428@n2100.arm.linux.org.uk>
 <20160505165901.GC3703@e104818-lin.cambridge.arm.com>
 <20160505170038.GZ19428@n2100.arm.linux.org.uk>
 <20160505171348.GE3703@e104818-lin.cambridge.arm.com>
Message-ID: <CAHF350K5nXGJ4iw10jyy9bxcUW4oPkU2cTV4dd-xHwxV8nU=Wg@mail.gmail.com>

On Thu, May 5, 2016 at 10:43 PM, Catalin Marinas
<catalin.marinas at arm.com> wrote:
> On Thu, May 05, 2016 at 06:00:38PM +0100, Russell King - ARM Linux wrote:
>> On Thu, May 05, 2016 at 05:59:01PM +0100, Catalin Marinas wrote:
>> > On Thu, May 05, 2016 at 05:04:57PM +0100, Russell King - ARM Linux wrote:
>> > > On Thu, May 05, 2016 at 04:17:08PM +0530, Dushyant Behl wrote:
>> > > > Also are there any other kernel pages which are marked with similar
>> > > > user bit and read only permissions in the pagetables with possible
>> > > > aliasing in the kernel's address space too?
>> > >
>> > > No.
>> >
>> > Actually, most read-only user pages (e.g. mmap'ed code) have an alias in
>> > the kernel linear mapping or temporarily in highmem (after kmap).
>>
>> If you want to be strict about it, all pages can end up in that state.
>>
>> I assumed, however, that the OP was asking about pages similar to the
>> special vector page.
>
> That was my first thought as well but given that we don't know the
> background to this question, I think it's better to state the other
> cases (maybe OP is trying to work around a hardware bug affecting page
> permission, you never know; I hope not).

Sorry for not being clear I actually wanted to know about pages similar to the
special vector pages. Thanks for the explanation.

Thanks,
Dushyant


From myselfdushyantbehl at gmail.com  Fri May  6 13:01:27 2016
From: myselfdushyantbehl at gmail.com (Dushyant Behl)
Date: Sat, 7 May 2016 01:31:27 +0530
Subject: Query regarding Linux Arm pagetable setup
In-Reply-To: <20160505165455.GB3703@e104818-lin.cambridge.arm.com>
References: <CAHF350KxPZ8bHERX6PUWxW=voV_iSdnSksxRzcVJ_8=vD1bdAw@mail.gmail.com>
 <20160505165455.GB3703@e104818-lin.cambridge.arm.com>
Message-ID: <CAHF350KE3NUp1idYS4Zmp=RyOdKex=2AYvWrTzO=Usht29LUHw@mail.gmail.com>

On Thu, May 5, 2016 at 10:24 PM, Catalin Marinas
<catalin.marinas at arm.com> wrote:
> On Thu, May 05, 2016 at 04:17:08PM +0530, Dushyant Behl wrote:
>> Can someone explain how the kernel is using both the TTBR0 and TTBR1
>> and how some mappings which should've been present in TTBR1 are
>> actually used through the TTBR0 register?
>
> With the 3-1 split, TTBR1 only needs to cover 1GB of virtual memory.
> This means that Level 1 page table is disabled (pgd/pud) and the first 3
> pmd pages are also skipped. The architecture does not allow TTBRx sizes
> with a single entry at the top level, meaning that the number of levels
> must be reduced.

Aah, this is the reason why the table looked strange to me. Thanks.

--
Dushyant


From stephen.boyd at linaro.org  Tue May 10 15:01:49 2016
From: stephen.boyd at linaro.org (Stephen Boyd)
Date: Tue, 10 May 2016 15:01:49 -0700
Subject: [PATCH] arm64: dts: qcom: Add msm8916 PMU node
Message-ID: <1462917709-29789-1-git-send-email-stephen.boyd@linaro.org>

Add the PMU so we can get proper perf event support on this SoC.

Signed-off-by: Stephen Boyd <stephen.boyd at linaro.org>
---
 arch/arm64/boot/dts/qcom/msm8916.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 96812007850e..c440fd6bc5cd 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -91,6 +91,11 @@
 		};
 	};
 
+	pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <GIC_PPI 7 GIC_CPU_MASK_SIMPLE(4)>;
+	};
+
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
-- 
2.8.0.rc4



From stephen.boyd at linaro.org  Tue May 10 15:26:00 2016
From: stephen.boyd at linaro.org (Stephen Boyd)
Date: Tue, 10 May 2016 15:26:00 -0700
Subject: [RFC/PATCHv3 v3 0/3] request_firmware() into pre-allocated buffers
Message-ID: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>

Some systems are memory constrained but they need to load very
large firmwares. The firmware subsystem allows drivers to request
this firmware be loaded from the filesystem, but this requires
that the entire firmware be loaded into kernel memory first
before it's provided to the driver. This can lead to a situation
where we map the firmware twice, once to load the firmware into
kernel memory and once to copy the firmware into the final
resting place.

This design creates needless memory pressure and delays loading
because we have to copy from kernel memory to somewhere else.
This patch sets adds support to the request firmware API to load the
firmware directly into a pre-allocated buffer, skipping the intermediate
copying step and alleviating memory pressure during firmware loading.
The drawback is that we can't use the firmware caching feature because
the memory for the firmware cache is not managed by the firmware
layer.

Patches based on v4.6-rc1.

Changes since v2:
 * Dropped DMA API changes and moved to dma coherent APIs per Catalin's
   suggestions
 * Reworked to request firmware directly into any pre-allocated buffer
 * Split off cleanup patch into patch #1 to ease review 
 * Added file reading enum for reading firmware directly into buffer

Changes since v1:
 * Rebased onto v4.6-rc1 (large conflicts due to movement of code from Mimi)
 * Added some CONFIG_HAS_DMA ifdefs around code that's using DMA ops

Stephen Boyd (2):
  firmware: Consolidate kmap/read/write logic
  firmware: Support loading into a pre-allocated buffer

Vikram Mulukutla (1):
  firmware: Provide infrastructure to make fw caching optional

 drivers/base/firmware_class.c   | 183 ++++++++++++++++++++++++++++------------
 fs/exec.c                       |  21 +++--
 include/linux/firmware.h        |   8 ++
 include/linux/fs.h              |   1 +
 security/integrity/ima/ima_fs.c |   3 +-
 5 files changed, 153 insertions(+), 63 deletions(-)

-- 
2.8.0.rc4



From stephen.boyd at linaro.org  Tue May 10 15:26:01 2016
From: stephen.boyd at linaro.org (Stephen Boyd)
Date: Tue, 10 May 2016 15:26:01 -0700
Subject: [RFC/PATCHv3 v3 1/3] firmware: Consolidate kmap/read/write logic
In-Reply-To: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
References: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
Message-ID: <1462919163-2503-2-git-send-email-stephen.boyd@linaro.org>

We use similar structured code to read and write the kmapped
firmware pages. The only difference is read copies from the kmap
region and write copies to it. Consolidate this into one function
to reduce duplication.

Cc: Vikram Mulukutla <markivx at codeaurora.org>
Signed-off-by: Stephen Boyd <stephen.boyd at linaro.org>
---
 drivers/base/firmware_class.c | 57 ++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 31 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 773fc3099769..01d55723d82c 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -691,6 +691,29 @@ out:
 
 static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
 
+static void firmware_rw(struct firmware_buf *buf, char *buffer,
+			loff_t offset, size_t count, bool read)
+{
+	while (count) {
+		void *page_data;
+		int page_nr = offset >> PAGE_SHIFT;
+		int page_ofs = offset & (PAGE_SIZE-1);
+		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
+
+		page_data = kmap(buf->pages[page_nr]);
+
+		if (read)
+			memcpy(buffer, page_data + page_ofs, page_cnt);
+		else
+			memcpy(page_data + page_ofs, buffer, page_cnt);
+
+		kunmap(buf->pages[page_nr]);
+		buffer += page_cnt;
+		offset += page_cnt;
+		count -= page_cnt;
+	}
+}
+
 static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
 				  struct bin_attribute *bin_attr,
 				  char *buffer, loff_t offset, size_t count)
@@ -715,21 +738,8 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
 
 	ret_count = count;
 
-	while (count) {
-		void *page_data;
-		int page_nr = offset >> PAGE_SHIFT;
-		int page_ofs = offset & (PAGE_SIZE-1);
-		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
-
-		page_data = kmap(buf->pages[page_nr]);
-
-		memcpy(buffer, page_data + page_ofs, page_cnt);
+	firmware_rw(buf, buffer, offset, count, true);
 
-		kunmap(buf->pages[page_nr]);
-		buffer += page_cnt;
-		offset += page_cnt;
-		count -= page_cnt;
-	}
 out:
 	mutex_unlock(&fw_lock);
 	return ret_count;
@@ -809,24 +819,9 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
 		goto out;
 
 	retval = count;
+	firmware_rw(buf, buffer, offset, count, false);
 
-	while (count) {
-		void *page_data;
-		int page_nr = offset >> PAGE_SHIFT;
-		int page_ofs = offset & (PAGE_SIZE - 1);
-		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
-
-		page_data = kmap(buf->pages[page_nr]);
-
-		memcpy(page_data + page_ofs, buffer, page_cnt);
-
-		kunmap(buf->pages[page_nr]);
-		buffer += page_cnt;
-		offset += page_cnt;
-		count -= page_cnt;
-	}
-
-	buf->size = max_t(size_t, offset, buf->size);
+	buf->size = max_t(size_t, offset + count, buf->size);
 out:
 	mutex_unlock(&fw_lock);
 	return retval;
-- 
2.8.0.rc4



From stephen.boyd at linaro.org  Tue May 10 15:26:02 2016
From: stephen.boyd at linaro.org (Stephen Boyd)
Date: Tue, 10 May 2016 15:26:02 -0700
Subject: [RFC/PATCHv3 v3 2/3] firmware: Provide infrastructure to make fw
 caching optional
In-Reply-To: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
References: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
Message-ID: <1462919163-2503-3-git-send-email-stephen.boyd@linaro.org>

From: Vikram Mulukutla <markivx at codeaurora.org>

Some low memory systems with complex peripherals cannot afford to
have the relatively large firmware images taking up valuable
memory during suspend and resume. Change the internal
implementation of firmware_class to disallow caching based on a
configurable option. In the near future, variants of
request_firmware will take advantage of this feature.

Signed-off-by: Vikram Mulukutla <markivx at codeaurora.org>
[stephen.boyd at linaro.org: Drop firmware_desc design and use flags]
Signed-off-by: Stephen Boyd <stephen.boyd at linaro.org>
---
 drivers/base/firmware_class.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 01d55723d82c..45ed20cefa10 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -112,6 +112,7 @@ static inline long firmware_loading_timeout(void)
 #define FW_OPT_FALLBACK		0
 #endif
 #define FW_OPT_NO_WARN	(1U << 3)
+#define FW_OPT_NOCACHE	(1U << 4)
 
 struct firmware_cache {
 	/* firmware_buf instance will be added into the below list */
@@ -1065,14 +1066,16 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
 	 * should be fixed in devres or driver core.
 	 */
 	/* don't cache firmware handled without uevent */
-	if (device && (opt_flags & FW_OPT_UEVENT))
+	if (device && (opt_flags & FW_OPT_UEVENT) &&
+	    !(opt_flags & FW_OPT_NOCACHE))
 		fw_add_devm_name(device, buf->fw_id);
 
 	/*
 	 * After caching firmware image is started, let it piggyback
 	 * on request firmware.
 	 */
-	if (buf->fwc->state == FW_LOADER_START_CACHE) {
+	if (!(opt_flags & FW_OPT_NOCACHE) &&
+	    buf->fwc->state == FW_LOADER_START_CACHE) {
 		if (fw_cache_piggyback_on_request(buf->fw_id))
 			kref_get(&buf->ref);
 	}
-- 
2.8.0.rc4



From stephen.boyd at linaro.org  Tue May 10 15:26:03 2016
From: stephen.boyd at linaro.org (Stephen Boyd)
Date: Tue, 10 May 2016 15:26:03 -0700
Subject: [RFC/PATCHv3 v3 3/3] firmware: Support loading into a pre-allocated
 buffer
In-Reply-To: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
References: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
Message-ID: <1462919163-2503-4-git-send-email-stephen.boyd@linaro.org>

Some systems are memory constrained but they need to load very
large firmwares. The firmware subsystem allows drivers to request
this firmware be loaded from the filesystem, but this requires
that the entire firmware be loaded into kernel memory first
before it's provided to the driver. This can lead to a situation
where we map the firmware twice, once to load the firmware into
kernel memory and once to copy the firmware into the final
resting place.

This creates needless memory pressure and delays loading because
we have to copy from kernel memory to somewhere else. Let's add a
request_firmware_into_buf() API that allows drivers to request
firmware be loaded directly into a pre-allocated buffer. This
skips the intermediate step of allocating a buffer in kernel
memory to hold the firmware image while it's read from the
filesystem. It also requires that drivers know how much memory
they'll require before requesting the firmware and negates any
benefits of firmware caching because the firmware layer doesn't
manage the buffer lifetime.

For a 16MB buffer, about half the time is spent performing a
memcpy from the buffer to the final resting place. I see loading
times go from 0.081171 seconds to 0.047696 seconds after applying
this patch. Plus the vmalloc pressure is reduced.

This is based on a patch from Vikram Mulukutla on
codeaurora.org[1].

[1] https://www.codeaurora.org/cgit/quic/la/kernel/msm-3.18/commit/drivers/base/firmware_class.c?h=rel/msm-3.18&id=0a328c5f6cd999f5c591f172216835636f39bcb5
Cc: Mimi Zohar <zohar at linux.vnet.ibm.com>
Cc: Vikram Mulukutla <markivx at codeaurora.org>
Signed-off-by: Stephen Boyd <stephen.boyd at linaro.org>
---
 drivers/base/firmware_class.c   | 125 +++++++++++++++++++++++++++++++---------
 fs/exec.c                       |  21 +++++--
 include/linux/firmware.h        |   8 +++
 include/linux/fs.h              |   1 +
 security/integrity/ima/ima_fs.c |   3 +-
 5 files changed, 125 insertions(+), 33 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 45ed20cefa10..6aec96a28b1a 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -46,7 +46,8 @@ MODULE_LICENSE("GPL");
 extern struct builtin_fw __start_builtin_fw[];
 extern struct builtin_fw __end_builtin_fw[];
 
-static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+static bool fw_get_builtin_firmware(struct firmware *fw, const char *name,
+				    void *buf, size_t size)
 {
 	struct builtin_fw *b_fw;
 
@@ -54,6 +55,9 @@ static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
 		if (strcmp(name, b_fw->name) == 0) {
 			fw->size = b_fw->size;
 			fw->data = b_fw->data;
+
+			if (buf && fw->size <= size)
+				memcpy(buf, fw->data, fw->size);
 			return true;
 		}
 	}
@@ -74,7 +78,9 @@ static bool fw_is_builtin_firmware(const struct firmware *fw)
 
 #else /* Module case - no builtin firmware support */
 
-static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
+static inline bool fw_get_builtin_firmware(struct firmware *fw,
+					   const char *name, void *buf,
+					   size_t size)
 {
 	return false;
 }
@@ -144,6 +150,7 @@ struct firmware_buf {
 	unsigned long status;
 	void *data;
 	size_t size;
+	size_t allocated_size;
 #ifdef CONFIG_FW_LOADER_USER_HELPER
 	bool is_paged_buf;
 	bool need_uevent;
@@ -179,7 +186,8 @@ static DEFINE_MUTEX(fw_lock);
 static struct firmware_cache fw_cache;
 
 static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
-					      struct firmware_cache *fwc)
+					      struct firmware_cache *fwc,
+					      void *dbuf, size_t size)
 {
 	struct firmware_buf *buf;
 
@@ -195,6 +203,8 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
 
 	kref_init(&buf->ref);
 	buf->fwc = fwc;
+	buf->data = dbuf;
+	buf->allocated_size = size;
 	init_completion(&buf->completion);
 #ifdef CONFIG_FW_LOADER_USER_HELPER
 	INIT_LIST_HEAD(&buf->pending_list);
@@ -218,7 +228,8 @@ static struct firmware_buf *__fw_lookup_buf(const char *fw_name)
 
 static int fw_lookup_and_allocate_buf(const char *fw_name,
 				      struct firmware_cache *fwc,
-				      struct firmware_buf **buf)
+				      struct firmware_buf **buf, void *dbuf,
+				      size_t size)
 {
 	struct firmware_buf *tmp;
 
@@ -230,7 +241,7 @@ static int fw_lookup_and_allocate_buf(const char *fw_name,
 		*buf = tmp;
 		return 1;
 	}
-	tmp = __allocate_fw_buf(fw_name, fwc);
+	tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size);
 	if (tmp)
 		list_add(&tmp->list, &fwc->head);
 	spin_unlock(&fwc->lock);
@@ -262,6 +273,7 @@ static void __fw_free_buf(struct kref *ref)
 		vfree(buf->pages);
 	} else
 #endif
+	if (!buf->allocated_size)
 		vfree(buf->data);
 	kfree_const(buf->fw_id);
 	kfree(buf);
@@ -302,13 +314,21 @@ static void fw_finish_direct_load(struct device *device,
 	mutex_unlock(&fw_lock);
 }
 
-static int fw_get_filesystem_firmware(struct device *device,
-				       struct firmware_buf *buf)
+static int
+fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
 {
 	loff_t size;
 	int i, len;
 	int rc = -ENOENT;
 	char *path;
+	enum kernel_read_file_id id = READING_FIRMWARE;
+	size_t msize = INT_MAX;
+
+	/* Already populated data member means we're loading into a buffer */
+	if (buf->data) {
+		id = READING_FIRMWARE_INTO_BUF;
+		msize = buf->allocated_size;
+	}
 
 	path = __getname();
 	if (!path)
@@ -327,8 +347,8 @@ static int fw_get_filesystem_firmware(struct device *device,
 		}
 
 		buf->size = 0;
-		rc = kernel_read_file_from_path(path, &buf->data, &size,
-						INT_MAX, READING_FIRMWARE);
+		rc = kernel_read_file_from_path(path, &buf->data, &size, msize,
+						id);
 		if (rc) {
 			if (rc == -ENOENT)
 				dev_dbg(device, "loading %s failed with error %d\n",
@@ -692,6 +712,15 @@ out:
 
 static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
 
+static void firmware_rw_buf(struct firmware_buf *buf, char *buffer,
+			   loff_t offset, size_t count, bool read)
+{
+	if (read)
+		memcpy(buffer, buf->data + offset, count);
+	else
+		memcpy(buf->data + offset, buffer, count);
+}
+
 static void firmware_rw(struct firmware_buf *buf, char *buffer,
 			loff_t offset, size_t count, bool read)
 {
@@ -739,7 +768,10 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
 
 	ret_count = count;
 
-	firmware_rw(buf, buffer, offset, count, true);
+	if (buf->data)
+		firmware_rw_buf(buf, buffer, offset, count, true);
+	else
+		firmware_rw(buf, buffer, offset, count, true);
 
 out:
 	mutex_unlock(&fw_lock);
@@ -815,12 +847,21 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
 		goto out;
 	}
 
-	retval = fw_realloc_buffer(fw_priv, offset + count);
-	if (retval)
-		goto out;
+	if (buf->data) {
+		if (offset + count > buf->allocated_size) {
+			retval = -ENOMEM;
+			goto out;
+		}
+		firmware_rw_buf(buf, buffer, offset, count, false);
+		retval = count;
+	} else {
+		retval = fw_realloc_buffer(fw_priv, offset + count);
+		if (retval)
+			goto out;
 
-	retval = count;
-	firmware_rw(buf, buffer, offset, count, false);
+		retval = count;
+		firmware_rw(buf, buffer, offset, count, false);
+	}
 
 	buf->size = max_t(size_t, offset + count, buf->size);
 out:
@@ -890,7 +931,8 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
 	struct firmware_buf *buf = fw_priv->buf;
 
 	/* fall back on userspace loading */
-	buf->is_paged_buf = true;
+	if (!buf->data)
+		buf->is_paged_buf = true;
 
 	dev_set_uevent_suppress(f_dev, true);
 
@@ -925,7 +967,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
 
 	if (is_fw_load_aborted(buf))
 		retval = -EAGAIN;
-	else if (!buf->data)
+	else if (buf->is_paged_buf && !buf->data)
 		retval = -ENOMEM;
 
 	device_del(f_dev);
@@ -1008,7 +1050,7 @@ static int sync_cached_firmware_buf(struct firmware_buf *buf)
  */
 static int
 _request_firmware_prepare(struct firmware **firmware_p, const char *name,
-			  struct device *device)
+			  struct device *device, void *dbuf, size_t size)
 {
 	struct firmware *firmware;
 	struct firmware_buf *buf;
@@ -1021,12 +1063,12 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
 		return -ENOMEM;
 	}
 
-	if (fw_get_builtin_firmware(firmware, name)) {
+	if (fw_get_builtin_firmware(firmware, name, dbuf, size)) {
 		dev_dbg(device, "using built-in %s\n", name);
 		return 0; /* assigned */
 	}
 
-	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf);
+	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size);
 
 	/*
 	 * bind with 'buf' now to avoid warning in failure path
@@ -1089,7 +1131,8 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device,
 /* called from request_firmware() and request_firmware_work_func() */
 static int
 _request_firmware(const struct firmware **firmware_p, const char *name,
-		  struct device *device, unsigned int opt_flags)
+		  struct device *device, void *buf, size_t size,
+		  unsigned int opt_flags)
 {
 	struct firmware *fw = NULL;
 	long timeout;
@@ -1103,7 +1146,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 		goto out;
 	}
 
-	ret = _request_firmware_prepare(&fw, name, device);
+	ret = _request_firmware_prepare(&fw, name, device, buf, size);
 	if (ret <= 0) /* error or already assigned */
 		goto out;
 
@@ -1182,7 +1225,7 @@ request_firmware(const struct firmware **firmware_p, const char *name,
 
 	/* Need to pin this module until return */
 	__module_get(THIS_MODULE);
-	ret = _request_firmware(firmware_p, name, device,
+	ret = _request_firmware(firmware_p, name, device, NULL, 0,
 				FW_OPT_UEVENT | FW_OPT_FALLBACK);
 	module_put(THIS_MODULE);
 	return ret;
@@ -1206,7 +1249,7 @@ int request_firmware_direct(const struct firmware **firmware_p,
 	int ret;
 
 	__module_get(THIS_MODULE);
-	ret = _request_firmware(firmware_p, name, device,
+	ret = _request_firmware(firmware_p, name, device, NULL, 0,
 				FW_OPT_UEVENT | FW_OPT_NO_WARN);
 	module_put(THIS_MODULE);
 	return ret;
@@ -1214,6 +1257,36 @@ int request_firmware_direct(const struct firmware **firmware_p,
 EXPORT_SYMBOL_GPL(request_firmware_direct);
 
 /**
+ * request_firmware_into_buf - load firmware into a previously allocated buffer
+ * @firmware_p: pointer to firmware image
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded and DMA region allocated
+ * @buf: address of buffer to load firmware into
+ * @size: size of buffer
+ *
+ * This function works pretty much like request_firmware(), but it doesn't
+ * allocate a buffer to hold the firmware data. Instead, the firmware
+ * is loaded directly into the buffer pointed to by @buf and the @firmware_p
+ * data member is pointed at @buf.
+ *
+ * This function doesn't cache firmware either.
+ */
+int
+request_firmware_into_buf(const struct firmware **firmware_p, const char *name,
+			  struct device *device, void *buf, size_t size)
+{
+	int ret;
+
+	__module_get(THIS_MODULE);
+	ret = _request_firmware(firmware_p, name, device, buf, size,
+				FW_OPT_UEVENT | FW_OPT_FALLBACK |
+				FW_OPT_NOCACHE);
+	module_put(THIS_MODULE);
+	return ret;
+}
+EXPORT_SYMBOL(request_firmware_into_buf);
+
+/**
  * release_firmware: - release the resource associated with a firmware image
  * @fw: firmware resource to release
  **/
@@ -1245,7 +1318,7 @@ static void request_firmware_work_func(struct work_struct *work)
 
 	fw_work = container_of(work, struct firmware_work, work);
 
-	_request_firmware(&fw, fw_work->name, fw_work->device,
+	_request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0,
 			  fw_work->opt_flags);
 	fw_work->cont(fw, fw_work->context);
 	put_device(fw_work->device); /* taken in request_firmware_nowait() */
@@ -1378,7 +1451,7 @@ static int uncache_firmware(const char *fw_name)
 
 	pr_debug("%s: %s\n", __func__, fw_name);
 
-	if (fw_get_builtin_firmware(&fw, fw_name))
+	if (fw_get_builtin_firmware(&fw, fw_name, NULL, 0))
 		return 0;
 
 	buf = fw_lookup_buf(fw_name);
diff --git a/fs/exec.c b/fs/exec.c
index c4010b8207a1..19894c36aea7 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -836,8 +836,8 @@ int kernel_read(struct file *file, loff_t offset,
 
 EXPORT_SYMBOL(kernel_read);
 
-int kernel_read_file(struct file *file, void **buf, loff_t *size,
-		     loff_t max_size, enum kernel_read_file_id id)
+static int _kernel_read_file(struct file *file, void **buf, loff_t *size,
+			     loff_t max_size, enum kernel_read_file_id id)
 {
 	loff_t i_size, pos;
 	ssize_t bytes = 0;
@@ -856,7 +856,8 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
 	if (i_size <= 0)
 		return -EINVAL;
 
-	*buf = vmalloc(i_size);
+	if (id != READING_FIRMWARE_INTO_BUF)
+		*buf = vmalloc(i_size);
 	if (!*buf)
 		return -ENOMEM;
 
@@ -885,11 +886,19 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
 
 out:
 	if (ret < 0) {
-		vfree(*buf);
-		*buf = NULL;
+		if (id != READING_FIRMWARE_INTO_BUF) {
+			vfree(*buf);
+			*buf = NULL;
+		}
 	}
 	return ret;
 }
+
+int kernel_read_file(struct file *file, void **buf, loff_t *size,
+		     loff_t max_size, enum kernel_read_file_id id)
+{
+	return _kernel_read_file(file, buf, size, max_size, id);
+}
 EXPORT_SYMBOL_GPL(kernel_read_file);
 
 int kernel_read_file_from_path(char *path, void **buf, loff_t *size,
@@ -905,7 +914,7 @@ int kernel_read_file_from_path(char *path, void **buf, loff_t *size,
 	if (IS_ERR(file))
 		return PTR_ERR(file);
 
-	ret = kernel_read_file(file, buf, size, max_size, id);
+	ret = _kernel_read_file(file, buf, size, max_size, id);
 	fput(file);
 	return ret;
 }
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 5c41c5e75b5c..bdc24ee92823 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -47,6 +47,8 @@ int request_firmware_nowait(
 	void (*cont)(const struct firmware *fw, void *context));
 int request_firmware_direct(const struct firmware **fw, const char *name,
 			    struct device *device);
+int request_firmware_into_buf(const struct firmware **firmware_p,
+	const char *name, struct device *device, void *buf, size_t size);
 
 void release_firmware(const struct firmware *fw);
 #else
@@ -75,5 +77,11 @@ static inline int request_firmware_direct(const struct firmware **fw,
 	return -EINVAL;
 }
 
+static inline int request_firmware_into_buf(const struct firmware **firmware_p,
+	const char *name, struct device *device, void *buf, size_t size);
+{
+	return -EINVAL;
+}
+
 #endif
 #endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 14a97194b34b..4fb8596b3dd4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2582,6 +2582,7 @@ extern int do_pipe_flags(int *, int);
 
 enum kernel_read_file_id {
 	READING_FIRMWARE = 1,
+	READING_FIRMWARE_INTO_BUF,
 	READING_MODULE,
 	READING_KEXEC_IMAGE,
 	READING_KEXEC_INITRAMFS,
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 60d011aaec38..b922d6ca2fb0 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -272,7 +272,8 @@ static ssize_t ima_read_policy(char *path)
 	datap = path;
 	strsep(&datap, "\n");
 
-	rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY);
+	rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY,
+					NULL);
 	if (rc < 0) {
 		pr_err("Unable to open file: %s (%d)", path, rc);
 		return rc;
-- 
2.8.0.rc4



From linux at armlinux.org.uk  Tue May 10 15:31:52 2016
From: linux at armlinux.org.uk (Russell King - ARM Linux)
Date: Tue, 10 May 2016 23:31:52 +0100
Subject: [PATCH] arm64: dts: qcom: Add msm8916 PMU node
In-Reply-To: <1462917709-29789-1-git-send-email-stephen.boyd@linaro.org>
References: <1462917709-29789-1-git-send-email-stephen.boyd@linaro.org>
Message-ID: <20160510223152.GM19428@n2100.arm.linux.org.uk>

I think you should be sending your patches to linux-arm-kernel rather
than linux-arm...

On Tue, May 10, 2016 at 03:01:49PM -0700, Stephen Boyd wrote:
> Add the PMU so we can get proper perf event support on this SoC.
> 
> Signed-off-by: Stephen Boyd <stephen.boyd at linaro.org>
> ---
>  arch/arm64/boot/dts/qcom/msm8916.dtsi | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
> index 96812007850e..c440fd6bc5cd 100644
> --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
> @@ -91,6 +91,11 @@
>  		};
>  	};
>  
> +	pmu {
> +		compatible = "arm,armv8-pmuv3";
> +		interrupts = <GIC_PPI 7 GIC_CPU_MASK_SIMPLE(4)>;
> +	};
> +
>  	timer {
>  		compatible = "arm,armv8-timer";
>  		interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
> -- 
> 2.8.0.rc4
> 
> 
> _______________________________________________
> linux-arm mailing list
> linux-arm at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.


From zohar at linux.vnet.ibm.com  Wed May 11 05:41:52 2016
From: zohar at linux.vnet.ibm.com (Mimi Zohar)
Date: Wed, 11 May 2016 08:41:52 -0400
Subject: [RFC/PATCHv3 v3 3/3] firmware: Support loading into a
 pre-allocated buffer
In-Reply-To: <1462919163-2503-4-git-send-email-stephen.boyd@linaro.org>
References: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
 <1462919163-2503-4-git-send-email-stephen.boyd@linaro.org>
Message-ID: <1462970512.12106.91.camel@linux.vnet.ibm.com>

Hi Stephen,

On Tue, 2016-05-10 at 15:26 -0700, Stephen Boyd wrote:

> -static int fw_get_filesystem_firmware(struct device *device,
> -				       struct firmware_buf *buf)
> +static int
> +fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
>  {
>  	loff_t size;
>  	int i, len;
>  	int rc = -ENOENT;
>  	char *path;
> +	enum kernel_read_file_id id = READING_FIRMWARE;
> +	size_t msize = INT_MAX;
> +
> +	/* Already populated data member means we're loading into a buffer */
> +	if (buf->data) {
> +		id = READING_FIRMWARE_INTO_BUF;

In both cases we're reading the firmware into a buffer.  In this case,
it is pre-allocated.  Other than it being pre-allocated, is there
anything special about this buffer?  There has to be a more appropriate
string identifier.

> +		msize = buf->allocated_size;
> +	}
> 
>  	path = __getname();
>  	if (!path)

> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -836,8 +836,8 @@ int kernel_read(struct file *file, loff_t offset,
> 
>  EXPORT_SYMBOL(kernel_read);
> 
> -int kernel_read_file(struct file *file, void **buf, loff_t *size,
> -		     loff_t max_size, enum kernel_read_file_id id)
> +static int _kernel_read_file(struct file *file, void **buf, loff_t *size,
> +			     loff_t max_size, enum kernel_read_file_id id)
>  {
>  	loff_t i_size, pos;
>  	ssize_t bytes = 0;
> @@ -856,7 +856,8 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
>  	if (i_size <= 0)
>  		return -EINVAL;
> 
> -	*buf = vmalloc(i_size);
> +	if (id != READING_FIRMWARE_INTO_BUF)
> +		*buf = vmalloc(i_size);
>  	if (!*buf)
>  		return -ENOMEM;
> 
> @@ -885,11 +886,19 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
> 
>  out:
>  	if (ret < 0) {
> -		vfree(*buf);
> -		*buf = NULL;
> +		if (id != READING_FIRMWARE_INTO_BUF) {
> +			vfree(*buf);
> +			*buf = NULL;
> +		}
>  	}
>  	return ret;
>  }
> +
> +int kernel_read_file(struct file *file, void **buf, loff_t *size,
> +		     loff_t max_size, enum kernel_read_file_id id)
> +{
> +	return _kernel_read_file(file, buf, size, max_size, id);
> +}
>  EXPORT_SYMBOL_GPL(kernel_read_file);

This seems to be exactly the same as the original version.

> 
>  int kernel_read_file_from_path(char *path, void **buf, loff_t *size,
> @@ -905,7 +914,7 @@ int kernel_read_file_from_path(char *path, void **buf, loff_t *size,
>  	if (IS_ERR(file))
>  		return PTR_ERR(file);
> 
> -	ret = kernel_read_file(file, buf, size, max_size, id);
> +	ret = _kernel_read_file(file, buf, size, max_size, id);
>  	fput(file);
>  	return ret;
>  }
> diff --git a/include/linux/firmware.h b/include/linux/firmware.h
> index 5c41c5e75b5c..bdc24ee92823 100644
> --- a/include/linux/firmware.h
> +++ b/include/linux/firmware.h
> @@ -47,6 +47,8 @@ int request_firmware_nowait(
>  	void (*cont)(const struct firmware *fw, void *context));
>  int request_firmware_direct(const struct firmware **fw, const char *name,
>  			    struct device *device);
> +int request_firmware_into_buf(const struct firmware **firmware_p,
> +	const char *name, struct device *device, void *buf, size_t size);
> 
>  void release_firmware(const struct firmware *fw);
>  #else
> @@ -75,5 +77,11 @@ static inline int request_firmware_direct(const struct firmware **fw,
>  	return -EINVAL;
>  }
> 
> +static inline int request_firmware_into_buf(const struct firmware **firmware_p,
> +	const char *name, struct device *device, void *buf, size_t size);
> +{
> +	return -EINVAL;
> +}
> +
>  #endif
>  #endif
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 14a97194b34b..4fb8596b3dd4 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2582,6 +2582,7 @@ extern int do_pipe_flags(int *, int);
> 
>  enum kernel_read_file_id {
>  	READING_FIRMWARE = 1,
> +	READING_FIRMWARE_INTO_BUF,
>  	READING_MODULE,
>  	READING_KEXEC_IMAGE,
>  	READING_KEXEC_INITRAMFS,

Commit "1284ab5 fs: define a string representation of the
kernel_read_file_id enumeration", which is queued to be upstreamed,
changes this a bit.

> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> index 60d011aaec38..b922d6ca2fb0 100644
> --- a/security/integrity/ima/ima_fs.c
> +++ b/security/integrity/ima/ima_fs.c
> @@ -272,7 +272,8 @@ static ssize_t ima_read_policy(char *path)
>  	datap = path;
>  	strsep(&datap, "\n");
> 
> -	rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY);
> +	rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY,
> +					NULL);

It doesn't look like kernel_read_file_from_path() changed.

Mimi

>  	if (rc < 0) {
>  		pr_err("Unable to open file: %s (%d)", path, rc);
>  		return rc;




From stephen.boyd at linaro.org  Wed May 11 13:22:32 2016
From: stephen.boyd at linaro.org (Stephen Boyd)
Date: Wed, 11 May 2016 13:22:32 -0700
Subject: [RFC/PATCHv3 v3 3/3] firmware: Support loading into a
 pre-allocated buffer
In-Reply-To: <1462970512.12106.91.camel@linux.vnet.ibm.com>
References: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
 <1462919163-2503-4-git-send-email-stephen.boyd@linaro.org>
 <1462970512.12106.91.camel@linux.vnet.ibm.com>
Message-ID: <20160511202231.8857.86068@sboyd-linaro>

Quoting Mimi Zohar (2016-05-11 05:41:52)
> Hi Stephen,
> 
> On Tue, 2016-05-10 at 15:26 -0700, Stephen Boyd wrote:
> 
> > -static int fw_get_filesystem_firmware(struct device *device,
> > -                                    struct firmware_buf *buf)
> > +static int
> > +fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
> >  {
> >       loff_t size;
> >       int i, len;
> >       int rc = -ENOENT;
> >       char *path;
> > +     enum kernel_read_file_id id = READING_FIRMWARE;
> > +     size_t msize = INT_MAX;
> > +
> > +     /* Already populated data member means we're loading into a buffer */
> > +     if (buf->data) {
> > +             id = READING_FIRMWARE_INTO_BUF;
> 
> In both cases we're reading the firmware into a buffer.  In this case,
> it is pre-allocated.  Other than it being pre-allocated, is there
> anything special about this buffer? 

No. I'm not sure what you're asking/implying.

> There has to be a more appropriate
> string identifier.

Ok. Any suggestions? The point of the new id is so that we know if we
need to allocate the buffer or not in kernel_read_file(). Alternatively
we could indicate that by a NULL *buf pointer, but it seems that half
the time that's not initialized to NULL so it didn't seem safe to rely
on that fact or update the callsites appropriately.

> 
> > +             msize = buf->allocated_size;
> > +     }
> > 
> >       path = __getname();
> >       if (!path)
> 
> > --- a/fs/exec.c
> > +++ b/fs/exec.c
> > @@ -836,8 +836,8 @@ int kernel_read(struct file *file, loff_t offset,
> > 
> >  EXPORT_SYMBOL(kernel_read);
> > 
> > -int kernel_read_file(struct file *file, void **buf, loff_t *size,
> > -                  loff_t max_size, enum kernel_read_file_id id)
> > +static int _kernel_read_file(struct file *file, void **buf, loff_t *size,
> > +                          loff_t max_size, enum kernel_read_file_id id)
> >  {
> >       loff_t i_size, pos;
> >       ssize_t bytes = 0;
> > @@ -856,7 +856,8 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
> >       if (i_size <= 0)
> >               return -EINVAL;
> > 
> > -     *buf = vmalloc(i_size);
> > +     if (id != READING_FIRMWARE_INTO_BUF)
> > +             *buf = vmalloc(i_size);
> >       if (!*buf)
> >               return -ENOMEM;
> > 
> > @@ -885,11 +886,19 @@ int kernel_read_file(struct file *file, void **buf, loff_t *size,
> > 
> >  out:
> >       if (ret < 0) {
> > -             vfree(*buf);
> > -             *buf = NULL;
> > +             if (id != READING_FIRMWARE_INTO_BUF) {
> > +                     vfree(*buf);
> > +                     *buf = NULL;
> > +             }
> >       }
> >       return ret;
> >  }
> > +
> > +int kernel_read_file(struct file *file, void **buf, loff_t *size,
> > +                  loff_t max_size, enum kernel_read_file_id id)
> > +{
> > +     return _kernel_read_file(file, buf, size, max_size, id);
> > +}
> >  EXPORT_SYMBOL_GPL(kernel_read_file);
> 
> This seems to be exactly the same as the original version.

Ah right, holdovers from previous patches.

> 
> > 
> >  int kernel_read_file_from_path(char *path, void **buf, loff_t *size,
> > @@ -905,7 +914,7 @@ int kernel_read_file_from_path(char *path, void **buf, loff_t *size,
> >       if (IS_ERR(file))
> >               return PTR_ERR(file);
> > 
> > -     ret = kernel_read_file(file, buf, size, max_size, id);
> > +     ret = _kernel_read_file(file, buf, size, max_size, id);
> >       fput(file);
> >       return ret;
> >  }
> > diff --git a/include/linux/firmware.h b/include/linux/firmware.h
> > index 5c41c5e75b5c..bdc24ee92823 100644
> > --- a/include/linux/firmware.h
> > +++ b/include/linux/firmware.h
> > @@ -47,6 +47,8 @@ int request_firmware_nowait(
> >       void (*cont)(const struct firmware *fw, void *context));
> >  int request_firmware_direct(const struct firmware **fw, const char *name,
> >                           struct device *device);
> > +int request_firmware_into_buf(const struct firmware **firmware_p,
> > +     const char *name, struct device *device, void *buf, size_t size);
> > 
> >  void release_firmware(const struct firmware *fw);
> >  #else
> > @@ -75,5 +77,11 @@ static inline int request_firmware_direct(const struct firmware **fw,
> >       return -EINVAL;
> >  }
> > 
> > +static inline int request_firmware_into_buf(const struct firmware **firmware_p,
> > +     const char *name, struct device *device, void *buf, size_t size);
> > +{
> > +     return -EINVAL;
> > +}
> > +
> >  #endif
> >  #endif
> > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > index 14a97194b34b..4fb8596b3dd4 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -2582,6 +2582,7 @@ extern int do_pipe_flags(int *, int);
> > 
> >  enum kernel_read_file_id {
> >       READING_FIRMWARE = 1,
> > +     READING_FIRMWARE_INTO_BUF,
> >       READING_MODULE,
> >       READING_KEXEC_IMAGE,
> >       READING_KEXEC_INITRAMFS,
> 
> Commit "1284ab5 fs: define a string representation of the
> kernel_read_file_id enumeration", which is queued to be upstreamed,
> changes this a bit.

Ok. Will update, thanks.

> 
> > diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> > index 60d011aaec38..b922d6ca2fb0 100644
> > --- a/security/integrity/ima/ima_fs.c
> > +++ b/security/integrity/ima/ima_fs.c
> > @@ -272,7 +272,8 @@ static ssize_t ima_read_policy(char *path)
> >       datap = path;
> >       strsep(&datap, "\n");
> > 
> > -     rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY);
> > +     rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY,
> > +                                     NULL);
> 
> It doesn't look like kernel_read_file_from_path() changed.
> 

Good catch. Holdovers from the previous patches. Will fix in next
version.


From zohar at linux.vnet.ibm.com  Wed May 11 13:46:46 2016
From: zohar at linux.vnet.ibm.com (Mimi Zohar)
Date: Wed, 11 May 2016 16:46:46 -0400
Subject: [RFC/PATCHv3 v3 3/3] firmware: Support loading into a
 pre-allocated buffer
In-Reply-To: <20160511202231.8857.86068@sboyd-linaro>
References: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
 <1462919163-2503-4-git-send-email-stephen.boyd@linaro.org>
 <1462970512.12106.91.camel@linux.vnet.ibm.com>
 <20160511202231.8857.86068@sboyd-linaro>
Message-ID: <1462999606.12416.37.camel@linux.vnet.ibm.com>

On Wed, 2016-05-11 at 13:22 -0700, Stephen Boyd wrote:
> Quoting Mimi Zohar (2016-05-11 05:41:52)
> > Hi Stephen,
> > 
> > On Tue, 2016-05-10 at 15:26 -0700, Stephen Boyd wrote:
> > 
> > > -static int fw_get_filesystem_firmware(struct device *device,
> > > -                                    struct firmware_buf *buf)
> > > +static int
> > > +fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
> > >  {
> > >       loff_t size;
> > >       int i, len;
> > >       int rc = -ENOENT;
> > >       char *path;
> > > +     enum kernel_read_file_id id = READING_FIRMWARE;
> > > +     size_t msize = INT_MAX;
> > > +
> > > +     /* Already populated data member means we're loading into a buffer */
> > > +     if (buf->data) {
> > > +             id = READING_FIRMWARE_INTO_BUF;
> > 
> > In both cases we're reading the firmware into a buffer.  In this case,
> > it is pre-allocated.  Other than it being pre-allocated, is there
> > anything special about this buffer? 
> 
> No. I'm not sure what you're asking/implying.
> 
> > There has to be a more appropriate
> > string identifier.
> 
> Ok. Any suggestions? The point of the new id is so that we know if we
> need to allocate the buffer or not in kernel_read_file().

If you're still using DMA, then perhaps "READING_FIRMWARE_DMA".   If the
only difference is that the buffer is pre-allocated, then maybe
"READING_FIRMWARE_PREALLOC_BUFFER". 

>  Alternatively
> we could indicate that by a NULL *buf pointer, but it seems that half
> the time that's not initialized to NULL so it didn't seem safe to rely
> on that fact or update the callsites appropriately.

Assuming that the pre-allocated buffer is smaller than the firmware
size, then a new name definitely needs to be specified, so that the
firmware signature can be verified on the security_kernel_read_file()
hook, as opposed to the security_kernel_post_read_file() hook.  The
patch would look something like:

diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 68b26c3..c799459 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -359,6 +359,10 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
 #endif
                return 0;       /* We rely on module signature checking */
        }
+
+       if (file && read_id == READING_FIRMWARE_INTO_BUF)
+               return process_measurement(file, NULL, 0, MAY_READ,
+                                          FIRMWARE_CHECK, 0);
        return 0;
 }

@@ -404,6 +408,9 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
                return 0;
        }

+       if (file && read_id == READING_FIRMWARE_INTO_BUF)
+               return 0;
+
        func = read_idmap[read_id] ?: FILE_CHECK;
        return process_measurement(file, buf, size, MAY_READ, func, 0);
 }

Once we've decided on a more appropriate identifier string, I'll post
the patch.

Mimi



From stephen.boyd at linaro.org  Wed May 11 15:11:01 2016
From: stephen.boyd at linaro.org (Stephen Boyd)
Date: Wed, 11 May 2016 15:11:01 -0700
Subject: [RFC/PATCHv3 v3 3/3] firmware: Support loading into a
 pre-allocated buffer
In-Reply-To: <1462999606.12416.37.camel@linux.vnet.ibm.com>
References: <1462919163-2503-1-git-send-email-stephen.boyd@linaro.org>
 <1462919163-2503-4-git-send-email-stephen.boyd@linaro.org>
 <1462970512.12106.91.camel@linux.vnet.ibm.com>
 <20160511202231.8857.86068@sboyd-linaro>
 <1462999606.12416.37.camel@linux.vnet.ibm.com>
Message-ID: <20160511221101.13510.96844@sboyd-linaro>

Quoting Mimi Zohar (2016-05-11 13:46:46)
> On Wed, 2016-05-11 at 13:22 -0700, Stephen Boyd wrote:
> > Quoting Mimi Zohar (2016-05-11 05:41:52)
> > > Hi Stephen,
> > > 
> > > On Tue, 2016-05-10 at 15:26 -0700, Stephen Boyd wrote:
> > > 
> > > > -static int fw_get_filesystem_firmware(struct device *device,
> > > > -                                    struct firmware_buf *buf)
> > > > +static int
> > > > +fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
> > > >  {
> > > >       loff_t size;
> > > >       int i, len;
> > > >       int rc = -ENOENT;
> > > >       char *path;
> > > > +     enum kernel_read_file_id id = READING_FIRMWARE;
> > > > +     size_t msize = INT_MAX;
> > > > +
> > > > +     /* Already populated data member means we're loading into a buffer */
> > > > +     if (buf->data) {
> > > > +             id = READING_FIRMWARE_INTO_BUF;
> > > 
> > > In both cases we're reading the firmware into a buffer.  In this case,
> > > it is pre-allocated.  Other than it being pre-allocated, is there
> > > anything special about this buffer? 
> > 
> > No. I'm not sure what you're asking/implying.
> > 
> > > There has to be a more appropriate
> > > string identifier.
> > 
> > Ok. Any suggestions? The point of the new id is so that we know if we
> > need to allocate the buffer or not in kernel_read_file().
> 
> If you're still using DMA, then perhaps "READING_FIRMWARE_DMA".   If the
> only difference is that the buffer is pre-allocated, then maybe
> "READING_FIRMWARE_PREALLOC_BUFFER". 

Sure, READING_FIRMWARE_PREALLOC_BUFFER is fine.

> 
> >  Alternatively
> > we could indicate that by a NULL *buf pointer, but it seems that half
> > the time that's not initialized to NULL so it didn't seem safe to rely
> > on that fact or update the callsites appropriately.
> 
> Assuming that the pre-allocated buffer is smaller than the firmware
> size, then a new name definitely needs to be specified, so that the
> firmware signature can be verified on the security_kernel_read_file()
> hook, as opposed to the security_kernel_post_read_file() hook.  The
> patch would look something like:

I don't think we care about the case of the pre-allocated buffer being
smaller than the firmware size though. In that case, 'max_size' will be
less than 'i_size' in kernel_read_file() and then we would fail that
function with -EFBIG. This should allow IMA to treat this the same as
the READING_FIRMWARE case.


