This is the archived Fall 2013 version of the course.
For the most recent version, see http://rust-class.org/class-16-applefanning.html.

Class 16: AppleFanning

Action Items

Problem Set 3 is due Monday, 28 October. (As students noted in class today, England qualified for the world cup during the PS3 assignment, so the class holiday extends the deadline for PS3 to Tuesday, 29 October at 11:59pm.)

Everyone should have received an email with their midterm results (and other recorded grades so far). If you didn't get it, send me email (evans@cs.virginia.edu). If you already sent me email but didn't get a response yet, please let me know after class today.

Project

4 Nov: Project Proposals (more details posted soon)

18 Nov: Project Design Reviews

5 Dec: Project Demos

Do something that is fun (for you to do, and others to see), relevant (to the class), technically interesting (to you and me), and useful (at least to you, hopefully to many). You probably can’t maximize all of these! It is okay to sacrifice one or two of them to increase others. A good project should be strong on at least 2 of these, which is much better than being mediocre of all four.

Examples

The examples are provided to hopefully give you some ideas for the kinds of things that might be possible, but you should not view them as guidelines or suggestions. Also, note that you have a lot more time (almost six weeks compared to 2-3) and background than these students, so should be able to do something much better.

Conveying Complexity Highlights from CS3102 including:



A Downfall Parody: P = NP [Video]
by Arthur Gordon, Allison Gurlitz, Stephen Lam, Eugene Moy
Note: Definitely worth clicking the YouTube link to see the comments.


Mario – Determinism vs. Nondeterminism [video]
by Navid Hosseini, John Koelling, Trung Tran, and Ben Powell

Winners of Udacity CS101 Contest including In-Video Word Search and DaveDaveFind (Documentation).

AppleFandumb?

From http://opensource.apple.com/source/AppleFan/AppleFan-110.3.1/AppleFan.cpp:

AppleFan.cpp   [plain text]
 /*
  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * The contents of this file constitute Original Code as defined in and
  * are subject to the Apple Public Source License Version 1.1 (the
  * "License").  You may not use this file except in compliance with the
  * License.  Please obtain a copy of the License at
  * http://www.apple.com/publicsource and read it before using this file.
  * 
  * This Original Code and all software distributed under the License are
  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  * License for the specific language governing rights and limitations
  * under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 /*
  * Copyright (c) 2002 Apple Computer, Inc.  All rights reserved.
  *
  */

#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/IOMessage.h>
#include <mach/clock_types.h>
#include "AppleFan.h"

 /*
  * Default Parameters
  *
  * First look for defaults in the personality, otherwise we fall back to these
  * hard coded ones.
  *
  * Speed Table: Linear Ramp, Minimum 57C, Maximum 62C
  *
  * Note: These temperatures are expressed in 8.8 fixed point values.
  */
static fan_speed_table_t gDefaultSpeedTable =
  { 0x3900, 0x3A4A, 0x3Ad3, 0x3B3C,
    0x3B94, 0x3BE3, 0x3C29, 0x3C6A,
    0x3CA6, 0x3CD7, 0x3D15, 0x3D48,
    0x3D78, 0x3DA7, 0x3DD4, 0x3E00 };

 /*
  * Hysteresis Temperature 55 C
  */
 static SInt16 gDefaultHysteresisTemp = 0x3700;

... // ~200 lines removed - see link for full code

/*************************************************************************************
doUpdate() is where we read the CPU temp and look it up in the speed table to
choose a fan speed.  Also here is the timer callback routine which repeatedly
calls doUpdate().
*************************************************************************************/

 void AppleFan::doUpdate(bool first)
 {
   AbsoluteTime interval;
   UInt8 newSpeed;
   SInt16 cpu_temp;

   DLOG("+AppleFan::doUpdate\n");

   // Get temperature data
   if (!getCPUTemp(&cpu_temp))
     {
       IOLog("AppleFan::doUpdate ERROR FETCHING CPU TEMP!!!\n");
       restoreADM1030State(&fSavedRegs);
       terminate();
       return;
     }

   // look up the fan speed
   newSpeed = 0;
   while ((cpu_temp >= fSpeedTable[newSpeed]) && (newSpeed < (kNumFanSpeeds - 1)))
     newSpeed++;

   // set fan speed cfg register
   setFanSpeed(newSpeed, cpu_temp, first);

   // implement a periodic timer
   if (first) clock_get_uptime(&fWakeTime);

   nanoseconds_to_absolutetime(fPollingPeriod, &interval);
   ADD_ABSOLUTETIME(&fWakeTime, &interval);

   thread_call_enter_delayed( timerCallout, fWakeTime );

   DLOG("-AppleFan::doUpdate\n");
 }

 /*************************************************************************************
Routines which take a fan speed as input and program the ADM1030 to run at the
desired speed.  Some nasty tricks are in this code, but it is pretty well
encapsulated and explained in comments...

The routines are setFanSpeed and setADM1030SpeedMagically (lots of comments in
the latter for obvious reasons...)
 *************************************************************************************/
 void AppleFan::setFanSpeed(UInt8 speed, SInt16 cpu_temp, bool first)
 {
   UInt8 desiredSpeed;
   SInt16 rmt_temp;
   AbsoluteTime ticksPassed;
   UInt64 nsecPassed;

   if (!getRemoteTemp(&rmt_temp))
     {
       IOLog("AppleFan::setFanSpeed FATAL ERROR FETCHING REMOTE CHANNEL TEMP!!!\n");
       restoreADM1030State(&fSavedRegs);
       terminate();
       return;
     }

   if (first)
     {
       // If this is the first run, don't apply any of the hysteresis mechanisms,
       // just program the chip with the speed that was produced from the table
       // lookup
       DLOG("@AppleFan::setFanSpeed initial speed is %u\n", speed);
       setADM1030SpeedMagically(speed, rmt_temp);
       clock_get_uptime(&fLastTransition);
     }
   else
     {
       if (speed == fLastFanSpeed)
     {
       if (rmt_temp != fLastRmtTemp)
         {
           // need to update the remote temp limit register
           DLOG("@AppleFan::setFanSpeed environmental update\n");
           setADM1030SpeedMagically(speed, rmt_temp);
           return;
         }

       DLOG("@AppleFan::setFanSpeed no update needed\n");
     }
       else 
     {
       // calculate nanoseconds since last speed change
       clock_get_uptime(&ticksPassed);
       SUB_ABSOLUTETIME(&ticksPassed, &fLastTransition);
       absolutetime_to_nanoseconds(ticksPassed, &nsecPassed);

       if (speed < fLastFanSpeed)
         {
           // Hysteresis mechanism - don't turn off the fan unless we've reached
           // the hysteresis temp
           if (speed == kDutyCycleOff && fLastFanSpeed == kDutyCycle07)
         {
           DLOG("@AppleFan::setFanSpeed hysteresis check cpu_temp 0x%04x fHysteresisTemp %04x\n",
            cpu_temp, fHysteresisTemp);

           if (cpu_temp > fHysteresisTemp)
             {
               DLOG("@AppleFan::setFanSpeed hysteresis active\n");

               // do an environmental update if needed
               if (rmt_temp != fLastRmtTemp)
             setADM1030SpeedMagicall}
         }
           else if (speed > fLastFanSpeed)
         {
           DLOG("@AppleFan::setFanSpeed upward check nsecPassed 0x%llX fSpeedupDelay 0x%llX\n",
            nsecPassed, fSpeedupDelay);

           // apply upward hysteresis

           if (nsecPassed > fSpeedupDelay)
             {
               desiredSpeed = fLastFanSpeed + 1;
               DLOG("@AppleFan::setFanSpeed speedup to %u\n", desiredSpeed);
               setADM1030SpeedMagically(desiredSpeed, rmt_temp);
               clock_get_uptime(&fLastTransition);
             }
           else
             {
               DLOG("@AppleFan::setFanSpeed speedup delay active\n");

               // do an environmental update if needed
               if (rmt_temp != fLastRmtTemp)
             setADM1030SpeedMagically(fLastFanSpeed, rmt_temp);
             }
         }
           else { /* not reached */ }
         }
     }
     }


   void AppleFan::setADM1030SpeedMagically(UInt8 desiredSpeed, SInt16 rmt_temp)
   {
     UInt8 TminTrange, speed;

     // shift rmt_temp(14:10) into TminTrange(7:3)
     TminTrange = (UInt8)(rmt_temp >> 7);
     TminTrange &= ~kTrangeMask;// clear out the 3 LSBs
     TminTrange |= 0x7;// T_range = highest possible

     /*
      * setFanSpeed() calculates a speed between 0x0 and 0xF and passes it
      * into this routine (in the variable named "speed").  setFanSpeed
      * is responsible for setting the remote T_min/T_range and the speed
      * config register to make the PWM match the requested speed.
      *
      * If we want the PWM to be completely inactive, we have to set
      * Tmin ABOVE the current remote temp.  We set the speed config
      * register to zero in this case.
      *
      * For other PWM values, we program Tmin to a value just below the
      * current remote temp.  This will instruct the ADM1030 to operate
      * the PWM at a speed just above whatever speed is programmed into
      * the speed config register (which, in automatic control mode,
      * sets the minimum speed at which the fan runs when the current
      * remote temp exceeds Tmin).  Then, we program the speed config
      * register with speed - 1 ; that is, one less than the value that
      * was passed in by doUpdate().  It may seem less than intuitive
      * to program the speed config register with 0 when we want speed
      * 1, just remember that the difference is made by Tmin -- is the
      * fan operating below the linear range (PWM completely inactive),
      * or just inside the linear range (PWM active)?
      */

     // The first "if" clause handles two cases:
     //
     // 1.  The fan is already set below the linear range.  This is
     //     when speed=0 and fLastFanSpeed=0.  We program Tmin 8 degrees
     //     above rmt_temp, and preserve the speed config reg at 0.
     //
     // 2.  The fan is currently in the linear range, but we are about
     //     to shift below the linear range and shut off PWM entirely.
     //     This is denoted by speed=0 and fLastFanSpeed=1.
     if (desiredSpeed == 0)
       {
     // Transition from 1 to 0 takes fan out of linear range
     TminTrange += 0x10;// raise Tmin above current rmt_temp
     speed = desiredSpeed;
     fLastFanSpeed = desiredSpeed;
       }
     // Put the hw control loop into the linear range
     else
       {
     TminTrange -= 0x08;
     speed = desiredSpeed - 1;
     fLastFanSpeed = desiredSpeed;
       }

     // Recored the rmt_temp at the time of this update
     fLastRmtTemp = rmt_temp;

#ifdef APPLEFAN_DEBUG
     char debug[16];
     temp2str(rmt_temp, debug);
#endif

     DLOG("@AppleFan::setADM1030SpeedMagically speed=%u rmt_temp=%x (%sC) TminTrange=%x\n",
      speed, rmt_temp, debug, TminTrange);

     if (!doI2COpen())
       {
     IOLog("AppleFan failed to open bus for setting fan speed\n");
     return;
       }

     if (!doI2CWrite(kRmtTminTrange, &TminTrange, 1))
       {
     doI2CClose();
     IOLog("AppleFan failed to write to T_min/T_range register!\n");
     return;
       }

     if (!doI2CWrite(kSpeedCfgReg, &speed, 1))
       {
     doI2CClose();
     IOLog("AppleFan failed to write to fan speed register\n");
     return;
       }

     doI2CClose();
   }

Is the mapping between sensed temperature and fan level really linear? What code should replace the while loop to set the fan speed?

Security

Why is it hard for a web server to control access using pathnames?

How does changing the effective uid to serve a web request follow the principle of least priviledge?

Hao Chen, David Wagner, and Drew Dean. Setuid Demystified (USENIX Security 2002).