summaryrefslogtreecommitdiff
path: root/i386/dos/i16/i16_vcpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'i386/dos/i16/i16_vcpi.c')
-rw-r--r--i386/dos/i16/i16_vcpi.c564
1 files changed, 0 insertions, 564 deletions
diff --git a/i386/dos/i16/i16_vcpi.c b/i386/dos/i16/i16_vcpi.c
deleted file mode 100644
index e021d6b..0000000
--- a/i386/dos/i16/i16_vcpi.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright (c) 1995-1994 The University of Utah and
- * the Computer Systems Laboratory at the University of Utah (CSL).
- * All rights reserved.
- *
- * Permission to use, copy, modify and distribute this software is hereby
- * granted provided that (1) source code retains these copyright, permission,
- * and disclaimer notices, and (2) redistributions including binaries
- * reproduce the notices in supporting documentation, and (3) all advertising
- * materials mentioning features or use of this software display the following
- * acknowledgement: ``This product includes software developed by the
- * Computer Systems Laboratory at the University of Utah.''
- *
- * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
- * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
- * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * CSL requests users of this software to return to csl-dist@cs.utah.edu any
- * improvements that they make and grant CSL redistribution rights.
- *
- * Author: Bryan Ford, University of Utah CSL
- */
-
-#include <mach/boolean.h>
-#include <mach/vm_param.h>
-#include <mach/machine/code16.h>
-#include <mach/machine/vm_types.h>
-#include <mach/machine/paging.h>
-#include <mach/machine/eflags.h>
-#include <mach/machine/proc_reg.h>
-#include <mach/machine/far_ptr.h>
-#include <mach/machine/vcpi.h>
-#include <mach/machine/asm.h>
-
-#include "config.h"
-#include "i16.h"
-#include "i16_dos.h"
-#include "cpu.h"
-#include "real.h"
-#include "debug.h"
-#include "vm_param.h"
-
-#ifdef ENABLE_VCPI
-
-static boolean_t ems_page_allocated;
-static unsigned short ems_handle;
-
-static vm_offset_t vcpi_pdir, vcpi_ptable0;
-
-struct far_pointer_32 vcpi_pmode_entry = {0, VCPI_CS};
-struct vcpi_switch_data vcpi_switch_data;
-
-static struct pseudo_descriptor gdt_pdesc, idt_pdesc;
-
-static boolean_t pic_reprogrammed;
-
-/* Save area for the DOS interrupt vectors
- that used to be in the place we relocated the master PIC to. */
-static struct far_pointer_16 master_save_vecs[8];
-
-
-#ifdef ENABLE_PAGING
-#define VCPI_PAGING_INIT(pdir_pa, first_unmapped_pa) vcpi_paging_init(pdir_pa, first_unmapped_pa)
-#else
-#define VCPI_PAGING_INIT(pdir_pa, first_unmapped_pa) ((void)0)
-#endif
-
-#ifdef ENABLE_KERNEL_LDT
-#define KERNEL_LDT_INIT() (vcpi_switch_data.ldt_sel = KERNEL_LDT)
-#else
-#define KERNEL_LDT_INIT() ((void)0)
-#endif
-
-
-CODE16
-
-static void i16_vcpi_switch_to_pmode()
-{
- extern vm_offset_t boot_image_pa;
-
- i16_cli();
-
- i16_assert(i16_get_ds() == i16_get_cs());
- i16_assert(i16_get_es() == i16_get_cs());
- i16_assert(i16_get_ss() == i16_get_cs());
-
- /* Make sure the TSS isn't marked busy. */
- cpu[0].tables.gdt[KERNEL_TSS_IDX].access &= ~ACC_TSS_BUSY;
-
- /* Ask the VCPI server to switch to protected mode. */
- asm volatile("
- movl %%esp,%%edx
- int $0x67
- "SEXT(pmode_return)":
- movl %%edx,%%esp
- movw %2,%%dx
- movw %%dx,%%ss
- movw %%dx,%%ds
- movw %%dx,%%es
- xorw %%dx,%%dx
- movw %%dx,%%fs
- movw %%dx,%%gs
- " :
- : "a" ((unsigned short)0xde0c),
- "S" (boot_image_pa + (vm_offset_t)&vcpi_switch_data),
- "i" (KERNEL_DS)
- : "eax", "edx", "esi");
-
- /* Make sure the direction flag is still clear. */
- i16_cld();
-}
-
-static void i16_vcpi_switch_to_real_mode()
-{
- i16_cli();
-
- /* As requested by VCPI spec... */
- i16_clts();
-
- /* Perform the switch. */
- asm volatile("
- movl %%esp,%%edx
- pushl %1
- pushl %1
- pushl %1
- pushl %1
- pushl %1
- pushl %%edx
- pushl $0
- pushl %1
- pushl $1f
- movw %2,%%ds
- lcall %%ss:"SEXT(vcpi_pmode_entry)"
- 1:
- " :
- : "a" ((unsigned short)0xde0c),
- "r" ((unsigned)real_cs),
- "r" ((unsigned short)LINEAR_DS)
- : "eax", "edx");
-
- i16_assert(!(i16_get_eflags() & EFL_IF));
- i16_assert(i16_get_ds() == i16_get_cs());
- i16_assert(i16_get_es() == i16_get_cs());
- i16_assert(i16_get_ss() == i16_get_cs());
-
- /* Make sure the direction flag is still clear. */
- i16_cld();
-}
-
-CODE32
-
-static void vcpi_real_int(int intnum, struct real_call_data *rcd)
-{
- do_16bit(
- unsigned int eflags;
-
- i16_vcpi_switch_to_real_mode();
- i16_real_int(intnum, rcd);
- i16_vcpi_switch_to_pmode();
- );
-}
-
-static void vcpi_exit(int rc)
-{
- do_16bit(
- i16_vcpi_switch_to_real_mode();
- i16_exit(rc);
- while (1);
- );
-}
-
-CODE16
-
-static inline void
-i16_vcpi_set_int_vecs(unsigned short master, unsigned short slave)
-{
- unsigned short rc;
-
- i16_assert(!(get_eflags() & EFL_IF));
- asm volatile("int $0x67"
- : "=a" (rc)
- : "a" ((unsigned short)0xde0b),
- "b" ((unsigned short)master),
- "c" ((unsigned short)slave));
- i16_assert((rc & 0xff00) == 0);
- i16_assert(!(get_eflags() & EFL_IF));
-}
-
-/* Find a (hopefully) empty set of interrupt vectors
- to use for the master hardware interrupts.
- We assume that eight interrupt vectors in a row
- that all have the same value are unused.
- If VCPI servers weren't so brain-damaged
- and took care of this during interrupt reflection
- (like we do when running in raw mode),
- this kludgery wouldn't be needed... */
-static int i16_find_free_vec_range()
-{
- /* i will track the first vector in a range;
- j will track the last. */
- int i, j;
- struct far_pointer_16 iv, jv;
-
- j = 0xff;
- i16_dos_get_int_vec(j, &jv);
-
- for (i = j-1; ; i--)
- {
- if (i == 0x50)
- {
- /* No completely free sets found.
- Stop here and just use 0x50-0x57. */
- break;
- }
-
- i16_dos_get_int_vec(i, &iv);
- if ((iv.ofs != jv.ofs) || (iv.seg != jv.seg))
- {
- /* Vector contents changed. */
- j = i;
- jv = iv;
- continue;
- }
-
- if ((j-i+1 >= 8) && ((i & 7) == 0))
- {
- /* Found a free range. */
- break;
- }
- }
-
- return i;
-}
-
-void i16_vcpi_check()
-{
- extern vm_offset_t dos_mem_phys_free_mem;
- extern vm_offset_t dos_mem_phys_free_size;
- extern void pmode_return();
- extern vm_offset_t boot_image_pa;
- extern void (*i16_switch_to_real_mode)();
- extern void (*i16_switch_to_pmode)();
-
- unsigned short rc;
- unsigned short first_free_pte;
- unsigned short vcpi_ver;
-
- i16_assert(boot_image_pa == kvtophys(0));
-
- /* Check for presence of EMM driver. */
- {
- int dev_info, out_status;
- int fh;
-
- fh = i16_dos_open("EMMXXXX0", 0);
- if (fh < 0)
- return;
- dev_info = i16_dos_get_device_info(fh);
- out_status = i16_dos_get_output_status(fh);
- i16_dos_close(fh);
- if ((dev_info < 0) || !(dev_info & 0x80)
- || (out_status != 0xff))
- return;
- }
-
- /* Allocate an EMS page to force the EMM to be turned on.
- If it fails, keep going anyway -
- it may simply mean all the EMS pages are allocated. */
- asm volatile("int $0x67"
- : "=a" (rc),
- "=d" (ems_handle)
- : "a" ((unsigned short)0x4300),
- "b" ((unsigned short)1));
- if (!(rc & 0xff00))
- ems_page_allocated = TRUE;
-
- /* Check for VCPI. */
- asm volatile("int $0x67" : "=a" (rc), "=b" (vcpi_ver) : "a" ((unsigned short)0xde00));
- if (rc & 0xff00)
- return;
- i16_assert(vcpi_ver >= 0x0100);
-
- /* OK, it's there - we're now committed to using VCPI. */
- i16_switch_to_real_mode = i16_vcpi_switch_to_real_mode;
- i16_switch_to_pmode = i16_vcpi_switch_to_pmode;
- real_int = vcpi_real_int;
- real_exit = vcpi_exit;
-
- do_debug(i16_puts("VCPI detected"));
-
- /* Allocate a page directory and page table from low DOS memory. */
- {
- vm_offset_t new_dos_mem;
-
- new_dos_mem = ((dos_mem_phys_free_mem + PAGE_MASK) & ~PAGE_MASK)
- + PAGE_SIZE*2;
- if ((!dos_mem_phys_free_mem)
- || (new_dos_mem - dos_mem_phys_free_mem
- > dos_mem_phys_free_size))
- i16_die("not enough low DOS memory available");
- dos_mem_phys_free_size -= new_dos_mem - dos_mem_phys_free_mem;
- dos_mem_phys_free_mem = new_dos_mem;
- vcpi_pdir = new_dos_mem - PAGE_SIZE*2;
- vcpi_ptable0 = vcpi_pdir + PAGE_SIZE;
- }
-
- /* Initialize them. */
- {
- int i;
- pt_entry_t pde0 = vcpi_ptable0
- | INTEL_PTE_VALID | INTEL_PTE_WRITE | INTEL_PTE_USER;
-
- set_fs(vcpi_pdir >> 4);
- asm volatile("movl %0,%%fs:(0)" : : "r" (pde0));
- for (i = 1; i < NPDES + NPTES; i++)
- asm volatile("movl $0,%%fs:(,%0,4)" : : "r" (i));
- }
-
- /* Initialize the protected-mode interface. */
- asm volatile("
- pushw %%es
- movw %4,%%es
- int $0x67
- popw %%es
- "
- : "=a" (rc),
- "=b" (vcpi_pmode_entry.ofs),
- "=D" (first_free_pte)
- : "a" ((unsigned short)0xde01),
- "r" ((unsigned short)(vcpi_ptable0 >> 4)),
- "D" (0),
- "S" (&cpu[0].tables.gdt[VCPI_CS_IDX]));
- i16_assert((rc & 0xff00) == 0);
- i16_assert(get_ds() == get_cs());
- i16_assert(get_es() == get_cs());
-
-#ifdef DEBUG
- /* Sanity check: make sure the server did what it was supposed to do. */
-
- i16_assert((cpu[0].tables.gdt[VCPI_CS_IDX].access & ACC_P|ACC_CODE) == ACC_P|ACC_CODE);
- if (cpu[0].tables.gdt[VCPI_CS_IDX].granularity & SZ_G)
- i16_assert(vcpi_pmode_entry.ofs <
- (((vm_offset_t)cpu[0].tables.gdt[VCPI_CS_IDX].limit_high << 28)
- | ((vm_offset_t)cpu[0].tables.gdt[VCPI_CS_IDX].limit_low << 12)
- | (vm_offset_t)0xfff));
- else
- i16_assert(vcpi_pmode_entry.ofs <
- (((vm_offset_t)cpu[0].tables.gdt[VCPI_CS_IDX].limit_high << 16)
- | (vm_offset_t)cpu[0].tables.gdt[VCPI_CS_IDX].limit_low));
-
- i16_assert(first_free_pte/sizeof(pt_entry_t) >= 1*1024*1024/PAGE_SIZE);
- i16_assert(first_free_pte/sizeof(pt_entry_t) <= 4*1024*1024/PAGE_SIZE);
-
- {
- int i;
-
- for (i = 0; i < 1*1024*1024/PAGE_SIZE; i++)
- {
- pt_entry_t entry;
-
- set_ds(vcpi_ptable0 >> 4);
- entry = ((pt_entry_t*)0)[i];
- set_ds(get_cs());
- i16_assert(entry & INTEL_PTE_VALID);
- if (i < 0xf0000/PAGE_SIZE)
- i16_assert(entry & INTEL_PTE_WRITE);
- i16_assert(entry & INTEL_PTE_USER);
- i16_assert(!(entry & INTEL_PTE_AVAIL));
- }
- }
-#endif /* DEBUG */
-
- /* Find the VCPI server's hardware interrupt vector mappings. */
- asm volatile("int $0x67"
- : "=a" (rc),
- "=b" (irq_master_base),
- "=c" (irq_slave_base)
- : "a" ((unsigned short)0xde0a));
- i16_assert((rc & 0xff00) == 0);
- irq_master_base &= 0xffff;
- irq_slave_base &= 0xffff;
- i16_assert((irq_master_base & 7) == 0);
- i16_assert((irq_master_base == 0x08) || (irq_master_base >= 0x20));
- i16_assert((irq_slave_base & 7) == 0);
- i16_assert(irq_slave_base >= 0x20);
-
- /* If they're the usual DOS values, change them. */
- if (irq_master_base == 0x08)
- {
- pic_reprogrammed = TRUE;
-
- i16_cli();
-
- irq_master_base = i16_find_free_vec_range();
-
- /* Save the old vectors in that range
- and set them to a copy of vectors 8-15. */
- {
- int i;
-
- for (i = 0; i < 8; i++)
- {
- struct far_pointer_16 hw_vec;
-
- i16_dos_get_int_vec(irq_master_base+i,
- &master_save_vecs[i]);
- i16_dos_get_int_vec(0x08+i, &hw_vec);
- i16_dos_set_int_vec(irq_master_base+i, &hw_vec);
- }
- }
-
- /* Reprogram the PIC. */
- i16_pic_set_master(irq_master_base);
-
- /* Inform the VCPI server. */
- i16_vcpi_set_int_vecs(irq_master_base, irq_slave_base);
- }
-
- /* Initialize the switch-to-pmode data structure. */
- vcpi_switch_data.phys_pdir = vcpi_pdir;
- vcpi_switch_data.lin_gdt = boot_image_pa+(vm_offset_t)&gdt_pdesc.limit;
- vcpi_switch_data.lin_idt = boot_image_pa+(vm_offset_t)&idt_pdesc.limit;
- vcpi_switch_data.tss_sel = KERNEL_TSS;
- vcpi_switch_data.entry_eip = (unsigned short)(vm_offset_t)&pmode_return;
- vcpi_switch_data.entry_cs = KERNEL_16_CS;
-
- /* Initialize the GDT and IDT pseudo-descriptors. */
- gdt_pdesc.limit = sizeof(cpu[0].tables.gdt)-1;
- gdt_pdesc.linear_base = boot_image_pa + (vm_offset_t)&cpu[0].tables.gdt;
- idt_pdesc.limit = sizeof(cpu[0].tables.idt)-1;
- idt_pdesc.linear_base = boot_image_pa + (vm_offset_t)&cpu[0].tables.idt;
-
- /* Set the GDT to temporary settings
- just for getting into pmode the first time. */
- i16_gdt_init_temp();
-
- /* VCPI insists on loading a TSS immediately on entering pmode,
- so initialize the KERNEL_TSS descriptor in the GDT. */
- i16_fill_gdt_descriptor(&cpu[0], KERNEL_TSS,
- boot_image_pa + (vm_offset_t)&cpu[0].tables.tss,
- sizeof(cpu[0].tables.tss)-1,
- ACC_PL_K|ACC_TSS, 0);
- cpu[0].tables.tss.io_bit_map_offset = sizeof(cpu[0].tables.tss);
-
-#if 0
- /* Dump the various VCPI data structures, for debugging. */
- {
- int i;
-
- i16_puts("Switch data");
- i16_writehexl(switch_data.phys_pdir); i16_putchar(' ');
- i16_writehexl(switch_data.lin_gdt); i16_putchar(' ');
- i16_writehexl(switch_data.lin_idt); i16_putchar(' ');
- i16_writehexw(switch_data.ldt_sel); i16_putchar(' ');
- i16_writehexw(switch_data.tss_sel); i16_putchar(' ');
- i16_writehexl(switch_data.entry_eip); i16_putchar(' ');
- i16_writehexw(switch_data.entry_cs); i16_puts("");
-
- i16_puts("GDT pdesc");
- i16_writehexw(gdt_pdesc.limit); i16_putchar(' ');
- i16_writehexl(gdt_pdesc.linear_base); i16_puts("");
-
- i16_puts("IDT pdesc");
- i16_writehexw(idt_pdesc.limit); i16_putchar(' ');
- i16_writehexl(idt_pdesc.linear_base); i16_puts("");
-
- i16_puts("GDT");
- for (i = 0; i < GDTSZ; i++)
- {
- i16_writehexw(i*8); i16_putchar(' ');
- i16_writehexll(*((long long*)&cpu[0].tables.gdt[i]));
- i16_puts("");
- }
- }
-#endif
-
- /* Switch into pmode briefly to initialize the CPU tables and such. */
- i16_vcpi_switch_to_pmode();
- i16_do_32bit(
-
- /* Note that right now we can only access the first 1MB of memory,
- because paging is enabled and that's the only memory region that's been mapped.
- The rest of physical memory won't be mapped until VCPI_PAGING_INIT,
- but VCPI_PAGING_INIT requires allocating memory for page tables,
- and we can't call phys_mem_collect() to provide memory to the allocator
- until all physical memory can be read and written.
- To get out of this catch-22,
- we call dos_mem_collect() beforehand here
- to make low DOS memory available for allocation by VCPI_PAGING_INIT.
- The call to phys_mem_collect() later will cause dos_mem_collect
- to be called a second time, but it'll just do nothing then. */
- dos_mem_collect();
-
- /* Initialize the basic CPU tables. */
- cpu_init(&cpu[0]);
-
- /* Initialize the paging system. */
- VCPI_PAGING_INIT(vcpi_pdir, (vm_offset_t)first_free_pte / 4 * PAGE_SIZE);
-
- /* Now that we can access all physical memory,
- collect the remaining memory regions we discovered while in 16-bit mode
- and add them to our free memory list. */
- phys_mem_collect();
-
- /* Initialize the hardware interrupt vectors in the IDT. */
- idt_irq_init();
-
- /* Now that we have an initialized LDT descriptor, start using it. */
- KERNEL_LDT_INIT();
-
- /* Switch to real mode and back again once more,
- to make sure everything's loaded properly. */
- do_16bit(
- i16_vcpi_switch_to_real_mode();
- i16_vcpi_switch_to_pmode();
- );
-
- vcpi_start();
- );
-}
-
-/* Shouldn't be necessary, but just in case the end of the above function,
- containing the .code16, gets "optimized away"... */
-CODE16
-
-void i16_vcpi_shutdown()
-{
- if (pic_reprogrammed)
- {
- pic_reprogrammed = FALSE;
-
- i16_cli();
-
- i16_assert(irq_master_base >= 0x20);
-
- /* Reprogram the PIC. */
- i16_pic_set_master(0x08);
-
- /* Inform the VCPI server. */
- i16_vcpi_set_int_vecs(0x08, irq_slave_base);
-
- /* Restore the old interrupt vectors. */
- {
- int i;
-
- for (i = 0; i < 8; i++)
- {
- i16_dos_set_int_vec(irq_master_base+i,
- &master_save_vecs[i]);
- }
- }
-
- i16_sti();
- }
-
- if (ems_page_allocated)
- {
- ems_page_allocated = 0;
- asm volatile("int $0x67" : : "a" (0x4500), "d" (ems_handle));
- }
-}
-
-#endif ENABLE_VCPI
-