From a77d087fd566f576da1f5b8726dd9d9f0f164e1f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 27 Nov 2018 09:11:15 -0800 Subject: lkdtm: Do not depend on BLOCK and clean up headers After the transition to kprobes, symbols are resolved at runtime. This means there is no need to have all the Kconfig and header logic to avoid build failures. This also paves the way to having arbitrary test locations. Reported-by: Christophe Leroy Signed-off-by: Kees Cook --- drivers/misc/lkdtm/core.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 2837dc77478e..5d41c2230d2e 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -37,16 +37,9 @@ #include #include #include -#include -#include #include -#include #include -#ifdef CONFIG_IDE -#include -#endif - #define DEFAULT_COUNT 10 static int lkdtm_debugfs_open(struct inode *inode, struct file *file); @@ -102,9 +95,7 @@ static struct crashpoint crashpoints[] = { CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"), CRASHPOINT("TIMERADD", "hrtimer_start"), CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"), -# ifdef CONFIG_IDE CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"), -# endif #endif }; -- cgit v1.2.3 From 4c411157a42f122051ae3469bee0b5cabe89e139 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 7 Nov 2018 20:14:10 +0000 Subject: lkdtm: Print real addresses Today, when doing a lkdtm test before the readiness of the random generator, (ptrval) is printed instead of the address at which it perform the fault: [ 1597.337030] lkdtm: Performing direct entry EXEC_USERSPACE [ 1597.337142] lkdtm: attempting ok execution at (ptrval) [ 1597.337398] lkdtm: attempting bad execution at (ptrval) [ 1597.337460] kernel tried to execute user page (77858000) -exploit attempt? (uid: 0) [ 1597.344769] Unable to handle kernel paging request for instruction fetch [ 1597.351392] Faulting instruction address: 0x77858000 [ 1597.356312] Oops: Kernel access of bad area, sig: 11 [#1] If the lkdtm test is done later on, it prints an hashed address. In both cases this is pointless. The purpose of the test is to ensure the kernel generates an Oops at the expected address, so real addresses needs to be printed. This patch fixes that. Signed-off-by: Christophe Leroy Signed-off-by: Kees Cook --- drivers/misc/lkdtm/perms.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c index 53b85c9d16b8..fa54add6375a 100644 --- a/drivers/misc/lkdtm/perms.c +++ b/drivers/misc/lkdtm/perms.c @@ -47,7 +47,7 @@ static noinline void execute_location(void *dst, bool write) { void (*func)(void) = dst; - pr_info("attempting ok execution at %p\n", do_nothing); + pr_info("attempting ok execution at %px\n", do_nothing); do_nothing(); if (write == CODE_WRITE) { @@ -55,7 +55,7 @@ static noinline void execute_location(void *dst, bool write) flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); } - pr_info("attempting bad execution at %p\n", func); + pr_info("attempting bad execution at %px\n", func); func(); } @@ -66,14 +66,14 @@ static void execute_user_location(void *dst) /* Intentionally crossing kernel/user memory boundary. */ void (*func)(void) = dst; - pr_info("attempting ok execution at %p\n", do_nothing); + pr_info("attempting ok execution at %px\n", do_nothing); do_nothing(); copied = access_process_vm(current, (unsigned long)dst, do_nothing, EXEC_SIZE, FOLL_WRITE); if (copied < EXEC_SIZE) return; - pr_info("attempting bad execution at %p\n", func); + pr_info("attempting bad execution at %px\n", func); func(); } @@ -82,7 +82,7 @@ void lkdtm_WRITE_RO(void) /* Explicitly cast away "const" for the test. */ unsigned long *ptr = (unsigned long *)&rodata; - pr_info("attempting bad rodata write at %p\n", ptr); + pr_info("attempting bad rodata write at %px\n", ptr); *ptr ^= 0xabcd1234; } @@ -100,7 +100,7 @@ void lkdtm_WRITE_RO_AFTER_INIT(void) return; } - pr_info("attempting bad ro_after_init write at %p\n", ptr); + pr_info("attempting bad ro_after_init write at %px\n", ptr); *ptr ^= 0xabcd1234; } @@ -112,7 +112,7 @@ void lkdtm_WRITE_KERN(void) size = (unsigned long)do_overwritten - (unsigned long)do_nothing; ptr = (unsigned char *)do_overwritten; - pr_info("attempting bad %zu byte write at %p\n", size, ptr); + pr_info("attempting bad %zu byte write at %px\n", size, ptr); memcpy(ptr, (unsigned char *)do_nothing, size); flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); @@ -185,11 +185,11 @@ void lkdtm_ACCESS_USERSPACE(void) ptr = (unsigned long *)user_addr; - pr_info("attempting bad read at %p\n", ptr); + pr_info("attempting bad read at %px\n", ptr); tmp = *ptr; tmp += 0xc0dec0de; - pr_info("attempting bad write at %p\n", ptr); + pr_info("attempting bad write at %px\n", ptr); *ptr = tmp; vm_munmap(user_addr, PAGE_SIZE); -- cgit v1.2.3 From 59a12205d3c32aee4c13ca36889fdf7cfed31126 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 14 Dec 2018 15:26:20 +0000 Subject: lkdtm: Add tests for NULL pointer dereference Introduce lkdtm tests for NULL pointer dereference: check access or exec at NULL address, since these errors tend to be reported differently from the general fault error text. For example from x86: pr_alert("BUG: unable to handle kernel %s at %px\n", address < PAGE_SIZE ? "NULL pointer dereference" : "paging request", (void *)address); Signed-off-by: Christophe Leroy Signed-off-by: Kees Cook --- drivers/misc/lkdtm/core.c | 2 ++ drivers/misc/lkdtm/lkdtm.h | 2 ++ drivers/misc/lkdtm/perms.c | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 5d41c2230d2e..c09133ac9803 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -143,7 +143,9 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(EXEC_VMALLOC), CRASHTYPE(EXEC_RODATA), CRASHTYPE(EXEC_USERSPACE), + CRASHTYPE(EXEC_NULL), CRASHTYPE(ACCESS_USERSPACE), + CRASHTYPE(ACCESS_NULL), CRASHTYPE(WRITE_RO), CRASHTYPE(WRITE_RO_AFTER_INIT), CRASHTYPE(WRITE_KERN), diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 3c6fd327e166..b69ee004a3f7 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -45,7 +45,9 @@ void lkdtm_EXEC_KMALLOC(void); void lkdtm_EXEC_VMALLOC(void); void lkdtm_EXEC_RODATA(void); void lkdtm_EXEC_USERSPACE(void); +void lkdtm_EXEC_NULL(void); void lkdtm_ACCESS_USERSPACE(void); +void lkdtm_ACCESS_NULL(void); /* lkdtm_refcount.c */ void lkdtm_REFCOUNT_INC_OVERFLOW(void); diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c index fa54add6375a..62f76d506f04 100644 --- a/drivers/misc/lkdtm/perms.c +++ b/drivers/misc/lkdtm/perms.c @@ -164,6 +164,11 @@ void lkdtm_EXEC_USERSPACE(void) vm_munmap(user_addr, PAGE_SIZE); } +void lkdtm_EXEC_NULL(void) +{ + execute_location(NULL, CODE_AS_IS); +} + void lkdtm_ACCESS_USERSPACE(void) { unsigned long user_addr, tmp = 0; @@ -195,6 +200,19 @@ void lkdtm_ACCESS_USERSPACE(void) vm_munmap(user_addr, PAGE_SIZE); } +void lkdtm_ACCESS_NULL(void) +{ + unsigned long tmp; + unsigned long *ptr = (unsigned long *)NULL; + + pr_info("attempting bad read at %px\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %px\n", ptr); + *ptr = tmp; +} + void __init lkdtm_perms_init(void) { /* Make sure we can write to __ro_after_init values during __init */ -- cgit v1.2.3 From 4ad84cb56b0088f62b0369f36451ebb0fe16f423 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 23 Dec 2018 20:17:51 +0200 Subject: mei: squash single_recv_buf into one bit in client properties single_recv_buf member of struct mei_client_properties has a boolean value and can be represented in on bit, to free other 7 bits for another usage. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 2b7f7677f8cc..b7d2487b8409 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -311,7 +311,8 @@ struct mei_client_properties { u8 protocol_version; u8 max_number_of_connections; u8 fixed_address; - u8 single_recv_buf; + u8 single_recv_buf:1; + u8 reserved:7; u32 max_msg_length; } __packed; -- cgit v1.2.3 From 87bf65bc108e5da18e7ec788e9a4fb96263f19b7 Mon Sep 17 00:00:00 2001 From: Silvio Cesare Date: Sat, 12 Jan 2019 16:28:37 +0100 Subject: lkdtm: change snprintf to scnprintf for possible overflow Change snprintf to scnprintf. There are generally two cases where using snprintf causes problems. 1) Uses of size += snprintf(buf, SIZE - size, fmt, ...) In this case, if snprintf would have written more characters than what the buffer size (SIZE) is, then size will end up larger than SIZE. In later uses of snprintf, SIZE - size will result in a negative number, leading to problems. Note that size might already be too large by using size = snprintf before the code reaches a case of size += snprintf. 2) If size is ultimately used as a length parameter for a copy back to user space, then it will potentially allow for a buffer overflow and information disclosure when size is greater than SIZE. When the size is used to index the buffer directly, we can have memory corruption. This also means when size = snprintf... is used, it may also cause problems since size may become large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel configuration. The solution to these issues is to use scnprintf which returns the number of characters actually written to the buffer, so the size variable will never exceed SIZE. Signed-off-by: Silvio Cesare Cc: Dan Carpenter Cc: Will Deacon Cc: Greg KH Acked-by: Kees Cook Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index c09133ac9803..b51cf182b031 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -340,9 +340,9 @@ static ssize_t lkdtm_debugfs_read(struct file *f, char __user *user_buf, if (buf == NULL) return -ENOMEM; - n = snprintf(buf, PAGE_SIZE, "Available crash types:\n"); + n = scnprintf(buf, PAGE_SIZE, "Available crash types:\n"); for (i = 0; i < ARRAY_SIZE(crashtypes); i++) { - n += snprintf(buf + n, PAGE_SIZE - n, "%s\n", + n += scnprintf(buf + n, PAGE_SIZE - n, "%s\n", crashtypes[i].name); } buf[n] = '\0'; -- cgit v1.2.3 From 068ad41ec565357f4c37e52d4026c896bdeaec56 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 21 Dec 2018 22:39:44 +0000 Subject: drivers: misc: ad525x_dpot: clean indentation issue, remove tabs There is a hunk of code in a case statement that is indented one level too deeply, fix this by removing extra tabs. Also remove one empty line. Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index a0afadefcc49..1f6d008e0036 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -202,22 +202,20 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) return dpot_read_r8d8(dpot, ctrl); case DPOT_UID(AD5272_ID): case DPOT_UID(AD5274_ID): - dpot_write_r8d8(dpot, + dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_READ_RDAC << 2), 0); - value = dpot_read_r8d16(dpot, - DPOT_AD5270_1_2_4_RDAC << 2); - - if (value < 0) - return value; - /* - * AD5272/AD5274 returns high byte first, however - * underling smbus expects low byte first. - */ - value = swab16(value); + value = dpot_read_r8d16(dpot, DPOT_AD5270_1_2_4_RDAC << 2); + if (value < 0) + return value; + /* + * AD5272/AD5274 returns high byte first, however + * underling smbus expects low byte first. + */ + value = swab16(value); - if (dpot->uid == DPOT_UID(AD5274_ID)) - value = value >> 2; + if (dpot->uid == DPOT_UID(AD5274_ID)) + value = value >> 2; return value; default: if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256)) -- cgit v1.2.3 From b05ae01fdb8966afff5b153e7a7ee24684745e2d Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Mon, 24 Dec 2018 11:31:13 -0600 Subject: misc/ics932s401: Add a missing check to i2c_smbus_read_word_data ics932s401_update_device may fail reading in i2c_smbus_read_word_data due to error in i2c_smbus_xfer. The fix checks the status and defaults the register to 0. Signed-off-by: Aditya Pakki Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ics932s401.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c index 81a0541ef3ac..294fb2f66bfe 100644 --- a/drivers/misc/ics932s401.c +++ b/drivers/misc/ics932s401.c @@ -146,6 +146,8 @@ static struct ics932s401_data *ics932s401_update_device(struct device *dev) */ for (i = 0; i < NUM_MIRRORED_REGS; i++) { temp = i2c_smbus_read_word_data(client, regs_to_copy[i]); + if (temp < 0) + data->regs[regs_to_copy[i]] = 0; data->regs[regs_to_copy[i]] = temp >> 8; } -- cgit v1.2.3 From 080038cc4575cc0a2e6231f81e12b33da781e14c Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Tue, 1 Jan 2019 18:02:24 +0800 Subject: misc/mic/vop/vop_main : remove unneeded semicolon Remove unnecessary semicolon in two functions. Signed-off-by: Peng Hao Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mic/vop/vop_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mic/vop/vop_main.c b/drivers/misc/mic/vop/vop_main.c index 6b212c8b78e7..216e864bb5df 100644 --- a/drivers/misc/mic/vop/vop_main.c +++ b/drivers/misc/mic/vop/vop_main.c @@ -226,7 +226,7 @@ static void vop_reset_inform_host(struct virtio_device *dev) if (ioread8(&dc->host_ack)) break; msleep(100); - }; + } dev_dbg(_vop_dev(vdev), "%s: retry: %d\n", __func__, retry); @@ -421,7 +421,7 @@ static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs, if (!ioread8(&dc->used_address_updated)) break; msleep(100); - }; + } dev_dbg(_vop_dev(vdev), "%s: retry: %d\n", __func__, retry); if (!retry) { -- cgit v1.2.3 From bffcd1129e86cca294a8ffe851f5b290e3f1feb3 Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Tue, 1 Jan 2019 18:12:47 +0800 Subject: misc/sgi-gru/grufault: fix a style error Fix a style error. Remove redundant space. Signed-off-by: Peng Hao Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-gru/grufault.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 93be82fc338a..2ec5808ba464 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c @@ -616,8 +616,8 @@ irqreturn_t gru_intr_mblade(int irq, void *dev_id) for_each_possible_blade(blade) { if (uv_blade_nr_possible_cpus(blade)) continue; - gru_intr(0, blade); - gru_intr(1, blade); + gru_intr(0, blade); + gru_intr(1, blade); } return IRQ_HANDLED; } -- cgit v1.2.3 From e3575c1201f009a24885804975b859d868314d9c Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 09:32:08 -0600 Subject: misc: enclosure: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/misc/enclosure.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 5a17bfeb80d3..74d4fda6c4a7 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -125,9 +125,7 @@ enclosure_register(struct device *dev, const char *name, int components, struct enclosure_component_callbacks *cb) { struct enclosure_device *edev = - kzalloc(sizeof(struct enclosure_device) + - sizeof(struct enclosure_component)*components, - GFP_KERNEL); + kzalloc(struct_size(edev, component, components), GFP_KERNEL); int err, i; BUG_ON(!cb); -- cgit v1.2.3 From 83d2aed4440c47acc813abeac4acf4390cb40a8c Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: scsi/atari_scsi: Don't select CONFIG_NVRAM On powerpc, setting CONFIG_NVRAM=n builds a kernel with no NVRAM support. Setting CONFIG_NVRAM=m enables the /dev/nvram misc device module without enabling NVRAM support in drivers. Setting CONFIG_NVRAM=y enables the misc device (built-in) and also enables NVRAM support in drivers. m68k shares the valkyriefb driver with powerpc, and since that driver uses NVRAM, it is affected by CONFIG_ATARI_SCSI, because of the use of "select NVRAM". We can avoid the "select" here, but drivers still have to interpret the CONFIG_NVRAM symbol consistently regardless of platform. In this patch and the subsequent fbdev driver patch, the convention is adopted across all relevant platforms whereby NVRAM functionality gets enabled in a given device driver when the nvram misc device is built-in or when both drivers are modules. Acked-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/Kconfig | 5 +---- drivers/scsi/Kconfig | 6 +++--- drivers/scsi/atari_scsi.c | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2e2ffe7010aa..a8cac68de177 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -244,7 +244,7 @@ source "drivers/char/hw_random/Kconfig" config NVRAM tristate "/dev/nvram support" - depends on ATARI || X86 || GENERIC_NVRAM + depends on X86 || GENERIC_NVRAM ---help--- If you say Y here and create a character special file /dev/nvram with major number 10 and minor number 144 using mknod ("man mknod"), @@ -262,9 +262,6 @@ config NVRAM should NEVER idly tamper with it. See Ralf Brown's interrupt list for a guide to the use of CMOS bytes by your BIOS. - On Atari machines, /dev/nvram is always configured and does not need - to be selected. - To compile this driver as a module, choose M here: the module will be called nvram. diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index f38882f6f37d..8f9d9e9fa695 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1369,14 +1369,14 @@ config ATARI_SCSI tristate "Atari native SCSI support" depends on ATARI && SCSI select SCSI_SPI_ATTRS - select NVRAM ---help--- If you have an Atari with built-in NCR5380 SCSI controller (TT, Falcon, ...) say Y to get it supported. Of course also, if you have a compatible SCSI controller (e.g. for Medusa). - To compile this driver as a module, choose M here: the - module will be called atari_scsi. + To compile this driver as a module, choose M here: the module will + be called atari_scsi. If you also enable NVRAM support, the SCSI + host's ID is taken from the setting in TT RTC NVRAM. This driver supports both styles of NCR integration into the system: the TT style (separate DMA), and the Falcon style (via diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index a503dc50c4f8..78b43200c99e 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -757,7 +757,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev) if (setup_hostid >= 0) { atari_scsi_template.this_id = setup_hostid & 7; - } else { + } else if (IS_REACHABLE(CONFIG_NVRAM)) { /* Test if a host id is set in the NVRam */ if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) { unsigned char b = nvram_read_byte(16); -- cgit v1.2.3 From 437ace3777abc15d013d04e6644b100040bc613d Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: m68k/atari: Move Atari-specific code out of drivers/char/nvram.c Move the m68k-specific code out of the driver to make the driver generic. I've used 'SPDX-License-Identifier: GPL-2.0+' for the new file because the old file is covered by MODULE_LICENSE("GPL"). Acked-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 280 +++++++-------------------------------------------- 1 file changed, 35 insertions(+), 245 deletions(-) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 25264d65e716..a9d4652f9e90 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -21,13 +21,6 @@ * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid * again; use with care!) * - * This file also provides some functions for other parts of the kernel that - * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}. - * Obviously this can be used only if this driver is always configured into - * the kernel and is not a module. Since the functions are used by some Atari - * drivers, this is the case on the Atari. - * - * * 1.1 Cesar Barros: SMP locking fixes * added changelog * 1.2 Erik Gilling: Cobalt Networks support @@ -39,64 +32,6 @@ #include #include - -#define PC 1 -#define ATARI 2 - -/* select machine configuration */ -#if defined(CONFIG_ATARI) -# define MACH ATARI -#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and ?? */ -# define MACH PC -#else -# error Cannot build nvram driver for this machine configuration. -#endif - -#if MACH == PC - -/* RTC in a PC */ -#define CHECK_DRIVER_INIT() 1 - -/* On PCs, the checksum is built only over bytes 2..31 */ -#define PC_CKS_RANGE_START 2 -#define PC_CKS_RANGE_END 31 -#define PC_CKS_LOC 32 -#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) - -#define mach_check_checksum pc_check_checksum -#define mach_set_checksum pc_set_checksum -#define mach_proc_infos pc_proc_infos - -#endif - -#if MACH == ATARI - -/* Special parameters for RTC in Atari machines */ -#include -#include -#define RTC_PORT(x) (TT_RTC_BAS + 2*(x)) -#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)) - -#define NVRAM_BYTES 50 - -/* On Ataris, the checksum is over all bytes except the checksum bytes - * themselves; these are at the very end */ -#define ATARI_CKS_RANGE_START 0 -#define ATARI_CKS_RANGE_END 47 -#define ATARI_CKS_LOC 48 - -#define mach_check_checksum atari_check_checksum -#define mach_set_checksum atari_set_checksum -#define mach_proc_infos atari_proc_infos - -#endif - -/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with - * rtc_lock held. Due to the index-port/data-port design of the RTC, we - * don't want two different things trying to get to it at once. (e.g. the - * periodic 11 min sync from kernel/time/ntp.c vs. this driver.) - */ - #include #include #include @@ -120,12 +55,9 @@ static int nvram_open_mode; /* special open modes */ #define NVRAM_WRITE 1 /* opened for writing (exclusive) */ #define NVRAM_EXCL 2 /* opened with O_EXCL */ -static int mach_check_checksum(void); -static void mach_set_checksum(void); - #ifdef CONFIG_PROC_FS -static void mach_proc_infos(unsigned char *contents, struct seq_file *seq, - void *offset); +static void pc_nvram_proc_read(unsigned char *contents, struct seq_file *seq, + void *offset); #endif /* @@ -139,6 +71,14 @@ static void mach_proc_infos(unsigned char *contents, struct seq_file *seq, * know about the RTC cruft. */ +#define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE) + +/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with + * rtc_lock held. Due to the index-port/data-port design of the RTC, we + * don't want two different things trying to get to it at once. (e.g. the + * periodic 11 min sync from kernel/time/ntp.c vs. this driver.) + */ + unsigned char __nvram_read_byte(int i) { return CMOS_READ(NVRAM_FIRST_BYTE + i); @@ -174,9 +114,22 @@ void nvram_write_byte(unsigned char c, int i) } EXPORT_SYMBOL(nvram_write_byte); +/* On PCs, the checksum is built only over bytes 2..31 */ +#define PC_CKS_RANGE_START 2 +#define PC_CKS_RANGE_END 31 +#define PC_CKS_LOC 32 + int __nvram_check_checksum(void) { - return mach_check_checksum(); + int i; + unsigned short sum = 0; + unsigned short expect; + + for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + expect = __nvram_read_byte(PC_CKS_LOC)<<8 | + __nvram_read_byte(PC_CKS_LOC+1); + return (sum & 0xffff) == expect; } EXPORT_SYMBOL(__nvram_check_checksum); @@ -194,7 +147,13 @@ EXPORT_SYMBOL(nvram_check_checksum); static void __nvram_set_checksum(void) { - mach_set_checksum(); + int i; + unsigned short sum = 0; + + for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) + sum += __nvram_read_byte(i); + __nvram_write_byte(sum >> 8, PC_CKS_LOC); + __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); } #if 0 @@ -384,7 +343,7 @@ static int nvram_proc_read(struct seq_file *seq, void *offset) contents[i] = __nvram_read_byte(i); spin_unlock_irq(&rtc_lock); - mach_proc_infos(contents, seq, offset); + pc_nvram_proc_read(contents, seq, offset); return 0; } @@ -418,10 +377,6 @@ static int __init nvram_init(void) { int ret; - /* First test whether the driver should init at all */ - if (!CHECK_DRIVER_INIT()) - return -ENODEV; - ret = misc_register(&nvram_dev); if (ret) { printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", @@ -451,36 +406,6 @@ static void __exit nvram_cleanup_module(void) module_init(nvram_init); module_exit(nvram_cleanup_module); -/* - * Machine specific functions - */ - -#if MACH == PC - -static int pc_check_checksum(void) -{ - int i; - unsigned short sum = 0; - unsigned short expect; - - for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) - sum += __nvram_read_byte(i); - expect = __nvram_read_byte(PC_CKS_LOC)<<8 | - __nvram_read_byte(PC_CKS_LOC+1); - return (sum & 0xffff) == expect; -} - -static void pc_set_checksum(void) -{ - int i; - unsigned short sum = 0; - - for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) - sum += __nvram_read_byte(i); - __nvram_write_byte(sum >> 8, PC_CKS_LOC); - __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); -} - #ifdef CONFIG_PROC_FS static const char * const floppy_types[] = { @@ -495,8 +420,8 @@ static const char * const gfx_types[] = { "monochrome", }; -static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq, - void *offset) +static void pc_nvram_proc_read(unsigned char *nvram, struct seq_file *seq, + void *offset) { int checksum; int type; @@ -557,143 +482,8 @@ static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq, return; } -#endif - -#endif /* MACH == PC */ - -#if MACH == ATARI - -static int atari_check_checksum(void) -{ - int i; - unsigned char sum = 0; - - for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) - sum += __nvram_read_byte(i); - return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) && - (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff)); -} - -static void atari_set_checksum(void) -{ - int i; - unsigned char sum = 0; - - for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) - sum += __nvram_read_byte(i); - __nvram_write_byte(~sum, ATARI_CKS_LOC); - __nvram_write_byte(sum, ATARI_CKS_LOC + 1); -} - -#ifdef CONFIG_PROC_FS - -static struct { - unsigned char val; - const char *name; -} boot_prefs[] = { - { 0x80, "TOS" }, - { 0x40, "ASV" }, - { 0x20, "NetBSD (?)" }, - { 0x10, "Linux" }, - { 0x00, "unspecified" } -}; - -static const char * const languages[] = { - "English (US)", - "German", - "French", - "English (UK)", - "Spanish", - "Italian", - "6 (undefined)", - "Swiss (French)", - "Swiss (German)" -}; - -static const char * const dateformat[] = { - "MM%cDD%cYY", - "DD%cMM%cYY", - "YY%cMM%cDD", - "YY%cDD%cMM", - "4 (undefined)", - "5 (undefined)", - "6 (undefined)", - "7 (undefined)" -}; - -static const char * const colors[] = { - "2", "4", "16", "256", "65536", "??", "??", "??" -}; - -static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq, - void *offset) -{ - int checksum = nvram_check_checksum(); - int i; - unsigned vmode; - - seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not "); - - seq_printf(seq, "Boot preference : "); - for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) { - if (nvram[1] == boot_prefs[i].val) { - seq_printf(seq, "%s\n", boot_prefs[i].name); - break; - } - } - if (i < 0) - seq_printf(seq, "0x%02x (undefined)\n", nvram[1]); - - seq_printf(seq, "SCSI arbitration : %s\n", - (nvram[16] & 0x80) ? "on" : "off"); - seq_printf(seq, "SCSI host ID : "); - if (nvram[16] & 0x80) - seq_printf(seq, "%d\n", nvram[16] & 7); - else - seq_printf(seq, "n/a\n"); - - /* the following entries are defined only for the Falcon */ - if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON) - return; - - seq_printf(seq, "OS language : "); - if (nvram[6] < ARRAY_SIZE(languages)) - seq_printf(seq, "%s\n", languages[nvram[6]]); - else - seq_printf(seq, "%u (undefined)\n", nvram[6]); - seq_printf(seq, "Keyboard language: "); - if (nvram[7] < ARRAY_SIZE(languages)) - seq_printf(seq, "%s\n", languages[nvram[7]]); - else - seq_printf(seq, "%u (undefined)\n", nvram[7]); - seq_printf(seq, "Date format : "); - seq_printf(seq, dateformat[nvram[8] & 7], - nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/'); - seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12); - seq_printf(seq, "Boot delay : "); - if (nvram[10] == 0) - seq_printf(seq, "default"); - else - seq_printf(seq, "%ds%s\n", nvram[10], - nvram[10] < 8 ? ", no memory test" : ""); - - vmode = (nvram[14] << 8) | nvram[15]; - seq_printf(seq, - "Video mode : %s colors, %d columns, %s %s monitor\n", - colors[vmode & 7], - vmode & 8 ? 80 : 40, - vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC"); - seq_printf(seq, " %soverscan, compat. mode %s%s\n", - vmode & 64 ? "" : "no ", - vmode & 128 ? "on" : "off", - vmode & 256 ? - (vmode & 16 ? ", line doubling" : ", half screen") : ""); - - return; -} -#endif -#endif /* MACH == ATARI */ +#endif /* CONFIG_PROC_FS */ MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(NVRAM_MINOR); -- cgit v1.2.3 From cb8d8006d43f22924e000c730d18862587a824ff Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: char/nvram: Re-order functions to remove forward declarations and #ifdefs Also give functions more sensible names: nvram_misc_* for misc device ops, nvram_proc_* for proc file ops and nvram_module_* for init and exit functions. This prevents name collisions with nvram.h helper functions and improves readability. Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 167 ++++++++++++++++++++++----------------------------- 1 file changed, 72 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index a9d4652f9e90..c660cff9faf4 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -55,11 +55,6 @@ static int nvram_open_mode; /* special open modes */ #define NVRAM_WRITE 1 /* opened for writing (exclusive) */ #define NVRAM_EXCL 2 /* opened with O_EXCL */ -#ifdef CONFIG_PROC_FS -static void pc_nvram_proc_read(unsigned char *contents, struct seq_file *seq, - void *offset); -#endif - /* * These functions are provided to be called internally or by other parts of * the kernel. It's up to the caller to ensure correct checksum before reading @@ -171,14 +166,14 @@ void nvram_set_checksum(void) * The are the file operation function for user access to /dev/nvram */ -static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) +static loff_t nvram_misc_llseek(struct file *file, loff_t offset, int origin) { return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE, NVRAM_BYTES); } -static ssize_t nvram_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static ssize_t nvram_misc_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; @@ -206,8 +201,8 @@ checksum_err: return -EIO; } -static ssize_t nvram_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t nvram_misc_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; unsigned i = *ppos; @@ -245,8 +240,8 @@ checksum_err: return -EIO; } -static long nvram_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static long nvram_misc_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int i; @@ -286,7 +281,7 @@ static long nvram_ioctl(struct file *file, unsigned int cmd, } } -static int nvram_open(struct inode *inode, struct file *file) +static int nvram_misc_open(struct inode *inode, struct file *file) { spin_lock(&nvram_state_lock); @@ -308,7 +303,7 @@ static int nvram_open(struct inode *inode, struct file *file) return 0; } -static int nvram_release(struct inode *inode, struct file *file) +static int nvram_misc_release(struct inode *inode, struct file *file) { spin_lock(&nvram_state_lock); @@ -325,87 +320,6 @@ static int nvram_release(struct inode *inode, struct file *file) return 0; } -#ifndef CONFIG_PROC_FS -static int nvram_add_proc_fs(void) -{ - return 0; -} - -#else - -static int nvram_proc_read(struct seq_file *seq, void *offset) -{ - unsigned char contents[NVRAM_BYTES]; - int i = 0; - - spin_lock_irq(&rtc_lock); - for (i = 0; i < NVRAM_BYTES; ++i) - contents[i] = __nvram_read_byte(i); - spin_unlock_irq(&rtc_lock); - - pc_nvram_proc_read(contents, seq, offset); - - return 0; -} - -static int nvram_add_proc_fs(void) -{ - if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) - return -ENOMEM; - return 0; -} - -#endif /* CONFIG_PROC_FS */ - -static const struct file_operations nvram_fops = { - .owner = THIS_MODULE, - .llseek = nvram_llseek, - .read = nvram_read, - .write = nvram_write, - .unlocked_ioctl = nvram_ioctl, - .open = nvram_open, - .release = nvram_release, -}; - -static struct miscdevice nvram_dev = { - NVRAM_MINOR, - "nvram", - &nvram_fops -}; - -static int __init nvram_init(void) -{ - int ret; - - ret = misc_register(&nvram_dev); - if (ret) { - printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", - NVRAM_MINOR); - goto out; - } - ret = nvram_add_proc_fs(); - if (ret) { - printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n"); - goto outmisc; - } - ret = 0; - printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n"); -out: - return ret; -outmisc: - misc_deregister(&nvram_dev); - goto out; -} - -static void __exit nvram_cleanup_module(void) -{ - remove_proc_entry("driver/nvram", NULL); - misc_deregister(&nvram_dev); -} - -module_init(nvram_init); -module_exit(nvram_cleanup_module); - #ifdef CONFIG_PROC_FS static const char * const floppy_types[] = { @@ -483,7 +397,70 @@ static void pc_nvram_proc_read(unsigned char *nvram, struct seq_file *seq, return; } +static int nvram_proc_read(struct seq_file *seq, void *offset) +{ + unsigned char contents[NVRAM_BYTES]; + int i = 0; + + spin_lock_irq(&rtc_lock); + for (i = 0; i < NVRAM_BYTES; ++i) + contents[i] = __nvram_read_byte(i); + spin_unlock_irq(&rtc_lock); + + pc_nvram_proc_read(contents, seq, offset); + + return 0; +} #endif /* CONFIG_PROC_FS */ +static const struct file_operations nvram_misc_fops = { + .owner = THIS_MODULE, + .llseek = nvram_misc_llseek, + .read = nvram_misc_read, + .write = nvram_misc_write, + .unlocked_ioctl = nvram_misc_ioctl, + .open = nvram_misc_open, + .release = nvram_misc_release, +}; + +static struct miscdevice nvram_misc = { + NVRAM_MINOR, + "nvram", + &nvram_misc_fops, +}; + +static int __init nvram_module_init(void) +{ + int ret; + + ret = misc_register(&nvram_misc); + if (ret) { + pr_err("nvram: can't misc_register on minor=%d\n", NVRAM_MINOR); + return ret; + } + +#ifdef CONFIG_PROC_FS + if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) { + pr_err("nvram: can't create /proc/driver/nvram\n"); + misc_deregister(&nvram_misc); + return -ENOMEM; + } +#endif + + pr_info("Non-volatile memory driver v" NVRAM_VERSION "\n"); + return 0; +} + +static void __exit nvram_module_exit(void) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("driver/nvram", NULL); +#endif + misc_deregister(&nvram_misc); +} + +module_init(nvram_module_init); +module_exit(nvram_module_exit); + MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(NVRAM_MINOR); -- cgit v1.2.3 From 1278cf66cf4b1c3d30e311200b50c45457c92baa Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: nvram: Replace nvram_* function exports with static functions Replace nvram_* functions with static functions in nvram.h. These will become wrappers for struct nvram_ops method calls. This patch effectively disables existing NVRAM functionality so as to allow the rest of the series to be bisected without build failures. That functionality is gradually re-implemented in subsequent patches. Replace the sole validate-checksum-and-read-byte sequence with a call to nvram_read() which will gain the same semantics in subsequent patches. Remove unused exports. Acked-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 27 +++++---------------------- drivers/scsi/atari_scsi.c | 8 +++++--- 2 files changed, 10 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index c660cff9faf4..c98775bfd896 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -74,13 +74,12 @@ static int nvram_open_mode; /* special open modes */ * periodic 11 min sync from kernel/time/ntp.c vs. this driver.) */ -unsigned char __nvram_read_byte(int i) +static unsigned char __nvram_read_byte(int i) { return CMOS_READ(NVRAM_FIRST_BYTE + i); } -EXPORT_SYMBOL(__nvram_read_byte); -unsigned char nvram_read_byte(int i) +static unsigned char pc_nvram_read_byte(int i) { unsigned long flags; unsigned char c; @@ -90,16 +89,14 @@ unsigned char nvram_read_byte(int i) spin_unlock_irqrestore(&rtc_lock, flags); return c; } -EXPORT_SYMBOL(nvram_read_byte); /* This races nicely with trying to read with checksum checking (nvram_read) */ -void __nvram_write_byte(unsigned char c, int i) +static void __nvram_write_byte(unsigned char c, int i) { CMOS_WRITE(c, NVRAM_FIRST_BYTE + i); } -EXPORT_SYMBOL(__nvram_write_byte); -void nvram_write_byte(unsigned char c, int i) +static void pc_nvram_write_byte(unsigned char c, int i) { unsigned long flags; @@ -107,14 +104,13 @@ void nvram_write_byte(unsigned char c, int i) __nvram_write_byte(c, i); spin_unlock_irqrestore(&rtc_lock, flags); } -EXPORT_SYMBOL(nvram_write_byte); /* On PCs, the checksum is built only over bytes 2..31 */ #define PC_CKS_RANGE_START 2 #define PC_CKS_RANGE_END 31 #define PC_CKS_LOC 32 -int __nvram_check_checksum(void) +static int __nvram_check_checksum(void) { int i; unsigned short sum = 0; @@ -126,19 +122,6 @@ int __nvram_check_checksum(void) __nvram_read_byte(PC_CKS_LOC+1); return (sum & 0xffff) == expect; } -EXPORT_SYMBOL(__nvram_check_checksum); - -int nvram_check_checksum(void) -{ - unsigned long flags; - int rv; - - spin_lock_irqsave(&rtc_lock, flags); - rv = __nvram_check_checksum(); - spin_unlock_irqrestore(&rtc_lock, flags); - return rv; -} -EXPORT_SYMBOL(nvram_check_checksum); static void __nvram_set_checksum(void) { diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 78b43200c99e..e809493d0d06 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -759,13 +759,15 @@ static int __init atari_scsi_probe(struct platform_device *pdev) atari_scsi_template.this_id = setup_hostid & 7; } else if (IS_REACHABLE(CONFIG_NVRAM)) { /* Test if a host id is set in the NVRam */ - if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) { - unsigned char b = nvram_read_byte(16); + if (ATARIHW_PRESENT(TT_CLK)) { + unsigned char b; + loff_t offset = 16; + ssize_t count = nvram_read(&b, 1, &offset); /* Arbitration enabled? (for TOS) * If yes, use configured host ID */ - if (b & 0x80) + if ((count == 1) && (b & 0x80)) atari_scsi_template.this_id = b & 7; } } -- cgit v1.2.3 From a156c7ba669c65b55c7afcc3994e1199cc0cad47 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: powerpc: Replace nvram_* extern declarations with standard header Remove the nvram_read_byte() and nvram_write_byte() declarations in powerpc/include/asm/nvram.h and use the cross-platform static functions in linux/nvram.h instead. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/generic_nvram.c | 1 + drivers/video/fbdev/matrox/matroxfb_base.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c index ff5394f47587..0c22b9503e84 100644 --- a/drivers/char/generic_nvram.c +++ b/drivers/char/generic_nvram.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/video/fbdev/matrox/matroxfb_base.c b/drivers/video/fbdev/matrox/matroxfb_base.c index 838869c6490c..0a4e5bad33f4 100644 --- a/drivers/video/fbdev/matrox/matroxfb_base.c +++ b/drivers/video/fbdev/matrox/matroxfb_base.c @@ -111,12 +111,12 @@ #include "matroxfb_g450.h" #include #include +#include #include #include #ifdef CONFIG_PPC_PMAC #include -unsigned char nvram_read_byte(int); static int default_vmode = VMODE_NVRAM; static int default_cmode = CMODE_NVRAM; #endif -- cgit v1.2.3 From d5bbb5021ce8d9ff561c7469f5b4589ccb3bc4a6 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: char/nvram: Adopt arch_nvram_ops NVRAMs on different platforms and architectures have different attributes and access methods. E.g. some platforms have byte-at-a-time accessor functions while others have byte-range accessor functions. Some have checksum functionality while others do not. By calling ops struct methods via the common wrapper functions, the nvram module and other drivers can make use of the available NVRAM functionality in a portable way. Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index c98775bfd896..2df391f78986 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -52,9 +52,11 @@ static DEFINE_MUTEX(nvram_mutex); static DEFINE_SPINLOCK(nvram_state_lock); static int nvram_open_cnt; /* #times opened */ static int nvram_open_mode; /* special open modes */ +static ssize_t nvram_size; #define NVRAM_WRITE 1 /* opened for writing (exclusive) */ #define NVRAM_EXCL 2 /* opened with O_EXCL */ +#ifdef CONFIG_X86 /* * These functions are provided to be called internally or by other parts of * the kernel. It's up to the caller to ensure correct checksum before reading @@ -145,6 +147,19 @@ void nvram_set_checksum(void) } #endif /* 0 */ +static ssize_t pc_nvram_get_size(void) +{ + return NVRAM_BYTES; +} + +const struct nvram_ops arch_nvram_ops = { + .read_byte = pc_nvram_read_byte, + .write_byte = pc_nvram_write_byte, + .get_size = pc_nvram_get_size, +}; +EXPORT_SYMBOL(arch_nvram_ops); +#endif /* CONFIG_X86 */ + /* * The are the file operation function for user access to /dev/nvram */ @@ -152,7 +167,7 @@ void nvram_set_checksum(void) static loff_t nvram_misc_llseek(struct file *file, loff_t offset, int origin) { return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE, - NVRAM_BYTES); + nvram_size); } static ssize_t nvram_misc_read(struct file *file, char __user *buf, @@ -303,8 +318,7 @@ static int nvram_misc_release(struct inode *inode, struct file *file) return 0; } -#ifdef CONFIG_PROC_FS - +#if defined(CONFIG_X86) && defined(CONFIG_PROC_FS) static const char * const floppy_types[] = { "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M", "3.5'' 2.88M", "3.5'' 2.88M" @@ -394,7 +408,7 @@ static int nvram_proc_read(struct seq_file *seq, void *offset) return 0; } -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_X86 && CONFIG_PROC_FS */ static const struct file_operations nvram_misc_fops = { .owner = THIS_MODULE, @@ -416,13 +430,17 @@ static int __init nvram_module_init(void) { int ret; + nvram_size = nvram_get_size(); + if (nvram_size < 0) + return nvram_size; + ret = misc_register(&nvram_misc); if (ret) { pr_err("nvram: can't misc_register on minor=%d\n", NVRAM_MINOR); return ret; } -#ifdef CONFIG_PROC_FS +#if defined(CONFIG_X86) && defined(CONFIG_PROC_FS) if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) { pr_err("nvram: can't create /proc/driver/nvram\n"); misc_deregister(&nvram_misc); @@ -436,7 +454,7 @@ static int __init nvram_module_init(void) static void __exit nvram_module_exit(void) { -#ifdef CONFIG_PROC_FS +#if defined(CONFIG_X86) && defined(CONFIG_PROC_FS) remove_proc_entry("driver/nvram", NULL); #endif misc_deregister(&nvram_misc); -- cgit v1.2.3 From 2d58636e0af724f38acad25246c1625efec36122 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: char/nvram: Allow the set_checksum and initialize ioctls to be omitted The drivers/char/nvram.c module has previously supported only RTC "CMOS" NVRAM, for which it provides appropriate checksum ioctls. Make these ioctls optional so the module can be re-used with other kinds of NVRAM. The ops struct methods that implement the ioctls now return error codes so that a multi-platform kernel binary can do the right thing when running on hardware without a suitable NVRAM. Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 70 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 2df391f78986..f88ef41d0598 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -136,16 +136,25 @@ static void __nvram_set_checksum(void) __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); } -#if 0 -void nvram_set_checksum(void) +static long pc_nvram_set_checksum(void) { - unsigned long flags; + spin_lock_irq(&rtc_lock); + __nvram_set_checksum(); + spin_unlock_irq(&rtc_lock); + return 0; +} - spin_lock_irqsave(&rtc_lock, flags); +static long pc_nvram_initialize(void) +{ + ssize_t i; + + spin_lock_irq(&rtc_lock); + for (i = 0; i < NVRAM_BYTES; ++i) + __nvram_write_byte(0, i); __nvram_set_checksum(); - spin_unlock_irqrestore(&rtc_lock, flags); + spin_unlock_irq(&rtc_lock); + return 0; } -#endif /* 0 */ static ssize_t pc_nvram_get_size(void) { @@ -156,6 +165,8 @@ const struct nvram_ops arch_nvram_ops = { .read_byte = pc_nvram_read_byte, .write_byte = pc_nvram_write_byte, .get_size = pc_nvram_get_size, + .set_checksum = pc_nvram_set_checksum, + .initialize = pc_nvram_initialize, }; EXPORT_SYMBOL(arch_nvram_ops); #endif /* CONFIG_X86 */ @@ -241,51 +252,50 @@ checksum_err: static long nvram_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int i; + long ret = -ENOTTY; switch (cmd) { - case NVRAM_INIT: /* initialize NVRAM contents and checksum */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - mutex_lock(&nvram_mutex); - spin_lock_irq(&rtc_lock); - - for (i = 0; i < NVRAM_BYTES; ++i) - __nvram_write_byte(0, i); - __nvram_set_checksum(); - - spin_unlock_irq(&rtc_lock); - mutex_unlock(&nvram_mutex); - return 0; - + if (arch_nvram_ops.initialize != NULL) { + mutex_lock(&nvram_mutex); + ret = arch_nvram_ops.initialize(); + mutex_unlock(&nvram_mutex); + } + break; case NVRAM_SETCKS: /* just set checksum, contents unchanged (maybe useful after * checksum garbaged somehow...) */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - mutex_lock(&nvram_mutex); - spin_lock_irq(&rtc_lock); - __nvram_set_checksum(); - spin_unlock_irq(&rtc_lock); - mutex_unlock(&nvram_mutex); - return 0; - - default: - return -ENOTTY; + if (arch_nvram_ops.set_checksum != NULL) { + mutex_lock(&nvram_mutex); + ret = arch_nvram_ops.set_checksum(); + mutex_unlock(&nvram_mutex); + } + break; } + return ret; } static int nvram_misc_open(struct inode *inode, struct file *file) { spin_lock(&nvram_state_lock); + /* Prevent multiple readers/writers if desired. */ if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || - (nvram_open_mode & NVRAM_EXCL) || - ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) { + (nvram_open_mode & NVRAM_EXCL)) { + spin_unlock(&nvram_state_lock); + return -EBUSY; + } + + /* Prevent multiple writers if the set_checksum ioctl is implemented. */ + if ((arch_nvram_ops.set_checksum != NULL) && + (file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE)) { spin_unlock(&nvram_state_lock); return -EBUSY; } -- cgit v1.2.3 From 109b3a89a7c48405d61a05d7a1720581a4f1574c Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: char/nvram: Implement NVRAM read/write methods Refactor the RTC "CMOS" NVRAM functions so that they can be used as arch_nvram_ops methods. Checksumming logic is moved from the misc device operations to the nvram read/write operations. This makes the misc device implementation more generic. This preserves the locking mechanism such that "read if checksum valid" and "write and update checksum" remain atomic operations. Some platforms implement byte-range read/write methods which are similar to file_operations struct methods. Other platforms provide only byte-at-a-time methods. The former are more efficient but may be unavailable so fall back on the latter methods when necessary. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 120 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index f88ef41d0598..adcc213c331e 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -161,7 +162,46 @@ static ssize_t pc_nvram_get_size(void) return NVRAM_BYTES; } +static ssize_t pc_nvram_read(char *buf, size_t count, loff_t *ppos) +{ + char *p = buf; + loff_t i; + + spin_lock_irq(&rtc_lock); + if (!__nvram_check_checksum()) { + spin_unlock_irq(&rtc_lock); + return -EIO; + } + for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p) + *p = __nvram_read_byte(i); + spin_unlock_irq(&rtc_lock); + + *ppos = i; + return p - buf; +} + +static ssize_t pc_nvram_write(char *buf, size_t count, loff_t *ppos) +{ + char *p = buf; + loff_t i; + + spin_lock_irq(&rtc_lock); + if (!__nvram_check_checksum()) { + spin_unlock_irq(&rtc_lock); + return -EIO; + } + for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p) + __nvram_write_byte(*p, i); + __nvram_set_checksum(); + spin_unlock_irq(&rtc_lock); + + *ppos = i; + return p - buf; +} + const struct nvram_ops arch_nvram_ops = { + .read = pc_nvram_read, + .write = pc_nvram_write, .read_byte = pc_nvram_read_byte, .write_byte = pc_nvram_write_byte, .get_size = pc_nvram_get_size, @@ -184,69 +224,57 @@ static loff_t nvram_misc_llseek(struct file *file, loff_t offset, int origin) static ssize_t nvram_misc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - unsigned char contents[NVRAM_BYTES]; - unsigned i = *ppos; - unsigned char *tmp; - - spin_lock_irq(&rtc_lock); + char *tmp; + ssize_t ret; - if (!__nvram_check_checksum()) - goto checksum_err; - for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp) - *tmp = __nvram_read_byte(i); + if (!access_ok(buf, count)) + return -EFAULT; + if (*ppos >= nvram_size) + return 0; - spin_unlock_irq(&rtc_lock); + count = min_t(size_t, count, nvram_size - *ppos); + count = min_t(size_t, count, PAGE_SIZE); - if (copy_to_user(buf, contents, tmp - contents)) - return -EFAULT; + tmp = kmalloc(count, GFP_KERNEL); + if (!tmp) + return -ENOMEM; - *ppos = i; + ret = nvram_read(tmp, count, ppos); + if (ret <= 0) + goto out; - return tmp - contents; + if (copy_to_user(buf, tmp, ret)) { + *ppos -= ret; + ret = -EFAULT; + } -checksum_err: - spin_unlock_irq(&rtc_lock); - return -EIO; +out: + kfree(tmp); + return ret; } static ssize_t nvram_misc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - unsigned char contents[NVRAM_BYTES]; - unsigned i = *ppos; - unsigned char *tmp; - - if (i >= NVRAM_BYTES) - return 0; /* Past EOF */ - - if (count > NVRAM_BYTES - i) - count = NVRAM_BYTES - i; - if (count > NVRAM_BYTES) - return -EFAULT; /* Can't happen, but prove it to gcc */ + char *tmp; + ssize_t ret; - if (copy_from_user(contents, buf, count)) + if (!access_ok(buf, count)) return -EFAULT; + if (*ppos >= nvram_size) + return 0; - spin_lock_irq(&rtc_lock); - - if (!__nvram_check_checksum()) - goto checksum_err; - - for (tmp = contents; count--; ++i, ++tmp) - __nvram_write_byte(*tmp, i); + count = min_t(size_t, count, nvram_size - *ppos); + count = min_t(size_t, count, PAGE_SIZE); - __nvram_set_checksum(); - - spin_unlock_irq(&rtc_lock); + tmp = memdup_user(buf, count); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); - *ppos = i; - - return tmp - contents; - -checksum_err: - spin_unlock_irq(&rtc_lock); - return -EIO; + ret = nvram_write(tmp, count, ppos); + kfree(tmp); + return ret; } static long nvram_misc_ioctl(struct file *file, unsigned int cmd, -- cgit v1.2.3 From 666047fe2a4c9e1bc255ca0549d825b40832886c Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: m68k/atari: Implement arch_nvram_ops methods and enable CONFIG_HAVE_ARCH_NVRAM_OPS Atari RTC NVRAM uses a checksum so implement the remaining arch_nvram_ops methods for the set_checksum and initialize ioctls. Enable CONFIG_HAVE_ARCH_NVRAM_OPS. Acked-by: Geert Uytterhoeven Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index a8cac68de177..ce9979529cf3 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -244,7 +244,8 @@ source "drivers/char/hw_random/Kconfig" config NVRAM tristate "/dev/nvram support" - depends on X86 || GENERIC_NVRAM + depends on X86 || GENERIC_NVRAM || HAVE_ARCH_NVRAM_OPS + default M68K ---help--- If you say Y here and create a character special file /dev/nvram with major number 10 and minor number 144 using mknod ("man mknod"), -- cgit v1.2.3 From 458c77f3de0edc8a2df1f54ac641823ccbd3ff56 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: macintosh/via-cuda: Don't rely on Cuda to end a transfer Certain Cuda transfers have to be ended by the driver. According to Apple's open source Cuda driver, as found in mkLinux and XNU, this applies to any "open ended request such as PRAM read". This fixes an infinite polling loop in cuda_pram_read_byte(). Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/macintosh/via-cuda.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index bbec6ac0a966..3581abfb0c6a 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -569,6 +569,7 @@ cuda_interrupt(int irq, void *arg) unsigned char ibuf[16]; int ibuf_len = 0; int complete = 0; + bool full; spin_lock_irqsave(&cuda_lock, flags); @@ -656,12 +657,13 @@ idle_state: break; case reading: - if (reading_reply ? ARRAY_FULL(current_req->reply, reply_ptr) - : ARRAY_FULL(cuda_rbuf, reply_ptr)) + full = reading_reply ? ARRAY_FULL(current_req->reply, reply_ptr) + : ARRAY_FULL(cuda_rbuf, reply_ptr); + if (full) (void)in_8(&via[SR]); else *reply_ptr++ = in_8(&via[SR]); - if (!TREQ_asserted(status)) { + if (!TREQ_asserted(status) || full) { if (mcu_is_egret) assert_TACK(); /* that's all folks */ -- cgit v1.2.3 From 7fc0ac05f3f54319f7cac19f556282d5dafad6e2 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: char/nvram: Add "devname:nvram" module alias Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index adcc213c331e..c9e295d73dc5 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -503,3 +503,4 @@ module_exit(nvram_module_exit); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(NVRAM_MINOR); +MODULE_ALIAS("devname:nvram"); -- cgit v1.2.3 From 95ac14b8a32817dcd1f13ae4787891484966d2d5 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: powerpc: Implement nvram ioctls Add the powerpc-specific ioctls to the nvram module. This allows the nvram module to replace the generic_nvram module. Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index c9e295d73dc5..944f05fddacd 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -48,6 +48,9 @@ #include #include +#ifdef CONFIG_PPC +#include +#endif static DEFINE_MUTEX(nvram_mutex); static DEFINE_SPINLOCK(nvram_state_lock); @@ -283,6 +286,38 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd, long ret = -ENOTTY; switch (cmd) { +#ifdef CONFIG_PPC + case OBSOLETE_PMAC_NVRAM_GET_OFFSET: + pr_warn("nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n"); + /* fall through */ + case IOC_NVRAM_GET_OFFSET: + ret = -EINVAL; +#ifdef CONFIG_PPC_PMAC + if (machine_is(powermac)) { + int part, offset; + + if (copy_from_user(&part, (void __user *)arg, + sizeof(part)) != 0) + return -EFAULT; + if (part < pmac_nvram_OF || part > pmac_nvram_NR) + return -EINVAL; + offset = pmac_get_partition(part); + if (copy_to_user((void __user *)arg, + &offset, sizeof(offset)) != 0) + return -EFAULT; + ret = 0; + } +#endif + break; + case IOC_NVRAM_SYNC: + if (ppc_md.nvram_sync != NULL) { + mutex_lock(&nvram_mutex); + ppc_md.nvram_sync(); + mutex_unlock(&nvram_mutex); + } + ret = 0; + break; +#elif defined(CONFIG_X86) || defined(CONFIG_M68K) case NVRAM_INIT: /* initialize NVRAM contents and checksum */ if (!capable(CAP_SYS_ADMIN)) @@ -306,6 +341,7 @@ static long nvram_misc_ioctl(struct file *file, unsigned int cmd, mutex_unlock(&nvram_mutex); } break; +#endif /* CONFIG_X86 || CONFIG_M68K */ } return ret; } @@ -321,12 +357,14 @@ static int nvram_misc_open(struct inode *inode, struct file *file) return -EBUSY; } +#if defined(CONFIG_X86) || defined(CONFIG_M68K) /* Prevent multiple writers if the set_checksum ioctl is implemented. */ if ((arch_nvram_ops.set_checksum != NULL) && (file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE)) { spin_unlock(&nvram_state_lock); return -EBUSY; } +#endif if (file->f_flags & O_EXCL) nvram_open_mode |= NVRAM_EXCL; -- cgit v1.2.3 From 066ac5c3c4bb467d6e8c7255e36c77060efe5ef7 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Tue, 15 Jan 2019 15:18:56 +1100 Subject: powerpc, fbdev: Use NV_CMODE and NV_VMODE only when CONFIG_PPC32 && CONFIG_PPC_PMAC && CONFIG_NVRAM This patch addresses inconsistencies in Mac framebuffer drivers and their use of Kconfig symbols relating to NVRAM, so PPC64 can use CONFIG_NVRAM. The defined(CONFIG_NVRAM) condition is replaced with the weaker IS_REACHABLE(CONFIG_NVRAM) condition, like atari_scsi. Macintosh framebuffer drivers use default settings for color mode and video mode that are found in NVRAM. On PCI Macs, MacOS stores display settings in the Name Registry (NR) partition in NVRAM*. On NuBus Macs, there is no NR partition and MacOS stores display mode settings in PRAM**. Early-model Macs are the ones most likely to benefit from these settings, since they are more likely to have a fixed-frequency monitor connected to the built-in framebuffer device. Moreove