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