summaryrefslogtreecommitdiff
path: root/arch/parisc/kernel/firmware.c
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2017-07-25 18:20:54 +0200
committerHelge Deller <deller@gmx.de>2017-07-25 18:24:39 +0200
commitf520e55241e1cf0c10d308ccf47513f28533f60a (patch)
treefa785945c28ff2e0d3c777d2f4a59fdf92756716 /arch/parisc/kernel/firmware.c
parent108ea18722df59d8977951eecd635d296fa64765 (diff)
parisc: Fix crash when calling PDC_PAT_MEM PDT firmware function
Commit c9c2877d08d9 ("parisc: Add Page Deallocation Table (PDT) support") introduced the pdc_pat_mem_read_pd_pdt() firmware helper function, which crashed the system because it trashed the stack if the pdc_pat_mem_read_pd_retinfo struct was located on the stack (and which is in size less than the required 32 64-bit values). Fix it by using the pdc_result struct instead when calling firmware and copy the return values back into the result struct when finished sucessfully. While debugging this code I noticed that the pdc_type wasn't set correctly either, so let's fix that too. Fixes: c9c2877d08d9 ("parisc: Add Page Deallocation Table (PDT) support") Signed-off-by: Helge Deller <deller@gmx.de>
Diffstat (limited to 'arch/parisc/kernel/firmware.c')
-rw-r--r--arch/parisc/kernel/firmware.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index 98190252c12f..526ed90ca56f 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -1481,12 +1481,19 @@ int pdc_pat_mem_read_pd_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
unsigned long offset)
{
int retval;
- unsigned long flags;
+ unsigned long flags, entries;
spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_PD_READ,
- __pa(&pret), __pa(pdt_entries_ptr),
+ __pa(&pdc_result), __pa(pdt_entries_ptr),
count, offset);
+
+ if (retval == PDC_OK) {
+ entries = min(pdc_result[0], count);
+ pret->actual_count_bytes = entries;
+ pret->pdt_entries = entries / sizeof(unsigned long);
+ }
+
spin_unlock_irqrestore(&pdc_lock, flags);
return retval;