Goto sanos source index

//
// mach.c
//
// Interface to physical/virtual machine
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer.  
// 2. 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.  
// 3. Neither the name of the project 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 COPYRIGHT OWNER OR 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.
// 

#include <os/krnl.h>

int probe_vmi(); // from vmi.c
int init_vmi(); // from vmi.c

static void hw_sti() {
  __asm sti;
}

static void hw_cli() {
  __asm cli;
}

static void hw_hlt() {
  __asm hlt;
}

static void hw_iretd() {
  __asm add esp,4;
  __asm iretd;
}

static void hw_sysret() {
  __asm add esp,4;
  __asm sysexit;
}

static __declspec(naked) int __fastcall hw_in(port_t port) {
  __asm {
    mov     dx,cx
    xor     eax,eax
    in      al,dx
    ret
  }
}

static __declspec(naked) unsigned short __fastcall hw_inw(port_t port) {
  __asm {
    mov     dx,cx
    in      ax,dx
    ret
  }
}

static __declspec(naked) unsigned long __fastcall hw_ind(port_t port) {
  __asm {
    mov     dx,cx
    in      eax,dx
    ret
  }
}

static void hw_insw(port_t port, void *buf, int count) {
  __asm {
    mov edx, port
    mov edi, buf
    mov ecx, count
    rep insw
  }
}

static void hw_insd(port_t port, void *buf, int count) {
  __asm {
    mov edx, port
    mov edi, buf
    mov ecx, count
    rep insd
  }
}

static __declspec(naked) int __fastcall hw_out(port_t port, int val) {
  __asm {
    mov     al,dl
    mov     dx,cx
    out     dx, al
    ret
  }
}

static __declspec(naked) unsigned short __fastcall hw_outw(port_t port, unsigned short val) {
  __asm {
    mov     ax,dx
    mov     dx,cx
    out     dx, ax
    ret
  }
}

static __declspec(naked) unsigned long __fastcall hw_outd(port_t port, unsigned long val) {
  __asm {
    mov     eax,edx
    mov     dx,cx
    out     dx, eax
    ret
  }
}

static void hw_outsw(port_t port, void *buf, int count) {
  __asm {
    mov edx, port
    mov esi, buf
    mov ecx, count
    rep outsw
  }
}

static void hw_outsd(port_t port, void *buf, int count) {
  __asm {
    mov edx, port
    mov esi, buf
    mov ecx, count
    rep outsd
  }
}

static void hw_cpuid(unsigned long reg, unsigned long values[4]) {
  __asm {
    mov    eax, reg
    cpuid
    mov    esi, values
    mov    [esi], eax
    mov    [esi+4], ebx
    mov    [esi+8], ecx
    mov    [esi+12], edx
  }
}

static unsigned long hw_get_cr0() {
  unsigned long val;

  __asm  {
    mov eax, cr0
    mov val, eax
  }

  return val;
}

static void hw_set_cr0(unsigned long val) {
  __asm {
    mov eax, val
    mov cr0, eax
  }
}

static unsigned long hw_get_cr2() {
  unsigned long val;

  __asm  {
    mov eax, cr2
    mov val, eax
  }

  return val;
}

static __declspec(naked) unsigned __int64 hw_rdtsc() {
  __asm  { 
    rdtsc
    ret 
  }
}

static void hw_wrmsr(unsigned long reg, unsigned long valuelow, unsigned long valuehigh) {
  __asm {
    mov ecx, reg
    mov eax, valuelow
    mov edx, valuehigh
    wrmsr
  }
}

static void hw_set_gdt_entry(int entry, unsigned long addr, unsigned long size, int access, int granularity) {
  seginit(&syspage->gdt[entry], addr, size, access, granularity);
}

static void hw_set_idt_gate(int intrno, void *handler) {
  syspage->idt[intrno].offset_low = (unsigned short) (((unsigned long) handler) & 0xFFFF);
  syspage->idt[intrno].selector = SEL_KTEXT | mach.kring;
  syspage->idt[intrno].access = D_PRESENT | D_INT | D_DPL0;
  syspage->idt[intrno].offset_high = (unsigned short) (((unsigned long) handler) >> 16);
}

static void hw_set_idt_trap(int intrno, void *handler) {
  syspage->idt[intrno].offset_low = (unsigned short) (((unsigned long) handler) & 0xFFFF);
  syspage->idt[intrno].selector = SEL_KTEXT | mach.kring;
  syspage->idt[intrno].access = D_PRESENT | D_TRAP | D_DPL3;
  syspage->idt[intrno].offset_high = (unsigned short) (((unsigned long) handler) >> 16);
}

static void hw_switch_kernel_stack() {
}

static void hw_flushtlb() {
  __asm { mov eax, cr3 }
  __asm { mov cr3, eax }
}

static void hw_invlpage(void *addr) {
  if (cpu.family < CPU_FAMILY_486) {
    __asm { mov eax, cr3 }
    __asm { mov cr3, eax }
  } else   {
    __asm { mov eax, addr }
    __asm { invlpg [eax] }
  }
}

static void hw_register_page_dir(unsigned long pfn) {
  // Do nothing
}

static void hw_register_page_table(unsigned long pfn) {
  // Do nothing
}

static void hw_set_page_dir_entry(pte_t *pde, unsigned long value) {
  *pde = value;
}

static void hw_set_page_table_entry(pte_t *pte, unsigned long value) {
  *pte = value;
}

static void hw_poweroff() {
  if (apm_enabled) {
    apm_power_off();
  } else {
    kprintf("kernel: power management not enabled, system stopped...\n");
  }

  while (1) {
    __asm {
      cli
      hlt
    }
  }
}

static void hw_reboot() {
  kbd_reboot();
}

struct mach mach = {
  0, // kernel ring

  hw_sti,
  hw_cli,
  hw_hlt,
  hw_iretd,
  hw_sysret,
  hw_in,
  hw_inw,
  hw_ind,
  hw_insw,
  hw_insd,
  hw_out,
  hw_outw,
  hw_outd,
  hw_outsw,
  hw_outsd,
  hw_cpuid,
  hw_get_cr0,
  hw_set_cr0,
  hw_get_cr2,
  hw_rdtsc,
  hw_wrmsr,
  hw_set_gdt_entry,
  hw_set_idt_gate,
  hw_set_idt_trap,
  hw_switch_kernel_stack,
  hw_flushtlb,
  hw_invlpage,
  hw_register_page_dir,
  hw_register_page_table,
  hw_set_page_dir_entry,
  hw_set_page_table_entry,
  hw_poweroff,
  hw_reboot
};

#ifdef VMACH

void init_mach() {
  kprintf("mach: running in machine virtualization mode\n");
  if (probe_vmi()) init_vmi();
}

#else

void init_mach() {
}

#endif