bootflag.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 254 行
C
254 行
/* * Implement 'Simple Boot Flag Specification 1.0' * */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <asm/io.h>#include <linux/mc146818rtc.h>#define SBF_RESERVED (0x78)#define SBF_PNPOS (1<<0)#define SBF_BOOTING (1<<1)#define SBF_DIAG (1<<2)#define SBF_PARITY (1<<7)struct sbf_boot{ u8 sbf_signature[4]; u32 sbf_len; u8 sbf_revision __attribute((packed)); u8 sbf_csum __attribute((packed)); u8 sbf_oemid[6] __attribute((packed)); u8 sbf_oemtable[8] __attribute((packed)); u8 sbf_revdata[4] __attribute((packed)); u8 sbf_creator[4] __attribute((packed)); u8 sbf_crearev[4] __attribute((packed)); u8 sbf_cmos __attribute((packed)); u8 sbf_spare[3] __attribute((packed));};static int sbf_port __initdata = -1;static int __init sbf_struct_valid(unsigned long tptr){ u8 *ap; u8 v; unsigned int i; struct sbf_boot sb; memcpy_fromio(&sb, tptr, sizeof(sb)); if(sb.sbf_len != 40 && sb.sbf_len != 39) // 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19). return 0; ap = (u8 *)&sb; v= 0; for(i=0;i<sb.sbf_len;i++) v+=*ap++; if(v) return 0; if(memcmp(sb.sbf_signature, "BOOT", 4)) return 0; if (sb.sbf_len == 39) printk (KERN_WARNING "SBF: ACPI BOOT descriptor is wrong length (%d)\n", sb.sbf_len); sbf_port = sb.sbf_cmos; /* Save CMOS port */ return 1;}static int __init parity(u8 v){ int x = 0; int i; for(i=0;i<8;i++) { x^=(v&1); v>>=1; } return x;}static void __init sbf_write(u8 v){ unsigned long flags; if(sbf_port != -1) { v &= ~SBF_PARITY; if(!parity(v)) v|=SBF_PARITY; printk(KERN_INFO "SBF: Setting boot flags 0x%x\n",v); spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(v, sbf_port); spin_unlock_irqrestore(&rtc_lock, flags); }}static u8 __init sbf_read(void){ u8 v; unsigned long flags; if(sbf_port == -1) return 0; spin_lock_irqsave(&rtc_lock, flags); v = CMOS_READ(sbf_port); spin_unlock_irqrestore(&rtc_lock, flags); return v;}static int __init sbf_value_valid(u8 v){ if(v&SBF_RESERVED) /* Reserved bits */ return 0; if(!parity(v)) return 0; return 1;}static void __init sbf_bootup(void){ u8 v; if(sbf_port == -1) return; v = sbf_read(); if(!sbf_value_valid(v)) printk(KERN_WARNING "SBF: Simple boot flag value 0x%x read from CMOS RAM was invalid\n",v); v &= ~SBF_RESERVED; v &= ~SBF_BOOTING; v &= ~SBF_DIAG;#if defined(CONFIG_ISAPNP) v |= SBF_PNPOS;#endif sbf_write(v);}static int __init sbf_init(void){ unsigned int i; void *rsdt; u32 rsdtlen = 0; u32 rsdtbase = 0; u8 sum = 0; int n; u8 *p; for(i=0xE0000; i <= 0xFFFE0; i+=16) { p = phys_to_virt(i); if(memcmp(p, "RSD PTR ", 8)) continue; sum = 0; for(n=0; n<20; n++) sum+=p[n]; if(sum != 0) continue; /* So it says RSD PTR and it checksums... */ /* * Process the RDSP pointer */ rsdtbase = *(u32 *)(p+16); /* * RSDT length is ACPI 2 only, for ACPI 1 we must map * and remap. */ if(p[15]>1) rsdtlen = *(u32 *)(p+20); else rsdtlen = 36; if(rsdtlen < 36 || rsdtlen > 1024) continue; break; } if(i>0xFFFE0) return 0; rsdt = ioremap(rsdtbase, rsdtlen); if(rsdt == 0) return 0; i = readl(rsdt + 4); /* * Remap if needed */ if(i > rsdtlen) { rsdtlen = i; iounmap(rsdt); rsdt = ioremap(rsdtbase, rsdtlen); if(rsdt == 0) return 0; } for(n = 0; n < i; n++) sum += readb(rsdt + n); if(sum) { iounmap(rsdt); return 0; } /* Ok the RSDT checksums too */ for(n = 36; n+3 < i; n += 4) { unsigned long rp = readl(rsdt+n); int len = 4096; if(rp > 0xFFFFFFFFUL - len) len = 0xFFFFFFFFUL - rp; /* Too close to the end!! */ if(len < 20) continue; rp = (unsigned long)ioremap(rp, 4096); if(rp == 0) continue; if(sbf_struct_valid(rp)) { /* Found the BOOT table and processed it */ printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n"); } iounmap((void *)rp); } iounmap(rsdt); sbf_bootup(); return 0;}module_init(sbf_init);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?