Annotation of Gnu-Mach/xen/block.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *  Copyright (C) 2006-2009, 2011 Free Software Foundation
        !             3:  *
        !             4:  * This program is free software ; you can redistribute it and/or modify
        !             5:  * it under the terms of the GNU General Public License as published by
        !             6:  * the Free Software Foundation ; either version 2 of the License, or
        !             7:  * (at your option) any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful,
        !            10:  * but WITHOUT ANY WARRANTY ; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
        !            12:  * GNU General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License
        !            15:  * along with the program ; if not, write to the Free Software
        !            16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            17:  */
        !            18: 
        !            19: #include <sys/types.h>
        !            20: #include <mach/mig_errors.h>
        !            21: #include <kern/kalloc.h>
        !            22: #include <ipc/ipc_port.h>
        !            23: #include <ipc/ipc_space.h>
        !            24: #include <vm/vm_kern.h>
        !            25: #include <vm/vm_user.h>
        !            26: #include <device/device_types.h>
        !            27: #include <device/device_port.h>
        !            28: #include <device/disk_status.h>
        !            29: #include <device/device_reply.user.h>
        !            30: #include <device/device_emul.h>
        !            31: #include <device/ds_routines.h>
        !            32: #include <xen/public/io/blkif.h>
        !            33: #include <xen/evt.h>
        !            34: #include <string.h>
        !            35: #include <util/atoi.h>
        !            36: #include "store.h"
        !            37: #include "block.h"
        !            38: #include "grant.h"
        !            39: #include "ring.h"
        !            40: #include "xen.h"
        !            41: 
        !            42: /* Hypervisor part */
        !            43: 
        !            44: struct block_data {
        !            45:        struct device   device;
        !            46:        char            *name;
        !            47:        int             open_count;
        !            48:        char            *backend;
        !            49:        domid_t         domid;
        !            50:        char            *vbd;
        !            51:        int             handle;
        !            52:        unsigned        info;
        !            53:        dev_mode_t      mode;
        !            54:        unsigned        sector_size;
        !            55:        unsigned long   nr_sectors;
        !            56:        ipc_port_t      port;
        !            57:        blkif_front_ring_t      ring;
        !            58:        evtchn_port_t   evt;
        !            59:        simple_lock_data_t lock;
        !            60:        simple_lock_data_t pushlock;
        !            61: };
        !            62: 
        !            63: static int n_vbds;
        !            64: static struct block_data *vbd_data;
        !            65: 
        !            66: struct device_emulation_ops hyp_block_emulation_ops;
        !            67: 
        !            68: static void hyp_block_intr(int unit) {
        !            69:        struct block_data *bd = &vbd_data[unit];
        !            70:        blkif_response_t *rsp;
        !            71:        int more;
        !            72:        io_return_t *err;
        !            73: 
        !            74:        simple_lock(&bd->lock);
        !            75:        more = RING_HAS_UNCONSUMED_RESPONSES(&bd->ring);
        !            76:        while (more) {
        !            77:                rmb(); /* make sure we see responses */
        !            78:                rsp = RING_GET_RESPONSE(&bd->ring, bd->ring.rsp_cons++);
        !            79:                err = (void *) (unsigned long) rsp->id;
        !            80:                switch (rsp->status) {
        !            81:                case BLKIF_RSP_ERROR:
        !            82:                        *err = D_IO_ERROR;
        !            83:                        break;
        !            84:                case BLKIF_RSP_OKAY:
        !            85:                        break;
        !            86:                default:
        !            87:                        printf("Unrecognized blkif status %d\n", rsp->status);
        !            88:                        goto drop;
        !            89:                }
        !            90:                thread_wakeup(err);
        !            91: drop:
        !            92:                thread_wakeup_one(bd);
        !            93:                RING_FINAL_CHECK_FOR_RESPONSES(&bd->ring, more);
        !            94:        }
        !            95:        simple_unlock(&bd->lock);
        !            96: }
        !            97: 
        !            98: #define VBD_PATH "device/vbd"
        !            99: void hyp_block_init(void) {
        !           100:        char **vbds, **vbd;
        !           101:        char *c;
        !           102:        int i, disk, partition;
        !           103:        int n; 
        !           104:        int grant;
        !           105:        char port_name[10];
        !           106:        char *prefix;
        !           107:        char device_name[32];
        !           108:        domid_t domid;
        !           109:        evtchn_port_t evt;
        !           110:        hyp_store_transaction_t t;
        !           111:        vm_offset_t addr;
        !           112:        struct block_data *bd;
        !           113:        blkif_sring_t   *ring;
        !           114: 
        !           115:        vbds = hyp_store_ls(0, 1, VBD_PATH);
        !           116:        if (!vbds) {
        !           117:                printf("hd: No block device (%s). Hoping you don't need any\n", hyp_store_error);
        !           118:                n_vbds = 0;
        !           119:                return;
        !           120:        }
        !           121: 
        !           122:        n = 0;
        !           123:        for (vbd = vbds; *vbd; vbd++)
        !           124:                n++;
        !           125: 
        !           126:        vbd_data = (void*) kalloc(n * sizeof(*vbd_data));
        !           127:        if (!vbd_data) {
        !           128:                printf("hd: No memory room for VBD\n");
        !           129:                n_vbds = 0;
        !           130:                return;
        !           131:        }
        !           132:        n_vbds = n;
        !           133: 
        !           134:        for (n = 0; n < n_vbds; n++) {
        !           135:                bd = &vbd_data[n];
        !           136:                mach_atoi((u_char *) vbds[n], &bd->handle);
        !           137:                if (bd->handle == MACH_ATOI_DEFAULT)
        !           138:                        continue;
        !           139: 
        !           140:                bd->open_count = -2;
        !           141:                bd->vbd = vbds[n];
        !           142: 
        !           143:                /* Get virtual number.  */
        !           144:                i = hyp_store_read_int(0, 5, VBD_PATH, "/", vbds[n], "/", "virtual-device");
        !           145:                if (i == -1)
        !           146:                        panic("hd: couldn't virtual device of VBD %s\n",vbds[n]);
        !           147:                if ((i >> 28) == 1) {
        !           148:                        /* xvd, new format */
        !           149:                        prefix = "xvd";
        !           150:                        disk = (i >> 8) & ((1 << 20) - 1);
        !           151:                        partition = i & ((1 << 8) - 1);
        !           152:                } else if ((i >> 8) == 202) {
        !           153:                        /* xvd, old format */
        !           154:                        prefix = "xvd";
        !           155:                        disk = (i >> 4) & ((1 << 4) - 1);
        !           156:                        partition = i & ((1 << 4) - 1);
        !           157:                } else if ((i >> 8) == 8) {
        !           158:                        /* SCSI */
        !           159:                        prefix = "sd";
        !           160:                        disk = (i >> 4) & ((1 << 4) - 1);
        !           161:                        partition = i & ((1 << 4) - 1);
        !           162:                } else if ((i >> 8) == 3) {
        !           163:                        /* IDE primary */
        !           164:                        prefix = "hd";
        !           165:                        disk = (i >> 6) & ((1 << 2) - 1);
        !           166:                        partition = i & ((1 << 6) - 1);
        !           167:                } else if ((i >> 8) == 22) {
        !           168:                        /* IDE secondary */
        !           169:                        prefix = "hd";
        !           170:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 2;
        !           171:                        partition = i & ((1 << 6) - 1);
        !           172:                } else if ((i >> 8) == 33) {
        !           173:                        /* IDE 3 */
        !           174:                        prefix = "hd";
        !           175:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 4;
        !           176:                        partition = i & ((1 << 6) - 1);
        !           177:                } else if ((i >> 8) == 34) {
        !           178:                        /* IDE 4 */
        !           179:                        prefix = "hd";
        !           180:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 6;
        !           181:                        partition = i & ((1 << 6) - 1);
        !           182:                } else if ((i >> 8) == 56) {
        !           183:                        /* IDE 5 */
        !           184:                        prefix = "hd";
        !           185:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 8;
        !           186:                        partition = i & ((1 << 6) - 1);
        !           187:                } else if ((i >> 8) == 57) {
        !           188:                        /* IDE 6 */
        !           189:                        prefix = "hd";
        !           190:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 10;
        !           191:                        partition = i & ((1 << 6) - 1);
        !           192:                } else if ((i >> 8) == 88) {
        !           193:                        /* IDE 7 */
        !           194:                        prefix = "hd";
        !           195:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 12;
        !           196:                        partition = i & ((1 << 6) - 1);
        !           197:                } else if ((i >> 8) == 89) {
        !           198:                        /* IDE 8 */
        !           199:                        prefix = "hd";
        !           200:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 14;
        !           201:                        partition = i & ((1 << 6) - 1);
        !           202:                } else if ((i >> 8) == 90) {
        !           203:                        /* IDE 9 */
        !           204:                        prefix = "hd";
        !           205:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 16;
        !           206:                        partition = i & ((1 << 6) - 1);
        !           207:                } else if ((i >> 8) == 91) {
        !           208:                        /* IDE 10 */
        !           209:                        prefix = "hd";
        !           210:                        disk = ((i >> 6) & ((1 << 2) - 1)) + 18;
        !           211:                        partition = i & ((1 << 6) - 1);
        !           212:                } else {
        !           213:                        printf("unsupported VBD number %d\n", i);
        !           214:                        continue;
        !           215:                }
        !           216:                if (partition)
        !           217:                        sprintf(device_name, "%s%ds%d", prefix, disk, partition);
        !           218:                else
        !           219:                        sprintf(device_name, "%s%d", prefix, disk);
        !           220:                bd->name = (char*) kalloc(strlen(device_name));
        !           221:                strcpy(bd->name, device_name);
        !           222: 
        !           223:                /* Get domain id of backend driver.  */
        !           224:                i = hyp_store_read_int(0, 5, VBD_PATH, "/", vbds[n], "/", "backend-id");
        !           225:                if (i == -1)
        !           226:                        panic("%s: couldn't read backend domid (%s)", device_name, hyp_store_error);
        !           227:                bd->domid = domid = i;
        !           228: 
        !           229:                do {
        !           230:                        t = hyp_store_transaction_start();
        !           231: 
        !           232:                        /* Get a page for ring */
        !           233:                        if ((addr = vm_page_grab_phys_addr()) == -1)
        !           234:                                panic("%s: couldn't allocate space for store ring\n", device_name);
        !           235:                        ring = (void*) phystokv(addr);
        !           236:                        SHARED_RING_INIT(ring);
        !           237:                        FRONT_RING_INIT(&bd->ring, ring, PAGE_SIZE);
        !           238:                        grant = hyp_grant_give(domid, atop(addr), 0);
        !           239: 
        !           240:                        /* and give it to backend.  */
        !           241:                        i = sprintf(port_name, "%d", grant);
        !           242:                        c = hyp_store_write(t, port_name, 5, VBD_PATH, "/", vbds[n], "/", "ring-ref");
        !           243:                        if (!c)
        !           244:                                panic("%s: couldn't store ring reference (%s)", device_name, hyp_store_error);
        !           245:                        kfree((vm_offset_t) c, strlen(c)+1);
        !           246: 
        !           247:                        /* Allocate an event channel and give it to backend.  */
        !           248:                        bd->evt = evt = hyp_event_channel_alloc(domid);
        !           249:                        hyp_evt_handler(evt, hyp_block_intr, n, SPL7);
        !           250:                        i = sprintf(port_name, "%lu", evt);
        !           251:                        c = hyp_store_write(t, port_name, 5, VBD_PATH, "/", vbds[n], "/", "event-channel");
        !           252:                        if (!c)
        !           253:                                panic("%s: couldn't store event channel (%s)", device_name, hyp_store_error);
        !           254:                        kfree((vm_offset_t) c, strlen(c)+1);
        !           255:                        c = hyp_store_write(t, hyp_store_state_initialized, 5, VBD_PATH, "/", vbds[n], "/", "state");
        !           256:                        if (!c)
        !           257:                                panic("%s: couldn't store state (%s)", device_name, hyp_store_error);
        !           258:                        kfree((vm_offset_t) c, strlen(c)+1);
        !           259:                } while (!hyp_store_transaction_stop(t));
        !           260:        /* TODO randomly wait? */
        !           261: 
        !           262:                c = hyp_store_read(0, 5, VBD_PATH, "/", vbds[n], "/", "backend");
        !           263:                if (!c)
        !           264:                        panic("%s: couldn't get path to backend (%s)", device_name, hyp_store_error);
        !           265:                bd->backend = c;
        !           266: 
        !           267:                while(1) {
        !           268:                        i = hyp_store_read_int(0, 3, bd->backend, "/", "state");
        !           269:                        if (i == MACH_ATOI_DEFAULT)
        !           270:                                panic("can't read state from %s", bd->backend);
        !           271:                        if (i == XenbusStateConnected)
        !           272:                                break;
        !           273:                        hyp_yield();
        !           274:                }
        !           275: 
        !           276:                i = hyp_store_read_int(0, 3, bd->backend, "/", "sectors");
        !           277:                if (i == -1)
        !           278:                        panic("%s: couldn't get number of sectors (%s)", device_name, hyp_store_error);
        !           279:                bd->nr_sectors = i;
        !           280:                
        !           281:                i = hyp_store_read_int(0, 3, bd->backend, "/", "sector-size");
        !           282:                if (i == -1)
        !           283:                        panic("%s: couldn't get sector size (%s)", device_name, hyp_store_error);
        !           284:                if (i & ~(2*(i-1)+1))
        !           285:                        panic("sector size %d is not a power of 2\n", i);
        !           286:                if (i > PAGE_SIZE || PAGE_SIZE % i != 0)
        !           287:                        panic("%s: couldn't handle sector size %d with pages of size %d\n", device_name, i, PAGE_SIZE);
        !           288:                bd->sector_size = i;
        !           289: 
        !           290:                i = hyp_store_read_int(0, 3, bd->backend, "/", "info");
        !           291:                if (i == -1)
        !           292:                        panic("%s: couldn't get info (%s)", device_name, hyp_store_error);
        !           293:                bd->info = i;
        !           294:                
        !           295:                c = hyp_store_read(0, 3, bd->backend, "/", "mode");
        !           296:                if (!c)
        !           297:                        panic("%s: couldn't get backend's mode (%s)", device_name, hyp_store_error);
        !           298:                if ((c[0] == 'w') && !(bd->info & VDISK_READONLY))
        !           299:                        bd->mode = D_READ|D_WRITE;
        !           300:                else
        !           301:                        bd->mode = D_READ;
        !           302: 
        !           303:                c = hyp_store_read(0, 3, bd->backend, "/", "params");
        !           304:                if (!c)
        !           305:                        panic("%s: couldn't get backend's real device (%s)", device_name, hyp_store_error);
        !           306: 
        !           307:                /* TODO: change suffix */
        !           308:                printf("%s: dom%d's VBD %s (%s,%c%s) %ldMB\n", device_name, domid,
        !           309:                        vbds[n], c, bd->mode & D_WRITE ? 'w' : 'r',
        !           310:                        bd->info & VDISK_CDROM ? ", cdrom" : "",
        !           311:                        bd->nr_sectors / ((1<<20) / 512));
        !           312:                kfree((vm_offset_t) c, strlen(c)+1);
        !           313: 
        !           314:                c = hyp_store_write(0, hyp_store_state_connected, 5, VBD_PATH, "/", bd->vbd, "/", "state");
        !           315:                if (!c)
        !           316:                        panic("couldn't store state for %s (%s)", device_name, hyp_store_error);
        !           317:                kfree((vm_offset_t) c, strlen(c)+1);
        !           318: 
        !           319:                bd->open_count = -1;
        !           320:                bd->device.emul_ops = &hyp_block_emulation_ops;
        !           321:                bd->device.emul_data = bd;
        !           322:                simple_lock_init(&bd->lock);
        !           323:                simple_lock_init(&bd->pushlock);
        !           324:        }
        !           325: }
        !           326: 
        !           327: static ipc_port_t
        !           328: dev_to_port(void *d)
        !           329: {
        !           330:        struct block_data *b = d;
        !           331:        if (!d)
        !           332:                return IP_NULL;
        !           333:        return ipc_port_make_send(b->port);
        !           334: }
        !           335: 
        !           336: static int
        !           337: device_close(void *devp)
        !           338: {
        !           339:        struct block_data *bd = devp;
        !           340:        if (--bd->open_count < 0)
        !           341:                panic("too many closes on %s", bd->name);
        !           342:        printf("close, %s count %d\n", bd->name, bd->open_count);
        !           343:        if (bd->open_count)
        !           344:                return 0;
        !           345:        ipc_kobject_set(bd->port, IKO_NULL, IKOT_NONE);
        !           346:        ipc_port_dealloc_kernel(bd->port);
        !           347:        return 0;
        !           348: }
        !           349: 
        !           350: static io_return_t
        !           351: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
        !           352:            dev_mode_t mode, char *name, device_t *devp /* out */)
        !           353: {
        !           354:        int i, err = 0;
        !           355:        ipc_port_t port, notify;
        !           356:        struct block_data *bd;
        !           357: 
        !           358:        for (i = 0; i < n_vbds; i++)
        !           359:                if (!strcmp(name, vbd_data[i].name))
        !           360:                        break;
        !           361: 
        !           362:        if (i == n_vbds)
        !           363:                return D_NO_SUCH_DEVICE;
        !           364: 
        !           365:        bd = &vbd_data[i];
        !           366:        if (bd->open_count == -2)
        !           367:                /* couldn't be initialized */
        !           368:                return D_NO_SUCH_DEVICE;
        !           369: 
        !           370:        if ((mode & D_WRITE) && !(bd->mode & D_WRITE))
        !           371:                return D_READ_ONLY;
        !           372: 
        !           373:        if (bd->open_count >= 0) {
        !           374:                *devp = &bd->device ;
        !           375:                bd->open_count++ ;
        !           376:                printf("re-open, %s count %d\n", bd->name, bd->open_count);
        !           377:                return D_SUCCESS;
        !           378:        }
        !           379: 
        !           380:        bd->open_count = 1;
        !           381:        printf("%s count %d\n", bd->name, bd->open_count);
        !           382: 
        !           383:        port = ipc_port_alloc_kernel();
        !           384:        if (port == IP_NULL) {
        !           385:                err = KERN_RESOURCE_SHORTAGE;
        !           386:                goto out;
        !           387:        }
        !           388:        bd->port = port;
        !           389: 
        !           390:        *devp = &bd->device;
        !           391: 
        !           392:        ipc_kobject_set (port, (ipc_kobject_t) &bd->device, IKOT_DEVICE);
        !           393: 
        !           394:        notify = ipc_port_make_sonce (bd->port);
        !           395:        ip_lock (bd->port);
        !           396:        ipc_port_nsrequest (bd->port, 1, notify, &notify);
        !           397:        assert (notify == IP_NULL);
        !           398: 
        !           399: out:
        !           400:        if (IP_VALID (reply_port))
        !           401:                ds_device_open_reply (reply_port, reply_port_type, D_SUCCESS, port);
        !           402:        else
        !           403:                device_close(bd);
        !           404:        return MIG_NO_REPLY;
        !           405: }
        !           406: 
        !           407: static io_return_t
        !           408: device_read (void *d, ipc_port_t reply_port,
        !           409:             mach_msg_type_name_t reply_port_type, dev_mode_t mode,
        !           410:             recnum_t bn, int count, io_buf_ptr_t *data,
        !           411:             unsigned *bytes_read)
        !           412: {
        !           413:   int resid, amt;
        !           414:   io_return_t err = 0;
        !           415:   vm_page_t pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        !           416:   grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        !           417:   int nbpages;
        !           418:   vm_map_copy_t copy;
        !           419:   vm_offset_t offset, alloc_offset, o;
        !           420:   vm_object_t object;
        !           421:   vm_page_t m;
        !           422:   vm_size_t len, size;
        !           423:   struct block_data *bd = d;
        !           424:   struct blkif_request *req;
        !           425: 
        !           426:   *data = 0;
        !           427:   *bytes_read = 0;
        !           428: 
        !           429:   if (count < 0)
        !           430:     return D_INVALID_SIZE;
        !           431:   if (count == 0)
        !           432:     return 0;
        !           433: 
        !           434:   /* Allocate an object to hold the data.  */
        !           435:   size = round_page (count);
        !           436:   object = vm_object_allocate (size);
        !           437:   if (! object)
        !           438:     {
        !           439:       err = D_NO_MEMORY;
        !           440:       goto out;
        !           441:     }
        !           442:   alloc_offset = offset = 0;
        !           443:   resid = count;
        !           444: 
        !           445:   while (resid && !err)
        !           446:     {
        !           447:       unsigned reqn;
        !           448:       int i;
        !           449:       int last_sect;
        !           450: 
        !           451:       nbpages = 0;
        !           452: 
        !           453:       /* Determine size of I/O this time around.  */
        !           454:       len = round_page(offset + resid) - offset;
        !           455:       if (len > PAGE_SIZE * BLKIF_MAX_SEGMENTS_PER_REQUEST)
        !           456:        len = PAGE_SIZE * BLKIF_MAX_SEGMENTS_PER_REQUEST;
        !           457: 
        !           458:       /* Allocate pages.  */
        !           459:       while (alloc_offset < offset + len)
        !           460:        {
        !           461:          while ((m = vm_page_grab (FALSE)) == 0)
        !           462:            VM_PAGE_WAIT (0);
        !           463:          assert (! m->active && ! m->inactive);
        !           464:          m->busy = TRUE;
        !           465:          assert(nbpages < BLKIF_MAX_SEGMENTS_PER_REQUEST);
        !           466:          pages[nbpages++] = m;
        !           467:          alloc_offset += PAGE_SIZE;
        !           468:        }
        !           469: 
        !           470:       /* Do the read.  */
        !           471:       amt = len;
        !           472:       if (amt > resid)
        !           473:        amt = resid;
        !           474: 
        !           475:       /* allocate a request */
        !           476:       spl_t spl = splsched();
        !           477:       while(1) {
        !           478:         simple_lock(&bd->lock);
        !           479:         if (!RING_FULL(&bd->ring))
        !           480:          break;
        !           481:        thread_sleep(bd, &bd->lock, FALSE);
        !           482:       }
        !           483:       mb();
        !           484:       reqn = bd->ring.req_prod_pvt++;;
        !           485:       simple_lock(&bd->pushlock);
        !           486:       simple_unlock(&bd->lock);
        !           487:       (void) splx(spl);
        !           488: 
        !           489:       req = RING_GET_REQUEST(&bd->ring, reqn);
        !           490:       req->operation = BLKIF_OP_READ;
        !           491:       req->nr_segments = nbpages;
        !           492:       req->handle = bd->handle;
        !           493:       req->id = (unsigned64_t) (unsigned long) &err; /* pointer on the stack */
        !           494:       req->sector_number = bn + offset / 512;
        !           495:       for (i = 0; i < nbpages; i++) {
        !           496:        req->seg[i].gref = gref[i] = hyp_grant_give(bd->domid, atop(pages[i]->phys_addr), 0);
        !           497:        req->seg[i].first_sect = 0;
        !           498:        req->seg[i].last_sect = PAGE_SIZE/512 - 1;
        !           499:       }
        !           500:       last_sect = ((amt - 1) & PAGE_MASK) / 512;
        !           501:       req->seg[nbpages-1].last_sect = last_sect;
        !           502: 
        !           503:       memset((void*) phystokv(pages[nbpages-1]->phys_addr
        !           504:              + (last_sect + 1) * 512),
        !           505:              0, PAGE_SIZE - (last_sect + 1) * 512);
        !           506: 
        !           507:       /* no need for a lock: as long as the request is not pushed, the event won't be triggered */
        !           508:       assert_wait((event_t) &err, FALSE);
        !           509: 
        !           510:       int notify;
        !           511:       wmb(); /* make sure it sees requests */
        !           512:       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bd->ring, notify);
        !           513:       if (notify)
        !           514:        hyp_event_channel_send(bd->evt);
        !           515:       simple_unlock(&bd->pushlock);
        !           516: 
        !           517:       thread_block(NULL);
        !           518: 
        !           519:       if (err)
        !           520:        printf("error reading %d bytes at sector %ld\n", amt,
        !           521:          bn + offset / 512);
        !           522: 
        !           523:       for (i = 0; i < nbpages; i++)
        !           524:        hyp_grant_takeback(gref[i]);
        !           525: 
        !           526:       /* Compute number of pages to insert in object.  */
        !           527:       o = offset;
        !           528: 
        !           529:       resid -= amt;
        !           530:       if (resid == 0)
        !           531:        offset = o + len;
        !           532:       else
        !           533:        offset += amt;
        !           534: 
        !           535:       /* Add pages to the object.  */
        !           536:       vm_object_lock (object);
        !           537:       for (i = 0; i < nbpages; i++)
        !           538:         {
        !           539:          m = pages[i];
        !           540:          assert (m->busy);
        !           541:          vm_page_lock_queues ();
        !           542:          PAGE_WAKEUP_DONE (m);
        !           543:          m->dirty = TRUE;
        !           544:          vm_page_insert (m, object, o);
        !           545:          vm_page_unlock_queues ();
        !           546:          o += PAGE_SIZE;
        !           547:        }
        !           548:       vm_object_unlock (object);
        !           549:     }
        !           550: 
        !           551: out:
        !           552:   if (! err)
        !           553:     err = vm_map_copyin_object (object, 0, round_page (count), &copy);
        !           554:   if (! err)
        !           555:     {
        !           556:       *data = (io_buf_ptr_t) copy;
        !           557:       *bytes_read = count - resid;
        !           558:     }
        !           559:   else
        !           560:     vm_object_deallocate (object);
        !           561:   return err;
        !           562: }
        !           563: 
        !           564: static io_return_t
        !           565: device_write(void *d, ipc_port_t reply_port,
        !           566:            mach_msg_type_name_t reply_port_type, dev_mode_t mode,
        !           567:            recnum_t bn, io_buf_ptr_t data, unsigned int count,
        !           568:            int *bytes_written)
        !           569: {
        !           570:   io_return_t err = 0;
        !           571:   vm_map_copy_t copy = (vm_map_copy_t) data;
        !           572:   vm_offset_t aligned_buffer = 0;
        !           573:   int copy_npages = atop(round_page(count));
        !           574:   vm_offset_t phys_addrs[copy_npages];
        !           575:   struct block_data *bd = d;
        !           576:   blkif_request_t *req;
        !           577:   grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        !           578:   unsigned reqn, size;
        !           579:   int i, nbpages, j;
        !           580: 
        !           581:   if (!(bd->mode & D_WRITE))
        !           582:     return D_READ_ONLY;
        !           583: 
        !           584:   if (count == 0) {
        !           585:     vm_map_copy_discard(copy);
        !           586:     return 0;
        !           587:   }
        !           588: 
        !           589:   if (count % bd->sector_size)
        !           590:     return D_INVALID_SIZE;
        !           591: 
        !           592:   if (count > copy->size)
        !           593:     return D_INVALID_SIZE;
        !           594: 
        !           595:   if (copy->type != VM_MAP_COPY_PAGE_LIST || copy->offset & PAGE_MASK) {
        !           596:     /* Unaligned write.  Has to copy data before passing it to the backend.  */
        !           597:     kern_return_t kr;
        !           598:     vm_offset_t buffer;
        !           599: 
        !           600:     kr = kmem_alloc(device_io_map, &aligned_buffer, count);
        !           601:     if (kr != KERN_SUCCESS)
        !           602:       return kr;
        !           603: 
        !           604:     kr = vm_map_copyout(device_io_map, &buffer, vm_map_copy_copy(copy));
        !           605:     if (kr != KERN_SUCCESS) {
        !           606:       kmem_free(device_io_map, aligned_buffer, count);
        !           607:       return kr;
        !           608:     }
        !           609: 
        !           610:     memcpy((void*) aligned_buffer, (void*) buffer, count);
        !           611: 
        !           612:     vm_deallocate (device_io_map, buffer, count);
        !           613: 
        !           614:     for (i = 0; i < copy_npages; i++)
        !           615:       phys_addrs[i] = kvtophys(aligned_buffer + ptoa(i));
        !           616:   } else {
        !           617:     for (i = 0; i < copy_npages; i++)
        !           618:       phys_addrs[i] = copy->cpy_page_list[i]->phys_addr;
        !           619:   }
        !           620: 
        !           621:   for (i=0; i<copy_npages; i+=nbpages) {
        !           622: 
        !           623:     nbpages = BLKIF_MAX_SEGMENTS_PER_REQUEST;
        !           624:     if (nbpages > copy_npages-i)
        !           625:       nbpages = copy_npages-i;
        !           626: 
        !           627:     /* allocate a request */
        !           628:     spl_t spl = splsched();
        !           629:     while(1) {
        !           630:       simple_lock(&bd->lock);
        !           631:       if (!RING_FULL(&bd->ring))
        !           632:        break;
        !           633:       thread_sleep(bd, &bd->lock, FALSE);
        !           634:     }
        !           635:     mb();
        !           636:     reqn = bd->ring.req_prod_pvt++;;
        !           637:     simple_lock(&bd->pushlock);
        !           638:     simple_unlock(&bd->lock);
        !           639:     (void) splx(spl);
        !           640: 
        !           641:     req = RING_GET_REQUEST(&bd->ring, reqn);
        !           642:     req->operation = BLKIF_OP_WRITE;
        !           643:     req->nr_segments = nbpages;
        !           644:     req->handle = bd->handle;
        !           645:     req->id = (unsigned64_t) (unsigned long) &err; /* pointer on the stack */
        !           646:     req->sector_number = bn + i*PAGE_SIZE / 512;
        !           647: 
        !           648:     for (j = 0; j < nbpages; j++) {
        !           649:       req->seg[j].gref = gref[j] = hyp_grant_give(bd->domid, atop(phys_addrs[i + j]), 1);
        !           650:       req->seg[j].first_sect = 0;
        !           651:       size = PAGE_SIZE;
        !           652:       if ((i + j + 1) * PAGE_SIZE > count)
        !           653:        size = count - (i + j) * PAGE_SIZE;
        !           654:       req->seg[j].last_sect = size/512 - 1;
        !           655:     }
        !           656: 
        !           657:     /* no need for a lock: as long as the request is not pushed, the event won't be triggered */
        !           658:     assert_wait((event_t) &err, FALSE);
        !           659: 
        !           660:     int notify;
        !           661:     wmb(); /* make sure it sees requests */
        !           662:     RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bd->ring, notify);
        !           663:     if (notify)
        !           664:            hyp_event_channel_send(bd->evt);
        !           665:     simple_unlock(&bd->pushlock);
        !           666: 
        !           667:     thread_block(NULL);
        !           668: 
        !           669:     for (j = 0; j < nbpages; j++)
        !           670:       hyp_grant_takeback(gref[j]);
        !           671: 
        !           672:     if (err) {
        !           673:       printf("error writing %u bytes at sector %d\n", count, bn);
        !           674:       break;
        !           675:     }
        !           676:   }
        !           677: 
        !           678:   if (aligned_buffer)
        !           679:     kmem_free(device_io_map, aligned_buffer, count);
        !           680: 
        !           681:   vm_map_copy_discard (copy);
        !           682: 
        !           683:   if (!err)
        !           684:     *bytes_written = count;
        !           685: 
        !           686:   if (IP_VALID(reply_port))
        !           687:     ds_device_write_reply (reply_port, reply_port_type, err, count);
        !           688: 
        !           689:   return MIG_NO_REPLY;
        !           690: }
        !           691: 
        !           692: static io_return_t
        !           693: device_get_status(void *d, dev_flavor_t flavor, dev_status_t status,
        !           694:                  mach_msg_type_number_t *status_count)
        !           695: {
        !           696:        struct block_data *bd = d;
        !           697: 
        !           698:        switch (flavor)
        !           699:        {
        !           700:                case DEV_GET_SIZE:
        !           701:                        status[DEV_GET_SIZE_DEVICE_SIZE] = (unsigned long long) bd->nr_sectors * 512;
        !           702:                        status[DEV_GET_SIZE_RECORD_SIZE] = bd->sector_size;
        !           703:                        *status_count = DEV_GET_SIZE_COUNT;
        !           704:                        break;
        !           705:                case DEV_GET_RECORDS:
        !           706:                        status[DEV_GET_RECORDS_DEVICE_RECORDS] = ((unsigned long long) bd->nr_sectors * 512) / bd->sector_size;
        !           707:                        status[DEV_GET_RECORDS_RECORD_SIZE] = bd->sector_size;
        !           708:                        *status_count = DEV_GET_RECORDS_COUNT;
        !           709:                        break;
        !           710:                default:
        !           711:                        printf("TODO: block_%s(%d)\n", __func__, flavor);
        !           712:                        return D_INVALID_OPERATION;
        !           713:        }
        !           714:        return D_SUCCESS;
        !           715: }
        !           716: 
        !           717: struct device_emulation_ops hyp_block_emulation_ops = {
        !           718:        NULL,   /* dereference */
        !           719:        NULL,   /* deallocate */
        !           720:        dev_to_port,
        !           721:        device_open,
        !           722:        device_close,
        !           723:        device_write,
        !           724:        NULL,   /* write_inband */
        !           725:        device_read,
        !           726:        NULL,   /* read_inband */
        !           727:        NULL,   /* set_status */
        !           728:        device_get_status,
        !           729:        NULL,   /* set_filter */
        !           730:        NULL,   /* map */
        !           731:        NULL,   /* no_senders */
        !           732:        NULL,   /* write_trap */
        !           733:        NULL,   /* writev_trap */
        !           734: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.