/* tab:4 * * * "Copyright (c) 2000-2002 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose, without fee, and without written * agreement is hereby granted, provided that the above copyright * notice, the following two paragraphs and the author appear in all * copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, * UPDATES, ENHANCEMENTS, OR MODIFICATIONS." * */ /* tab:4 * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * By downloading, copying, installing or using the software you * agree to this license. If you do not agree to this license, do * not download, install, copy or use the software. * * Intel Open Source License * * Copyright (c) 2002 Intel Corporation * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * */ /* * Authors: Philip Levis * Neil Patel * History: Apr 11, 2003 Inception. * */ includes AM; includes Bombilla; module BombillaEngine { provides { interface StdControl; interface BombillaError; command result_t computeInstruction(BombillaContext* context); command result_t executeContext(BombillaContext* context); command result_t alertSendContext(BombillaContext* caller, BombillaStackVariable* var); command result_t alertReceiveContext(TOS_MsgPtr msg); } uses { interface StdControl as SubControlTimer; interface StdControl as SubControlNetwork; interface StdControl as SubControl; interface Timer as ClockTimer; interface Leds; interface Random; interface SendMsg as SendError; interface ReceiveMsg as ReceivePacket; interface BombillaStacks as Stacks; interface BombillaBuffer as Buffer; interface BombillaLocks as Locks; interface BombillaContextSynch as Synch; interface BombillaInstruction as Instruction; interface BombillaQueue as Queue; interface BombillaVirus as Virus; interface BombillaAnalysis as Analysis; interface BombillaBytecode as Bytecode[uint8_t bytecode] ; } } implementation { BombillaContext clockContext; BombillaContext sendContext; BombillaContext recvContext; //BombillaContext onceContext; BombillaState state; command result_t StdControl.init() { uint16_t i; dbg(DBG_BOOT, "VM: Bombilla initializing.\n"); call Leds.init(); call Random.init(); call SubControlTimer.init(); call SubControlNetwork.init(); call SubControl.init(); state.inErrorState = FALSE; clockContext.rootCapsule = &state.capsules[BOMB_CAPSULE_CLOCK_INDEX]; clockContext.state = BOMB_STATE_HALT; sendContext.rootCapsule = &state.capsules[BOMB_CAPSULE_SEND_INDEX]; sendContext.state = BOMB_STATE_HALT; recvContext.rootCapsule = &state.capsules[BOMB_CAPSULE_RECV_INDEX]; recvContext.state = BOMB_STATE_HALT; /* onceContext.rootCapsule = &state.capsules[BOMB_CAPSULE_ONCE_INDEX]; onceContext.state = BOMB_STATE_HALT; */ call Queue.init(&state.readyQueue); for (i = 0; i < BOMB_BUF_NUM; i++) { state.buffers[i].type = BOMB_DATA_NONE; state.buffers[i].size = 0; } clockContext.which = BOMB_CAPSULE_CLOCK; sendContext.which = BOMB_CAPSULE_SEND; recvContext.which = BOMB_CAPSULE_RECV; /* onceContext.which = BOMB_CAPSULE_ONCE; */ for (i = 0; i < BOMB_HEAPSIZE; i++) { state.heap[(int)i].type = BOMB_TYPE_VALUE; state.heap[(int)i].value.var = 0; } state.capsules[BOMB_CAPSULE_SUB0].capsule.type = BOMB_CAPSULE_SUB0; state.capsules[BOMB_CAPSULE_SUB1].capsule.type = BOMB_CAPSULE_SUB1; state.capsules[BOMB_CAPSULE_SUB2].capsule.type = BOMB_CAPSULE_SUB2; state.capsules[BOMB_CAPSULE_SUB3].capsule.type = BOMB_CAPSULE_SUB3; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.type = BOMB_CAPSULE_CLOCK; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.type = BOMB_CAPSULE_RECV; state.capsules[BOMB_CAPSULE_SEND_INDEX].capsule.type = BOMB_CAPSULE_SEND; state.capsules[BOMB_CAPSULE_ONCE_INDEX].capsule.type = BOMB_CAPSULE_ONCE; for (i = 0; i < BOMB_CAPSULE_NUM; i++) { state.capsules[i].capsule.type |= BOMB_OPTION_FORWARD; if (TOS_LOCAL_ADDRESS == 25 && i == BOMB_CAPSULE_CLOCK_INDEX) { state.capsules[i].capsule.version = 1; state.capsules[i].capsule.type |= BOMB_OPTION_FORWARD; } else { state.capsules[i].capsule.version = 0; } call Virus.registerCapsule(state.capsules[i].capsule.type, &(state.capsules[i].capsule)); } { int pc = 0; /* state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPpushc|1; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPsense; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPgetvar|1; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPadd; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPcopy; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPcopy; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPpushc|7; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPland; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPputled; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPsetvar|1; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPpushc|2; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbpush0; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPadd; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPadd; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbsize; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbpush0; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbtail; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbpush0; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbclear; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPhalt; */ state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPpushc | 1; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPgetvar | 0; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPadd; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPcopy; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPcopy; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPsetvar | 0; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPpushc | 7; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPland; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPputled; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbpush0; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPbclear; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPadd; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPsendr; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.code[pc++] = OPhalt; state.capsules[BOMB_CAPSULE_CLOCK_INDEX].capsule.version = 0; pc = 0; state.capsules[BOMB_CAPSULE_SEND_INDEX].capsule.code[pc++] = OPpushc; state.capsules[BOMB_CAPSULE_SEND_INDEX].capsule.code[pc++] = OPlnot; state.capsules[BOMB_CAPSULE_SEND_INDEX].capsule.code[pc++] = OPsendr; state.capsules[BOMB_CAPSULE_SEND_INDEX].capsule.code[pc++] = OPhalt; state.capsules[BOMB_CAPSULE_SEND_INDEX].capsule.options = 0; state.capsules[BOMB_CAPSULE_SEND_INDEX].capsule.version = 0; pc = 0; //state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.code[pc++] = OPpushc; //state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.code[pc++] = OPbyank; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.code[pc++] = OPbhead; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.code[pc++] = OPpushc | 7; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.code[pc++] = OPland; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.code[pc++] = OPputled; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.code[pc++] = OPhalt; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.options = 0; state.capsules[BOMB_CAPSULE_RECV_INDEX].capsule.version = 0; } call Analysis.analyzeCapsuleVars(&state, BOMB_CAPSULE_CLOCK_INDEX); call Analysis.analyzeCapsuleVars(&state, BOMB_CAPSULE_SEND_INDEX); call Analysis.analyzeCapsuleVars(&state, BOMB_CAPSULE_RECV_INDEX); return SUCCESS; } task void ClockTask() { call computeInstruction(&clockContext); if (clockContext.state == BOMB_STATE_RUN) { dbg(DBG_USR1, "VM: Posting ClockTask in task.\n"); post ClockTask(); } } task void SendTask() { call computeInstruction(&sendContext); if (sendContext.state == BOMB_STATE_RUN) { dbg(DBG_USR1, "VM: Posting SendTask in task.\n"); post SendTask(); } } task void RecvTask() { call computeInstruction(&recvContext); if (recvContext.state == BOMB_STATE_RUN) { post RecvTask(); } } /* task void OnceTask() { call computeInstruction(&onceContext); if (onceContext.state == BOMB_STATE_RUN) { post OnceTask(); } } */ command result_t executeContext(BombillaContext* context) { dbg(DBG_USR1, "VM: At beginning of execCon.\n"); if (context->state != BOMB_STATE_RUN) {return FAIL;} switch(context->which) { case BOMB_CAPSULE_CLOCK: dbg(DBG_USR1, "VM: Posting ClockTask in execCon.\n"); return post ClockTask(); dbg(DBG_USR1, "VM: Posted ClockTask.\n"); //return SUCCESS; dbg(DBG_USR1, "VM: after return.\n"); break; dbg(DBG_USR1, "VM: after break.\n"); case BOMB_CAPSULE_SEND: dbg(DBG_USR1, "VM: Posting SendTask in execCon.\n"); post SendTask(); return SUCCESS; break; case BOMB_CAPSULE_RECV: post RecvTask(); return SUCCESS; break; /* case BOMB_CAPSULE_ONCE: return post OnceTask(); case BOMB_CAPSULE_OUTER: */ default: dbg(DBG_ERROR, "VM: Tried to run context not yet supported: %i\n", context->which); return FAIL; } dbg(DBG_USR1, "VM: At end of execCon.\n"); return FAIL; } command result_t alertSendContext(BombillaContext* caller, BombillaStackVariable* arg) { if (sendContext.state == BOMB_STATE_HALT) { nmemcpy(&state.sendrBuffer, arg->buffer.var, sizeof(BombillaDataBuffer)); call Synch.initializeContext(&sendContext, &state); call Stacks.pushBuffer(&sendContext, &state.sendrBuffer); dbg(DBG_USR1, "VM: Calling resumeCon for sendContext in alertSend. \n"); call Synch.resumeContext(caller, &sendContext, &(state.readyQueue), state.locks); // This yield/resume allows locks to be yielded to the send context, // and if none are shared, then it will just continue executing if (caller->releaseSet) { call Synch.releaseLocks(caller, caller, state.locks); call Synch.yieldContext(caller, &(state.readyQueue), state.locks); //call Synch.resumeContext(caller, caller, &(state.readyQueue), state.locks); } } else { // Don't send, fail silently -- send context busy } return SUCCESS; } command result_t alertReceiveContext(TOS_MsgPtr msg) { if (!msg->crc) {return FAIL;} if (recvContext.state != BOMB_STATE_HALT) { dbg(DBG_USR1, "VM: Received packet, receive context busy, drop.\n"); } else { int i; BombillaPacket* packet = (BombillaPacket*)(msg->data); BombillaDataBuffer* buffer = (BombillaDataBuffer*)&(packet->payload); dbg(DBG_USR1, "VM: Received packet, enqueuing receive context to run.\n"); dbg(DBG_USR1, "VM: Copying %i bytes of header over:\n ", sizeof(recvContext.header)); for (i = 0; i < sizeof(recvContext.header); i++) { dbg_clear(DBG_USR1, "%02hhx", packet->header[i]); } dbg_clear(DBG_USR1, "\n->"); nmemcpy(&(recvContext.header), packet->header, sizeof(recvContext.header)); for (i = 0; i < sizeof(recvContext.header); i++) { dbg_clear(DBG_USR1, "%02hhx", ((uint8_t*)recvContext.header)[i]); } dbg_clear(DBG_USR1, "\n"); nmemcpy(&(state.recvBuffer), buffer, sizeof(BombillaDataBuffer)); call Synch.initializeContext(&recvContext, &state); call Stacks.pushBuffer(&recvContext, &state.recvBuffer); dbg(DBG_USR1, "VM: Calling resumeCon for recvCon in alertRec.\n"); call Synch.resumeContext(&recvContext, &recvContext, &(state.readyQueue), state.locks); } return SUCCESS; } command result_t StdControl.start() { result_t res1, res2; dbg(DBG_BOOT, "VM: Starting.\n"); res1 = call SubControlTimer.start(); res2 = call SubControlNetwork.start(); res2 = call SubControl.start(); call ClockTimer.start(TIMER_REPEAT, 1024); return rcombine(res1, res2); } command result_t StdControl.stop() { result_t res1, res2; dbg(DBG_BOOT, "VM: Stopping.\n"); call ClockTimer.stop(); res1 = call SubControlTimer.stop(); res2 = call SubControlNetwork.stop(); res2 = call SubControl.stop(); return rcombine(res1, res2); } command result_t BombillaError.error(BombillaContext* context, uint8_t cause) { state.inErrorState = TRUE; dbg(DBG_ERROR|DBG_USR1, "VM: Entering ERROR state. Context: %i, cause %i\n", (int)context->which, (int)cause); call Leds.redOn(); call Leds.greenOn(); call Leds.yellowOn(); state.errorContext = context; if (context != NULL) { state.errorContext = context; state.errorMsg.context = context->which; state.errorMsg.reason = cause; state.errorMsg.capsule = context->capsule->capsule.type; state.errorMsg.instruction = context->pc - 1; context->state = BOMB_STATE_HALT; } else { state.errorMsg.context = BOMB_CAPSULE_INVALID; state.errorMsg.reason = cause; state.errorMsg.capsule = BOMB_CAPSULE_INVALID; state.errorMsg.instruction = 255; } return SUCCESS; } task void ClockErrorTask() { dbg(DBG_USR1|DBG_ERROR, "VM: ERROR\n"); call Leds.redToggle(); call Leds.greenToggle(); call Leds.yellowToggle(); nmemcpy(state.errorContext->msg.data, &state.errorMsg, sizeof(BombillaErrorMsg)); if (state.errorFlipFlop) { call SendError.send(TOS_UART_ADDR, sizeof(BombillaErrorMsg), (TOS_MsgPtr)&(state.errorContext->msg)); } else { call SendError.send(TOS_BCAST_ADDR, sizeof(BombillaErrorMsg), (TOS_MsgPtr)&(state.errorContext->msg)); } state.errorFlipFlop = !state.errorFlipFlop; } task void ClockEventTask() { if (clockContext.state == BOMB_STATE_HALT) { call Synch.initializeContext(&clockContext, &state); clockContext.state = BOMB_STATE_RUN; //initializeContext(&clockContext); dbg(DBG_USR1, "VM: Calling ResumeCon for clockCon in ClockEventTask.\n"); call Synch.resumeContext(&clockContext, &clockContext, &(state.readyQueue), state.locks); //resumeContext(&clockContext, &clockContext); } else { dbg(DBG_TEMP, "VM: Clock context not halted.\n"); // Can log a clock miss error here, but probably // not a good idea } } event result_t ClockTimer.fired() { dbg(DBG_USR1, "VM: clock timer fired, posting ClockEventTask.\n"); if (state.inErrorState) {post ClockErrorTask();} else {post ClockEventTask();} return SUCCESS; } event result_t SendError.sendDone(TOS_MsgPtr msg, result_t success) { return SUCCESS; } event TOS_MsgPtr ReceivePacket.receive(TOS_MsgPtr msg) { return msg; } command result_t computeInstruction(BombillaContext* context) { uint8_t instr = context->capsule->capsule.code[(int)context->pc]; // dbg(DBG_USR1, "VM (%hhi): Issuing instruction 0x%hhx.\n", context->which, instr); if (context->state != BOMB_STATE_RUN) { dbg(DBG_ERROR, "VM: (%hhi) Tried to execute instruction in non-run state: %hhi\n", context->which, context->state); return FAIL; } context->pc++; call Bytecode.execute[instr](instr, context, &state); return SUCCESS; } default command result_t Bytecode.execute[uint8_t opcode](uint8_t instr, BombillaContext* context, BombillaState* vmState) { dbg(DBG_ERROR|DBG_USR1, "VM: Executing default instruction: halt!\n"); context->state = BOMB_STATE_HALT; return FAIL; } event result_t Virus.capsuleInstalled(BombillaCapsule* capsule) { //capsuleAnalysis(capsule->type & BOMB_OPTION_MASK); return SUCCESS; } event result_t Virus.enableExecution() { return SUCCESS; } event result_t Virus.disableExecution() { return SUCCESS; } event result_t Virus.capsuleHeard(uint8_t type) { return SUCCESS; } event void Virus.capsuleForce(uint8_t type) { return; } event result_t Synch.makeRunnable(BombillaContext* context) { dbg(DBG_USR1, "VM: make runnable event occured for %i.\n", (int)context->which); context->state = BOMB_STATE_RUN; dbg(DBG_USR1, "VM: calling execCon.\n"); return call executeContext(context); } }