/****************************************************************************** * Arch-specific dom0_ops.c * * Process command requests from domain-0 guest OS. * * Copyright (c) 2002, K A Fraser */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mtrr/mtrr.h" #define TRC_DOM0OP_ENTER_BASE 0x00020000 #define TRC_DOM0OP_LEAVE_BASE 0x00030000 extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int); static int msr_cpu_mask; static unsigned long msr_addr; static unsigned long msr_lo; static unsigned long msr_hi; static void write_msr_for(void *unused) { if (((1 << current->processor) & msr_cpu_mask)) (void)wrmsr_user(msr_addr, msr_lo, msr_hi); } static void read_msr_for(void *unused) { if (((1 << current->processor) & msr_cpu_mask)) (void)rdmsr_user(msr_addr, msr_lo, msr_hi); } long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) { long ret = 0; if ( !IS_PRIV(current->domain) ) return -EPERM; switch ( op->cmd ) { case DOM0_MSR: { if ( op->u.msr.write ) { msr_cpu_mask = op->u.msr.cpu_mask; msr_addr = op->u.msr.msr; msr_lo = op->u.msr.in1; msr_hi = op->u.msr.in2; smp_call_function(write_msr_for, NULL, 1, 1); write_msr_for(NULL); } else { msr_cpu_mask = op->u.msr.cpu_mask; msr_addr = op->u.msr.msr; smp_call_function(read_msr_for, NULL, 1, 1); read_msr_for(NULL); op->u.msr.out1 = msr_lo; op->u.msr.out2 = msr_hi; copy_to_user(u_dom0_op, op, sizeof(*op)); } ret = 0; } break; case DOM0_SHADOW_CONTROL: { struct domain *d; ret = -ESRCH; d = find_domain_by_id(op->u.shadow_control.domain); if ( d != NULL ) { ret = shadow_mode_control(d, &op->u.shadow_control); put_domain(d); copy_to_user(u_dom0_op, op, sizeof(*op)); } } break; case DOM0_ADD_MEMTYPE: { ret = mtrr_add_page( op->u.add_memtype.pfn, op->u.add_memtype.nr_pfns, op->u.add_memtype.type, 1); } break; case DOM0_DEL_MEMTYPE: { ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0); } break; case DOM0_READ_MEMTYPE: { unsigned long pfn; unsigned int nr_pfns; mtrr_type type; ret = -EINVAL; if ( op->u.read_memtype.reg < num_var_ranges ) { mtrr_if->get(op->u.read_memtype.reg, &pfn, &nr_pfns, &type); (void)__put_user(pfn, &u_dom0_op->u.read_memtype.pfn); (void)__put_user(nr_pfns, &u_dom0_op->u.read_memtype.nr_pfns); (void)__put_user(type, &u_dom0_op->u.read_memtype.type); ret = 0; } } break; case DOM0_MICROCODE: { extern int microcode_update(void *buf, unsigned long len); ret = microcode_update(op->u.microcode.data, op->u.microcode.length); } break; case DOM0_IOPL: { ret = -EINVAL; if ( op->u.iopl.domain == DOMID_SELF ) { current->arch.iopl = op->u.iopl.iopl & 3; ret = 0; } } break; case DOM0_PHYSINFO: { dom0_physinfo_t *pi = &op->u.physinfo; pi->ht_per_core = opt_noht ? 1 : ht_per_core; pi->cores = smp_num_cpus / pi->ht_per_core; pi->total_pages = max_page; pi->free_pages = avail_domheap_pages(); pi->cpu_khz = cpu_khz; copy_to_user(u_dom0_op, op, sizeof(*op)); ret = 0; } break; case DOM0_GETPAGEFRAMEINFO: { struct pfn_info *page; unsigned long pfn = op->u.getpageframeinfo.pfn; domid_t dom = op->u.getpageframeinfo.domain; struct domain *d; ret = -EINVAL; if ( unlikely(pfn >= max_page) || unlikely((d = find_domain_by_id(dom)) == NULL) ) break; page = &frame_table[pfn]; if ( likely(get_page(page, d)) ) { ret = 0; op->u.getpageframeinfo.type = NOTAB; if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) { switch ( page->u.inuse.type_info & PGT_type_mask ) { case PGT_l1_page_table: op->u.getpageframeinfo.type = L1TAB; break; case PGT_l2_page_table: op->u.getpageframeinfo.type = L2TAB; break; case PGT_l3_page_table: op->u.getpageframeinfo.type = L3TAB; break; case PGT_l4_page_table: op->u.getpageframeinfo.type = L4TAB; break; } } put_page(page); } put_domain(d); copy_to_user(u_dom0_op, op, sizeof(*op)); } break; case DOM0_GETPAGEFRAMEINFO2: { #define GPF2_BATCH 128 int n,j; int num = op->u.getpageframeinfo2.num; domid_t dom = op->u.getpageframeinfo2.domain; unsigned long *s_ptr = (unsigned long*) op->u.getpageframeinfo2.array; struct domain *d; unsigned long *l_arr; ret = -ESRCH; if ( unlikely((d = find_domain_by_id(dom)) == NULL) ) break; if ( unlikely(num > 1024) ) { ret = -E2BIG; break; } l_arr = (unsigned long *)alloc_xenheap_page(); ret = 0; for( n = 0; n < num; ) { int k = ((num-n)>GPF2_BATCH)?GPF2_BATCH:(num-n); if ( copy_from_user(l_arr, &s_ptr[n], k*sizeof(unsigned long)) ) { ret = -EINVAL; break; } for( j = 0; j < k; j++ ) { struct pfn_info *page; unsigned long mfn = l_arr[j]; if ( unlikely(mfn >= max_page) ) goto e2_err; page = &frame_table[mfn]; if ( likely(get_page(page, d)) ) { unsigned long type = 0; switch( page->u.inuse.type_info & PGT_type_mask ) { case PGT_l1_page_table: type = L1TAB; break; case PGT_l2_page_table: type = L2TAB; break; case PGT_l3_page_table: type = L3TAB; break; case PGT_l4_page_table: type = L4TAB; break; } if ( page->u.inuse.type_info & PGT_pinned ) type |= LPINTAB; l_arr[j] |= type; put_page(page); } else { e2_err: l_arr[j] |= XTAB; } } if ( copy_to_user(&s_ptr[n], l_arr, k*sizeof(unsigned long)) ) { ret = -EINVAL; break; } n += j; } free_xenheap_page((unsigned long)l_arr); put_domain(d); } break; case DOM0_GETMEMLIST: { int i; struct domain *d = find_domain_by_id(op->u.getmemlist.domain); unsigned long max_pfns = op->u.getmemlist.max_pfns; unsigned long pfn; unsigned long *buffer = op->u.getmemlist.buffer; struct list_head *list_ent; ret = -EINVAL; if ( d != NULL ) { ret = 0; spin_lock(&d->page_alloc_lock); list_ent = d->page_list.next; for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ ) { pfn = list_entry(list_ent, struct pfn_info, list) - frame_table; if ( put_user(pfn, buffer) ) { ret = -EFAULT; break; } buffer++; list_ent = frame_table[pfn].list.next; } spin_unlock(&d->page_alloc_lock); op->u.getm
/*
    ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <ch.h>

#include "board.h"
#include "at91lib/aic.h"

#include <sam7x_serial.h>

/*
 * FIQ Handler, unused in this demo.
 */
__attribute__((interrupt("FIQ")))
static void FiqHandler(void) {
}

static CH_IRQ_HANDLER(SpuriousHandler) {

  CH_IRQ_PROLOGUE();

  AT91C_BASE_AIC->AIC_EOICR = 0;

  CH_IRQ_EPILOGUE();
}

/*
 * SYS IRQ handling here.
 */
static CH_IRQ_HANDLER(SYSIrqHandler) {

  CH_IRQ_PROLOGUE();

  if (AT91C_BASE_PITC->PITC_PISR & AT91C_PITC_PITS) {
    (void) AT91C_BASE_PITC->PITC_PIVR;
    chSysLockFromIsr();
    chSysTimerHandlerI();
    chSysUnlockFromIsr();
  }
  AT91C_BASE_AIC->AIC_EOICR = 0;

  CH_IRQ_EPILOGUE();
}

/*
 * Early initialization code.
 * This initialization is performed just after reset before BSS and DATA
 * segments initialization.
 */
void hwinit0(void) {
  /*
   * Flash Memory: 1 wait state, about 50 cycles in a microsecond.
   */
  AT91C_BASE_MC->MC_FMR = (AT91C_MC_FMCN & (50 << 16)) | AT91C_MC_FWS_1FWS;

  /*
   * Watchdog disabled.
   */
  AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;

  /*
   * Enables the main oscillator and waits 56 slow cycles as startup time.
   */
  AT91C_BASE_PMC->PMC_MOR = (AT91C_CKGR_OSCOUNT & (7 << 8)) | AT91C_CKGR_MOSCEN;
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS))
    ;

  /*
   * PLL setup: DIV = 14, MUL = 72, PLLCOUNT = 10
   * PLLfreq = 96109714 Hz (rounded)
   */
  AT91C_BASE_PMC->PMC_PLLR = (AT91C_CKGR_DIV & 14) |
                             (AT91C_CKGR_PLLCOUNT & (10 << 8)) |
                             (AT91C_CKGR_MUL & (72 << 16));
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK))
    ;

  /*
   * Master clock = PLLfreq / 2 = 48054858 Hz (rounded)
   */
  AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | AT91C_PMC_PRES_CLK_2;
  while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY))
    ;

  /*
   * I/O setup, enable clocks, initially all pins are inputs with pullups.
   */
  AT91C_BASE_PMC->PMC_PCER   = (1 << AT91C_ID_PIOA) | (1 << AT91C_ID_PIOB);
  AT91C_BASE_PIOA->PIO_PER   = 0xFFFFFFFF;
  AT91C_BASE_PIOB->PIO_PER   = 0xFFFFFFFF;
}

/*
 * Late initialization code.
 * This initialization is performed after BSS and DATA segments initialization
 * and before invoking the main() function.
 */
void hwinit1(void) {
  int i;

  /*
   * Default AIC setup, the device drivers will modify it as needed.
   */
  AT91C_BASE_AIC->AIC_ICCR = 0xFFFFFFFF;
  AT91C_BASE_AIC->AIC_SVR[0] = (AT91_REG)FiqHandler;
  for (i = 1; i < 31; i++) {
    AT91C_BASE_AIC->AIC_SVR[i] = (AT91_REG)NULL;
    AT91C_BASE_AIC->AIC_EOICR = (AT91_REG)i;
  }
  AT91C_BASE_AIC->AIC_SPU  = (AT91_REG)SpuriousHandler;

  /*
   * LCD pins setup.
   */
  AT91C_BASE_PIOB->PIO_CODR   = PIOB_LCD_BL;    // Set to low.
  AT91C_BASE_PIOB->PIO_OER    = PIOB_LCD_BL;    // Configure as output.
  AT91C_BASE_PIOB->PIO_PPUDR  = PIOB_LCD_BL;    // Disable internal pullup resistor.

  AT91C_BASE_PIOA->PIO_SODR   = PIOA_LCD_RESET; // Set to high.
  AT91C_BASE_PIOA->PIO_OER    = PIOA_LCD_RESET; // Configure as output.
  AT91C_BASE_PIOA->PIO_PPUDR  = PIOA_LCD_RESET; // Disable internal pullup resistor.

  /*
   * Joystick and buttons, disable pullups, already inputs.
   */
  AT91C_BASE_PIOA->PIO_PPUDR = PIOA_B1 | PIOA_B2 | PIOA_B3 | PIOA_B4 | PIOA_B5;
  AT91C_BASE_PIOB->PIO_PPUDR = PIOB_SW1 | PIOB_SW2;

  /*
   * MMC/SD slot, disable pullups, already inputs.
   */
  AT91C_BASE_SYS->PIOB_PPUDR = PIOB_MMC_WP | PIOB_MMC_CP;

  /*
   * PIT Initialization.
   */
  AIC_ConfigureIT(AT91C_ID_SYS,
                  AT91C_AIC_SRCTYPE_HIGH_LEVEL | (AT91C_AIC_PRIOR_HIGHEST - 1),
                  SYSIrqHandler);
  AIC_EnableIT(AT91C_ID_SYS);
  AT91C_BASE_PITC->PITC_PIMR = (MCK / 16 / CH_FREQUENCY) - 1;
  AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN | AT91C_PITC_PITIEN;

  /*
   * Serial driver initialization, RTS/CTS pins enabled for USART0 only.
   */
  serial_init(AT91C_AIC_PRIOR_HIGHEST - 2, AT91C_AIC_PRIOR_HIGHEST - 2);
  AT91C_BASE_PIOA->PIO_PDR   = AT91C_PA3_RTS0 | AT91C_PA4_CTS0;
  AT91C_BASE_PIOA->PIO_ASR   = AT91C_PIO_PA3 | AT91C_PIO_PA4;
  AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PIO_PA3 | AT91C_PIO_PA4;

  /*
   * ChibiOS/RT initialization.
   */
  chSysInit();
}