home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / i386 / kernel / vm86.c < prev   
Encoding:
C/C++ Source or Header  |  1995-02-05  |  9.5 KB  |  405 lines

  1. /*
  2.  *  linux/kernel/vm86.c
  3.  *
  4.  *  Copyright (C) 1994  Linus Torvalds
  5.  */
  6. #include <linux/errno.h>
  7. #include <linux/sched.h>
  8. #include <linux/kernel.h>
  9. #include <linux/signal.h>
  10. #include <linux/string.h>
  11. #include <linux/ptrace.h>
  12. #include <linux/mm.h>
  13.  
  14. #include <asm/segment.h>
  15. #include <asm/pgtable.h>
  16. #include <asm/io.h>
  17.  
  18. /*
  19.  * Known problems:
  20.  *
  21.  * Interrupt handling is not guaranteed:
  22.  * - a real x86 will disable all interrupts for one instruction
  23.  *   after a "mov ss,xx" to make stack handling atomic even without
  24.  *   the 'lss' instruction. We can't guarantee this in v86 mode,
  25.  *   as the next instruction might result in a page fault or similar.
  26.  * - a real x86 will have interrupts disabled for one instruction
  27.  *   past the 'sti' that enables them. We don't bother with all the
  28.  *   details yet..
  29.  *
  30.  * Hopefully these problems do not actually matter for anything.
  31.  */
  32.  
  33. /*
  34.  * 8- and 16-bit register defines..
  35.  */
  36. #define AL(regs)    (((unsigned char *)&((regs)->eax))[0])
  37. #define AH(regs)    (((unsigned char *)&((regs)->eax))[1])
  38. #define IP(regs)    (*(unsigned short *)&((regs)->eip))
  39. #define SP(regs)    (*(unsigned short *)&((regs)->esp))
  40.  
  41. /*
  42.  * virtual flags (16 and 32-bit versions)
  43.  */
  44. #define VFLAGS    (*(unsigned short *)&(current->tss.v86flags))
  45. #define VEFLAGS    (current->tss.v86flags)
  46.  
  47. #define set_flags(X,new,mask) \
  48. ((X) = ((X) & ~(mask)) | ((new) & (mask)))
  49.  
  50. #define SAFE_MASK    (0xDD5)
  51. #define RETURN_MASK    (0xDFF)
  52.  
  53. asmlinkage struct pt_regs * save_v86_state(struct vm86_regs * regs)
  54. {
  55.     unsigned long tmp;
  56.  
  57.     if (!current->tss.vm86_info) {
  58.         printk("no vm86_info: BAD\n");
  59.         do_exit(SIGSEGV);
  60.     }
  61.     set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->tss.v86mask);
  62.     memcpy_tofs(¤t->tss.vm86_info->regs,regs,sizeof(*regs));
  63.     put_fs_long(current->tss.screen_bitmap,¤t->tss.vm86_info->screen_bitmap);
  64.     tmp = current->tss.esp0;
  65.     current->tss.esp0 = current->saved_kernel_stack;
  66.     current->saved_kernel_stack = 0;
  67.     return (struct pt_regs *) tmp;
  68. }
  69.  
  70. static void mark_screen_rdonly(struct task_struct * tsk)
  71. {
  72.     pgd_t *pg_dir;
  73.  
  74.     pg_dir = PAGE_DIR_OFFSET(tsk, 0);
  75.     if (!pgd_none(*pg_dir)) {
  76.         pte_t *pg_table;
  77.         int i;
  78.  
  79.         if (pgd_bad(*pg_dir)) {
  80.             printk("vm86: bad page table directory entry %08lx\n", pgd_val(*pg_dir));
  81.             pgd_clear(pg_dir);
  82.             return;
  83.         }
  84.         pg_table = (pte_t *) pgd_page(*pg_dir);
  85.         pg_table += 0xA0000 >> PAGE_SHIFT;
  86.         for (i = 0 ; i < 32 ; i++) {
  87.             if (pte_present(*pg_table))
  88.                 *pg_table = pte_wrprotect(*pg_table);
  89.             pg_table++;
  90.         }
  91.     }
  92. }
  93.  
  94. asmlinkage int sys_vm86(struct vm86_struct * v86)
  95. {
  96.     struct vm86_struct info;
  97.     struct pt_regs * pt_regs = (struct pt_regs *) &v86;
  98.     int error;
  99.  
  100.     if (current->saved_kernel_stack)
  101.         return -EPERM;
  102.     /* v86 must be readable (now) and writable (for save_v86_state) */
  103.     error = verify_area(VERIFY_WRITE,v86,sizeof(*v86));
  104.     if (error)
  105.         return error;
  106.     memcpy_fromfs(&info,v86,sizeof(info));
  107. /*
  108.  * make sure the vm86() system call doesn't try to do anything silly
  109.  */
  110.     info.regs.__null_ds = 0;
  111.     info.regs.__null_es = 0;
  112.     info.regs.__null_fs = 0;
  113.     info.regs.__null_gs = 0;
  114. /*
  115.  * The eflags register is also special: we cannot trust that the user
  116.  * has set it up safely, so this makes sure interrupt etc flags are
  117.  * inherited from protected mode.
  118.  */
  119.      VEFLAGS = info.regs.eflags;
  120.     info.regs.eflags &= SAFE_MASK;
  121.     info.regs.eflags |= pt_regs->eflags & ~SAFE_MASK;
  122.     info.regs.eflags |= VM_MASK;
  123.  
  124.     switch (info.cpu_type) {
  125.         case CPU_286:
  126.             current->tss.v86mask = 0;
  127.             break;
  128.         case CPU_386:
  129.             current->tss.v86mask = NT_MASK | IOPL_MASK;
  130.             break;
  131.         case CPU_486:
  132.             current->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
  133.             break;
  134.         default:
  135.             current->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
  136.             break;
  137.     }
  138.  
  139. /*
  140.  * Save old state, set default return value (%eax) to 0
  141.  */
  142.     pt_regs->eax = 0;
  143.     current->saved_kernel_stack = current->tss.esp0;
  144.     current->tss.esp0 = (unsigned long) pt_regs;
  145.     current->tss.vm86_info = v86;
  146.  
  147.     current->tss.screen_bitmap = info.screen_bitmap;
  148.     if (info.flags & VM86_SCREEN_BITMAP)
  149.         mark_screen_rdonly(current);
  150.     __asm__ __volatile__("movl %0,%%esp\n\t"
  151.         "jmp ret_from_sys_call"
  152.         : /* no outputs */
  153.         :"r" (&info.regs));
  154.     return 0;
  155. }
  156.  
  157. static inline void return_to_32bit(struct vm86_regs * regs16, int retval)
  158. {
  159.     struct pt_regs * regs32;
  160.  
  161.     regs32 = save_v86_state(regs16);
  162.     regs32->eax = retval;
  163.     __asm__ __volatile__("movl %0,%%esp\n\t"
  164.         "jmp ret_from_sys_call"
  165.         : : "r" (regs32));
  166. }
  167.  
  168. static inline void set_IF(struct vm86_regs * regs)
  169. {
  170.     VEFLAGS |= VIF_MASK;
  171.     if (VEFLAGS & VIP_MASK)
  172.         return_to_32bit(regs, VM86_STI);
  173. }
  174.  
  175. static inline void clear_IF(struct vm86_regs * regs)
  176. {
  177.     VEFLAGS &= ~VIF_MASK;
  178. }
  179.  
  180. static inline void clear_TF(struct vm86_regs * regs)
  181. {
  182.     regs->eflags &= ~TF_MASK;
  183. }
  184.  
  185. static inline void set_vflags_long(unsigned long eflags, struct vm86_regs * regs)
  186. {
  187.     set_flags(VEFLAGS, eflags, current->tss.v86mask);
  188.     set_flags(regs->eflags, eflags, SAFE_MASK);
  189.     if (eflags & IF_MASK)
  190.         set_IF(regs);
  191. }
  192.  
  193. static inline void set_vflags_short(unsigned short flags, struct vm86_regs * regs)
  194. {
  195.     set_flags(VFLAGS, flags, current->tss.v86mask);
  196.     set_flags(regs->eflags, flags, SAFE_MASK);
  197.     if (flags & IF_MASK)
  198.         set_IF(regs);
  199. }
  200.  
  201. static inline unsigned long get_vflags(struct vm86_regs * regs)
  202. {
  203.     unsigned long flags = regs->eflags & RETURN_MASK;
  204.  
  205.     if (VEFLAGS & VIF_MASK)
  206.         flags |= IF_MASK;
  207.     return flags | (VEFLAGS & current->tss.v86mask);
  208. }
  209.  
  210. static inline int is_revectored(int nr, struct revectored_struct * bitmap)
  211. {
  212.     __asm__ __volatile__("btl %2,%%fs:%1\n\tsbbl %0,%0"
  213.         :"=r" (nr)
  214.         :"m" (*bitmap),"r" (nr));
  215.     return nr;
  216. }
  217.  
  218. /*
  219.  * Boy are these ugly, but we need to do the correct 16-bit arithmetic.
  220.  * Gcc makes a mess of it, so we do it inline and use non-obvious calling
  221.  * conventions..
  222.  */
  223. #define pushb(base, ptr, val) \
  224. __asm__ __volatile__( \
  225.     "decw %w0\n\t" \
  226.     "movb %2,%%fs:0(%1,%0)" \
  227.     : "=r" (ptr) \
  228.     : "r" (base), "q" (val), "0" (ptr))
  229.  
  230. #define pushw(base, ptr, val) \
  231. __asm__ __volatile__( \
  232.     "decw %w0\n\t" \
  233.     "movb %h2,%%fs:0(%1,%0)\n\t" \
  234.     "decw %w0\n\t" \
  235.     "movb %b2,%%fs:0(%1,%0)" \
  236.     : "=r" (ptr) \
  237.     : "r" (base), "q" (val), "0" (ptr))
  238.  
  239. #define pushl(base, ptr, val) \
  240. __asm__ __volatile__( \
  241.     "decw %w0\n\t" \
  242.     "rorl $16,%2\n\t" \
  243.     "movb %h2,%%fs:0(%1,%0)\n\t" \
  244.     "decw %w0\n\t" \
  245.     "movb %b2,%%fs:0(%1,%0)\n\t" \
  246.     "decw %w0\n\t" \
  247.     "rorl $16,%2\n\t" \
  248.     "movb %h2,%%fs:0(%1,%0)\n\t" \
  249.     "decw %w0\n\t" \
  250.     "movb %b2,%%fs:0(%1,%0)" \
  251.     : "=r" (ptr) \
  252.     : "r" (base), "q" (val), "0" (ptr))
  253.  
  254. #define popb(base, ptr) \
  255. ({ unsigned long __res; \
  256. __asm__ __volatile__( \
  257.     "movb %%fs:0(%1,%0),%b2\n\t" \
  258.     "incw %w0" \
  259.     : "=r" (ptr), "=r" (base), "=q" (__res) \
  260.     : "0" (ptr), "1" (base), "2" (0)); \
  261. __res; })
  262.  
  263. #define popw(base, ptr) \
  264. ({ unsigned long __res; \
  265. __asm__ __volatile__( \
  266.     "movb %%fs:0(%1,%0),%b2\n\t" \
  267.     "incw %w0\n\t" \
  268.     "movb %%fs:0(%1,%0),%h2\n\t" \
  269.     "incw %w0" \
  270.     : "=r" (ptr), "=r" (base), "=q" (__res) \
  271.     : "0" (ptr), "1" (base), "2" (0)); \
  272. __res; })
  273.  
  274. #define popl(base, ptr) \
  275. ({ unsigned long __res; \
  276. __asm__ __volatile__( \
  277.     "movb %%fs:0(%1,%0),%b2\n\t" \
  278.     "incw %w0\n\t" \
  279.     "movb %%fs:0(%1,%0),%h2\n\t" \
  280.     "incw %w0\n\t" \
  281.     "rorl $16,%2\n\t" \
  282.     "movb %%fs:0(%1,%0),%b2\n\t" \
  283.     "incw %w0\n\t" \
  284.     "movb %%fs:0(%1,%0),%h2\n\t" \
  285.     "incw %w0\n\t" \
  286.     "rorl $16,%2" \
  287.     : "=r" (ptr), "=r" (base), "=q" (__res) \
  288.     : "0" (ptr), "1" (base)); \
  289. __res; })
  290.  
  291. static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp)
  292. {
  293.     unsigned short seg = get_fs_word((void *) ((i<<2)+2));
  294.  
  295.     if (seg == BIOSSEG || regs->cs == BIOSSEG ||
  296.         is_revectored(i, ¤t->tss.vm86_info->int_revectored))
  297.         return_to_32bit(regs, VM86_INTx + (i << 8));
  298.     if (i==0x21 && is_revectored(AH(regs),¤t->tss.vm86_info->int21_revectored))
  299.         return_to_32bit(regs, VM86_INTx + (i << 8));
  300.     pushw(ssp, sp, get_vflags(regs));
  301.     pushw(ssp, sp, regs->cs);
  302.     pushw(ssp, sp, IP(regs));
  303.     regs->cs = seg;
  304.     SP(regs) -= 6;
  305.     IP(regs) = get_fs_word((void *) (i<<2));
  306.     clear_TF(regs);
  307.     clear_IF(regs);
  308.     return;
  309. }
  310.  
  311. void handle_vm86_debug(struct vm86_regs * regs, long error_code)
  312. {
  313. #if 0
  314.     do_int(regs, 1, (unsigned char *) (regs->ss << 4), SP(regs));
  315. #else
  316.     if (current->flags & PF_PTRACED)
  317.         current->blocked &= ~(1 << (SIGTRAP-1));
  318.     send_sig(SIGTRAP, current, 1);
  319.     current->tss.trap_no = 1;
  320.     current->tss.error_code = error_code;
  321. #endif
  322. }
  323.  
  324. void handle_vm86_fault(struct vm86_regs * regs, long error_code)
  325. {
  326.     unsigned char *csp, *ssp;
  327.     unsigned long ip, sp;
  328.  
  329.     csp = (unsigned char *) (regs->cs << 4);
  330.     ssp = (unsigned char *) (regs->ss << 4);
  331.     sp = SP(regs);
  332.     ip = IP(regs);
  333.  
  334.     switch (popb(csp, ip)) {
  335.  
  336.     /* operand size override */
  337.     case 0x66:
  338.         switch (popb(csp, ip)) {
  339.  
  340.         /* pushfd */
  341.         case 0x9c:
  342.             SP(regs) -= 4;
  343.             IP(regs) += 2;
  344.             pushl(ssp, sp, get_vflags(regs));
  345.             return;
  346.  
  347.         /* popfd */
  348.         case 0x9d:
  349.             SP(regs) += 4;
  350.             IP(regs) += 2;
  351.             set_vflags_long(popl(ssp, sp), regs);
  352.             return;
  353.         }
  354.  
  355.     /* pushf */
  356.     case 0x9c:
  357.         SP(regs) -= 2;
  358.         IP(regs)++;
  359.         pushw(ssp, sp, get_vflags(regs));
  360.         return;
  361.  
  362.     /* popf */
  363.     case 0x9d:
  364.         SP(regs) += 2;
  365.         IP(regs)++;
  366.         set_vflags_short(popw(ssp, sp), regs);
  367.         return;
  368.  
  369.     /* int xx */
  370.     case 0xcd:
  371.         IP(regs) += 2;
  372.         do_int(regs, popb(csp, ip), ssp, sp);
  373.         return;
  374.  
  375.     /* iret */
  376.     case 0xcf:
  377.         SP(regs) += 6;
  378.         IP(regs) = popw(ssp, sp);
  379.         regs->cs = popw(ssp, sp);
  380.         set_vflags_short(popw(ssp, sp), regs);
  381.         return;
  382.  
  383.     /* cli */
  384.     case 0xfa:
  385.         IP(regs)++;
  386.         clear_IF(regs);
  387.         return;
  388.  
  389.     /* sti */
  390.     /*
  391.      * Damn. This is incorrect: the 'sti' instruction should actually
  392.      * enable interrupts after the /next/ instruction. Not good.
  393.      *
  394.      * Probably needs some horsing around with the TF flag. Aiee..
  395.      */
  396.     case 0xfb:
  397.         IP(regs)++;
  398.         set_IF(regs);
  399.         return;
  400.  
  401.     default:
  402.         return_to_32bit(regs, VM86_UNKNOWN);
  403.     }
  404. }
  405.