The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/apm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Interface to Advanced Power Management 1.2 BIOS
    3  *
    4  * This is, in many ways, a giant hack, and when things settle down 
    5  * a bit and standardize, hopefully we can write a driver that deals
    6  * more directly with the hardware and thus might be a bit cleaner.
    7  * 
    8  * ACPI might be the answer, but at the moment this is simpler
    9  * and more widespread.
   10  */
   11 
   12 #include        "u.h"
   13 #include        "../port/lib.h"
   14 #include        "mem.h"
   15 #include        "dat.h"
   16 #include        "fns.h"
   17 #include        "io.h"
   18 #include        "ureg.h"
   19 
   20 extern int apmfarcall(ushort, ulong, Ureg*);            /* apmjump.s */
   21 
   22 static int
   23 getreg(ulong *reg, ISAConf *isa, char *name)
   24 {
   25         int i;
   26         int nl;
   27 
   28         nl = strlen(name);
   29         for(i=0; i<isa->nopt; i++){
   30                 if(cistrncmp(isa->opt[i], name, nl)==0 && isa->opt[i][nl] == '='){
   31                         *reg = strtoul(isa->opt[i]+nl+1, nil, 16);
   32                         return 0;
   33                 }
   34         }
   35         return -1;
   36 }
   37 
   38 /*
   39  * Segment descriptors look like this.
   40  *
   41  * d1: [base 31:24] [gran] [is32bit] [0] [unused] [limit 19:16] 
   42                 [present] [privlev] [type 3:0] [base 23:16]
   43  * d0: [base 15:00] [limit 15:00]
   44  *
   45  * gran is 0 for 1-byte granularity, 1 for 4k granularity
   46  * type is 0 for system segment, 1 for code/data.
   47  *
   48  * clearly we know way too much about the memory unit.
   49  * however, knowing this much about the memory unit
   50  * means that the memory unit need not know anything
   51  * about us.
   52  *
   53  * what a crock.
   54  */
   55 static void
   56 setgdt(int sel, ulong base, ulong limit, int flag)
   57 {
   58         if(sel < 0 || sel >= NGDT)
   59                 panic("setgdt");
   60 
   61         base = (ulong)KADDR(base);
   62         m->gdt[sel].d0 = (base<<16) | (limit&0xFFFF);
   63         m->gdt[sel].d1 = (base&0xFF000000) | (limit&0x000F0000) |
   64                         ((base>>16)&0xFF) | SEGP | SEGPL(0) | flag;
   65 }
   66 
   67 static  ulong ax, cx, dx, di, ebx, esi;
   68 static Ureg apmu;
   69 static long
   70 apmread(Chan*, void *a, long n, vlong off)
   71 {
   72         if(off < 0)
   73                 error("badarg");
   74 
   75         if(n+off > sizeof apmu)
   76                 n = sizeof apmu - off;
   77         if(n <= 0)
   78                 return 0;
   79         memmove(a, (char*)&apmu+off, n);
   80         return n;
   81 }
   82 
   83 static long
   84 apmwrite(Chan*, void *a, long n, vlong off)
   85 {
   86         int s;
   87         if(off || n != sizeof apmu)
   88                 error("write a Ureg");
   89 
   90         memmove(&apmu, a, sizeof apmu);
   91         s = splhi();
   92         apmfarcall(APMCSEL, ebx, &apmu);
   93         splx(s);
   94         return n;
   95 }
   96 
   97 void
   98 apmlink(void)
   99 {
  100         ISAConf isa;
  101         char *s;
  102 
  103         if(isaconfig("apm", 0, &isa) == 0)
  104                 return;
  105 
  106 /* XXX use realmode() */
  107 
  108         /*
  109          * APM info passed from boot loader.
  110          * Now we need to set up the GDT entries for APM.
  111          *
  112          * AX = 32-bit code segment base address
  113          * EBX = 32-bit code segment offset
  114          * CX = 16-bit code segment base address
  115          * DX = 32-bit data segment base address
  116          * ESI = <16-bit code segment length> <32-bit code segment length> (hi then lo)
  117          * DI = 32-bit data segment length
  118          */
  119 
  120         if(getreg(&ax, &isa, s="ax") < 0
  121         || getreg(&ebx, &isa, s="ebx") < 0
  122         || getreg(&cx, &isa, s="cx") < 0
  123         || getreg(&dx, &isa, s="dx") < 0
  124         || getreg(&esi, &isa, s="esi") < 0
  125         || getreg(&di, &isa, s="di") < 0){
  126                 print("apm: missing register %s\n", s);
  127                 return;
  128         }
  129 
  130         /*
  131          * The NEC Versa SX bios does not report the correct 16-bit code
  132          * segment length when loaded directly from mbr -> 9load (as compared
  133          * with going through ld.com).  We'll make both code segments 64k-1 bytes.
  134          */
  135         esi = 0xFFFFFFFF;
  136 
  137         /*
  138          * We are required by the BIOS to set up three consecutive segments,
  139          * one for the APM 32-bit code, one for the APM 16-bit code, and 
  140          * one for the APM data.  The BIOS handler uses the code segment it
  141          * get called with to determine the other two segment selector.
  142          */
  143         setgdt(APMCSEG, ax<<4, ((esi&0xFFFF)-1)&0xFFFF, SEGEXEC|SEGR|SEGD);
  144         setgdt(APMCSEG16, cx<<4, ((esi>>16)-1)&0xFFFF, SEGEXEC|SEGR);
  145         setgdt(APMDSEG, dx<<4, (di-1)&0xFFFF, SEGDATA|SEGW|SEGD);
  146 
  147         addarchfile("apm", 0660, apmread, apmwrite);
  148 
  149 print("apm0: configured cbase %.8lux off %.8lux\n", ax<<4, ebx);
  150 
  151         return;
  152 }
  153 

Cache object: b2d3003c718adf8db71be2b8af4667af


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.