1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Implement 'Simple Boot Flag Specification 2.0' 4 */ 5 #include <linux/types.h> 6 #include <linux/kernel.h> 7 #include <linux/init.h> 8 #include <linux/string.h> 9 #include <linux/spinlock.h> 10 #include <linux/acpi.h> 11 #include <asm/io.h> 12 13 #include <linux/mc146818rtc.h> 14 15 #define SBF_RESERVED (0x78) 16 #define SBF_PNPOS (1<<0) 17 #define SBF_BOOTING (1<<1) 18 #define SBF_DIAG (1<<2) 19 #define SBF_PARITY (1<<7) 20 21 int sbf_port __initdata = -1; /* set via acpi_boot_init() */ 22 23 static int __init parity(u8 v) 24 { 25 int x = 0; 26 int i; 27 28 for (i = 0; i < 8; i++) { 29 x ^= (v & 1); 30 v >>= 1; 31 } 32 33 return x; 34 } 35 36 static void __init sbf_write(u8 v) 37 { 38 unsigned long flags; 39 40 if (sbf_port != -1) { 41 v &= ~SBF_PARITY; 42 if (!parity(v)) 43 v |= SBF_PARITY; 44 45 printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n", 46 sbf_port, v); 47 48 spin_lock_irqsave(&rtc_lock, flags); 49 CMOS_WRITE(v, sbf_port); 50 spin_unlock_irqrestore(&rtc_lock, flags); 51 } 52 } 53 54 static u8 __init sbf_read(void) 55 { 56 unsigned long flags; 57 u8 v; 58 59 if (sbf_port == -1) 60 return 0; 61 62 spin_lock_irqsave(&rtc_lock, flags); 63 v = CMOS_READ(sbf_port); 64 spin_unlock_irqrestore(&rtc_lock, flags); 65 66 return v; 67 } 68 69 static int __init sbf_value_valid(u8 v) 70 { 71 if (v & SBF_RESERVED) /* Reserved bits */ 72 return 0; 73 if (!parity(v)) 74 return 0; 75 76 return 1; 77 } 78 79 static int __init sbf_init(void) 80 { 81 u8 v; 82 83 if (sbf_port == -1) 84 return 0; 85 86 v = sbf_read(); 87 if (!sbf_value_valid(v)) { 88 printk(KERN_WARNING "Simple Boot Flag value 0x%x read from " 89 "CMOS RAM was invalid\n", v); 90 } 91 92 v &= ~SBF_RESERVED; 93 v &= ~SBF_BOOTING; 94 v &= ~SBF_DIAG; 95 #if defined(CONFIG_ISAPNP) 96 v |= SBF_PNPOS; 97 #endif 98 sbf_write(v); 99 100 return 0; 101 } 102 arch_initcall(sbf_init); 103