v86 monitor

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
intel_breaker
Member
Member
Posts: 46
Joined: Tue Jan 04, 2005 12:00 am
Location: Poland
Contact:

Re: v86 monitor

Post 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.
digo_rp
Member
Member
Posts: 233
Joined: Sun Jun 05, 2005 11:00 pm

Re: v86 monitor

Post 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
User avatar
intel_breaker
Member
Member
Posts: 46
Joined: Tue Jan 04, 2005 12:00 am
Location: Poland
Contact:

Re: v86 monitor

Post by intel_breaker »

And with which offset do you compile it? What is your default 16bits programs offset?
Da_Maestro
Member
Member
Posts: 144
Joined: Tue Oct 26, 2004 11:00 pm
Location: Australia

Re: v86 monitor

Post by Da_Maestro »

Isn't the default for a .com file offset 0x100?
Two things are infinite: The universe and human stupidity. But I'm not quite sure about the universe.
--- Albert Einstein
digo_rp
Member
Member
Posts: 233
Joined: Sun Jun 05, 2005 11:00 pm

Re: v86 monitor

Post 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...
User avatar
intel_breaker
Member
Member
Posts: 46
Joined: Tue Jan 04, 2005 12:00 am
Location: Poland
Contact:

Re: v86 monitor

Post 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]
digo_rp
Member
Member
Posts: 233
Joined: Sun Jun 05, 2005 11:00 pm

Re: v86 monitor

Post 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?
User avatar
intel_breaker
Member
Member
Posts: 46
Joined: Tue Jan 04, 2005 12:00 am
Location: Poland
Contact:

Re: v86 monitor

Post by intel_breaker »

nope, you don't have to set anything on this tss, except esp0 and ss0
Post Reply