xref: /linux/arch/x86/kernel/bootflag.c (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
29a163ed8SThomas Gleixner /*
39a163ed8SThomas Gleixner  *	Implement 'Simple Boot Flag Specification 2.0'
49a163ed8SThomas Gleixner  */
59a163ed8SThomas Gleixner #include <linux/types.h>
69a163ed8SThomas Gleixner #include <linux/kernel.h>
79a163ed8SThomas Gleixner #include <linux/init.h>
89a163ed8SThomas Gleixner #include <linux/string.h>
99a163ed8SThomas Gleixner #include <linux/spinlock.h>
109a163ed8SThomas Gleixner #include <linux/acpi.h>
119a163ed8SThomas Gleixner #include <asm/io.h>
129a163ed8SThomas Gleixner 
139a163ed8SThomas Gleixner #include <linux/mc146818rtc.h>
149a163ed8SThomas Gleixner 
159a163ed8SThomas Gleixner #define SBF_RESERVED (0x78)
169a163ed8SThomas Gleixner #define SBF_PNPOS    (1<<0)
179a163ed8SThomas Gleixner #define SBF_BOOTING  (1<<1)
189a163ed8SThomas Gleixner #define SBF_DIAG     (1<<2)
199a163ed8SThomas Gleixner #define SBF_PARITY   (1<<7)
209a163ed8SThomas Gleixner 
219a163ed8SThomas Gleixner int sbf_port __initdata = -1;	/* set via acpi_boot_init() */
229a163ed8SThomas Gleixner 
parity(u8 v)239a163ed8SThomas Gleixner static int __init parity(u8 v)
249a163ed8SThomas Gleixner {
259a163ed8SThomas Gleixner 	int x = 0;
269a163ed8SThomas Gleixner 	int i;
279a163ed8SThomas Gleixner 
288eed9260SCyrill Gorcunov 	for (i = 0; i < 8; i++) {
299a163ed8SThomas Gleixner 		x ^= (v & 1);
309a163ed8SThomas Gleixner 		v >>= 1;
319a163ed8SThomas Gleixner 	}
328eed9260SCyrill Gorcunov 
339a163ed8SThomas Gleixner 	return x;
349a163ed8SThomas Gleixner }
359a163ed8SThomas Gleixner 
sbf_write(u8 v)369a163ed8SThomas Gleixner static void __init sbf_write(u8 v)
379a163ed8SThomas Gleixner {
389a163ed8SThomas Gleixner 	unsigned long flags;
398eed9260SCyrill Gorcunov 
408eed9260SCyrill Gorcunov 	if (sbf_port != -1) {
419a163ed8SThomas Gleixner 		v &= ~SBF_PARITY;
429a163ed8SThomas Gleixner 		if (!parity(v))
439a163ed8SThomas Gleixner 			v |= SBF_PARITY;
449a163ed8SThomas Gleixner 
458eed9260SCyrill Gorcunov 		printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n",
468eed9260SCyrill Gorcunov 			sbf_port, v);
479a163ed8SThomas Gleixner 
489a163ed8SThomas Gleixner 		spin_lock_irqsave(&rtc_lock, flags);
499a163ed8SThomas Gleixner 		CMOS_WRITE(v, sbf_port);
509a163ed8SThomas Gleixner 		spin_unlock_irqrestore(&rtc_lock, flags);
519a163ed8SThomas Gleixner 	}
529a163ed8SThomas Gleixner }
539a163ed8SThomas Gleixner 
sbf_read(void)549a163ed8SThomas Gleixner static u8 __init sbf_read(void)
559a163ed8SThomas Gleixner {
569a163ed8SThomas Gleixner 	unsigned long flags;
578eed9260SCyrill Gorcunov 	u8 v;
588eed9260SCyrill Gorcunov 
599a163ed8SThomas Gleixner 	if (sbf_port == -1)
609a163ed8SThomas Gleixner 		return 0;
618eed9260SCyrill Gorcunov 
629a163ed8SThomas Gleixner 	spin_lock_irqsave(&rtc_lock, flags);
639a163ed8SThomas Gleixner 	v = CMOS_READ(sbf_port);
649a163ed8SThomas Gleixner 	spin_unlock_irqrestore(&rtc_lock, flags);
658eed9260SCyrill Gorcunov 
669a163ed8SThomas Gleixner 	return v;
679a163ed8SThomas Gleixner }
689a163ed8SThomas Gleixner 
sbf_value_valid(u8 v)699a163ed8SThomas Gleixner static int __init sbf_value_valid(u8 v)
709a163ed8SThomas Gleixner {
719a163ed8SThomas Gleixner 	if (v & SBF_RESERVED)		/* Reserved bits */
729a163ed8SThomas Gleixner 		return 0;
739a163ed8SThomas Gleixner 	if (!parity(v))
749a163ed8SThomas Gleixner 		return 0;
758eed9260SCyrill Gorcunov 
769a163ed8SThomas Gleixner 	return 1;
779a163ed8SThomas Gleixner }
789a163ed8SThomas Gleixner 
sbf_init(void)799a163ed8SThomas Gleixner static int __init sbf_init(void)
809a163ed8SThomas Gleixner {
819a163ed8SThomas Gleixner 	u8 v;
828eed9260SCyrill Gorcunov 
839a163ed8SThomas Gleixner 	if (sbf_port == -1)
849a163ed8SThomas Gleixner 		return 0;
858eed9260SCyrill Gorcunov 
869a163ed8SThomas Gleixner 	v = sbf_read();
878eed9260SCyrill Gorcunov 	if (!sbf_value_valid(v)) {
888eed9260SCyrill Gorcunov 		printk(KERN_WARNING "Simple Boot Flag value 0x%x read from "
898eed9260SCyrill Gorcunov 			"CMOS RAM was invalid\n", v);
908eed9260SCyrill Gorcunov 	}
919a163ed8SThomas Gleixner 
929a163ed8SThomas Gleixner 	v &= ~SBF_RESERVED;
939a163ed8SThomas Gleixner 	v &= ~SBF_BOOTING;
949a163ed8SThomas Gleixner 	v &= ~SBF_DIAG;
959a163ed8SThomas Gleixner #if defined(CONFIG_ISAPNP)
969a163ed8SThomas Gleixner 	v |= SBF_PNPOS;
979a163ed8SThomas Gleixner #endif
989a163ed8SThomas Gleixner 	sbf_write(v);
998eed9260SCyrill Gorcunov 
1009a163ed8SThomas Gleixner 	return 0;
1019a163ed8SThomas Gleixner }
1021206f535SPaul Gortmaker arch_initcall(sbf_init);
103