Page 2 of 2

Re: v86 monitor

Posted: Sun Feb 12, 2006 12:00 am
by intel_breaker
Okay, but are you sure that under cs and offset which you specified is a valid 16bits code?
Dump this memory area and make sure, that its a good 16bit code.

Re: v86 monitor

Posted: Sun Feb 12, 2006 12:00 am
by digo_rp
this is the test.asm I compile with nasm -f bin teste.asm - teste.com

[BITS 16]

[section .text]



start:

mov bx, 0B800h

mov es, bx

mov al, 'A'



looping

mov byte [es:0], 'V'

mov byte [es:2], '8'

mov byte [es:4], '6'

mov byte [es:8], 'T'

mov byte [es:10],'a'

mov byte [es:12],'s'

mov byte [es:14],'k'

mov byte [es:16],'['

mov byte [es:18], al

mov byte [es:19],1Fh

mov byte [es:20],']'

inc al

cmp al, 0xff

je clearal

jmp looping

clearal

xor al, al

jmp looping

Re: v86 monitor

Posted: Sun Feb 12, 2006 12:00 am
by intel_breaker
And with which offset do you compile it? What is your default 16bits programs offset?

Re: v86 monitor

Posted: Sun Feb 12, 2006 12:00 am
by Da_Maestro
Isn't the default for a .com file offset 0x100?

Re: v86 monitor

Posted: Mon Feb 13, 2006 12:00 am
by digo_rp
no I compile only starting at 0 no org 0x100

I only need to use vesa

another question, how do you set up your v86 stack layout? example what do you put at reg cs/eip
ss esp eflags...

Re: v86 monitor

Posted: Mon Feb 13, 2006 12:00 am
by intel_breaker
It's my whole v86 support code;)
Glimpse on it, then you can use this file under the terms of GPL license;)

Code: Select all

/*
 *  Glass Operating System
 *  Copyright 2005(C) Glass Operating System Team
 *
 *
 *  This program 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 2 of the License, or (at your option)
 *  any later version.
 *
 *  This program 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, write to the Free Software Foundation, Inc.,
 *  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
*/

#include <types.h>
#include <arch/io.h>
#include <arch/paging.h>
#include <arch/v86.h>
#include <arch/idt.h>
#include <arch/eflags.h>
#include <arch/segments.h>
#include <process/process.h>
#include <process/scheduler.h>
#include <memory/sma.h>
#include <mutex/spinlocks.h>
#include <mutex/futex.h>

spinlock v86_internal_mutex;

struct process *v86d;

/* it's very good code=) and it's veery simple code too;)
   because many systems repeat bug with share real mode enviroment, 
   we will not repeat it any longer=) This enviroment musn't be share!
   So this code call interrupt, then back to the function, which will disable daemon,
   it should be works fine:) */

static uint8 vm86_code[] = {
    0xcd, 0x10,
    0xcd, 0x80,
};

/* Generaly v86_init() creates a v86 deamon 
   We'll put v86 stack after GDT(see init.S) and v86 code after stack, so we'll decrase our free conventional
   memory block over 0x1000 bytes. So new offset to interrupt number is 0x1C801 */

sint32 vm86_init() {
    uint32 stack0;

    v86d = (struct process *)kalloc(sizeof(struct process), 1);
    stack0 = kalloc(0x4000,1);

    v86d->ss0 = KERNEL_DS;
    v86d->esp0 = stack0 + 0x4000-4;

    v86d->cs = (USER_CS)|0x3;
    v86d->ds = (USER_DS)|0x3;

    /* let use monitor kernel page directory */
    v86d->cr3=v86d->cached_cr3=v86d->done_cr3=paging_kernel_PGD();

    memcpy(0x1C800, vm86_code, sizeof(vm86_code));

    uint32 fp=0x1C800;
    uint32 ss=0x1C800-0x4;

    v86d->arch_frame=(struct intr_frame *)(v86d->esp0-sizeof(struct intr_frame));
    v86d->esp0=v86d->arch_frame;

    v86d->arch_frame->eax=0;
    v86d->arch_frame->ebx=0;
    v86d->arch_frame->ecx=0;
    v86d->arch_frame->edx=0;
    v86d->arch_frame->edi=0;
    v86d->arch_frame->esi=0;
    v86d->arch_frame->ebp=0;
    v86d->arch_frame->old_esp=0;

    v86d->arch_frame->cs=SEGMENT(fp);
    v86d->arch_frame->eip=OFFSET(fp);

    v86d->arch_frame->ss=SEGMENT(ss);
    v86d->arch_frame->esp=OFFSET(ss);

    /* ds=cs */
    v86d->arch_frame->v_ds=v86d->arch_frame->v_es=v86d->arch_frame->v_fs=v86d->arch_frame->v_gs=SEGMENT(fp);
    v86d->arch_frame->flags=EFLAG_BASE | EFLAG_V86;

    v86d->arch_frame->fs=v86d->arch_frame->gs=v86d->arch_frame->es=v86d->arch_frame->ds=v86d->ds;

    v86d->v86 = 1;
    v86d->v86_if = 1;

    strcpy(v86d->pName, "v86d monitor");
    v86d->pid = 70;
    v86d->pState=STATE_SLEEPING;

    /* Oh, god please change this ugly code:/// */
    disable();
    scheduler_spawn(v86d);
    scheduler_sleep(v86d);
    enable();

    futex_cls( &v86_internal_mutex );

    return 0;
}

void vm86_reset(void) {
    uint32 fp=0x1C800;
    uint32 ss=0x1C800-0x4;
    
    v86d->arch_frame=(struct intr_frame *)(v86d->esp0-sizeof(struct intr_frame));
    v86d->esp0=v86d->arch_frame;

    v86d->arch_frame->old_esp=0;

    v86d->arch_frame->cs=SEGMENT(fp);
    v86d->arch_frame->eip=OFFSET(fp);

    v86d->arch_frame->ss=SEGMENT(ss);
    v86d->arch_frame->esp=OFFSET(ss);
    
    v86d->v86=1;
    v86d->v86_if=1;
}

sint32 realInt( uint8 intnr, struct rm_regs *regs) {
    /* yeah, we need to put in offset intnr */
    uint8 *intoff=(uint8 *)0x1BC01;

    futex_up( &v86_internal_mutex );

    *intoff=intnr;

    v86d->arch_frame->eax=regs->eax;
    v86d->arch_frame->ebx=regs->ebx;
    v86d->arch_frame->ecx=regs->ecx;
    v86d->arch_frame->edx=regs->edx;
    v86d->arch_frame->edi=regs->edi;
    v86d->arch_frame->esi=regs->esi;
    v86d->arch_frame->ebp=regs->ebp;

    /* TODO: flag change support */

    v86d->arch_frame->v_ds=regs->ds;
    v86d->arch_frame->v_es=regs->es;
    v86d->arch_frame->v_fs=regs->fs;
    v86d->arch_frame->v_gs=regs->gs;

    scheduler_wakeup( v86d );

    /* wait for finish v86 daemon work */
    while( scheduler_ready(v86d) );

    regs->eax=v86d->arch_frame->eax;
    regs->ebx=v86d->arch_frame->ebx;
    regs->ecx=v86d->arch_frame->ecx;
    regs->edx=v86d->arch_frame->edx;
    regs->edi=v86d->arch_frame->edi;
    regs->esi=v86d->arch_frame->esi;
    regs->ebp=v86d->arch_frame->ebp;

    /* reset v86 monitor */
    vm86_reset();

    futex_down( &v86_internal_mutex );
    return 0;
}

void realInt_test(void) {
    struct rm_regs regs;

    memset(&regs, 0, sizeof(struct rm_regs));
    regs.eax=0x4f02;
    regs.ebx=0x101;

    realInt(0x10, &regs);
}

sint32 i386V86Gpf(struct process *proc, struct intr_frame *ctx) {
    uint8 *ip;
    uint16 *stack, *ivt;
    uint32 *stack32;
    sint8 is_operand32, is_address32;

    ip = (uint8 *)LINEAR(ctx->cs, ctx->eip);
    ivt = (uint16 *)0;
    stack = (uint16 *)LINEAR(ctx->ss, ctx->esp);
    stack32 = (uint32*)stack;

    is_operand32 = is_address32 = 0;
    uint16 init_eip = ctx -> eip;

    //printk("v86Gpf: ip = 0x%x:0x%x\n",ip[0],ip[1]);

    while(1) {
	switch( ip[0] ) {
		case 0x66:            /* O32 */
			is_operand32 = 1;
            		ip++;
            		ctx->eip = (uint16)(ctx->eip + 1);
            		break;
			
        	case 0x67:            /* A32 */
			is_address32 = 1;
            		ip++;
            		ctx->eip = (uint16) (ctx->eip + 1);
            		break;
			
            	case 0x9c:            /* PUSHF */
            		if (is_operand32) {
                	    ctx->esp = ((ctx->esp & 0xffff) - 4) & 0xffff;
                	    stack32--;
                	    stack32[0] = ctx->flags & VALID_FLAGS;

                	    if( proc -> v86_if )
                    	        stack32[0] |= EFLAG_INTERRUPT; else
                    		stack32[0] &= ~EFLAG_INTERRUPT;
            		}
            		else {
                		ctx->esp = ((ctx->esp & 0xffff) - 2) & 0xffff;
                		stack--;
                		stack[0] = (uint16) ctx->flags;

                		if( proc -> v86_if )
                    			stack[0] |= EFLAG_INTERRUPT;
                		else
                    			stack[0] &= ~EFLAG_INTERRUPT;
            		}
            		ctx->eip = (uint16)(ctx->eip + 1);
            		return 0;

        	case 0x9d:            /* POPF */
			if( is_operand32 ) {
                		ctx->flags = EFLAG_INTERRUPT | EFLAG_V86 | (stack32[0] & VALID_FLAGS);
                		proc->v86_if = (stack32[0] & EFLAG_INTERRUPT) != 0;
                		ctx->esp = ((ctx->esp & 0xffff) + 4) & 0xffff;
            		}
            		else {
				ctx->flags = EFLAG_INTERRUPT | EFLAG_V86 | stack[0];
                		proc->v86_if = (stack[0] & EFLAG_INTERRUPT) != 0;
                		ctx->esp = ((ctx->esp & 0xffff) + 2) & 0xffff;
            		}
            
            		ctx->eip = (uint16)(ctx->eip + 1);
            		return 0;

        	case 0xcd:            /* INT n */
            		switch (ip[1]) {
				case 0x80:
				    //printk("V86 finish session!!!!!!! (Eax=0x%x, Ebx=0x%x)\n",ctx->eax,ctx->ebx);
				    scheduler_sleep( v86d );
				    /* this means that we must finish this v86 session */
				    break;

            			default:
                		    stack -= 3;
                		    ctx->esp = ((ctx->esp & 0xffff) - 6) & 0xffff;

                		    stack[0] = (uint16)(ctx->eip + 2);
                		    stack[1] = ctx->cs;
                		    stack[2] = (uint16)ctx->flags;
                
                		    if( proc->v86_if )
                    		        stack[2] |= EFLAG_INTERRUPT;
                		    else
                    			stack[2] &= ~EFLAG_INTERRUPT;

                		    ctx->cs = ivt[ip[1] * 2 + 1];
                		    ctx->eip = ivt[ip[1] * 2];
                		    return 1;
            		}
            		break;

        	case 0xcf:            /* IRET */
            		ctx->eip = stack[0];
            		ctx->cs = stack[1];
            		ctx->flags = EFLAG_INTERRUPT | EFLAG_V86 | stack[2];
            		proc->v86_if = (stack[2] & EFLAG_INTERRUPT) != 0;
            		ctx->esp = ((ctx->esp & 0xffff) + 6) & 0xffff;
            		return 1;
        	case 0xfa:            /* CLI */
            		proc->v86_if = 0;
            		ctx->eip = (uint16)(ctx->eip + 1);
            		return 0;

        	case 0xfb:            /* STI */
            		proc->v86_if = 1;
            		ctx->eip = (uint16)(ctx->eip + 1);
            		return 1;
	    
		case 0xE4:
			/* OUT imm8,AL */
				
		case 0xE6:
			ctx->eip = init_eip;
			return 1;
				
		case 0xE5:
			/* IN [E]AX,imm8 */
			
		case 0xE7:
			/* OUT imm8,[E]AX */
			ctx->eip = init_eip;
			return 1;
				
		case 0x6C:
			/* INSB */
			
		case 0x6E:
			/* OUTSB */
			
		case 0xEC:
			/* IN AL,DX */
			
		case 0xEE:
			/* OUT DX,AL */
			ctx->eip = init_eip;
			return 0;
				
		case 0x6D:
			/* INSW, INSD */
				
		case 0x6F:
			/* OUTSW, OUTSD */
				
		case 0xED:
			/* IN [E]AX,DX */
				
		case 0xEF:
			/* OUT DX,[E]AX */
			ctx->eip = init_eip;
			return 1;

        	default:
            		printk("v86Gpf: unhandled opcode 0x%x\n", ip[0]);
			scheduler_sleep( v86d );
            		return 0;
	}
    }

    return 0;
}
[/code]

Re: v86 monitor

Posted: Mon Feb 13, 2006 12:00 am
by digo_rp
other simple question, on stack based taskswitching we have only one tss right? so from that tss we only set tss.ss0 and esp0 each taskwitch
right? so to use v86 program we have to set anything on that tss? like eflags/cs/es/esp

anything?

Re: v86 monitor

Posted: Mon Feb 13, 2006 12:00 am
by intel_breaker
nope, you don't have to set anything on this tss, except esp0 and ss0