1/* 2 * Copyright (c) 2014, University of Washington. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <assert.h> 13#include <unistd.h> 14#include <errno.h> 15#include <sys/types.h> 16#include <sys/stat.h> 17#include <fcntl.h> 18#include <string.h> 19#include <errors/errno.h> 20#include <storage/vsic.h> 21#include <storage/vsa.h> 22 23//#define DO_ACTUAL_IO 24 25#define MAX_CBS 1000 26 27#define CPU_FREQ 2200 // MHz 28#define READ_LATENCY (1 * CPU_FREQ) // us 29#define WRITE_LATENCY (15 * CPU_FREQ) // us 30#define FLUSH_LATENCY (0 * CPU_FREQ) // us 31 32enum ramcb_cmd { 33 CMD_READ, 34 CMD_WRITE, 35 CMD_FLUSH 36}; 37 38struct ramcb { 39 uint64_t execute_time; 40 off_t offset; 41 void *buf; 42 size_t nbytes; 43 void *handle; 44 enum ramcb_cmd cmd; 45}; 46 47struct ram_vsic { 48 void *vsa_area; 49 struct ramcb cb[MAX_CBS]; 50 const struct ramcb *cb_list[MAX_CBS]; 51}; 52 53#ifndef BARRELFISH 54static inline uint64_t rdtsc(void) 55{ 56 uint32_t eax, edx; 57 __asm volatile ("rdtsc" : "=a" (eax), "=d" (edx)); 58 return ((uint64_t)edx << 32) | eax; 59} 60#endif 61 62static struct ramcb *get_ramcb(struct ram_vsic *vsic) 63{ 64 for(int i = 0; i < MAX_CBS; i++) { 65 if(vsic->cb_list[i] == NULL) { 66 vsic->cb_list[i] = &vsic->cb[i]; 67 return &vsic->cb[i]; 68 } 69 } 70 71 return NULL; 72} 73 74static errval_t vsic_write(struct storage_vsic *vsic, struct storage_vsa *vsa, 75 off_t offset, size_t size, void *buffer) 76{ 77 assert(vsic != NULL); 78 assert(vsa != NULL); 79 assert(buffer != NULL); 80 struct ram_vsic *mydata = vsic->data; 81 struct ramcb *cb = get_ramcb(mydata); 82 assert(cb != NULL); 83 84#ifdef DO_ACTUAL_IO 85 memcpy(mydata->vsa_area + offset, buffer, size); 86#endif 87 88 cb->execute_time = rdtsc() + WRITE_LATENCY; 89 cb->offset = offset; 90 cb->buf = buffer; 91 cb->nbytes = size; 92 cb->cmd = CMD_WRITE; 93 cb->handle = NULL; 94 95 return SYS_ERR_OK; 96} 97 98static errval_t vsic_read(struct storage_vsic *vsic, struct storage_vsa *vsa, 99 off_t offset, size_t size, void *buffer) 100{ 101 assert(vsic != NULL); 102 assert(vsa != NULL); 103 assert(buffer != NULL); 104 struct ram_vsic *mydata = vsic->data; 105 struct ramcb *cb = get_ramcb(mydata); 106 assert(cb != NULL); 107 108 cb->execute_time = rdtsc() + READ_LATENCY; 109 cb->offset = offset; 110 cb->buf = buffer; 111 cb->nbytes = size; 112 cb->cmd = CMD_READ; 113 cb->handle = NULL; 114 115 return SYS_ERR_OK; 116} 117 118static errval_t vsic_flush(struct storage_vsic *vsic, struct storage_vsa *vsa) 119{ 120 assert(vsic != NULL); 121 assert(vsa != NULL); 122 struct ram_vsic *mydata = vsic->data; 123 struct ramcb *cb = get_ramcb(mydata); 124 assert(cb != NULL); 125 126 cb->execute_time = rdtsc() + FLUSH_LATENCY; 127 cb->cmd = CMD_FLUSH; 128 cb->handle = NULL; 129 130 return SYS_ERR_OK; 131} 132 133static errval_t vsic_flush2(struct storage_vsic *vsic, struct storage_vsa *vsa, void *handle) 134{ 135 assert(vsic != NULL); 136 assert(vsa != NULL); 137 struct ram_vsic *mydata = vsic->data; 138 struct ramcb *cb = get_ramcb(mydata); 139 assert(cb != NULL); 140 141 cb->execute_time = rdtsc() + FLUSH_LATENCY; 142 cb->cmd = CMD_FLUSH; 143 cb->handle = handle; 144 145 return SYS_ERR_OK; 146} 147 148static errval_t vsic_poll(struct storage_vsic *vsic, void **handle) 149{ 150 assert(vsic != NULL); 151 struct ram_vsic *mydata = vsic->data; 152 153 for(int i = 0; i < MAX_CBS; i++) { 154 if(mydata->cb_list[i] != NULL) { 155 const struct ramcb *cb = mydata->cb_list[i]; 156 157 if(rdtsc() >= cb->execute_time) { 158#ifdef DO_ACTUAL_IO 159 if(cb->cmd == CMD_READ) { 160 memcpy(cb->buf, mydata->vsa_area + cb->offset, cb->size); 161 } 162#endif 163 164 // Completed successfully 165 mydata->cb_list[i] = NULL; 166 *handle = cb->handle; 167 return SYS_ERR_OK; 168 } 169 } 170 } 171 172 return FLOUNDER_ERR_TX_BUSY; 173} 174 175static errval_t vsic_wait(struct storage_vsic *vsic) 176{ 177 assert(vsic != NULL); 178 struct ram_vsic *mydata = vsic->data; 179 180 for(;;) { 181 int entries = 0; 182 183 for(int i = 0; i < MAX_CBS; i++) { 184 if(mydata->cb_list[i] != NULL) { 185 const struct ramcb *cb = mydata->cb_list[i]; 186 187 if(rdtsc() < cb->execute_time) { 188 // Still in progress 189 entries++; 190 } else { 191#ifdef DO_ACTUAL_IO 192 if(cb->cmd == CMD_READ) { 193 memcpy(cb->buf, mydata->vsa_area + cb->offset, cb->size); 194 } 195#endif 196 197 // Completed successfully 198 mydata->cb_list[i] = NULL; 199 } 200 } 201 } 202 203 if(entries == 0) { 204 break; 205 } 206 207 // TODO: Might want to sleep 208 } 209 210 return SYS_ERR_OK; 211} 212 213static struct storage_vsic_ops file_ops = { 214 .write = vsic_write, 215 .read = vsic_read, 216 .flush = vsic_flush, 217 .wait = vsic_wait, 218 .poll = vsic_poll, 219 .flush2 = vsic_flush2, 220}; 221 222errval_t storage_vsic_driver_init(int argc, const char **argv, 223 struct storage_vsic *vsic) 224{ 225 assert(vsic != NULL); 226 struct ram_vsic *mydata = malloc(sizeof(struct ram_vsic)); 227 assert(mydata != NULL); 228 memset(mydata, 0, sizeof(struct ram_vsic)); 229 230 mydata->vsa_area = malloc(10 * 1024 * 1024); 231 assert(mydata->vsa_area != NULL); 232 233 // Init VSIC data structures 234 vsic->ops = file_ops; 235 vsic->data = mydata; 236 vsic->blocksize = 512; // XXX: Determine from drive? 237 238 return SYS_ERR_OK; 239} 240 241errval_t storage_vsa_acquire(struct storage_vsa *vsa, const char *name, 242 size_t size) 243{ 244 return SYS_ERR_OK; 245} 246 247#if 0 248errval_t storage_vsa_resize(struct storage_vsa *vsa, size_t size) 249{ 250 // No-op 251 return SYS_ERR_OK; 252} 253#endif 254