/*-
 * Copyright (c) 2002-2018 The UbixOS Project.
 * All rights reserved.
 *
 * This was developed by Christopher W. Olsen for the UbixOS Project.
 *
 * 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, the following disclaimer and the list of authors.
 * 2) Redistributions in binary form must reproduce the above copyright notice, this list of
 *    conditions, the following disclaimer and the list of authors in the documentation and/or
 *    other materials provided with the distribution.
 * 3) Neither the name of the UbixOS 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 AUTHOR 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 <vmm/vmm.h>
#include <vmm/mmap.h>
#include <sys/types.h>
#include <lib/kprintf.h>
#include <sys/descrip.h>
#include <ubixos/kpanic.h>
#include <ubixos/spinlock.h>
#include <ubixos/sched.h>
int freebsd6_mmap( struct thread *td, struct freebsd6_mmap_args *uap ) {
	vm_size_t size_0;
	vm_size_t size_1;
	vm_size_t pageoff;
	off_t pos;
	int align;
	int flags;
	int error;
	vm_offset_t addr	= 0x0;
    int i;
    error	= 0;
    size_0	= uap->len;
    flags	= uap->flags;
    pos		= uap->pos;
    kprintf("uap->flags: [0x%X]\n", uap->flags);
    kprintf("uap->addr:  [0x%X]\n", uap->addr);
    kprintf("uap->len:   [0x%X]\n", uap->len);
    kprintf("uap->prot:  [0x%X]\n", uap->prot);
    kprintf("uap->fd:    [%i]\n", uap->fd);
    kprintf("uap->pad:   [0x%X]\n", uap->pad);
    kprintf("uap->pos:   [0x%X]\n", uap->pos);
    if( ( uap->flags & MAP_ANON ) != 0 )
        pos = 0;
    /*
     * Align the file position to a page boundary,
     * and save its page offset component.
     */
    pageoff	= ( pos & PAGE_MASK );
    pos		-= pageoff;
    /* Adjust size for rounding (on both ends). */
    size_0	+= pageoff;
    size_1	= ( vm_size_t ) round_page( size_0 );
    size_0	= size_1;
    //	Ensure alignment is at least a page and fits in a pointer.
    align	= flags & MAP_ALIGNMENT_MASK;
    if( align != 0 && align != MAP_ALIGNED_SUPER && ( align >> MAP_ALIGNMENT_SHIFT >= sizeof( void * ) * NBBY || align >> MAP_ALIGNMENT_SHIFT < PAGE_SHIFT ) )
        return( EINVAL );
    if( flags & MAP_FIXED ) {
    	kprintf( "FIXED NOT SUPPORTED YET" );
    	return( EINVAL );
    } else {
        /* At Some Point I Need To  Proc Lock Incase It's Threaded */
        /* MrOlsen (2016-01-15) Temporary comment out
         if ( addr == 0 || (addr >= round_page( (vm_offset_t) vms->vm_taddr ) && addr < round_page( (vm_offset_t) vms->vm_daddr + lim_max( td->td_proc, RLIMIT_DATA ) )) )
         addr = round_page( (vm_offset_t) vms->vm_daddr + lim_max( td->td_proc, RLIMIT_DATA ) );
         */
    }
    if( flags & MAP_ANON ) {
        /*
         * Mapping blank space is trivial.
         */
        /*
         handle = NULL;
         handle_type = OBJT_DEFAULT;
         maxprot = VM_PROT_ALL;
         cap_maxprot = VM_PROT_ALL;
         */
        for( i = addr; i < ( addr + size_0 ); i += 0x1000 ) {
        	if( vmm_remapPage( vmm_findFreePage( _current->id ), i, PAGE_DEFAULT, _current->id, 0 ) == 0x0 )
                K_PANIC( "remap Failed" );
        }
        kprintf( "td->vm_dsize should be adjust but isn't" );
    } else {
    	/* Mapping File */
    	kprintf( "File Mapping Not Supported Yet" );
        return( EINVAL );
    }
    return( 0x0 );
}
int sys_munmap( struct thread *td, struct sys_munmap_args *uap ) {
	//TEMP
	kprintf( "[%s:%i] munmap(0x%X:%i)", __FILE__, __LINE__, uap->addr, uap->len );
	td->td_retval[0] = 0;
    return(0x0);
}
int sys_mmap( struct thread *td, struct sys_mmap_args *uap ) {
	vm_offset_t addr	= 0x0;
	char *tmp			= 0x0;
	struct file *fd		= 0x0;
	int x				= 0x0;
    kprintf("[%s:%i] mmap(%i-0x%X-%i)\n", __FILE__, __LINE__, uap->fd, uap->addr, uap->len);
    addr	= (vm_offset_t) uap->addr;
    if( uap->fd == -1 ) {
    	if( uap->addr != 0x0 ) {
    		for( x = 0x0; x < round_page( uap->len ); x += PAGE_SIZE ) {
    			vmm_unmapPage( ( ( uint32_t ) uap->addr & 0xFFFFF000 ) + x, VMM_FREE );
    			//	Make readonly and read/write !!!
                if( vmm_remapPage( vmm_findFreePage( _current->id ), ( ( ( uint32_t ) uap->addr & 0xFFFFF000 ) + x ), PAGE_DEFAULT, _current->id, 0 ) == 0x0 )
                    K_PANIC( "Remap Page Failed" );
    		}
    		kprintf("(tmp3: 0x%X)\n", tmp);
    		tmp = uap->addr;
    		kprintf("(tmp4: 0x%X)\n", tmp);
    		bzero( tmp, uap->len );
    		td->td_retval[0] = ( uint32_t ) tmp;
    		return( 0x0 );
    	}
    	kprintf("[tmp5.0: %i:%i]\n", _current->id, round_page( uap->len ) / PAGE_SIZE );
        td->td_retval[0] = ( void * ) vmm_getFreeVirtualPage( _current->id, round_page( uap->len ) / PAGE_SIZE, VM_TASK );
        if( td->td_retval[0] == 0x0 )
        	K_PANIC( "UNABLE TO GET FREE VIRTUAL PAGE" );
        kprintf("(tmp5.1: 0x%X)\n", td->td_retval[0]);
        bzero( td->td_retval[0], uap->len );
        kprintf("<tmp5.2: BZREO>\n");
        kprintf("<tmp5.3: BZREO>\n");
        return( 0x0 );  //vmm_getFreeVirtualPage(_current->id, round_page( uap->len ) / 0x1000, VM_THRD));
    } else {
    	getfd( td, &fd, uap->fd );
        if( uap->addr == 0x0 ) {
        	tmp = ( char * ) vmm_getFreeVirtualPage( _current->id, round_page( uap->len ) / PAGE_SIZE, VM_TASK );
        } else {
            for( x = 0x0; x < round_page( uap->len ); x += 0x1000 ) {
                vmm_unmapPage( ( ( uint32_t ) uap->addr & 0xFFFFF000 ) + x, 1 );
                //	Make readonly and read/write !!!
                if( vmm_remapPage( vmm_findFreePage( _current->id ), ( ( ( uint32_t ) uap->addr & 0xFFFFF000 ) + x ), PAGE_DEFAULT, _current->id, 0 ) == 0x0 )
                    K_PANIC( "Remap Page Failed" );
            }
            //kprintf("(tmp1: 0x%X)\n", tmp);
            tmp = uap->addr;
            //kprintf("(tmp2: 0x%X)\n", tmp);
        }
        kern_fseek( fd->fd, uap->pos, 0x0 );
        fread( tmp, uap->len, 0x1, fd->fd );
        td->td_retval[0] = ( uint32_t ) tmp;
        if( td->td_retval[0] == ( int ) -1 )
            kpanic( "MMAP_FAILED" );
    }
    return( 0x0 );
}