⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apm.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* * Interface to Advanced Power Management 1.2 BIOS * * This is, in many ways, a giant hack, and when things settle down  * a bit and standardize, hopefully we can write a driver that deals * more directly with the hardware and thus might be a bit cleaner. *  * ACPI might be the answer, but at the moment this is simpler * and more widespread. */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"ureg.h"extern int apmfarcall(ushort, ulong, Ureg*);		/* apmjump.s */static intgetreg(ulong *reg, ISAConf *isa, char *name){	int i;	int nl;	nl = strlen(name);	for(i=0; i<isa->nopt; i++){		if(cistrncmp(isa->opt[i], name, nl)==0 && isa->opt[i][nl] == '='){			*reg = strtoul(isa->opt[i]+nl+1, nil, 16);			return 0;		}	}	return -1;}/* * Segment descriptors look like this. * * d1: [base 31:24] [gran] [is32bit] [0] [unused] [limit 19:16] 		[present] [privlev] [type 3:0] [base 23:16] * d0: [base 15:00] [limit 15:00] * * gran is 0 for 1-byte granularity, 1 for 4k granularity * type is 0 for system segment, 1 for code/data. * * clearly we know way too much about the memory unit. * however, knowing this much about the memory unit * means that the memory unit need not know anything * about us. * * what a crock. */static voidsetgdt(int sel, ulong base, ulong limit, int flag){	if(sel < 0 || sel >= NGDT)		panic("setgdt");	base = (ulong)KADDR(base);	m->gdt[sel].d0 = (base<<16) | (limit&0xFFFF);	m->gdt[sel].d1 = (base&0xFF000000) | (limit&0x000F0000) |			((base>>16)&0xFF) | SEGP | SEGPL(0) | flag;}static	ulong ax, cx, dx, di, ebx, esi;static Ureg apmu;static longapmread(Chan*, void *a, long n, vlong off){	if(off < 0)		error("badarg");	if(n+off > sizeof apmu)		n = sizeof apmu - off;	if(n <= 0)		return 0;	memmove(a, (char*)&apmu+off, n);	return n;}static longapmwrite(Chan*, void *a, long n, vlong off){	int s;	if(off || n != sizeof apmu)		error("write a Ureg");	memmove(&apmu, a, sizeof apmu);	s = splhi();	apmfarcall(APMCSEL, ebx, &apmu);	splx(s);	return n;}voidapmlink(void){	ISAConf isa;	char *s;	if(isaconfig("apm", 0, &isa) == 0)		return;/* XXX use realmode() */	/*	 * APM info passed from boot loader.	 * Now we need to set up the GDT entries for APM.	 *	 * AX = 32-bit code segment base address	 * EBX = 32-bit code segment offset	 * CX = 16-bit code segment base address	 * DX = 32-bit data segment base address	 * ESI = <16-bit code segment length> <32-bit code segment length> (hi then lo)	 * DI = 32-bit data segment length	 */	if(getreg(&ax, &isa, s="ax") < 0	|| getreg(&ebx, &isa, s="ebx") < 0	|| getreg(&cx, &isa, s="cx") < 0	|| getreg(&dx, &isa, s="dx") < 0	|| getreg(&esi, &isa, s="esi") < 0	|| getreg(&di, &isa, s="di") < 0){		print("apm: missing register %s\n", s);		return;	}	/*	 * The NEC Versa SX bios does not report the correct 16-bit code	 * segment length when loaded directly from mbr -> 9load (as compared	 * with going through ld.com).  We'll make both code segments 64k-1 bytes.	 */	esi = 0xFFFFFFFF;	/*	 * We are required by the BIOS to set up three consecutive segments,	 * one for the APM 32-bit code, one for the APM 16-bit code, and 	 * one for the APM data.  The BIOS handler uses the code segment it	 * get called with to determine the other two segment selector.	 */	setgdt(APMCSEG, ax<<4, ((esi&0xFFFF)-1)&0xFFFF, SEGEXEC|SEGR|SEGD);	setgdt(APMCSEG16, cx<<4, ((esi>>16)-1)&0xFFFF, SEGEXEC|SEGR);	setgdt(APMDSEG, dx<<4, (di-1)&0xFFFF, SEGDATA|SEGW|SEGD);	addarchfile("apm", 0660, apmread, apmwrite);print("apm0: configured cbase %.8lux off %.8lux\n", ax<<4, ebx);	return;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -