aboutsummaryrefslogtreecommitdiffstats
path: root/rules.mk
Commit message (Expand)AuthorAgeFilesLines
* build: disable the use of -iremap for UML (#21851)Felix Fietkau2016-02-131-1/+1
* rules.mk: add TARGET_INIT_PATH toplevel variablesJo-Philipp Wich2016-02-081-0/+2
* build: filter out -fno-plt for the kernel build, fixes #21712Felix Fietkau2016-01-281-2/+2
* build: use -iremap feature to replace __FILE__ absolute path names in package...Felix Fietkau2016-01-251-0/+4
* rules.mk: make the locked template available even if flock has not been built...Felix Fietkau2016-01-201-3/+7
* build: use a separate variable checking the subdir path (for host packages)Felix Fietkau2016-01-201-1/+2
* host-build.mk: change default installation prefix of package/* host builds to...Felix Fietkau2016-01-201-2/+2
* build: move host build directories of package/* to build_dir/target-*/host/Felix Fietkau2016-01-201-2/+5
* build: add pure make tolower/toupper funtions that do not require shell callsFelix Fietkau2016-01-031-0/+14
* gcc: remove version 4.6, it is no longer neededFelix Fietkau2015-11-101-1/+1
* build: add -Wno-error=unused-result to target cflagsFelix Fietkau2015-11-101-1/+1
* rules.mk: export STAGING_DIR_HOST to sub-makefiles and shellsFelix Fietkau2015-11-071-1/+1
* build: Allow kernel modules to set build ID debug symbolFelix Fietkau2015-10-301-1/+2
* rules.mk: remove GCC 4.4 and GCC 4.5 conditionalFelix Fietkau2015-08-251-2/+2
* toolchain: only use fortify-headers for muslSteven Barth2015-06-291-1/+5
* toolchain: add fortify-headers, enable FORTIFY_SOURCE by defaultSteven Barth2015-06-231-1/+1
* toolchain: switch to musl by default, except for mips64Felix Fietkau2015-06-151-1/+1
* build: add integration for managing opkg package feed keysFelix Fietkau2015-04-061-0/+2
* rules.mk: add newline definitionJohn Crispin2015-03-151-0/+5
* rules.mk: don't add staging_dir/host/bin/ path againJo-Philipp Wich2015-02-101-1/+1
* scripts: extend rstrip.sh to remove bad rpathsJo-Philipp Wich2015-02-101-0/+1
* rules.mk: use relative paths for BASH, TAR, FIND, PATCH, PYTHONJo-Philipp Wich2015-02-061-5/+5
* include: declare variables formerly set in tmp/.host.mkJo-Philipp Wich2015-02-051-0/+6
* build: do not assume that gcc-{ar,ranlib,nm} is usable with an external toolc...Felix Fietkau2015-01-101-1/+1
* build: use gcc-provided ar, nm and ranlib where appropriateFelix Fietkau2014-12-271-5/+13
* rules.mk: reduce shexport to one line to allow it to be put in a target contextFelix Fietkau2014-10-221-2/+1
* build: clean up and optimize ipkg control generator codeFelix Fietkau2014-10-221-0/+1
* build: add $(STAGING_DIR_HOST)/usr/{include, lib} to build search path.John Crispin2014-10-201-2/+2
* build: override hardcoded paths to bison and m4 to make the SDK more relocatableFelix Fietkau2014-08-261-0/+3
* partially revert "build: remove check for nonexistant CONFIG_TAR_VERBOSITY va...Felix Fietkau2014-03-221-0/+2
* build: remove GREP_OPTIONS export from rules.mk, defining it in the top-level...Felix Fietkau2014-03-211-3/+0
* build: remove check to nonexistant CONFIG_ENABLE_LOCALE variable and move DIS...Felix Fietkau2014-03-211-6/+0
* build: remove check for nonexistant CONFIG_TAR_VERBOSITY variable and move TA...Felix Fietkau2014-03-211-6/+0
* build: add a variable for the name of the {build,staging}_dir/{target,toolcha...Felix Fietkau2014-03-101-10/+10
* FPU type should not interfere with the ABI selection.Imre Kaloz2013-11-291-1/+8
* allow configuration of the target directory for binariesImre Kaloz2013-11-221-1/+1
* build: include the cpu type as part of the toolchain/target directory nameFelix Fietkau2013-09-261-11/+4
* build: decouple the mips16 support flag from the toolchainFelix Fietkau2013-08-141-8/+2
* build: unify target independent optimization optionsFelix Fietkau2013-07-291-1/+2
* build: add required exports for dependency trackingFelix Fietkau2013-07-181-1/+1
* build: move the XARGS variable out of the host checks, since a working xargs ...Felix Fietkau2013-07-101-0/+1
* rules.mk: use qstrip to reduce syntax highlighting issuesFelix Fietkau2013-07-101-1/+1
* toolchain: eliminate the INSTALL_LIBSTDCPP config symbol and make c++ support...Felix Fietkau2013-05-091-1/+1
* rules.mk: add _dsp to ARCH_SUFFIX if the dsp ase is usedJohn Crispin2013-05-061-0/+6
* toolchain: allow choosing the MIPS64 user-land ABIFlorian Fainelli2013-04-051-0/+5
* buildroot: factor knowledge of a 64bits architectureFlorian Fainelli2013-04-051-1/+1
* buildroot: allow enabling MIPS16 user-space buildFlorian Fainelli2013-04-051-0/+3
* rules.mk: MIPS16 builds get a different toolchainFlorian Fainelli2013-04-051-0/+1
* rules.mk: Create TARGET_ASFLAGS; force -mno-mips16Florian Fainelli2013-04-051-1/+5
* build: add a HOSTCXX variable pointing at the c++ compilerFelix Fietkau2013-03-221-0/+3
n618' href='#n618'>618 619 620 621
/******************************************************************************
 * xencomm.c
 *
 * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Copyright (C) IBM Corp. 2006
 *
 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
 *          Tristan Gingold <tristan.gingold@bull.net>
 *          Isaku Yamahata <yamahata@valinux.co.jp> multiple page support
 */

#include <xen/config.h>
#include <xen/mm.h>
#include <xen/sched.h>
#include <xen/xencomm.h>
#include <public/xen.h>
#include <public/xencomm.h>

#undef DEBUG
#ifdef DEBUG
#define xc_dprintk(f, a...) printk("[xencomm]" f , ## a)
#else
#define xc_dprintk(f, a...) ((void)0)
#endif

static void *
xencomm_vaddr(unsigned long paddr, struct page_info *page)
{
    return (void*)((paddr & ~PAGE_MASK) | (unsigned long)page_to_virt(page));
}

/* get_page() to prevent another vcpu freeing the page. */
static int
xencomm_get_page(unsigned long paddr, struct page_info **page)
{
    unsigned long maddr = paddr_to_maddr(paddr);
    if ( maddr == 0 )
        return -EFAULT;
        
    *page = maddr_to_page(maddr);
    if ( !get_page(*page, current->domain) )
    {
        /*
         * This page might be a page granted by another domain, or this page 
         * is freed with decrease reservation hypercall at the same time.
         */
        gdprintk(XENLOG_WARNING,
                 "bad page is passed. paddr 0x%lx maddr 0x%lx\n",
                 paddr, maddr);
        return -EFAULT;
    }

    return 0;
}

/* check if struct desc doesn't cross page boundry */
static int
xencomm_desc_cross_page_boundary(unsigned long paddr)
{
    unsigned long offset = paddr & ~PAGE_MASK;
    if ( offset > PAGE_SIZE - sizeof(struct xencomm_desc) )
        return 1;
    return 0;
}

struct xencomm_ctxt {
    struct xencomm_desc __user *desc_in_paddr;
    uint32_t nr_addrs;

    struct page_info *page;
    unsigned long *address;
};

static uint32_t
xencomm_ctxt_nr_addrs(const struct xencomm_ctxt *ctxt)
{
    return ctxt->nr_addrs;
}

static unsigned long*
xencomm_ctxt_address(struct xencomm_ctxt *ctxt)
{
    return ctxt->address;
}

static int
xencomm_ctxt_init(const void *handle, struct xencomm_ctxt *ctxt)
{
    struct page_info *page;
    struct xencomm_desc *desc;
    int ret;

    /* Avoid unaligned access. */
    if ( ((unsigned long)handle % __alignof__(*desc)) != 0 )
        return -EINVAL;
    if ( xencomm_desc_cross_page_boundary((unsigned long)handle) )
        return -EINVAL;

    /* First we need to access the descriptor. */
    ret = xencomm_get_page((unsigned long)handle, &page);
    if ( ret )
        return ret;

    desc = xencomm_vaddr((unsigned long)handle, page);
    if ( desc->magic != XENCOMM_MAGIC )
    {
        printk("%s: error: %p magic was 0x%x\n", __func__, desc, desc->magic);
        put_page(page);
        return -EINVAL;
    }

    /* Copy before use: It is possible for a guest to modify concurrently. */
    ctxt->nr_addrs = desc->nr_addrs;
    ctxt->desc_in_paddr = (struct xencomm_desc*)handle;
    ctxt->page = page;
    ctxt->address = &desc->address[0];
    return 0;
}

/*
 * Calculate the vaddr of &ctxt->desc_in_paddr->address[i] and get_page().
 * And put the results in ctxt->page and ctxt->address.
 * If there is the previous page, put_page().
 *
 * A guest domain passes the array, ctxt->desc_in_paddr->address[].
 * It is gpaddr-contiguous, but not maddr-contiguous so that
 * we can't obtain the vaddr by simple offsetting.
 * We need to convert gpaddr, &ctxt->desc_in_paddr->address[i],
 * into maddr and then convert it to the xen virtual address in order
 * to access there.
 * The conversion can be optimized out by using the last result of
 * ctxt->address because we access the array sequentially.
 * The conversion, gpaddr -> maddr -> vaddr, is necessary only when
 * crossing page boundary.
 */
static int
xencomm_ctxt_next(struct xencomm_ctxt *ctxt, int i)
{
    unsigned long paddr;
    struct page_info *page;
    int ret;

    BUG_ON(i >= ctxt->nr_addrs);

    /* For i == 0 case we already calculated it in xencomm_ctxt_init(). */
    if ( i != 0 )
        ctxt->address++;

    if ( ((unsigned long)ctxt->address & ~PAGE_MASK) != 0 )
        return 0;

    /* Crossing page boundary: machine address must be calculated. */
    paddr = (unsigned long)&ctxt->desc_in_paddr->address[i];
    ret = xencomm_get_page(paddr, &page);
    if ( ret )
        return ret;

    put_page(ctxt->page);
    ctxt->page = page;
    ctxt->address = xencomm_vaddr(paddr, page);

    return 0;
}

static void
xencomm_ctxt_done(struct xencomm_ctxt *ctxt)
{
    put_page(ctxt->page);
}

static int
xencomm_copy_chunk_from(
    unsigned long to, unsigned long paddr, unsigned int  len)
{
    struct page_info *page;
    int res;

    do {
        res = xencomm_get_page(paddr, &page);
    } while ( res == -EAGAIN );

    if ( res )
        return res;

    xc_dprintk("%lx[%d] -> %lx\n",
               (unsigned long)xencomm_vaddr(paddr, page), len, to);

    memcpy((void *)to, xencomm_vaddr(paddr, page), len);
    put_page(page);

    return 0;
}

static unsigned long
xencomm_inline_from_guest(
    void *to, const void *from, unsigned int n, unsigned int skip)
{
    unsigned long src_paddr = xencomm_inline_addr(from) + skip;

    while ( n > 0 )
    {
        unsigned int chunksz, bytes;

        chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE);
        bytes   = min(chunksz, n);

        if ( xencomm_copy_chunk_from((unsigned long)to, src_paddr, bytes) )
            return n;
        src_paddr += bytes;
        to += bytes;
        n -= bytes;
    }

    /* Always successful. */
    return 0;
}

/**
 * xencomm_copy_from_guest: Copy a block of data from domain space.
 * @to:   Machine address.
 * @from: Physical address to a xencomm buffer descriptor.
 * @n:    Number of bytes to copy.
 * @skip: Number of bytes from the start to skip.
 *
 * Copy data from domain to hypervisor.
 *
 * Returns number of bytes that could not be copied.
 * On success, this will be zero.
 */
unsigned long
xencomm_copy_from_guest(
    void *to, const void *from, unsigned int n, unsigned int skip)
{
    struct xencomm_ctxt ctxt;
    unsigned int from_pos = 0;
    unsigned int to_pos = 0;
    unsigned int i = 0;

    if ( xencomm_is_inline(from) )
        return xencomm_inline_from_guest(to, from, n, skip);

    if ( xencomm_ctxt_init(from, &ctxt) )
        return n;

    /* Iterate through the descriptor, copying up to a page at a time */
    while ( (to_pos < n) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
    {
        unsigned long src_paddr;
        unsigned int pgoffset, chunksz, chunk_skip;

        if ( xencomm_ctxt_next(&ctxt, i) )
            goto out;
        src_paddr = *xencomm_ctxt_address(&ctxt);
        if ( src_paddr == XENCOMM_INVALID )
        {
            i++;
            continue;
        }

        pgoffset = src_paddr % PAGE_SIZE;
        chunksz = PAGE_SIZE - pgoffset;

        chunk_skip = min(chunksz, skip);
        from_pos += chunk_skip;
        chunksz -= chunk_skip;
        skip -= chunk_skip;

        if ( skip == 0 && chunksz > 0 )
        {
            unsigned int bytes = min(chunksz, n - to_pos);

            if ( xencomm_copy_chunk_from((unsigned long)to + to_pos,
                                         src_paddr + chunk_skip, bytes) )
                goto out;
            from_pos += bytes;
            to_pos += bytes;
        }

        i++;
    }

out:
    xencomm_ctxt_done(&ctxt);
    return n - to_pos;
}

static int
xencomm_copy_chunk_to(
    unsigned long paddr, unsigned long from, unsigned int  len)
{
    struct page_info *page;
    int res;

    do {
        res = xencomm_get_page(paddr, &page);
    } while ( res == -EAGAIN );

    if ( res )
        return res;

    xc_dprintk("%lx[%d] -> %lx\n", from, len,
               (unsigned long)xencomm_vaddr(paddr, page));

    memcpy(xencomm_vaddr(paddr, page), (void *)from, len);
    xencomm_mark_dirty((unsigned long)xencomm_vaddr(paddr, page), len);
    put_page(page);

    return 0;
}

static unsigned long
xencomm_inline_to_guest(
    void *to, const void *from, unsigned int n, unsigned int skip)
{
    unsigned long dest_paddr = xencomm_inline_addr(to) + skip;

    while ( n > 0 )
    {
        unsigned int chunksz, bytes;

        chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
        bytes   = min(chunksz, n);

        if ( xencomm_copy_chunk_to(dest_paddr, (unsigned long)from, bytes) )
            return n;
        dest_paddr += bytes;
        from += bytes;
        n -= bytes;
    }

    /* Always successful. */
    return 0;
}

/**
 * xencomm_copy_to_guest: Copy a block of data to domain space.
 * @to:     Physical address to xencomm buffer descriptor.
 * @from:   Machine address.
 * @n:      Number of bytes to copy.
 * @skip: Number of bytes from the start to skip.
 *
 * Copy data from hypervisor to domain.
 *
 * Returns number of bytes that could not be copied.
 * On success, this will be zero.
 */
unsigned long
xencomm_copy_to_guest(
    void *to, const void *from, unsigned int n, unsigned int skip)
{
    struct xencomm_ctxt ctxt;
    unsigned int from_pos = 0;
    unsigned int to_pos = 0;
    unsigned int i = 0;

    if ( xencomm_is_inline(to) )
        return xencomm_inline_to_guest(to, from, n, skip);

    if ( xencomm_ctxt_init(to, &ctxt) )
        return n;

    /* Iterate through the descriptor, copying up to a page at a time */
    while ( (from_pos < n) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
    {
        unsigned long dest_paddr;
        unsigned int pgoffset, chunksz, chunk_skip;

        if ( xencomm_ctxt_next(&ctxt, i) )
            goto out;
        dest_paddr = *xencomm_ctxt_address(&ctxt);
        if ( dest_paddr == XENCOMM_INVALID )
        {
            i++;
            continue;
        }

        pgoffset = dest_paddr % PAGE_SIZE;
        chunksz = PAGE_SIZE - pgoffset;

        chunk_skip = min(chunksz, skip);
        to_pos += chunk_skip;
        chunksz -= chunk_skip;
        skip -= chunk_skip;

        if ( skip == 0 && chunksz > 0 )
        {
            unsigned int bytes = min(chunksz, n - from_pos);

            if ( xencomm_copy_chunk_to(dest_paddr + chunk_skip,
                                      (unsigned long)from + from_pos, bytes) )
                goto out;
            from_pos += bytes;
            to_pos += bytes;
        }

        i++;
    }

out:
    xencomm_ctxt_done(&ctxt);
    return n - from_pos;
}

static int
xencomm_clear_chunk(
    unsigned long paddr, unsigned int  len)
{
    struct page_info *page;
    int res;

    do {
        res = xencomm_get_page(paddr, &page);
    } while ( res == -EAGAIN );

    if ( res )
        return res;

    memset(xencomm_vaddr(paddr, page), 0x00, len);
    xencomm_mark_dirty((unsigned long)xencomm_vaddr(paddr, page), len);
    put_page(page);

    return 0;
}

static unsigned long
xencomm_inline_clear_guest(
    void *to, unsigned int n, unsigned int skip)
{
    unsigned long dest_paddr = xencomm_inline_addr(to) + skip;

    while ( n > 0 )
    {
        unsigned int chunksz, bytes;

        chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
        bytes   = min(chunksz, n);

        if ( xencomm_clear_chunk(dest_paddr, bytes) )
            return n;
        dest_paddr += bytes;
        n -= bytes;
    }

    /* Always successful. */
    return 0;
}

/**
 * xencomm_clear_guest: Clear a block of data in domain space.
 * @to:     Physical address to xencomm buffer descriptor.
 * @n:      Number of bytes to copy.
 * @skip: Number of bytes from the start to skip.
 *
 * Clear domain data
 *
 * Returns number of bytes that could not be cleared
 * On success, this will be zero.
 */
unsigned long
xencomm_clear_guest(
    void *to, unsigned int n, unsigned int skip)
{
    struct xencomm_ctxt ctxt;
    unsigned int from_pos = 0;
    unsigned int to_pos = 0;
    unsigned int i = 0;

    if ( xencomm_is_inline(to) )
        return xencomm_inline_clear_guest(to, n, skip);

    if ( xencomm_ctxt_init(to, &ctxt) )
        return n;

    /* Iterate through the descriptor, copying up to a page at a time */
    while ( (from_pos < n) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
    {
        unsigned long dest_paddr;
        unsigned int pgoffset, chunksz, chunk_skip;

        if ( xencomm_ctxt_next(&ctxt, i) )
            goto out;
        dest_paddr = *xencomm_ctxt_address(&ctxt);
        if ( dest_paddr == XENCOMM_INVALID )
        {
            i++;
            continue;
        }

        pgoffset = dest_paddr % PAGE_SIZE;
        chunksz = PAGE_SIZE - pgoffset;

        chunk_skip = min(chunksz, skip);
        to_pos += chunk_skip;
        chunksz -= chunk_skip;
        skip -= chunk_skip;

        if ( skip == 0 && chunksz > 0 )
        {
            unsigned int bytes = min(chunksz, n - from_pos);

            if ( xencomm_clear_chunk(dest_paddr + chunk_skip, bytes) )
                goto out;
            from_pos += bytes;
            to_pos += bytes;
        }

        i++;
    }

out:
    xencomm_ctxt_done(&ctxt);
    return n - from_pos;
}

static int xencomm_inline_add_offset(void **handle, unsigned int bytes)
{
    *handle += bytes;
    return 0;
}

/* Offset page addresses in 'handle' to skip 'bytes' bytes. Set completely
 * exhausted pages to XENCOMM_INVALID. */
int xencomm_add_offset(void **handle, unsigned int bytes)
{
    struct xencomm_ctxt ctxt;
    int i = 0;
    int res = 0;

    if ( xencomm_is_inline(*handle) )
        return xencomm_inline_add_offset(handle, bytes);

    res = xencomm_ctxt_init(handle, &ctxt);
    if ( res != 0 )
        return res;

    /* Iterate through the descriptor incrementing addresses */
    while ( (bytes > 0) && (i < xencomm_ctxt_nr_addrs(&ctxt)) )
    {
        unsigned long *address;
        unsigned long dest_paddr;
        unsigned int pgoffset, chunksz, chunk_skip;

        res = xencomm_ctxt_next(&ctxt, i);
        if ( res )
            goto out;
        address = xencomm_ctxt_address(&ctxt);
        dest_paddr = *address;
        if ( dest_paddr == XENCOMM_INVALID )
        {
            i++;
            continue;
        }

        pgoffset = dest_paddr % PAGE_SIZE;
        chunksz = PAGE_SIZE - pgoffset;

        chunk_skip = min(chunksz, bytes);
        if ( chunk_skip == chunksz )
            *address = XENCOMM_INVALID; /* exhausted this page */
        else
            *address += chunk_skip;
        bytes -= chunk_skip;

        i++;
    }

out:
    xencomm_ctxt_done(&ctxt);
    return res;
}

int xencomm_handle_is_null(void *handle)
{
    struct xencomm_ctxt ctxt;
    int i;
    int res = 1;

    if ( xencomm_is_inline(handle) )
        return xencomm_inline_addr(handle) == 0;

    if ( xencomm_ctxt_init(handle, &ctxt) )
        return 1;

    for ( i = 0; i < xencomm_ctxt_nr_addrs(&ctxt); i++ )
    {
        if ( xencomm_ctxt_next(&ctxt, i) )
            goto out;
        if ( *xencomm_ctxt_address(&ctxt) != XENCOMM_INVALID )
        {
            res = 0;
            goto out;
        }
    }

out:
    xencomm_ctxt_done(&ctxt);
    return res;
}

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */