Matthew Fioravante
2012-Sep-27 17:09 UTC
[PATCH 01/11] Add ioread/iowrite functions to mini-os
This patch adds iowritexx() and ioreadxx() functions for interacting with hardware memory to mini-os. The functions are available in a header iorw.h Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/extras/mini-os/arch/ia64/iorw.c b/extras/mini-os/arch/ia64/iorw.c new file mode 100644 index 0000000..aa58807 --- /dev/null +++ b/extras/mini-os/arch/ia64/iorw.c @@ -0,0 +1,48 @@ +#include <mini-os/iorw.h> +#include <mini-os/console.h> + +void iowrite8(volatile void* addr, uint8_t val) +{ + printk("iorw not implemented!!\n"); + BUG(); +} +void iowrite16(volatile void* addr, uint16_t val) +{ + printk("iorw not implemented!!\n"); + BUG(); +} +void iowrite32(volatile void* addr, uint32_t val) +{ + printk("iorw not implemented!!\n"); + BUG(); +} +void iowrite64(volatile void* addr, uint64_t val) +{ + printk("iorw not implemented!!\n"); + BUG(); +} + +uint8_t ioread8(volatile void* addr) +{ + printk("iorw not implemented!!\n"); + BUG(); + return 0; +} +uint16_t ioread16(volatile void* addr) +{ + printk("iorw not implemented!!\n"); + BUG(); + return 0; +} +uint32_t ioread32(volatile void* addr) +{ + printk("iorw not implemented!!\n"); + BUG(); + return 0; +} +uint64_t ioread64(volatile void* addr) +{ + printk("iorw not implemented!!\n"); + BUG(); + return 0; +} diff --git a/extras/mini-os/arch/x86/iorw.c b/extras/mini-os/arch/x86/iorw.c new file mode 100644 index 0000000..3080769 --- /dev/null +++ b/extras/mini-os/arch/x86/iorw.c @@ -0,0 +1,35 @@ +#include <mini-os/iorw.h> + +void iowrite8(volatile void* addr, uint8_t val) +{ + *((volatile uint8_t*)addr) = val; +} +void iowrite16(volatile void* addr, uint16_t val) +{ + *((volatile uint16_t*)addr) = val; +} +void iowrite32(volatile void* addr, uint32_t val) +{ + *((volatile uint32_t*)addr) = val; +} +void iowrite64(volatile void* addr, uint64_t val) +{ + *((volatile uint64_t*)addr) = val; +} + +uint8_t ioread8(volatile void* addr) +{ + return *((volatile uint8_t*) addr); +} +uint16_t ioread16(volatile void* addr) +{ + return *((volatile uint16_t*) addr); +} +uint32_t ioread32(volatile void* addr) +{ + return *((volatile uint32_t*) addr); +} +uint64_t ioread64(volatile void* addr) +{ + return *((volatile uint64_t*) addr); +} diff --git a/extras/mini-os/include/iorw.h b/extras/mini-os/include/iorw.h new file mode 100644 index 0000000..d5ec065 --- /dev/null +++ b/extras/mini-os/include/iorw.h @@ -0,0 +1,16 @@ +#ifndef MINIOS_IORW_H +#define MINIOS_IORW_H + +#include <mini-os/types.h> + +void iowrite8(volatile void* addr, uint8_t val); +void iowrite16(volatile void* addr, uint16_t val); +void iowrite32(volatile void* addr, uint32_t val); +void iowrite64(volatile void* addr, uint64_t val); + +uint8_t ioread8(volatile void* addr); +uint16_t ioread16(volatile void* addr); +uint32_t ioread32(volatile void* addr); +uint64_t ioread64(volatile void* addr); + +#endif -- 1.7.9.5
This patch adds posix io support (read,write,lseek) to block devices using blkfront. Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/extras/mini-os/blkfront.c b/extras/mini-os/blkfront.c index 74b8b26..66c65c9 100644 --- a/extras/mini-os/blkfront.c +++ b/extras/mini-os/blkfront.c @@ -392,6 +392,7 @@ void blkfront_aio(struct blkfront_aiocb *aiocbp, int write) static void blkfront_aio_cb(struct blkfront_aiocb *aiocbp, int ret) { aiocbp->data = (void*) 1; + aiocbp->aio_cb = NULL; } void blkfront_io(struct blkfront_aiocb *aiocbp, int write) @@ -547,9 +548,150 @@ moretodo: #ifdef HAVE_LIBC int blkfront_open(struct blkfront_dev *dev) { + /* Silently prevent multiple opens */ + if(dev->fd != -1) { + return dev->fd; + } dev->fd = alloc_fd(FTYPE_BLK); printk("blk_open(%s) -> %d\n", dev->nodename, dev->fd); files[dev->fd].blk.dev = dev; + files[dev->fd].blk.offset = 0; return dev->fd; } + +int blkfront_posix_rwop(int fd, uint8_t* buf, size_t count, int write) +{ + struct blkfront_dev* dev = files[fd].blk.dev; + off_t offset = files[fd].blk.offset; + struct blkfront_aiocb aiocb; + unsigned long long disksize = dev->info.sectors * dev->info.sector_size; + unsigned int blocksize = dev->info.sector_size; + + int blknum; + int blkoff; + size_t bytes; + int rc = 0; + int alignedbuf = 0; + uint8_t* copybuf = NULL; + + /* RW 0 bytes is just a NOP */ + if(count == 0) { + return 0; + } + /* Check for NULL buffer */ + if( buf == NULL ) { + errno = EFAULT; + return -1; + } + + /* Write mode checks */ + if(write) { + /*Make sure we have write permission */ + if(dev->info.info & VDISK_READONLY || (dev->info.mode != O_RDWR && dev->info.mode != O_WRONLY)) { + errno = EACCES; + return -1; + } + /*Make sure disk is big enough for this write */ + if(offset + count > disksize) { + errno = ENOSPC; + return -1; + } + } + /* Read mode checks */ + else + { + /*If the requested read is bigger than the disk, just + * read as much as we can until the end */ + if(offset + count > disksize) { + count = offset >= disksize ? 0 : disksize - offset; + } + } + /* Determine which block to start at and which offset inside of it */ + blknum = offset / blocksize; + blkoff = offset % blocksize; + + /* Optimization: We need to check if buf is aligned to the sector size. + * This is somewhat tricky code. We have to add the blocksize - block offset + * because the first block may be a partial block and then for every subsequent + * block rw the buffer will be offset.*/ + if(!((uintptr_t) (buf +(blocksize - blkoff)) & (dev->info.sector_size-1))) { + alignedbuf = 1; + } + + /* Setup aiocb block object */ + aiocb.aio_dev = dev; + aiocb.aio_nbytes = blocksize; + aiocb.aio_offset = blknum * blocksize; + aiocb.aio_cb = NULL; + aiocb.data = NULL; + + /* If our buffer is unaligned or its aligned but we will need to rw a partial block + * then a copy will have to be done */ + if(!alignedbuf || blkoff != 0 || count % blocksize != 0) { + copybuf = _xmalloc(blocksize, dev->info.sector_size); + } + + rc = count; + while(count > 0) { + /* determine how many bytes to read/write from/to the current block buffer */ + bytes = count > (blocksize - blkoff) ? blocksize - blkoff : count; + + /* read operation */ + if(!write) { + if (alignedbuf && bytes >= blocksize) { + /* If aligned and were reading a whole block, just read right into buf */ + aiocb.aio_buf = buf; + blkfront_read(&aiocb); + } else { + /* If not then we have to do a copy */ + aiocb.aio_buf = copybuf; + blkfront_read(&aiocb); + memcpy(buf, ©buf[blkoff], bytes); + } + } + /* Write operation */ + else { + if(alignedbuf && bytes >= blocksize) { + /* If aligned and were writing a whole block, just write directly from buf */ + aiocb.aio_buf = buf; + blkfront_write(&aiocb); + } else { + /* If not then we have to do a copy. */ + aiocb.aio_buf = copybuf; + /* If we''re writing a partial block, we need to read the current contents first + * so we don''t overwrite the extra bits with garbage */ + if(blkoff != 0 || bytes < blocksize) { + blkfront_read(&aiocb); + } + memcpy(©buf[blkoff], buf, bytes); + blkfront_write(&aiocb); + } + } + /* Will start at beginning of all remaining blocks */ + blkoff = 0; + + /* Increment counters and continue */ + count -= bytes; + buf += bytes; + aiocb.aio_offset += blocksize; + } + + free(copybuf); + files[fd].blk.offset += rc; + return rc; + +} + +int blkfront_posix_fstat(int fd, struct stat* buf) +{ + struct blkfront_dev* dev = files[fd].blk.dev; + + buf->st_mode = dev->info.mode; + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_size = dev->info.sectors * dev->info.sector_size; + buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL); + + return 0; +} #endif diff --git a/extras/mini-os/include/blkfront.h b/extras/mini-os/include/blkfront.h index 724137e..3528af9 100644 --- a/extras/mini-os/include/blkfront.h +++ b/extras/mini-os/include/blkfront.h @@ -28,7 +28,17 @@ struct blkfront_info }; struct blkfront_dev *init_blkfront(char *nodename, struct blkfront_info *info); #ifdef HAVE_LIBC +#include <sys/stat.h> +/* POSIX IO functions: + * use blkfront_open() to get a file descriptor to the block device + * Don''t use the other blkfront posix functions here directly, instead use + * read(), write(), lseek() and fstat() on the file descriptor + */ int blkfront_open(struct blkfront_dev *dev); +int blkfront_posix_rwop(int fd, uint8_t* buf, size_t count, int write); +#define blkfront_posix_write(fd, buf, count) blkfront_posix_rwop(fd, (uint8_t*)buf, count, 1) +#define blkfront_posix_read(fd, buf, count) blkfront_posix_rwop(fd, (uint8_t*)buf, count, 0) +int blkfront_posix_fstat(int fd, struct stat* buf); #endif void blkfront_aio(struct blkfront_aiocb *aiocbp, int write); #define blkfront_aio_read(aiocbp) blkfront_aio(aiocbp, 0) diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h index 1af2717..d4641b6 100644 --- a/extras/mini-os/include/lib.h +++ b/extras/mini-os/include/lib.h @@ -174,6 +174,7 @@ extern struct file { } tap; struct { struct blkfront_dev *dev; + off_t offset; } blk; struct { struct kbdfront_dev *dev; diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c index a7d35d6..7ddbbf8 100644 --- a/extras/mini-os/lib/sys.c +++ b/extras/mini-os/lib/sys.c @@ -289,6 +289,11 @@ int read(int fd, void *buf, size_t nbytes) return ret * sizeof(union xenfb_in_event); } #endif +#ifdef CONFIG_BLKFRONT + case FTYPE_BLK: { + return blkfront_posix_read(fd, buf, nbytes); + } +#endif default: break; } @@ -321,6 +326,10 @@ int write(int fd, const void *buf, size_t nbytes) netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes); return nbytes; #endif +#ifdef CONFIG_BLKFRONT + case FTYPE_BLK: + return blkfront_posix_write(fd, buf, nbytes); +#endif default: break; } @@ -331,8 +340,37 @@ int write(int fd, const void *buf, size_t nbytes) off_t lseek(int fd, off_t offset, int whence) { - errno = ESPIPE; - return (off_t) -1; + switch(files[fd].type) { +#ifdef CONFIG_BLKFRONT + case FTYPE_BLK: + switch (whence) { + case SEEK_SET: + files[fd].file.offset = offset; + break; + case SEEK_CUR: + files[fd].file.offset += offset; + break; + case SEEK_END: + { + struct stat st; + int ret; + ret = fstat(fd, &st); + if (ret) + return -1; + files[fd].file.offset = st.st_size + offset; + break; + } + default: + errno = EINVAL; + return -1; + } + return files[fd].file.offset; + break; +#endif + default: /* Not implemented on this FTYPE */ + errno = ESPIPE; + return (off_t) -1; + } } int fsync(int fd) { @@ -445,6 +483,10 @@ int fstat(int fd, struct stat *buf) buf->st_ctime = time(NULL); return 0; } +#ifdef CONFIG_BLKFRONT + case FTYPE_BLK: + return blkfront_posix_fstat(fd, buf); +#endif default: break; } -- 1.7.9.5
Matthew Fioravante
2012-Sep-27 17:09 UTC
[PATCH 03/11] Add endian, byteswap, and wordsize macros to mini-os
This patch addes byte swapping macros and endian support to mini-os. Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/extras/mini-os/include/byteorder.h b/extras/mini-os/include/byteorder.h new file mode 100644 index 0000000..c0e29df --- /dev/null +++ b/extras/mini-os/include/byteorder.h @@ -0,0 +1,36 @@ +#ifndef MINIOS_BYTEORDER_H +#define MINIOS_BYTEORDER_H + +#include <mini-os/byteswap.h> +#include <mini-os/endian.h> + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define be16_to_cpu(v) bswap_16(v) +#define be32_to_cpu(v) bswap_32(v) +#define be64_to_cpu(v) bswap_64(v) + +#define le16_to_cpu(v) (v) +#define le32_to_cpu(v) (v) +#define le64_to_cpu(v) (v) + +#else /*__BIG_ENDIAN*/ +#define be16_to_cpu(v) (v) +#define be32_to_cpu(v) (v) +#define be64_to_cpu(v) (v) + +#define le16_to_cpu(v) bswap_16(v) +#define le32_to_cpu(v) bswap_32(v) +#define le64_to_cpu(v) bswap_64(v) + +#endif + +#define cpu_to_be16(v) be16_to_cpu(v) +#define cpu_to_be32(v) be32_to_cpu(v) +#define cpu_to_be64(v) be64_to_cpu(v) + +#define cpu_to_le16(v) le16_to_cpu(v) +#define cpu_to_le32(v) le32_to_cpu(v) +#define cpu_to_le64(v) le64_to_cpu(v) + + +#endif diff --git a/extras/mini-os/include/byteswap.h b/extras/mini-os/include/byteswap.h index 46821ae..992c8bd 100644 --- a/extras/mini-os/include/byteswap.h +++ b/extras/mini-os/include/byteswap.h @@ -4,30 +4,36 @@ /* Unfortunately not provided by newlib. */ #include <mini-os/types.h> -static inline uint16_t bswap_16(uint16_t x) -{ - return - ((((x) & 0xff00) >> 8) | (((x) & 0xff) << 8)); -} - -static inline uint32_t bswap_32(uint32_t x) -{ - return - ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | - (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)); -} - -static inline uint64_t bswap_64(uint64_t x) -{ - return - ((((x) & 0xff00000000000000ULL) >> 56) | - (((x) & 0x00ff000000000000ULL) >> 40) | - (((x) & 0x0000ff0000000000ULL) >> 24) | - (((x) & 0x000000ff00000000ULL) >> 8) | - (((x) & 0x00000000ff000000ULL) << 8) | - (((x) & 0x0000000000ff0000ULL) << 24) | - (((x) & 0x000000000000ff00ULL) << 40) | - (((x) & 0x00000000000000ffULL) << 56)); -} + +#define bswap_16(x) ((uint16_t)( \ + (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(x) & (uint16_t)0xff00U) >> 8))) + +/* Use gcc optimized versions if they exist */ +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) +#define bswap_32(v) __builtin_bswap32(v) +#define bswap_64(v) __builtin_bswap64(v) +#else + +#define bswap_32(x) ((uint32_t)( \ + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24))) + +#define bswap_64(x) ((uint64_t)( \ + (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56))) + +#endif + + + #endif /* _BYTESWAP_H */ diff --git a/extras/mini-os/include/endian.h b/extras/mini-os/include/endian.h new file mode 100644 index 0000000..cdf432b --- /dev/null +++ b/extras/mini-os/include/endian.h @@ -0,0 +1,15 @@ +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 + +#define ARCH_ENDIAN_H +/* This will define __BYTE_ORDER for the current arch */ +#include <arch_endian.h> +#undef ARCH_ENDIAN_H + +#include <arch_wordsize.h> + +#endif /* endian.h */ diff --git a/extras/mini-os/include/ia64/arch_endian.h b/extras/mini-os/include/ia64/arch_endian.h new file mode 100644 index 0000000..0771683 --- /dev/null +++ b/extras/mini-os/include/ia64/arch_endian.h @@ -0,0 +1,7 @@ +#ifndef ARCH_ENDIAN_H +#error "Do not include arch_endian by itself, include endian.h" +#else + +#define __BYTE_ORDER __LITTLE_ENDIAN + +#endif diff --git a/extras/mini-os/include/ia64/arch_wordsize.h b/extras/mini-os/include/ia64/arch_wordsize.h new file mode 100644 index 0000000..1b5a00f --- /dev/null +++ b/extras/mini-os/include/ia64/arch_wordsize.h @@ -0,0 +1 @@ +#define __WORDSIZE 64 diff --git a/extras/mini-os/include/x86/arch_endian.h b/extras/mini-os/include/x86/arch_endian.h new file mode 100644 index 0000000..0771683 --- /dev/null +++ b/extras/mini-os/include/x86/arch_endian.h @@ -0,0 +1,7 @@ +#ifndef ARCH_ENDIAN_H +#error "Do not include arch_endian by itself, include endian.h" +#else + +#define __BYTE_ORDER __LITTLE_ENDIAN + +#endif diff --git a/extras/mini-os/include/x86/x86_32/arch_wordsize.h b/extras/mini-os/include/x86/x86_32/arch_wordsize.h new file mode 100644 index 0000000..b47eee9 --- /dev/null +++ b/extras/mini-os/include/x86/x86_32/arch_wordsize.h @@ -0,0 +1 @@ +#define __WORDSIZE 32 diff --git a/extras/mini-os/include/x86/x86_64/arch_wordsize.h b/extras/mini-os/include/x86/x86_64/arch_wordsize.h new file mode 100644 index 0000000..3048136 --- /dev/null +++ b/extras/mini-os/include/x86/x86_64/arch_wordsize.h @@ -0,0 +1,2 @@ +#define __WORDSIZE 64 +#define __WORDSIZE_COMPAT32 1 -- 1.7.9.5
Matthew Fioravante
2012-Sep-27 17:09 UTC
[PATCH 04/11] Disable the mfn_is_ram() check, it doesn''t work correctly on all systems
This patch disables the mfn_is_ram check in mini-os. The current check is insufficient and fails on some systems with larger than 4gb memory. Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c index 80aceac..5813a08 100644 --- a/extras/mini-os/arch/x86/mm.c +++ b/extras/mini-os/arch/x86/mm.c @@ -850,6 +850,8 @@ unsigned long alloc_contig_pages(int order, unsigned int addr_bits) static long system_ram_end_mfn; int mfn_is_ram(unsigned long mfn) { + /* This is broken on systems with large ammounts of ram. Always return 0 for now */ + return 0; /* very crude check if a given MFN is memory or not. Probably should * make this a little more sophisticated ;) */ return (mfn <= system_ram_end_mfn) ? 1 : 0; -- 1.7.9.5
This patch adds a CONFIG_XC option to mini-os, to allow conditional support for libxc for mini-os domains. Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile index c425f76..b4236e8 100644 --- a/extras/mini-os/Makefile +++ b/extras/mini-os/Makefile @@ -27,6 +27,7 @@ CONFIG_FBFRONT ?= y CONFIG_KBDFRONT ?= y CONFIG_CONSFRONT ?= y CONFIG_XENBUS ?= y +CONFIG_XC ?=y CONFIG_LWIP ?= $(lwip) # Export config items as compiler directives diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c index 7ddbbf8..6cb97b1 100644 --- a/extras/mini-os/lib/sys.c +++ b/extras/mini-os/lib/sys.c @@ -397,6 +397,7 @@ int close(int fd) return res; } #endif +#ifdef CONFIG_XC case FTYPE_XC: minios_interface_close_fd(fd); return 0; @@ -406,6 +407,7 @@ int close(int fd) case FTYPE_GNTMAP: minios_gnttab_close_fd(fd); return 0; +#endif #ifdef CONFIG_NETFRONT case FTYPE_TAP: shutdown_netfront(files[fd].tap.dev); @@ -1195,10 +1197,13 @@ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset if (fd == -1) return map_zero(n, 1); +#ifdef CONFIG_XC else if (files[fd].type == FTYPE_XC) { unsigned long zero = 0; return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, NULL, 0); - } else if (files[fd].type == FTYPE_MEM) { + } +#endif + else if (files[fd].type == FTYPE_MEM) { unsigned long first_mfn = offset >> PAGE_SHIFT; return map_frames_ex(&first_mfn, n, 0, 1, 1, DOMID_IO, NULL, _PAGE_PRESENT|_PAGE_RW); } else ASSERT(0); -- 1.7.9.5
Matthew Fioravante
2012-Sep-27 17:10 UTC
[PATCH 06/11] add select definition to sys/time.h when HAVE_LIBC is defined
This patch adds the select function to sys/time.h when HAVE_LIBC is defined, which is according to standard (see the select() manpage). Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/extras/mini-os/include/sys/time.h b/extras/mini-os/include/sys/time.h index d6623a4..3be3653 100644 --- a/extras/mini-os/include/sys/time.h +++ b/extras/mini-os/include/sys/time.h @@ -22,6 +22,7 @@ #ifdef HAVE_LIBC #include_next <sys/time.h> + #else struct timespec { time_t tv_sec; @@ -37,6 +38,10 @@ struct timeval { }; int gettimeofday(struct timeval *tv, void *tz); + +#endif +#ifdef HAVE_LIBC +#include <sys/select.h> #endif #endif /* _MINIOS_SYS_TIME_H_ */ -- 1.7.9.5
This patch adds floating point and sse support to mini-os by initializing the floating point unit and the see unit during domain boot up. Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> diff --git a/extras/mini-os/arch/x86/setup.c b/extras/mini-os/arch/x86/setup.c index 923901e..54046d3 100644 --- a/extras/mini-os/arch/x86/setup.c +++ b/extras/mini-os/arch/x86/setup.c @@ -74,9 +74,28 @@ shared_info_t *map_shared_info(unsigned long pa) return (shared_info_t *)shared_info; } +static inline void fpu_init(void) { + asm volatile("fninit"); +} + +#ifdef __SSE__ +static inline void sse_init(void) { + unsigned long status = 0x1f80; + asm volatile("ldmxcsr %0" : : "m" (status)); +} +#else +#define sse_init() +#endif + void arch_init(start_info_t *si) { + /*Initialize floating point unit */ + fpu_init(); + + /* Initialize SSE */ + sse_init(); + /* Copy the start_info struct to a globally-accessible area. */ /* WARN: don''t do printk before here, it uses information from shared_info. Use xprintk instead. */ @@ -99,6 +118,7 @@ arch_init(start_info_t *si) (unsigned long)failsafe_callback, 0); #endif + } void -- 1.7.9.5
Matthew Fioravante
2012-Sep-27 17:10 UTC
[PATCH 08/11] add tpmfront, tpm_tis, and tpmback drivers to mini-os
This patch adds 3 new drivers to mini-os. tpmfront - paravirtualized tpm frontend driver tpmback - paravirtualized tpm backend driver tpm_tis - hardware tpm driver Unfortunately these drivers were derived from GPL licensed linux kernel drivers so they must carry the GPL license. However, since mini-os now supports conditional compilation, hopefully these drivers can be included into the xen tree and conditionally removed from non-gpl projects. By default they are disabled in the makefile. Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile index b4236e8..02fab14 100644 --- a/extras/mini-os/Makefile +++ b/extras/mini-os/Makefile @@ -22,6 +22,9 @@ CONFIG_QEMU_XS_ARGS ?= n CONFIG_TEST ?= n CONFIG_PCIFRONT ?= n CONFIG_BLKFRONT ?= y +CONFIG_TPMFRONT ?= n +CONFIG_TPM_TIS ?= n +CONFIG_TPMBACK ?= n CONFIG_NETFRONT ?= y CONFIG_FBFRONT ?= y CONFIG_KBDFRONT ?= y @@ -36,6 +39,9 @@ flags-$(CONFIG_SPARSE_BSS) += -DCONFIG_SPARSE_BSS flags-$(CONFIG_QEMU_XS_ARGS) += -DCONFIG_QEMU_XS_ARGS flags-$(CONFIG_PCIFRONT) += -DCONFIG_PCIFRONT flags-$(CONFIG_BLKFRONT) += -DCONFIG_BLKFRONT +flags-$(CONFIG_TPMFRONT) += -DCONFIG_TPMFRONT +flags-$(CONFIG_TPM_TIS) += -DCONFIG_TPM_TIS +flags-$(CONFIG_TPMBACK) += -DCONFIG_TPMBACK flags-$(CONFIG_NETFRONT) += -DCONFIG_NETFRONT flags-$(CONFIG_KBDFRONT) += -DCONFIG_KBDFRONT flags-$(CONFIG_FBFRONT) += -DCONFIG_FBFRONT @@ -67,6 +73,9 @@ TARGET := mini-os SUBDIRS := lib xenbus console src-$(CONFIG_BLKFRONT) += blkfront.c +src-$(CONFIG_TPMFRONT) += tpmfront.c +src-$(CONFIG_TPM_TIS) += tpm_tis.c +src-$(CONFIG_TPMBACK) += tpmback.c src-y += daytime.c src-y += events.c src-$(CONFIG_FBFRONT) += fbfront.c diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h index d4641b6..935bede 100644 --- a/extras/mini-os/include/lib.h +++ b/extras/mini-os/include/lib.h @@ -142,6 +142,8 @@ enum fd_type { FTYPE_FB, FTYPE_MEM, FTYPE_SAVEFILE, + FTYPE_TPMFRONT, + FTYPE_TPM_TIS, }; LIST_HEAD(evtchn_port_list, evtchn_port_info); @@ -185,6 +187,20 @@ extern struct file { struct { struct consfront_dev *dev; } cons; +#ifdef CONFIG_TPMFRONT + struct { + struct tpmfront_dev *dev; + int respgot; + off_t offset; + } tpmfront; +#endif +#ifdef CONFIG_TPM_TIS + struct { + struct tpm_chip *dev; + int respgot; + off_t offset; + } tpm_tis; +#endif #ifdef CONFIG_XENBUS struct { /* To each xenbus FD is associated a queue of watch events for this diff --git a/extras/mini-os/include/tpm_tis.h b/extras/mini-os/include/tpm_tis.h new file mode 100644 index 0000000..b463cea --- /dev/null +++ b/extras/mini-os/include/tpm_tis.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2012 United States Government, as represented by + * the Secretary of Defense. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Based upon the files: + * drivers/char/tpm/tpm_tis.c + * drivers/char/tpm/tpm.c + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation + */ +#ifndef TPM_TIS_H +#define TPM_TIS_H + +#include <mini-os/types.h> +#include <mini-os/byteorder.h> + +#define TPM_TIS_EN_LOCL0 1 +#define TPM_TIS_EN_LOCL1 (1 << 1) +#define TPM_TIS_EN_LOCL2 (1 << 2) +#define TPM_TIS_EN_LOCL3 (1 << 3) +#define TPM_TIS_EN_LOCL4 (1 << 4) +#define TPM_TIS_EN_LOCLALL (TPM_TIS_EN_LOCL0 | TPM_TIS_EN_LOCL1 | TPM_TIS_EN_LOCL2 | TPM_TIS_EN_LOCL3 | TPM_TIS_EN_LOCL4) +#define TPM_TIS_LOCL_INT_TO_FLAG(x) (1 << x) +#define TPM_BASEADDR 0xFED40000 +#define TPM_PROBE_IRQ 0xFFFF + +struct tpm_chip; + +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities, unsigned int irq); +void shutdown_tpm_tis(struct tpm_chip* tpm); + +int tpm_tis_request_locality(struct tpm_chip* tpm, int locality); +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen, uint8_t** resp, size_t* resplen); + +#ifdef HAVE_LIBC +#include <sys/stat.h> +#include <fcntl.h> +/* POSIX IO functions: + * use tpm_tis_open() to get a file descriptor to the tpm device + * use write() on the fd to send a command to the backend. You must + * include the entire command in a single call to write(). + * use read() on the fd to read the response. You can use + * fstat() to get the size of the response and lseek() to seek on it. + */ +int tpm_tis_open(struct tpm_chip* tpm); +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count); +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count); +int tpm_tis_posix_fstat(int fd, struct stat* buf); +#endif + +#endif diff --git a/extras/mini-os/include/tpmback.h b/extras/mini-os/include/tpmback.h new file mode 100644 index 0000000..bc41d2c --- /dev/null +++ b/extras/mini-os/include/tpmback.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010-2012 United States Government, as represented by + * the Secretary of Defense. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Based upon the files: + * drivers/xen/tpmbk.c + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation + */ +#include <xen/io/tpmif.h> +#include <xen/io/xenbus.h> +#include <mini-os/types.h> +#include <xen/xen.h> +#ifndef TPMBACK_H +#define TPMBACK_H + +struct tpmcmd { + domid_t domid; /* Domid of the frontend */ + unsigned int handle; /* Handle of the frontend */ + char* uuid; /* uuid of the tpm interface - allocated internally, dont free it */ + + unsigned int req_len; /* Size of the command in buf - set by tpmback driver */ + uint8_t* req; /* tpm command bits, allocated by driver, DON''T FREE IT */ + unsigned int resp_len; /* Size of the outgoing command, + you set this before passing the cmd object to tpmback_resp */ + uint8_t* resp; /* Buffer for response - YOU MUST ALLOCATE IT, YOU MUST ALSO FREE IT */ +}; +typedef struct tpmcmd tpmcmd_t; + +/* Initialize the tpm backend driver + * @exclusive_domname - This is NULL terminated list of vtpm uuid strings. If this list + * is non-empty, then only frontend domains with vtpm uuid''s matching + * entries in this list will be allowed to connect. + * Other connections will be immediatly closed. + * Set this argument to NULL to allow any vtpm to connect. + */ +void init_tpmback(char** exclusive_uuids); +/* Shutdown tpm backend driver */ +void shutdown_tpmback(void); + +/* Blocks until a tpm command is sent from any front end. + * Returns a pointer to the tpm command to handle. + * Do not try to free this pointer or the req buffer + * This function will return NULL if the tpm backend driver + * is shutdown or any other error occurs */ +tpmcmd_t* tpmback_req_any(void); + +/* Blocks until a tpm command from the frontend at domid/handle + * is sent. + * Returns NULL if domid/handle is not connected, tpmback is + * shutdown or shutting down, or if there is an error + */ +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle); + +/* Send the response to the tpm command back to the frontend + * This function will free the tpmcmd object, but you must free the resp + * buffer yourself */ +void tpmback_resp(tpmcmd_t* tpmcmd); + +/* Waits for the first frontend to connect and then sets domid and handle appropriately. + * If one or more frontends are already connected, this will set domid and handle to one + * of them arbitrarily. The main use for this function is to wait until a single + * frontend connection has occured. + * returns 0 on success, non-zero on failure */ +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int *handle); + +/* returns the number of frontends connected */ +int tpmback_num_frontends(void); + +/* Returns the uuid of the specified frontend, NULL on error */ +char* tpmback_get_uuid(domid_t domid, unsigned int handle); + +/* Specify a function to call when a new tpm device connects */ +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int)); + +/* Specify a function to call when a tpm device disconnects */ +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int)); + +//Not Implemented +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int)); +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)); + +#endif diff --git a/extras/mini-os/include/tpmfront.h b/extras/mini-os/include/tpmfront.h new file mode 100644 index 0000000..eccaacc --- /dev/null +++ b/extras/mini-os/include/tpmfront.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2010-2012 United States Government, as represented by + * the Secretary of Defense. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Based upon the files: + * drivers/char/tpm/tpm_vtpm.c + * drivers/char/tpm/tpm_xen.c + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation + */ +#ifndef TPMFRONT_H +#define TPMFRONT_H + +#include <mini-os/types.h> +#include <mini-os/os.h> +#include <mini-os/events.h> +#include <mini-os/wait.h> +#include <xen/xen.h> +#include <xen/io/xenbus.h> +#include <xen/io/tpmif.h> + +struct tpmfront_dev { + grant_ref_t ring_ref; + evtchn_port_t evtchn; + + tpmif_tx_interface_t* tx; + + void** pages; + + domid_t bedomid; + char* nodename; + char* bepath; + + XenbusState state; + + uint8_t waiting; + struct wait_queue_head waitq; + + uint8_t* respbuf; + size_t resplen; + +#ifdef HAVE_LIBC + int fd; +#endif + +}; + + +/*Initialize frontend */ +struct tpmfront_dev* init_tpmfront(const char* nodename); +/*Shutdown frontend */ +void shutdown_tpmfront(struct tpmfront_dev* dev); + +/* Send a tpm command to the backend and wait for the response + * + * @dev - frontend device + * @req - request buffer + * @reqlen - length of request buffer + * @resp - *resp will be set to internal response buffer, don''t free it! Value is undefined on error + * @resplen - *resplen will be set to the length of the response. Value is undefined on error + * + * returns 0 on success, non zero on failure. + * */ +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, uint8_t** resp, size_t* resplen); + +#ifdef HAVE_LIBC +#include <sys/stat.h> +/* POSIX IO functions: + * use tpmfront_open() to get a file descriptor to the tpm device + * use write() on the fd to send a command to the backend. You must + * include the entire command in a single call to write(). + * use read() on the fd to read the response. You can use + * fstat() to get the size of the response and lseek() to seek on it. + */ +int tpmfront_open(struct tpmfront_dev* dev); +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count); +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count); +int tpmfront_posix_fstat(int fd, struct stat* buf); +#endif + + +#endif diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c index 6cb97b1..d212969 100644 --- a/extras/mini-os/lib/sys.c +++ b/extras/mini-os/lib/sys.c @@ -27,6 +27,8 @@ #include <netfront.h> #include <blkfront.h> #include <fbfront.h> +#include <tpmfront.h> +#include <tpm_tis.h> #include <xenbus.h> #include <xenstore.h> @@ -294,6 +296,16 @@ int read(int fd, void *buf, size_t nbytes) return blkfront_posix_read(fd, buf, nbytes); } #endif +#ifdef CONFIG_TPMFRONT + case FTYPE_TPMFRONT: { + return tpmfront_posix_read(fd, buf, nbytes); + } +#endif +#ifdef CONFIG_TPM_TIS + case FTYPE_TPM_TIS: { + return tpm_tis_posix_read(fd, buf, nbytes); + } +#endif default: break; } @@ -330,6 +342,14 @@ int write(int fd, const void *buf, size_t nbytes) case FTYPE_BLK: return blkfront_posix_write(fd, buf, nbytes); #endif +#ifdef CONFIG_TPMFRONT + case FTYPE_TPMFRONT: + return tpmfront_posix_write(fd, buf, nbytes); +#endif +#ifdef CONFIG_TPM_TIS + case FTYPE_TPM_TIS: + return tpm_tis_posix_write(fd, buf, nbytes); +#endif default: break; } @@ -341,8 +361,16 @@ int write(int fd, const void *buf, size_t nbytes) off_t lseek(int fd, off_t offset, int whence) { switch(files[fd].type) { +#if defined(CONFIG_BLKFRONT) || defined(CONFIG_TPMFRONT) || defined(CONFIG_TPM_TIS) #ifdef CONFIG_BLKFRONT case FTYPE_BLK: +#endif +#ifdef CONFIG_TPMFRNT + case FTYPE_TPMFRONT: +#endif +#ifdef CONFIG_TPM_TIS + case FTYPE_TPM_TIS: +#endif switch (whence) { case SEEK_SET: files[fd].file.offset = offset; @@ -420,6 +448,18 @@ int close(int fd) files[fd].type = FTYPE_NONE; return 0; #endif +#ifdef CONFIG_TPMFRONT + case FTYPE_TPMFRONT: + shutdown_tpmfront(files[fd].tpmfront.dev); + files[fd].type = FTYPE_NONE; + return 0; +#endif +#ifdef CONFIG_TPM_TIS + case FTYPE_TPM_TIS: + shutdown_tpm_tis(files[fd].tpm_tis.dev); + files[fd].type = FTYPE_NONE; + return 0; +#endif #ifdef CONFIG_KBDFRONT case FTYPE_KBD: shutdown_kbdfront(files[fd].kbd.dev); @@ -489,6 +529,14 @@ int fstat(int fd, struct stat *buf) case FTYPE_BLK: return blkfront_posix_fstat(fd, buf); #endif +#ifdef CONFIG_TPMFRONT + case FTYPE_TPMFRONT: + return tpmfront_posix_fstat(fd, buf); +#endif +#ifdef CONFIG_TPM_TIS + case FTYPE_TPM_TIS: + return tpm_tis_posix_fstat(fd, buf); +#endif default: break; } diff --git a/extras/mini-os/tpm_tis.c b/extras/mini-os/tpm_tis.c new file mode 100644 index 0000000..2acb2dc --- /dev/null +++ b/extras/mini-os/tpm_tis.c @@ -0,0 +1,1355 @@ +/* + * Copyright (c) 2010-2012 United States Government, as represented by + * the Secretary of Defense. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Based upon the files: + * drivers/char/tpm/tpm_tis.c + * drivers/char/tpm/tpm.c + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation + */ +#include <mini-os/ioremap.h> +#include <mini-os/iorw.h> +#include <mini-os/tpm_tis.h> +#include <mini-os/os.h> +#include <mini-os/sched.h> +#include <mini-os/byteorder.h> +#include <mini-os/events.h> +#include <mini-os/wait.h> +#include <mini-os/xmalloc.h> +#include <errno.h> +#include <stdbool.h> + +#ifndef min + #define min( a, b ) ( ((a) < (b)) ? (a) : (b) ) +#endif + +#define TPM_HEADER_SIZE 10 + +#define TPM_BUFSIZE 2048 + +struct tpm_input_header { + uint16_t tag; + uint32_t length; + uint32_t ordinal; +}__attribute__((packed)); + +struct tpm_output_header { + uint16_t tag; + uint32_t length; + uint32_t return_code; +}__attribute__((packed)); + +struct stclear_flags_t { + uint16_t tag; + uint8_t deactivated; + uint8_t disableForceClear; + uint8_t physicalPresence; + uint8_t physicalPresenceLock; + uint8_t bGlobalLock; +}__attribute__((packed)); + +struct tpm_version_t { + uint8_t Major; + uint8_t Minor; + uint8_t revMajor; + uint8_t revMinor; +}__attribute__((packed)); + +struct tpm_version_1_2_t { + uint16_t tag; + uint8_t Major; + uint8_t Minor; + uint8_t revMajor; + uint8_t revMinor; +}__attribute__((packed)); + +struct timeout_t { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; +}__attribute__((packed)); + +struct duration_t { + uint32_t tpm_short; + uint32_t tpm_medium; + uint32_t tpm_long; +}__attribute__((packed)); + +struct permanent_flags_t { + uint16_t tag; + uint8_t disable; + uint8_t ownership; + uint8_t deactivated; + uint8_t readPubek; + uint8_t disableOwnerClear; + uint8_t allowMaintenance; + uint8_t physicalPresenceLifetimeLock; + uint8_t physicalPresenceHWEnable; + uint8_t physicalPresenceCMDEnable; + uint8_t CEKPUsed; + uint8_t TPMpost; + uint8_t TPMpostLock; + uint8_t FIPS; + uint8_t operator; + uint8_t enableRevokeEK; + uint8_t nvLocked; + uint8_t readSRKPub; + uint8_t tpmEstablished; + uint8_t maintenanceDone; + uint8_t disableFullDALogicInfo; +}__attribute__((packed)); + +typedef union { + struct permanent_flags_t perm_flags; + struct stclear_flags_t stclear_flags; + bool owned; + uint32_t num_pcrs; + struct tpm_version_t tpm_version; + struct tpm_version_1_2_t tpm_version_1_2; + uint32_t manufacturer_id; + struct timeout_t timeout; + struct duration_t duration; +} cap_t; + +struct tpm_getcap_params_in { + uint32_t cap; + uint32_t subcap_size; + uint32_t subcap; +}__attribute__((packed)); + +struct tpm_getcap_params_out { + uint32_t cap_size; + cap_t cap; +}__attribute__((packed)); + +struct tpm_readpubek_params_out { + uint8_t algorithm[4]; + uint8_t encscheme[2]; + uint8_t sigscheme[2]; + uint32_t paramsize; + uint8_t parameters[12]; /*assuming RSA*/ + uint32_t keysize; + uint8_t modulus[256]; + uint8_t checksum[20]; +}__attribute__((packed)); + +typedef union { + struct tpm_input_header in; + struct tpm_output_header out; +} tpm_cmd_header; + +#define TPM_DIGEST_SIZE 20 +struct tpm_pcrread_out { + uint8_t pcr_result[TPM_DIGEST_SIZE]; +}__attribute__((packed)); + +struct tpm_pcrread_in { + uint32_t pcr_idx; +}__attribute__((packed)); + +struct tpm_pcrextend_in { + uint32_t pcr_idx; + uint8_t hash[TPM_DIGEST_SIZE]; +}__attribute__((packed)); + +typedef union { + struct tpm_getcap_params_out getcap_out; + struct tpm_readpubek_params_out readpubek_out; + uint8_t readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)]; + struct tpm_getcap_params_in getcap_in; + struct tpm_pcrread_in pcrread_in; + struct tpm_pcrread_out pcrread_out; + struct tpm_pcrextend_in pcrextend_in; +} tpm_cmd_params; + +struct tpm_cmd_t { + tpm_cmd_header header; + tpm_cmd_params params; +}__attribute__((packed)); + + +enum tpm_duration { + TPM_SHORT = 0, + TPM_MEDIUM = 1, + TPM_LONG = 2, + TPM_UNDEFINED, +}; + +#define TPM_MAX_ORDINAL 243 +#define TPM_MAX_PROTECTED_ORDINAL 12 +#define TPM_PROTECTED_ORDINAL_MASK 0xFF + +extern const uint8_t tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL]; +extern const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL]; + +#define TPM_DIGEST_SIZE 20 +#define TPM_ERROR_SIZE 10 +#define TPM_RET_CODE_IDX 6 + +/* tpm_capabilities */ +#define TPM_CAP_FLAG cpu_to_be32(4) +#define TPM_CAP_PROP cpu_to_be32(5) +#define CAP_VERSION_1_1 cpu_to_be32(0x06) +#define CAP_VERSION_1_2 cpu_to_be32(0x1A) + +/* tpm_sub_capabilities */ +#define TPM_CAP_PROP_PCR cpu_to_be32(0x101) +#define TPM_CAP_PROP_MANUFACTURER cpu_to_be32(0x103) +#define TPM_CAP_FLAG_PERM cpu_to_be32(0x108) +#define TPM_CAP_FLAG_VOL cpu_to_be32(0x109) +#define TPM_CAP_PROP_OWNER cpu_to_be32(0x111) +#define TPM_CAP_PROP_TIS_TIMEOUT cpu_to_be32(0x115) +#define TPM_CAP_PROP_TIS_DURATION cpu_to_be32(0x120) + + +#define TPM_INTERNAL_RESULT_SIZE 200 +#define TPM_TAG_RQU_COMMAND cpu_to_be16(193) +#define TPM_ORD_GET_CAP cpu_to_be32(101) + +extern const struct tpm_input_header tpm_getcap_header; + + + +const uint8_t tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, +}; + +const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_LONG, + TPM_MEDIUM, /* 15 */ + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, /* 20 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, /* 25 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 30 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 35 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 40 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 45 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_LONG, + TPM_MEDIUM, /* 50 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 55 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 60 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 65 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 70 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 75 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 80 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, + TPM_UNDEFINED, /* 85 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 90 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 95 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 100 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 105 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 110 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 115 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 120 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 125 */ + TPM_SHORT, + TPM_LONG, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 130 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_MEDIUM, + TPM_UNDEFINED, /* 135 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 140 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 145 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 150 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 155 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 160 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 165 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 170 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 175 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 180 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, /* 185 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 190 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 195 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 200 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 205 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 210 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, /* 215 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 220 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 225 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 230 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 235 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 240 */ + TPM_UNDEFINED, + TPM_MEDIUM, +}; + +const struct tpm_input_header tpm_getcap_header = { + .tag = TPM_TAG_RQU_COMMAND, + .length = cpu_to_be32(22), + .ordinal = TPM_ORD_GET_CAP +}; + + +enum tis_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, /* (R) */ + TPM_ACCESS_RELINQUISH_LOCALITY = 0x20,/* (W) */ + TPM_ACCESS_REQUEST_PENDING = 0x04, /* (W) */ + TPM_ACCESS_REQUEST_USE = 0x02, /* (W) */ +}; + +enum tis_status { + TPM_STS_VALID = 0x80, /* (R) */ + TPM_STS_COMMAND_READY = 0x40, /* (R) */ + TPM_STS_DATA_AVAIL = 0x10, /* (R) */ + TPM_STS_DATA_EXPECT = 0x08, /* (R) */ + TPM_STS_GO = 0x20, /* (W) */ +}; + +enum tis_int_flags { + TPM_GLOBAL_INT_ENABLE = 0x80000000, + TPM_INTF_BURST_COUNT_STATIC = 0x100, + TPM_INTF_CMD_READY_INT = 0x080, + TPM_INTF_INT_EDGE_FALLING = 0x040, + TPM_INTF_INT_EDGE_RISING = 0x020, + TPM_INTF_INT_LEVEL_LOW = 0x010, + TPM_INTF_INT_LEVEL_HIGH = 0x008, + TPM_INTF_LOCALITY_CHANGE_INT = 0x004, + TPM_INTF_STS_VALID_INT = 0x002, + TPM_INTF_DATA_AVAIL_INT = 0x001, +}; + +enum tis_defaults { + TIS_MEM_BASE = 0xFED40000, + TIS_MEM_LEN = 0x5000, + TIS_SHORT_TIMEOUT = 750, /*ms*/ + TIS_LONG_TIMEOUT = 2000, /*2 sec */ +}; + +#define TPM_TIMEOUT 5 + +#define TPM_ACCESS(t, l) (((uint8_t*)t->pages[l]) + 0x0000) +#define TPM_INT_ENABLE(t, l) ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0008)) +#define TPM_INT_VECTOR(t, l) (((uint8_t*)t->pages[l]) + 0x000C) +#define TPM_INT_STATUS(t, l) (((uint8_t*)t->pages[l]) + 0x0010) +#define TPM_INTF_CAPS(t, l) ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0014)) +#define TPM_STS(t, l) ((uint8_t*)(((uint8_t*)t->pages[l]) + 0x0018)) +#define TPM_DATA_FIFO(t, l) (((uint8_t*)t->pages[l]) + 0x0024) + +#define TPM_DID_VID(t, l) ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0F00)) +#define TPM_RID(t, l) (((uint8_t*)t->pages[l]) + 0x0F04) + +struct tpm_chip { + int enabled_localities; + int locality; + unsigned long baseaddr; + uint8_t* pages[5]; + int did, vid, rid; + + uint8_t data_buffer[TPM_BUFSIZE]; + int data_len; + + s_time_t timeout_a, timeout_b, timeout_c, timeout_d; + s_time_t duration[3]; + +#ifdef HAVE_LIBC + int fd; +#endif + + unsigned int irq; + struct wait_queue_head read_queue; + struct wait_queue_head int_queue; +}; + + +static void __init_tpm_chip(struct tpm_chip* tpm) { + tpm->enabled_localities = TPM_TIS_EN_LOCLALL; + tpm->locality = -1; + tpm->baseaddr = 0; + tpm->pages[0] = tpm->pages[1] = tpm->pages[2] = tpm->pages[3] = tpm->pages[4] = NULL; + tpm->vid = 0; + tpm->did = 0; + tpm->irq = 0; + init_waitqueue_head(&tpm->read_queue); + init_waitqueue_head(&tpm->int_queue); + + tpm->data_len = -1; + +#ifdef HAVE_LIBC + tpm->fd = -1; +#endif +} + +/* + * Returns max number of nsecs to wait + */ +s_time_t tpm_calc_ordinal_duration(struct tpm_chip *chip, + uint32_t ordinal) +{ + int duration_idx = TPM_UNDEFINED; + s_time_t duration = 0; + + if (ordinal < TPM_MAX_ORDINAL) + duration_idx = tpm_ordinal_duration[ordinal]; + else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < + TPM_MAX_PROTECTED_ORDINAL) + duration_idx + tpm_protected_ordinal_duration[ordinal & + TPM_PROTECTED_ORDINAL_MASK]; + + if (duration_idx != TPM_UNDEFINED) { + duration = chip->duration[duration_idx]; + } + + if (duration <= 0) { + return SECONDS(120); + } + else + { + return duration; + } +} + + +static int locality_enabled(struct tpm_chip* tpm, int l) { + return tpm->enabled_localities & (1 << l); +} + +static int check_locality(struct tpm_chip* tpm, int l) { + if(locality_enabled(tpm, l) && (ioread8(TPM_ACCESS(tpm, l)) & + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) =+ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { + return l; + } + return -1; +} + +void release_locality(struct tpm_chip* tpm, int l, int force) +{ + if (locality_enabled(tpm, l) && (force || (ioread8(TPM_ACCESS(tpm, l)) & + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) =+ (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))) { + iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_RELINQUISH_LOCALITY); + } +} + +int tpm_tis_request_locality(struct tpm_chip* tpm, int l) { + + s_time_t stop; + /*Make sure locality is valid */ + if(!locality_enabled(tpm, l)) { + printk("tpm_tis_change_locality() Tried to change to locality %d, but it is disabled or invalid!\n", l); + return -1; + } + /* Check if we already have the current locality */ + if(check_locality(tpm, l) >= 0) { + return tpm->locality = l; + } + /* Set the new locality*/ + iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_REQUEST_USE); + + if(tpm->irq) { + /* Wait for interrupt */ + wait_event_deadline(tpm->int_queue, (check_locality(tpm, l) >= 0), NOW() + tpm->timeout_a); + + /* FIXME: Handle timeout event, should return error in that case */ + return l; + } else { + /* Wait for burstcount */ + stop = NOW() + tpm->timeout_a; + do { + if(check_locality(tpm, l) >= 0) { + return tpm->locality = l; + } + msleep(TPM_TIMEOUT); + } while(NOW() < stop); + } + + printk("REQ LOCALITY FAILURE\n"); + return -1; +} + +static uint8_t tpm_tis_status(struct tpm_chip* tpm) { + return ioread8(TPM_STS(tpm, tpm->locality)); +} + +/* This causes the current command to be aborted */ +static void tpm_tis_ready(struct tpm_chip* tpm) { + iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_COMMAND_READY); +} +#define tpm_tis_cancel_cmd(v) tpm_tis_ready(v) + +static int get_burstcount(struct tpm_chip* tpm) { + s_time_t stop; + int burstcnt; + + stop = NOW() + tpm->timeout_d; + do { + burstcnt = ioread8((TPM_STS(tpm, tpm->locality) + 1)); + burstcnt += ioread8(TPM_STS(tpm, tpm->locality) + 2) << 8; + + if (burstcnt) { + return burstcnt; + } + msleep(TPM_TIMEOUT); + } while(NOW() < stop); + return -EBUSY; +} + +static int wait_for_stat(struct tpm_chip* tpm, uint8_t mask, + unsigned long timeout, struct wait_queue_head* queue) { + s_time_t stop; + uint8_t status; + + status = tpm_tis_status(tpm); + if((status & mask) == mask) { + return 0; + } + + if(tpm->irq) { + wait_event_deadline(*queue, ((tpm_tis_status(tpm) & mask) == mask), timeout); + /* FIXME: Check for timeout and return -ETIME */ + return 0; + } else { + stop = NOW() + timeout; + do { + msleep(TPM_TIMEOUT); + status = tpm_tis_status(tpm); + if((status & mask) == mask) + return 0; + } while( NOW() < stop); + } + return -ETIME; +} + +static int recv_data(struct tpm_chip* tpm, uint8_t* buf, size_t count) { + int size = 0; + int burstcnt; + while( size < count && + wait_for_stat(tpm, + TPM_STS_DATA_AVAIL | TPM_STS_VALID, + tpm->timeout_c, + &tpm->read_queue) + == 0) { + burstcnt = get_burstcount(tpm); + for(; burstcnt > 0 && size < count; --burstcnt) + { + buf[size++] = ioread8(TPM_DATA_FIFO(tpm, tpm->locality)); + } + } + return size; +} + +int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) { + int size = 0; + int expected, status; + + if (count < TPM_HEADER_SIZE) { + size = -EIO; + goto out; + } + + /* read first 10 bytes, including tag, paramsize, and result */ + if((size + recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { + printk("Error reading tpm cmd header\n"); + goto out; + } + + expected = be32_to_cpu(*((uint32_t*)(buf + 2))); + if(expected > count) { + size = -EIO; + goto out; + } + + if((size += recv_data(tpm, & buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE)) < expected) { + printk("Unable to read rest of tpm command size=%d expected=%d\n", size, expected); + size = -ETIME; + goto out; + } + + wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue); + status = tpm_tis_status(tpm); + if(status & TPM_STS_DATA_AVAIL) { + printk("Error: left over data\n"); + size = -EIO; + goto out; + } + +out: + tpm_tis_ready(tpm); + release_locality(tpm, tpm->locality, 0); + return size; +} +int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) { + int rc; + int status, burstcnt = 0; + int count = 0; + uint32_t ordinal; + + if(tpm_tis_request_locality(tpm, tpm->locality) < 0) { + return -EBUSY; + } + + status = tpm_tis_status(tpm); + if((status & TPM_STS_COMMAND_READY) == 0) { + tpm_tis_ready(tpm); + if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b, &tpm->int_queue) < 0) { + rc = -ETIME; + goto out_err; + } + } + + while(count < len - 1) { + burstcnt = get_burstcount(tpm); + for(;burstcnt > 0 && count < len -1; --burstcnt) { + iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]); + } + + wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue); + status = tpm_tis_status(tpm); + if((status & TPM_STS_DATA_EXPECT) == 0) { + rc = -EIO; + goto out_err; + } + } + + /*Write last byte*/ + iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]); + wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue); + status = tpm_tis_status(tpm); + if((status & TPM_STS_DATA_EXPECT) != 0) { + rc = -EIO; + goto out_err; + } + + /*go and do it*/ + iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO); + + if(tpm->irq) { + /*Wait for interrupt */ + ordinal = be32_to_cpu(*(buf + 6)); + if(wait_for_stat(tpm, + TPM_STS_DATA_AVAIL | TPM_STS_VALID, + tpm_calc_ordinal_duration(tpm, ordinal), + &tpm->read_queue) < 0) { + rc = -ETIME; + goto out_err; + } + } +#ifdef HAVE_LIBC + if(tpm->fd >= 0) { + files[tpm->fd].read = 0; + files[tpm->fd].tpm_tis.respgot = 0; + files[tpm->fd].tpm_tis.offset = 0; + } +#endif + return len; + +out_err: + tpm_tis_ready(tpm); + release_locality(tpm, tpm->locality, 0); + return rc; +} + +static void tpm_tis_irq_handler(evtchn_port_t port, struct pt_regs *regs, void* data) +{ + struct tpm_chip* tpm = data; + uint32_t interrupt; + int i; + + interrupt = ioread32(TPM_INT_STATUS(tpm, tpm->locality)); + if(interrupt == 0) { + return; + } + + if(interrupt & TPM_INTF_DATA_AVAIL_INT) { + wake_up(&tpm->read_queue); + } + if(interrupt & TPM_INTF_LOCALITY_CHANGE_INT) { + for(i = 0; i < 5; ++i) { + if(check_locality(tpm, i) >= 0) { + break; + } + } + } + if(interrupt & (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | + TPM_INTF_CMD_READY_INT)) { + wake_up(&tpm->int_queue); + } + + /* Clear interrupts handled with TPM_EOI */ + iowrite32(TPM_INT_STATUS(tpm, tpm->locality), interrupt); + ioread32(TPM_INT_STATUS(tpm, tpm->locality)); + return; +} + +/* + * Internal kernel interface to transmit TPM commands + */ +static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf, + size_t bufsiz) +{ + ssize_t rc; + uint32_t count, ordinal; + s_time_t stop; + + count = be32_to_cpu(*((uint32_t *) (buf + 2))); + ordinal = be32_to_cpu(*((uint32_t *) (buf + 6))); + if (count == 0) + return -ENODATA; + if (count > bufsiz) { + printk("Error: invalid count value %x %zx \n", count, bufsiz); + return -E2BIG; + } + + //down(&chip->tpm_mutex); + + if ((rc = tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) { + printk("tpm_transmit: tpm_send: error %zd\n", rc); + goto out; + } + + if (chip->irq) + goto out_recv; + + stop = NOW() + tpm_calc_ordinal_duration(chip, ordinal); + do { + uint8_t status = tpm_tis_status(chip); + if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) =+ (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) + goto out_recv; + + if ((status == TPM_STS_COMMAND_READY)) { + printk("TPM Error: Operation Canceled\n"); + rc = -ECANCELED; + goto out; + } + + msleep(TPM_TIMEOUT); /* CHECK */ + rmb(); + } while (NOW() < stop); + + /* Cancel the command */ + tpm_tis_cancel_cmd(chip); + printk("TPM Operation Timed out\n"); + rc = -ETIME; + goto out; + +out_recv: + if((rc = tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) { + printk("tpm_transmit: tpm_recv: error %d\n", rc); + } +out: + //up(&chip->tpm_mutex); + return rc; +} + +static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, + int len, const char *desc) +{ + int err; + + len = tpm_transmit(chip,(uint8_t *) cmd, len); + if (len < 0) + return len; + if (len == TPM_ERROR_SIZE) { + err = be32_to_cpu(cmd->header.out.return_code); + printk("A TPM error (%d) occurred %s\n", err, desc); + return err; + } + return 0; +} + +void tpm_get_timeouts(struct tpm_chip *chip) +{ + struct tpm_cmd_t tpm_cmd; + struct timeout_t *timeout_cap; + struct duration_t *duration_cap; + ssize_t rc; + uint32_t timeout; + + tpm_cmd.header.in = tpm_getcap_header; + tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); + tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; + + if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the timeouts")) != 0) { + printk("transmit failed %d\n", rc); + goto duration; + } + + if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size) + != 4 * sizeof(uint32_t)) { + printk("Out len check failure %lu \n", be32_to_cpu(tpm_cmd.header.out.length)); + goto duration; + } + + timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; + /* Don''t overwrite default if value is 0 */ + timeout = be32_to_cpu(timeout_cap->a); + if (timeout) + chip->timeout_a = MICROSECS(timeout); /*Convert to msec */ + timeout = be32_to_cpu(timeout_cap->b); + if (timeout) + chip->timeout_b = MICROSECS(timeout); /*Convert to msec */ + timeout = be32_to_cpu(timeout_cap->c); + if (timeout) + chip->timeout_c = MICROSECS(timeout); /*Convert to msec */ + timeout = be32_to_cpu(timeout_cap->d); + if (timeout) + chip->timeout_d = MICROSECS(timeout); /*Convert to msec */ + +duration: + tpm_cmd.header.in = tpm_getcap_header; + tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); + tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; + + if((rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the durations")) < 0) { + return; + } + + if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size) + != 3 * sizeof(uint32_t)) { + return; + } + duration_cap = &tpm_cmd.params.getcap_out.cap.duration; + chip->duration[TPM_SHORT] = be32_to_cpu(duration_cap->tpm_short); + /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above + * value wrong and apparently reports msecs rather than usecs. So we + * fix up the resulting too-small TPM_SHORT value to make things work. + */ + if (chip->duration[TPM_SHORT] < 10) { + chip->duration[TPM_SHORT] = MILLISECS(chip->duration[TPM_SHORT]); + } else { + chip->duration[TPM_SHORT] = MICROSECS(chip->duration[TPM_SHORT]); + } + + chip->duration[TPM_MEDIUM] = MICROSECS(be32_to_cpu(duration_cap->tpm_medium)); + chip->duration[TPM_LONG] = MICROSECS(be32_to_cpu(duration_cap->tpm_long)); +} + + + +void tpm_continue_selftest(struct tpm_chip* chip) { + uint8_t data[] = { + 0, 193, /* TPM_TAG_RQU_COMMAND */ + 0, 0, 0, 10, /* length */ + 0, 0, 0, 83, /* TPM_ORD_GetCapability */ + }; + + tpm_transmit(chip, data, sizeof(data)); +} + +ssize_t tpm_getcap(struct tpm_chip *chip, uint32_t subcap_id, cap_t *cap, + const char *desc) +{ + struct tpm_cmd_t tpm_cmd; + int rc; + + tpm_cmd.header.in = tpm_getcap_header; + if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) { + tpm_cmd.params.getcap_in.cap = subcap_id; + /*subcap field not necessary */ + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); + tpm_cmd.header.in.length -= cpu_to_be32(sizeof(uint32_t)); + } else { + if (subcap_id == TPM_CAP_FLAG_PERM || + subcap_id == TPM_CAP_FLAG_VOL) + tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG; + else + tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); + tpm_cmd.params.getcap_in.subcap = subcap_id; + } + rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); + if (!rc) + *cap = tpm_cmd.params.getcap_out.cap; + return rc; +} + + +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities, unsigned int irq) +{ + int i; + unsigned long addr; + struct tpm_chip* tpm = NULL; + uint32_t didvid; + uint32_t intfcaps; + uint32_t intmask; + + printk("============= Init TPM TIS Driver ==============\n"); + + /*Sanity check the localities input */ + if(localities & ~TPM_TIS_EN_LOCLALL) { + printk("init_tpm_tis() Invalid locality specification! %X\n", localities); + goto abort_egress; + } + + printk("IOMEM Machine Base Address: %lX\n", baseaddr); + + /* Create the tpm data structure */ + tpm = malloc(sizeof(struct tpm_chip)); + __init_tpm_chip(tpm); + + /* Set the enabled localities - if 0 we leave default as all enabled */ + if(localities != 0) { + tpm->enabled_localities = localities; + } + printk("Enabled Localities: "); + for(i = 0; i < 5; ++i) { + if(locality_enabled(tpm, i)) { + printk("%d ", i); + } + } + printk("\n"); + + /* Set the base machine address */ + tpm->baseaddr = baseaddr; + + /* Set default timeouts */ + tpm->timeout_a = MILLISECS(TIS_SHORT_TIMEOUT); + tpm->timeout_b = MILLISECS(TIS_LONG_TIMEOUT); + tpm->timeout_c = MILLISECS(TIS_SHORT_TIMEOUT); + tpm->timeout_d = MILLISECS(TIS_SHORT_TIMEOUT); + + /*Map the mmio pages */ + addr = tpm->baseaddr; + for(i = 0; i < 5; ++i) { + if(locality_enabled(tpm, i)) { + /* Map the page in now */ + if((tpm->pages[i] = ioremap_nocache(addr, PAGE_SIZE)) == NULL) { + printk("Unable to map iomem page a address %p\n", addr); + goto abort_egress; + } + + /* Set default locality to the first enabled one */ + if (tpm->locality < 0) { + if(tpm_tis_request_locality(tpm, i) < 0) { + printk("Unable to request locality %d??\n", i); + goto abort_egress; + } + } + } + addr += PAGE_SIZE; + } + + + /* Get the vendor and device ids */ + didvid = ioread32(TPM_DID_VID(tpm, tpm->locality)); + tpm->did = didvid >> 16; + tpm->vid = didvid & 0xFFFF; + + + /* Get the revision id */ + tpm->rid = ioread8(TPM_RID(tpm, tpm->locality)); + + printk("1.2 TPM (device-id=0x%X vendor-id = %X rev-id = %X)\n", tpm->did, tpm->vid, tpm->rid); + + intfcaps = ioread32(TPM_INTF_CAPS(tpm, tpm->locality)); + printk("TPM interface capabilities (0x%x):\n", intfcaps); + if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) + printk("\tBurst Count Static\n"); + if (intfcaps & TPM_INTF_CMD_READY_INT) + printk("\tCommand Ready Int Support\n"); + if (intfcaps & TPM_INTF_INT_EDGE_FALLING) + printk("\tInterrupt Edge Falling\n"); + if (intfcaps & TPM_INTF_INT_EDGE_RISING) + printk("\tInterrupt Edge Rising\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_LOW) + printk("\tInterrupt Level Low\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) + printk("\tInterrupt Level High\n"); + if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) + printk("\tLocality Change Int Support\n"); + if (intfcaps & TPM_INTF_STS_VALID_INT) + printk("\tSts Valid Int Support\n"); + if (intfcaps & TPM_INTF_DATA_AVAIL_INT) + printk("\tData Avail Int Support\n"); + + /*Interupt setup */ + intmask = ioread32(TPM_INT_ENABLE(tpm, tpm->locality)); + + intmask |= TPM_INTF_CMD_READY_INT + | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT + | TPM_INTF_STS_VALID_INT; + + iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask); + + /*If interupts are enabled, handle it */ + if(irq) { + if(irq != TPM_PROBE_IRQ) { + tpm->irq = irq; + } else { + /*FIXME add irq probing feature later */ + printk("IRQ probing not implemented\n"); + } + } + + if(tpm->irq) { + iowrite8(TPM_INT_VECTOR(tpm, tpm->locality), tpm->irq); + + if(bind_pirq(tpm->irq, 1, tpm_tis_irq_handler, tpm) != 0) { + printk("Unabled to request irq: %u for use\n", tpm->irq); + printk("Will use polling mode\n"); + tpm->irq = 0; + } else { + /* Clear all existing */ + iowrite32(TPM_INT_STATUS(tpm, tpm->locality), ioread32(TPM_INT_STATUS(tpm, tpm->locality))); + + /* Turn on interrupts */ + iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask | TPM_GLOBAL_INT_ENABLE); + } + } + + tpm_get_timeouts(tpm); + tpm_continue_selftest(tpm); + + + return tpm; +abort_egress: + if(tpm != NULL) { + shutdown_tpm_tis(tpm); + } + return NULL; +} + +void shutdown_tpm_tis(struct tpm_chip* tpm){ + int i; + + printk("Shutting down tpm_tis device\n"); + + iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), ~TPM_GLOBAL_INT_ENABLE); + + /*Unmap all of the mmio pages */ + for(i = 0; i < 5; ++i) { + if(tpm->pages[i] != NULL) { + iounmap(tpm->pages[i], PAGE_SIZE); + tpm->pages[i] = NULL; + } + } + free(tpm); + return; +} + + +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen, uint8_t** resp, size_t* resplen) +{ + if(tpm->locality < 0) { + printk("tpm_tis_cmd() failed! locality not set!\n"); + return -1; + } + if(reqlen > TPM_BUFSIZE) { + reqlen = TPM_BUFSIZE; + } + memcpy(tpm->data_buffer, req, reqlen); + *resplen = tpm_transmit(tpm, tpm->data_buffer, TPM_BUFSIZE); + + *resp = malloc(*resplen); + memcpy(*resp, tpm->data_buffer, *resplen); + return 0; +} + +#ifdef HAVE_LIBC +int tpm_tis_open(struct tpm_chip* tpm) +{ + /* Silently prevent multiple opens */ + if(tpm->fd != -1) { + return tpm->fd; + } + + tpm->fd = alloc_fd(FTYPE_TPM_TIS); + printk("tpm_tis_open() -> %d\n", tpm->fd); + files[tpm->fd].tpm_tis.dev = tpm; + files[tpm->fd].tpm_tis.offset = 0; + files[tpm->fd].tpm_tis.respgot = 0; + return tpm->fd; +} + +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count) +{ + struct tpm_chip* tpm; + tpm = files[fd].tpm_tis.dev; + + if(tpm->locality < 0) { + printk("tpm_tis_posix_write() failed! locality not set!\n"); + errno = EINPROGRESS; + return -1; + } + if(count == 0) { + return 0; + } + + /* Return an error if we are already processing a command */ + if(count > TPM_BUFSIZE) { + count = TPM_BUFSIZE; + } + /* Send the command now */ + memcpy(tpm->data_buffer, buf, count); + if((tpm->data_len = tpm_transmit(tpm, tpm->data_buffer, TPM_BUFSIZE)) < 0) { + errno = EIO; + return -1; + } + return count; +} + +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count) +{ + int rc; + struct tpm_chip* tpm; + tpm = files[fd].tpm_tis.dev; + + if(count == 0) { + return 0; + } + + /* If there is no tpm resp to read, return EIO */ + if(tpm->data_len < 0) { + errno = EIO; + return -1; + } + + + /* Handle EOF case */ + if(files[fd].tpm_tis.offset >= tpm->data_len) { + rc = 0; + } else { + rc = min(tpm->data_len - files[fd].tpm_tis.offset, count); + memcpy(buf, tpm->data_buffer + files[fd].tpm_tis.offset, rc); + } + files[fd].tpm_tis.offset += rc; + /* Reset the data pending flag */ + return rc; +} +int tpm_tis_posix_fstat(int fd, struct stat* buf) +{ + struct tpm_chip* tpm; + tpm = files[fd].tpm_tis.dev; + + buf->st_mode = O_RDWR; + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_size = be32_to_cpu(*((uint32_t*)(tpm->data_buffer + 2))); + buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL); + return 0; +} + + +#endif diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c new file mode 100644 index 0000000..c709019 --- /dev/null +++ b/extras/mini-os/tpmback.c @@ -0,0 +1,1125 @@ +/* + * Copyright (c) 2010-2012 United States Government, as represented by + * the Secretary of Defense. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Based upon the files: + * drivers/xen/tpmbk.c + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation + */ +#include <mini-os/os.h> +#include <mini-os/xenbus.h> +#include <mini-os/events.h> +#include <errno.h> +#include <mini-os/gnttab.h> +#include <xen/io/xenbus.h> +#include <xen/io/tpmif.h> +#include <xen/io/protocols.h> +#include <mini-os/xmalloc.h> +#include <time.h> +#include <mini-os/tpmback.h> +#include <mini-os/lib.h> +#include <fcntl.h> +#include <mini-os/mm.h> +#include <mini-os/posix/sys/mman.h> +#include <mini-os/semaphore.h> +#include <mini-os/wait.h> + + +#ifndef HAVE_LIBC +#define strtoul simple_strtoul +#endif + +//#define TPMBACK_PRINT_DEBUG +#ifdef TPMBACK_PRINT_DEBUG +#define TPMBACK_DEBUG(fmt,...) printk("Tpmback:Debug("__FILE__":%d) " fmt, __LINE__, ##__VA_ARGS__) +#define TPMBACK_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__) +#else +#define TPMBACK_DEBUG(fmt,...) +#endif +#define TPMBACK_ERR(fmt,...) printk("Tpmback:Error " fmt, ##__VA_ARGS__) +#define TPMBACK_LOG(fmt,...) printk("Tpmback:Info " fmt, ##__VA_ARGS__) + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +/* Default size of the tpmif array at initialization */ +#define DEF_ARRAY_SIZE 1 + +/* tpmif and tpmdev flags */ +#define TPMIF_CLOSED 1 +#define TPMIF_REQ_READY 2 + +struct tpmif { + domid_t domid; + unsigned int handle; + + char* fe_path; + char* fe_state_path; + + /* Locally bound event channel*/ + evtchn_port_t evtchn; + + /* Shared page */ + tpmif_tx_interface_t* tx; + + /* pointer to TPMIF_RX_RING_SIZE pages */ + void** pages; + + enum xenbus_state state; + enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; + + char* uuid; + + /* state flags */ + int flags; +}; +typedef struct tpmif tpmif_t; + +struct tpmback_dev { + + tpmif_t** tpmlist; + unsigned long num_tpms; + unsigned long num_alloc; + + struct gntmap map; + + /* True if at least one tpmif has a request to be handled */ + int flags; + + /* exclusive domains, see init_tpmback comment in tpmback.h */ + char** exclusive_uuids; + + xenbus_event_queue events; + + /* Callbacks */ + void (*open_callback)(domid_t, unsigned int); + void (*close_callback)(domid_t, unsigned int); + void (*suspend_callback)(domid_t, unsigned int); + void (*resume_callback)(domid_t, unsigned int); +}; +typedef struct tpmback_dev tpmback_dev_t; + +enum { EV_NONE, EV_NEWFE, EV_STCHNG } tpm_ev_enum; + +/* Global objects */ +static struct thread* eventthread = NULL; +static tpmback_dev_t gtpmdev = { + .tpmlist = NULL, + .num_tpms = 0, + .num_alloc = 0, + .flags = TPMIF_CLOSED, + .events = NULL, + .open_callback = NULL, + .close_callback = NULL, + .suspend_callback = NULL, + .resume_callback = NULL, +}; +struct wait_queue_head waitq; +int globalinit = 0; + +/************************************ + * TPMIF SORTED ARRAY FUNCTIONS + * tpmback_dev_t.tpmlist is a sorted array, sorted by domid and then handle number + * Duplicates are not allowed + * **********************************/ + +inline void tpmif_req_ready(tpmif_t* tpmif) { + tpmif->flags |= TPMIF_REQ_READY; + gtpmdev.flags |= TPMIF_REQ_READY; +} + +inline void tpmdev_check_req(void) { + int i; + int flags; + local_irq_save(flags); + for(i = 0; i < gtpmdev.num_tpms; ++i) { + if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) { + gtpmdev.flags |= TPMIF_REQ_READY; + local_irq_restore(flags); + return; + } + } + gtpmdev.flags &= ~TPMIF_REQ_READY; + local_irq_restore(flags); +} + +inline void tpmif_req_finished(tpmif_t* tpmif) { + tpmif->flags &= ~TPMIF_REQ_READY; + tpmdev_check_req(); +} + +int __get_tpmif_index(int st, int n, domid_t domid, unsigned int handle) +{ + int i = st + n /2; + tpmif_t* tmp; + + if( n <= 0 ) + return -1; + + tmp = gtpmdev.tpmlist[i]; + if(domid == tmp->domid && tmp->handle == handle) { + return i; + } else if ( (domid < tmp->domid) || + (domid == tmp->domid && handle < tmp->handle)) { + return __get_tpmif_index(st, n/2, domid, handle); + } else { + return __get_tpmif_index(i + 1, n/2 - ((n +1) % 2), domid, handle); + } +} + +/* Returns the array index of the tpmif domid/handle. Returns -1 if no such tpmif exists */ +int get_tpmif_index(domid_t domid, unsigned int handle) +{ + int flags; + int index; + local_irq_save(flags); + index = __get_tpmif_index(0, gtpmdev.num_tpms, domid, handle); + local_irq_restore(flags); + return index; +} + +/* Returns the tpmif domid/handle or NULL if none exists */ +tpmif_t* get_tpmif(domid_t domid, unsigned int handle) +{ + int flags; + int i; + tpmif_t* ret; + local_irq_save(flags); + i = get_tpmif_index(domid, handle); + if (i < 0) { + ret = NULL; + } else { + ret = gtpmdev.tpmlist[i]; + } + local_irq_restore(flags); + return ret; +} + +/* Remove the given tpmif. Returns 0 if it was removed, -1 if it was not removed */ +int remove_tpmif(tpmif_t* tpmif) +{ + int i, j; + char* err; + int flags; + local_irq_save(flags); + + /* Find the index in the array if it exists */ + i = get_tpmif_index(tpmif->domid, tpmif->handle); + if (i < 0) { + goto error; + } + + /* Remove the interface from the list */ + for(j = i; j < gtpmdev.num_tpms - 1; ++j) { + gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j+1]; + } + gtpmdev.tpmlist[j] = NULL; + --gtpmdev.num_tpms; + + /* If removed tpm was the only ready tpm, then we need to check and turn off the ready flag */ + tpmdev_check_req(); + + local_irq_restore(flags); + + /* Stop listening for events on this tpm interface */ + if((err = xenbus_unwatch_path_token(XBT_NIL, tpmif->fe_state_path, tpmif->fe_state_path))) { + TPMBACK_ERR("Unable to unwatch path token `%s'' Error was %s Ignoring..\n", tpmif->fe_state_path, err); + free(err); + } + + return 0; +error: + local_irq_restore(flags); + return -1; +} + +/* Insert tpmif into dev->tpmlist. Returns 0 on success and non zero on error. + * It is an error to insert a tpmif with the same domid and handle + * number + * as something already in the list */ +int insert_tpmif(tpmif_t* tpmif) +{ + int flags; + unsigned int i, j; + tpmif_t* tmp; + char* err; + + local_irq_save(flags); + + /*Check if we need to allocate more space */ + if (gtpmdev.num_tpms == gtpmdev.num_alloc) { + gtpmdev.num_alloc *= 2; + gtpmdev.tpmlist = realloc(gtpmdev.tpmlist, gtpmdev.num_alloc); + } + + /*Find where to put the new interface */ + for(i = 0; i < gtpmdev.num_tpms; ++i) + { + tmp = gtpmdev.tpmlist[i]; + if(tpmif->domid == tmp->domid && tpmif->handle == tmp->handle) { + TPMBACK_ERR("Tried to insert duplicate tpm interface %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; + } + if((tpmif->domid < tmp->domid) || + (tpmif->domid == tmp->domid && tpmif->handle < tmp->handle)) { + break; + } + } + + /*Shift all the tpm pointers past i down one */ + for(j = gtpmdev.num_tpms; j > i; --j) { + gtpmdev.tpmlist[j] = gtpmdev.tpmlist[j-1]; + } + + /*Add the new interface */ + gtpmdev.tpmlist[i] = tpmif; + ++gtpmdev.num_tpms; + + /*Should not be needed, anything inserted with ready flag is probably an error */ + tpmdev_check_req(); + + local_irq_restore(flags); + + /*Listen for state changes on the new interface */ + if((err = xenbus_watch_path_token(XBT_NIL, tpmif->fe_state_path, tpmif->fe_state_path, >pmdev.events))) + { + /* if we got an error here we should carefully remove the interface and then return */ + TPMBACK_ERR("Unable to watch path token `%s'' Error was %s\n", tpmif->fe_state_path, err); + free(err); + remove_tpmif(tpmif); + goto error_post_irq; + } + + return 0; +error: + local_irq_restore(flags); +error_post_irq: + return -1; +} + + +/***************** + * CHANGE BACKEND STATE + * *****************/ +/*Attempts to change the backend state in xenstore + * returns 0 on success and non-zero on error */ +int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state) +{ + char path[512]; + char *value; + char *err; + enum xenbus_state readst; + TPMBACK_DEBUG("Backend state change %u/%u from=%d to=%d\n", (unsigned int) tpmif->domid, tpmif->handle, tpmif->state, state); + if (tpmif->state == state) + return 0; + + snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int) tpmif->domid, tpmif->handle); + + if((err = xenbus_read(XBT_NIL, path, &value))) { + TPMBACK_ERR("Unable to read backend state %s, error was %s\n", path, err); + free(err); + return -1; + } + if(sscanf(value, "%d", &readst) != 1) { + TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path); + free(value); + return -1; + } + free(value); + + /* It''s possible that the backend state got updated by hotplug or something else behind our back */ + if(readst != tpmif->state) { + TPMBACK_DEBUG("tpm interface state was %d but xenstore state was %d!\n", tpmif->state, readst); + tpmif->state = readst; + } + + /*If if the state isnt changing, then we dont update xenstore b/c we dont want to fire extraneous events */ + if(tpmif->state == state) { + return 0; + } + + /*update xenstore*/ + snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + if((err = xenbus_printf(XBT_NIL, path, "state", "%u", state))) { + TPMBACK_ERR("Error writing to xenstore %s, error was %s new state=%d\n", path, err, state); + free(err); + return -1; + } + + tpmif->state = state; + + return 0; +} +/********************************** + * TPMIF CREATION AND DELETION + * *******************************/ +inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) +{ + tpmif_t* tpmif; + tpmif = malloc(sizeof(*tpmif)); + tpmif->domid = domid; + tpmif->handle = handle; + tpmif->fe_path = NULL; + tpmif->fe_state_path = NULL; + tpmif->state = XenbusStateInitialising; + tpmif->status = DISCONNECTED; + tpmif->tx = NULL; + tpmif->pages = NULL; + tpmif->flags = 0; + tpmif->uuid = NULL; + return tpmif; +} + +void __free_tpmif(tpmif_t* tpmif) +{ + if(tpmif->pages) { + free(tpmif->pages); + } + if(tpmif->fe_path) { + free(tpmif->fe_path); + } + if(tpmif->fe_state_path) { + free(tpmif->fe_state_path); + } + if(tpmif->uuid) { + free(tpmif->uuid); + } + free(tpmif); +} +/* Creates a new tpm interface, adds it to the sorted array and returns it. + * returns NULL on error + * If the tpm interface already exists, it is returned*/ +tpmif_t* new_tpmif(domid_t domid, unsigned int handle) +{ + tpmif_t* tpmif; + char* err; + char path[512]; + + /* Make sure we haven''t already created this tpm + * Double events can occur */ + if((tpmif = get_tpmif(domid, handle)) != NULL) { + return tpmif; + } + + tpmif = __init_tpmif(domid, handle); + + /* Get the uuid from xenstore */ + snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domid, handle); + if((err = xenbus_read(XBT_NIL, path, &tpmif->uuid))) { + TPMBACK_ERR("Error reading %s, Error = %s\n", path, err); + free(err); + goto error; + } + + /* Do the exclusive uuid check now */ + if(gtpmdev.exclusive_uuids != NULL) { + char** ptr; + + /* Check that its in the whitelist */ + for(ptr = gtpmdev.exclusive_uuids; *ptr != NULL; ++ptr) { + if(!strcmp(tpmif->uuid, *ptr)) { + break; + } + } + /* If *ptr == NULL then we went through the whole list without a match, so close the connection */ + if(*ptr == NULL) { + tpmif_change_state(tpmif, XenbusStateClosed); + TPMBACK_ERR("Frontend %u/%u tried to connect with invalid uuid=%s\n", (unsigned int) domid, handle, tpmif->uuid); + goto error; + } + } + + /* allocate pages to be used for shared mapping */ + if((tpmif->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE)) == NULL) { + goto error; + } + memset(tpmif->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); + + if(tpmif_change_state(tpmif, XenbusStateInitWait)) { + goto error; + } + + snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int) domid, handle); + if((err = xenbus_read(XBT_NIL, path, &tpmif->fe_path))) { + TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s), Error = %s", path, err); + free(err); + goto error; + } + + /*Set the state path */ + tpmif->fe_state_path = malloc(strlen(tpmif->fe_path) + 7); + strcpy(tpmif->fe_state_path, tpmif->fe_path); + strcat(tpmif->fe_state_path, "/state"); + + if(insert_tpmif(tpmif)) { + goto error; + } + TPMBACK_DEBUG("New tpmif %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); + /* Do the callback now */ + if(gtpmdev.open_callback) { + gtpmdev.open_callback(tpmif->domid, tpmif->handle); + } + return tpmif; +error: + __free_tpmif(tpmif); + return NULL; + +} + +/* Removes tpmif from dev->tpmlist and frees it''s memory usage */ +void free_tpmif(tpmif_t* tpmif) +{ + char* err; + char path[512]; + TPMBACK_DEBUG("Free tpmif %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); + if(tpmif->flags & TPMIF_CLOSED) { + TPMBACK_ERR("Tried to free an instance twice! Theres a bug somewhere!\n"); + BUG(); + } + tpmif->flags = TPMIF_CLOSED; + + tpmif_change_state(tpmif, XenbusStateClosing); + + /* Unmap share page and unbind event channel */ + if(tpmif->status == CONNECTED) { + tpmif->status = DISCONNECTING; + mask_evtchn(tpmif->evtchn); + + if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1)) { + TPMBACK_ERR("%u/%u Error occured while trying to unmap shared page\n", (unsigned int) tpmif->domid, tpmif->handle); + } + + unbind_evtchn(tpmif->evtchn); + } + tpmif->status = DISCONNECTED; + tpmif_change_state(tpmif, XenbusStateClosed); + + /* Do the callback now */ + if(gtpmdev.close_callback) { + gtpmdev.close_callback(tpmif->domid, tpmif->handle); + } + + /* remove from array */ + remove_tpmif(tpmif); + + /* Wake up anyone possibly waiting on this interface and let them exit */ + wake_up(&waitq); + schedule(); + + /* Remove the old xenbus entries */ + snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + if((err = xenbus_rm(XBT_NIL, path))) { + TPMBACK_ERR("Error cleaning up xenbus entries path=%s error=%s\n", path, err); + free(err); + } + + TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int) tpmif->domid, tpmif->handle); + + /* free memory */ + __free_tpmif(tpmif); + +} + +/********************** + * REMAINING TPMBACK FUNCTIONS + * ********************/ + +/*Event channel handler */ +void tpmback_handler(evtchn_port_t port, struct pt_regs *regs, void *data) +{ + tpmif_t* tpmif = (tpmif_t*) data; + tpmif_tx_request_t* tx = &tpmif->tx->ring[0].req; + /* Throw away 0 size events, these can trigger from event channel unmasking */ + if(tx->size == 0) + return; + + TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); + tpmif_req_ready(tpmif); + wake_up(&waitq); + +} + +/* Connect to frontend */ +int connect_fe(tpmif_t* tpmif) +{ + char path[512]; + char* err, *value; + uint32_t domid; + grant_ref_t ringref; + evtchn_port_t evtchn; + + /* If already connected then quit */ + if (tpmif->status == CONNECTED) { + TPMBACK_DEBUG("%u/%u tried to connect while it was already connected?\n", (unsigned int) tpmif->domid, tpmif->handle); + return 0; + } + + /* Fetch the grant reference */ + snprintf(path, 512, "%s/ring-ref", tpmif->fe_path); + if((err = xenbus_read(XBT_NIL, path, &value))) { + TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s) Error = %s", path, err); + free(err); + return -1; + } + if(sscanf(value, "%d", &ringref) != 1) { + TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path); + free(value); + return -1; + } + free(value); + + + /* Fetch the event channel*/ + snprintf(path, 512, "%s/event-channel", tpmif->fe_path); + if((err = xenbus_read(XBT_NIL, path, &value))) { + TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s) Error = %s", path, err); + free(err); + return -1; + } + if(sscanf(value, "%d", &evtchn) != 1) { + TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path); + free(value); + return -1; + } + free(value); + + domid = tpmif->domid; + if((tpmif->tx = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &ringref, PROT_READ | PROT_WRITE)) == NULL) { + TPMBACK_ERR("Failed to map grant reference %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); + return -1; + } + memset(tpmif->tx, 0, PAGE_SIZE); + + /*Bind the event channel */ + if((evtchn_bind_interdomain(tpmif->domid, evtchn, tpmback_handler, tpmif, &tpmif->evtchn))) + { + TPMBACK_ERR("%u/%u Unable to bind to interdomain event channel!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error_post_map; + } + unmask_evtchn(tpmif->evtchn); + + /* Write the ready flag and change status to connected */ + snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid, tpmif->handle); + if((err = xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) { + TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n", (unsigned int) tpmif->domid, tpmif->handle); + free(err); + goto error_post_evtchn; + } + tpmif->status = CONNECTED; + if((tpmif_change_state(tpmif, XenbusStateConnected))){ + goto error_post_evtchn; + } + + TPMBACK_LOG("Frontend %u/%u connected\n", (unsigned int) tpmif->domid, tpmif->handle); + + return 0; +error_post_evtchn: + mask_evtchn(tpmif->evtchn); + unbind_evtchn(tpmif->evtchn); +error_post_map: + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1); + return -1; +} + +static int frontend_changed(tpmif_t* tpmif) +{ + int state = xenbus_read_integer(tpmif->fe_state_path); + if(state < 0) { + state = XenbusStateUnknown; + } + + TPMBACK_DEBUG("Frontend %u/%u state changed to %d\n", (unsigned int) tpmif->domid, tpmif->handle, state); + + switch (state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + break; + + case XenbusStateConnected: + if(connect_fe(tpmif)) { + TPMBACK_ERR("Failed to connect to front end %u/%u\n", (unsigned int) tpmif->domid, tpmif->handle); + tpmif_change_state(tpmif, XenbusStateClosed); + return -1; + } + break; + + case XenbusStateClosing: + tpmif_change_state(tpmif, XenbusStateClosing); + break; + + case XenbusStateUnknown: /* keep it here */ + case XenbusStateClosed: + free_tpmif(tpmif); + break; + + default: + TPMBACK_DEBUG("BAD STATE CHANGE %u/%u state = %d for tpmif\n", (unsigned int) tpmif->domid, tpmif->handle, state); + return -1; + } + return 0; +} + + +/* parses the string that comes out of xenbus_watch_wait_return. */ +static int parse_eventstr(const char* evstr, domid_t* domid, unsigned int* handle) +{ + int ret; + char cmd[40]; + char* err; + char* value; + unsigned int udomid = 0; + tpmif_t* tpmif; + /* First check for new frontends, this occurs when /backend/vtpm/<domid>/<handle> gets created. Note we what the sscanf to fail on the last %s */ + if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd) == 2) { + *domid = udomid; + /* Make sure the entry exists, if this event triggers because the entry dissapeared then ignore it */ + if((err = xenbus_read(XBT_NIL, evstr, &value))) { + free(err); + return EV_NONE; + } + free(value); + /* Make sure the tpmif entry does not already exist, this should not happen */ + if((tpmif = get_tpmif(*domid, *handle)) != NULL) { + TPMBACK_DEBUG("Duplicate tpm entries! %u %u\n", tpmif->domid, tpmif->handle); + return EV_NONE; + } + return EV_NEWFE; + } else if((ret = sscanf(evstr, "/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) == 3) { + *domid = udomid; + if (!strcmp(cmd, "state")) + return EV_STCHNG; + } + return EV_NONE; +} + +void handle_backend_event(char* evstr) { + tpmif_t* tpmif; + domid_t domid; + unsigned int handle; + int event; + + TPMBACK_DEBUG("Xenbus Event: %s\n", evstr); + + event = parse_eventstr(evstr, &domid, &handle); + + switch(event) { + case EV_NEWFE: + if(new_tpmif(domid, handle) == NULL) { + TPMBACK_ERR("Failed to create new tpm instance %u/%u\n", (unsigned int) domid, handle); + } + wake_up(&waitq); + break; + case EV_STCHNG: + if((tpmif = get_tpmif(domid, handle))) { + frontend_changed(tpmif); + } else { + TPMBACK_DEBUG("Event Received for non-existant tpm! instance=%u/%u xenbus_event=%s\n", (unsigned int) domid, handle, evstr); + } + break; + } +} + +/* Runs through the given path and creates events recursively + * for all of its children. + * @path - xenstore path to scan */ +static void generate_backend_events(const char* path) +{ + char* err; + int i, len; + char **dirs; + char *entry; + + if((err = xenbus_ls(XBT_NIL, path, &dirs)) != NULL) { + free(err); + return; + } + + for(i = 0; dirs[i] != NULL; ++i) { + len = strlen(path) + strlen(dirs[i]) + 2; + entry = malloc(len); + snprintf(entry, len, "%s/%s", path, dirs[i]); + + /* Generate and handle event for the entry itself */ + handle_backend_event(entry); + + /* Do children */ + generate_backend_events(entry); + + /* Cleanup */ + free(entry); + free(dirs[i]); + } + free(dirs); + return; +} + +char* tpmback_get_uuid(domid_t domid, unsigned int handle) +{ + tpmif_t* tpmif; + if((tpmif = get_tpmif(domid, handle)) == NULL) { + TPMBACK_DEBUG("get_uuid() failed, %u/%u is an invalid frontend\n", (unsigned int) domid, handle); + return NULL; + } + + return tpmif->uuid; +} + +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int)) +{ + gtpmdev.open_callback = cb; +} +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int)) +{ + gtpmdev.close_callback = cb; +} +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int)) +{ + gtpmdev.suspend_callback = cb; +} +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)) +{ + gtpmdev.resume_callback = cb; +} + +static void event_listener(void) +{ + const char* bepath = "backend/vtpm"; + char **path; + char* err; + + /* Setup the backend device watch */ + if((err = xenbus_watch_path_token(XBT_NIL, bepath, bepath, >pmdev.events)) != NULL) { + TPMBACK_ERR("xenbus_watch_path_token(%s) failed with error %s!\n", bepath, err); + free(err); + goto egress; + } + + /* Check for any frontends that connected before we set the watch. + * This is almost guaranteed to happen if both domains are started + * immediatly one after the other. + * We do this by manually generating events on everything in the backend + * path */ + generate_backend_events(bepath); + + /* Wait and listen for changes in frontend connections */ + while(1) { + path = xenbus_wait_for_watch_return(>pmdev.events); + + /*If quit flag was set then exit */ + if(gtpmdev.flags & TPMIF_CLOSED) { + TPMBACK_DEBUG("listener thread got quit event. Exiting..\n"); + free(path); + break; + } + handle_backend_event(*path); + free(path); + + } + + if((err = xenbus_unwatch_path_token(XBT_NIL, bepath, bepath)) != NULL) { + free(err); + } +egress: + return; +} + +void event_thread(void* p) { + event_listener(); +} + +void init_tpmback(char** exclusive_uuids) +{ + if(!globalinit) { + init_waitqueue_head(&waitq); + globalinit = 1; + } + printk("============= Init TPM BACK ================\n"); + gtpmdev.tpmlist = malloc(sizeof(tpmif_t*) * DEF_ARRAY_SIZE); + gtpmdev.num_alloc = DEF_ARRAY_SIZE; + gtpmdev.num_tpms = 0; + gtpmdev.flags = 0; + gtpmdev.exclusive_uuids = exclusive_uuids; + + gtpmdev.open_callback = gtpmdev.close_callback = NULL; + gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL; + + eventthread = create_thread("tpmback-listener", event_thread, NULL); + +} + +void shutdown_tpmback(void) +{ + /* Disable callbacks */ + gtpmdev.open_callback = gtpmdev.close_callback = NULL; + gtpmdev.suspend_callback = gtpmdev.resume_callback = NULL; + + TPMBACK_LOG("Shutting down tpm backend\n"); + /* Set the quit flag */ + gtpmdev.flags = TPMIF_CLOSED; + + //printk("num tpms is %d\n", gtpmdev.num_tpms); + /*Free all backend instances */ + while(gtpmdev.num_tpms) { + free_tpmif(gtpmdev.tpmlist[0]); + } + free(gtpmdev.tpmlist); + gtpmdev.tpmlist = NULL; + gtpmdev.num_alloc = 0; + + /* Wake up anyone possibly waiting on the device and let them exit */ + wake_up(&waitq); + schedule(); +} + +inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int handle, char* uuid) +{ + tpmcmd->domid = domid; + tpmcmd->handle = handle; + tpmcmd->uuid = uuid; + tpmcmd->req = NULL; + tpmcmd->req_len = 0; + tpmcmd->resp = NULL; + tpmcmd->resp_len = 0; +} + +tpmcmd_t* get_request(tpmif_t* tpmif) { + tpmcmd_t* cmd; + tpmif_tx_request_t* tx; + int offset; + int tocopy; + int i; + uint32_t domid; + int flags; + + local_irq_save(flags); + + /* Allocate the cmd object to hold the data */ + if((cmd = malloc(sizeof(*cmd))) == NULL) { + goto error; + } + init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid); + + tx = &tpmif->tx->ring[0].req; + cmd->req_len = tx->size; + /* Allocate the buffer */ + if(cmd->req_len) { + if((cmd->req = malloc(cmd->req_len)) == NULL) { + goto error; + } + } + /* Copy the bits from the shared pages */ + offset = 0; + for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->req_len; ++i) { + tx = &tpmif->tx->ring[i].req; + + /* Map the page with the data */ + domid = (uint32_t)tpmif->domid; + if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_READ)) == NULL) { + TPMBACK_ERR("%u/%u Unable to map shared page during read!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; + } + + /* do the copy now */ + tocopy = min(cmd->req_len - offset, PAGE_SIZE); + memcpy(&cmd->req[offset], tpmif->pages[i], tocopy); + offset += tocopy; + + /* release the page */ + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); + + } + +#ifdef TPMBACK_PRINT_DEBUG + TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->req_len); + for(i = 0; i < cmd->req_len; ++i) { + if (!(i % 30)) { + TPMBACK_DEBUG_MORE("\n"); + } + TPMBACK_DEBUG_MORE("%02hhX ", cmd->req[i]); + } + TPMBACK_DEBUG_MORE("\n\n"); +#endif + + local_irq_restore(flags); + return cmd; +error: + if(cmd != NULL) { + if (cmd->req != NULL) { + free(cmd->req); + cmd->req = NULL; + } + free(cmd); + cmd = NULL; + } + local_irq_restore(flags); + return NULL; + +} + +void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) +{ + tpmif_tx_request_t* tx; + int offset; + int i; + uint32_t domid; + int tocopy; + int flags; + + local_irq_save(flags); + + tx = &tpmif->tx->ring[0].req; + tx->size = cmd->resp_len; + + offset = 0; + for(i = 0; i < TPMIF_TX_RING_SIZE && offset < cmd->resp_len; ++i) { + tx = &tpmif->tx->ring[i].req; + + /* Map the page with the data */ + domid = (uint32_t)tpmif->domid; + if((tpmif->pages[i] = gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0, &tx->ref, PROT_WRITE)) == NULL) { + TPMBACK_ERR("%u/%u Unable to map shared page during write!\n", (unsigned int) tpmif->domid, tpmif->handle); + goto error; + } + + /* do the copy now */ + tocopy = min(cmd->resp_len - offset, PAGE_SIZE); + memcpy(tpmif->pages[i], &cmd->resp[offset], tocopy); + offset += tocopy; + + /* release the page */ + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1); + + } + +#ifdef TPMBACK_PRINT_DEBUG + TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int) tpmif->domid, tpmif->handle, cmd->resp_len); + for(i = 0; i < cmd->resp_len; ++i) { + if (!(i % 30)) { + TPMBACK_DEBUG_MORE("\n"); + } + TPMBACK_DEBUG_MORE("%02hhX ", cmd->resp[i]); + } + TPMBACK_DEBUG_MORE("\n\n"); +#endif + /* clear the ready flag and send the event channel notice to the frontend */ + tpmif_req_finished(tpmif); + notify_remote_via_evtchn(tpmif->evtchn); +error: + local_irq_restore(flags); + return; +} + +tpmcmd_t* tpmback_req_any(void) +{ + int i; + /* Block until something has a request */ + wait_event(waitq, (gtpmdev.flags & (TPMIF_REQ_READY | TPMIF_CLOSED))); + + /* Check if were shutting down */ + if(gtpmdev.flags & TPMIF_CLOSED) { + /* if something was waiting for us to give up the queue so it can shutdown, let it finish */ + schedule(); + return NULL; + } + + for(i = 0; i < gtpmdev.num_tpms; ++i) { + if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) { + return get_request(gtpmdev.tpmlist[i]); + } + } + + TPMBACK_ERR("backend request ready flag was set but no interfaces were actually ready\n"); + return NULL; +} + +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle) +{ + tpmif_t* tpmif; + tpmif = get_tpmif(domid, handle); + if(tpmif == NULL) { + return NULL; + } + + wait_event(waitq, (tpmif->flags & (TPMIF_REQ_READY | TPMIF_CLOSED) || gtpmdev.flags & TPMIF_CLOSED)); + + /* Check if were shutting down */ + if(tpmif->flags & TPMIF_CLOSED || gtpmdev.flags & TPMIF_CLOSED) { + /* if something was waiting for us to give up the queue so it can free this instance, let it finish */ + schedule(); + return NULL; + } + + return get_request(tpmif); +} + +void tpmback_resp(tpmcmd_t* tpmcmd) +{ + tpmif_t* tpmif; + + /* Get the associated interface, if it doesnt exist then just quit */ + tpmif = get_tpmif(tpmcmd->domid, tpmcmd->handle); + if(tpmif == NULL) { + TPMBACK_ERR("Tried to send a reponse to non existant frontend %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle); + goto end; + } + + if(!(tpmif->flags & TPMIF_REQ_READY)) { + TPMBACK_ERR("Tried to send response to a frontend that was not waiting for one %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle); + goto end; + } + + /* Send response to frontend */ + send_response(tpmcmd, tpmif); + +end: + if(tpmcmd->req != NULL) { + free(tpmcmd->req); + } + free(tpmcmd); + return; +} + +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int *handle) +{ + tpmif_t* tpmif; + int flags; + wait_event(waitq, ((gtpmdev.num_tpms > 0) || gtpmdev.flags & TPMIF_CLOSED)); + if(gtpmdev.flags & TPMIF_CLOSED) { + return -1; + } + local_irq_save(flags); + tpmif = gtpmdev.tpmlist[0]; + *domid = tpmif->domid; + *handle = tpmif->handle; + local_irq_restore(flags); + + return 0; +} + +int tpmback_num_frontends(void) +{ + return gtpmdev.num_tpms; +} diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c new file mode 100644 index 0000000..a2f9175 --- /dev/null +++ b/extras/mini-os/tpmfront.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2010-2012 United States Government, as represented by + * the Secretary of Defense. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Based upon the files: + * drivers/char/tpm/tpm_vtpm.c + * drivers/char/tpm/tpm_xen.c + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation + */ +#include <mini-os/os.h> +#include <mini-os/xenbus.h> +#include <mini-os/xmalloc.h> +#include <mini-os/events.h> +#include <mini-os/wait.h> +#include <mini-os/gnttab.h> +#include <xen/io/xenbus.h> +#include <xen/io/tpmif.h> +#include <mini-os/tpmfront.h> +#include <fcntl.h> + +//#define TPMFRONT_PRINT_DEBUG +#ifdef TPMFRONT_PRINT_DEBUG +#define TPMFRONT_DEBUG(fmt,...) printk("Tpmfront:Debug("__FILE__":%d) " fmt, __LINE__, ##__VA_ARGS__) +#define TPMFRONT_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__) +#else +#define TPMFRONT_DEBUG(fmt,...) +#endif +#define TPMFRONT_ERR(fmt,...) printk("Tpmfront:Error " fmt, ##__VA_ARGS__) +#define TPMFRONT_LOG(fmt,...) printk("Tpmfront:Info " fmt, ##__VA_ARGS__) + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data) { + struct tpmfront_dev* dev = (struct tpmfront_dev*) data; + /*If we get a response when we didnt make a request, just ignore it */ + if(!dev->waiting) { + return; + } + + dev->waiting = 0; +#ifdef HAVE_LIBC + if(dev->fd >= 0) { + files[dev->fd].read = 1; + } +#endif + wake_up(&dev->waitq); +} + +static int publish_xenbus(struct tpmfront_dev* dev) { + xenbus_transaction_t xbt; + int retry; + char* err; + /* Write the grant reference and event channel to xenstore */ +again: + if((err = xenbus_transaction_start(&xbt))) { + TPMFRONT_ERR("Unable to start xenbus transaction, error was %s\n", err); + free(err); + return -1; + } + + if((err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u", (unsigned int) dev->ring_ref))) { + TPMFRONT_ERR("Unable to write %s/ring-ref, error was %s\n", dev->nodename, err); + free(err); + goto abort_transaction; + } + + if((err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", (unsigned int) dev->evtchn))) { + TPMFRONT_ERR("Unable to write %s/event-channel, error was %s\n", dev->nodename, err); + free(err); + goto abort_transaction; + } + + if((err = xenbus_transaction_end(xbt, 0, &retry))) { + TPMFRONT_ERR("Unable to complete xenbus transaction, error was %s\n", err); + free(err); + return -1; + } + if(retry) { + goto again; + } + + return 0; +abort_transaction: + if((err = xenbus_transaction_end(xbt, 1, &retry))) { + free(err); + } + return -1; +} + +static int wait_for_backend_connect(xenbus_event_queue* events, char* path) +{ + int state; + + TPMFRONT_LOG("Waiting for backend connection..\n"); + /* Wait for the backend to connect */ + while(1) { + state = xenbus_read_integer(path); + if ( state < 0) + state = XenbusStateUnknown; + switch(state) { + /* Bad states, we quit with error */ + case XenbusStateUnknown: + case XenbusStateClosing: + case XenbusStateClosed: + TPMFRONT_ERR("Unable to connect to backend\n"); + return -1; + /* If backend is connected then break out of loop */ + case XenbusStateConnected: + TPMFRONT_LOG("Backend Connected\n"); + return 0; + default: + xenbus_wait_for_watch(events); + } + } + +} + +static int wait_for_backend_closed(xenbus_event_queue* events, char* path) +{ + int state; + + TPMFRONT_LOG("Waiting for backend to close..\n"); + while(1) { + state = xenbus_read_integer(path); + if ( state < 0) + state = XenbusStateUnknown; + switch(state) { + case XenbusStateUnknown: + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); + return -1; + case XenbusStateClosed: + TPMFRONT_LOG("Backend Closed\n"); + return 0; + default: + xenbus_wait_for_watch(events); + } + } + +} + +static int wait_for_backend_state_changed(struct tpmfront_dev* dev, XenbusState state) { + char* err; + int ret = 0; + xenbus_event_queue events = NULL; + char path[512]; + + snprintf(path, 512, "%s/state", dev->bepath); + /*Setup the watch to wait for the backend */ + if((err = xenbus_watch_path_token(XBT_NIL, path, path, &events))) { + TPMFRONT_ERR("Could not set a watch on %s, error was %s\n", path, err); + free(err); + return -1; + } + + /* Do the actual wait loop now */ + switch(state) { + case XenbusStateConnected: + ret = wait_for_backend_connect(&events, path); + break; + case XenbusStateClosed: + ret = wait_for_backend_closed(&events, path); + break; + default: + break; + } + + if((err = xenbus_unwatch_path_token(XBT_NIL, path, path))) { + TPMFRONT_ERR("Unable to unwatch %s, error was %s, ignoring..\n", path, err); + free(err); + } + return ret; +} + +static int tpmfront_connect(struct tpmfront_dev* dev) +{ + char* err; + /* Create shared page */ + dev->tx = (tpmif_tx_interface_t*) alloc_page(); + if(dev->tx == NULL) { + TPMFRONT_ERR("Unable to allocate page for shared memory\n"); + goto error; + } + memset(dev->tx, 0, PAGE_SIZE); + dev->ring_ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->tx), 0); + TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref); + + /*Create event channel */ + if(evtchn_alloc_unbound(dev->bedomid, tpmfront_handler, dev, &dev->evtchn)) { + TPMFRONT_ERR("Unable to allocate event channel\n"); + goto error_postmap; + } + unmask_evtchn(dev->evtchn); + TPMFRONT_DEBUG("event channel is %lu\n", (unsigned long) dev->evtchn); + + /* Write the entries to xenstore */ + if(publish_xenbus(dev)) { + goto error_postevtchn; + } + + /* Change state to connected */ + dev->state = XenbusStateConnected; + + /* Tell the backend that we are ready */ + if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", dev->state))) { + TPMFRONT_ERR("Unable to write to xenstore %s/state, value=%u", dev->nodename, XenbusStateConnected); + free(err); + goto error; + } + + return 0; +error_postevtchn: + mask_evtchn(dev->evtchn); + unbind_evtchn(dev->evtchn); +error_postmap: + gnttab_end_access(dev->ring_ref); + free_page(dev->tx); +error: + return -1; +} + +struct tpmfront_dev* init_tpmfront(const char* _nodename) +{ + struct tpmfront_dev* dev; + const char* nodename; + char path[512]; + char* value, *err; + unsigned long long ival; + int i; + + printk("============= Init TPM Front ================\n"); + + dev = malloc(sizeof(struct tpmfront_dev)); + memset(dev, 0, sizeof(struct tpmfront_dev)); + +#ifdef HAVE_LIBC + dev->fd = -1; +#endif + + nodename = _nodename ? _nodename : "device/vtpm/0"; + dev->nodename = strdup(nodename); + + init_waitqueue_head(&dev->waitq); + + /* Get backend domid */ + snprintf(path, 512, "%s/backend-id", dev->nodename); + if((err = xenbus_read(XBT_NIL, path, &value))) { + TPMFRONT_ERR("Unable to read %s during tpmfront initialization! error = %s\n", path, err); + free(err); + goto error; + } + if(sscanf(value, "%llu", &ival) != 1) { + TPMFRONT_ERR("%s has non-integer value (%s)\n", path, value); + free(value); + goto error; + } + free(value); + dev->bedomid = ival; + + /* Get backend xenstore path */ + snprintf(path, 512, "%s/backend", dev->nodename); + if((err = xenbus_read(XBT_NIL, path, &dev->bepath))) { + TPMFRONT_ERR("Unable to read %s during tpmfront initialization! error = %s\n", path, err); + free(err); + goto error; + } + + /* Create and publish grant reference and event channel */ + if (tpmfront_connect(dev)) { + goto error; + } + + /* Wait for backend to connect */ + if( wait_for_backend_state_changed(dev, XenbusStateConnected)) { + goto error; + } + + /* Allocate pages that will contain the messages */ + dev->pages = malloc(sizeof(void*) * TPMIF_TX_RING_SIZE); + if(dev->pages == NULL) { + goto error; + } + memset(dev->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); + for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { + dev->pages[i] = (void*)alloc_page(); + if(dev->pages[i] == NULL) { + goto error; + } + } + + TPMFRONT_LOG("Initialization Completed successfully\n"); + + return dev; + +error: + shutdown_tpmfront(dev); + return NULL; +} +void shutdown_tpmfront(struct tpmfront_dev* dev) +{ + char* err; + char path[512]; + int i; + tpmif_tx_request_t* tx; + if(dev == NULL) { + return; + } + TPMFRONT_LOG("Shutting down tpmfront\n"); + /* disconnect */ + if(dev->state == XenbusStateConnected) { + dev->state = XenbusStateClosing; + //FIXME: Transaction for this? + /* Tell backend we are closing */ + if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { + free(err); + } + + /* Clean up xenstore entries */ + snprintf(path, 512, "%s/event-channel", dev->nodename); + if((err = xenbus_rm(XBT_NIL, path))) { + free(err); + } + snprintf(path, 512, "%s/ring-ref", dev->nodename); + if((err = xenbus_rm(XBT_NIL, path))) { + free(err); + } + + /* Tell backend we are closed */ + dev->state = XenbusStateClosed; + if((err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", (unsigned int) dev->state))) { + TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodename, err); + free(err); + } + + /* Wait for the backend to close and unmap shared pages, ignore any errors */ + wait_for_backend_state_changed(dev, XenbusStateClosed); + + /* Cleanup any shared pages */ + if(dev->pages) { + for(i = 0; i < TPMIF_TX_RING_SIZE; ++i) { + if(dev->pages[i]) { + tx = &dev->tx->ring[i].req; + if(tx->ref != 0) { + gnttab_end_access(tx->ref); + } + free_page(dev->pages[i]); + } + } + free(dev->pages); + } + + /* Close event channel and unmap shared page */ + mask_evtchn(dev->evtchn); + unbind_evtchn(dev->evtchn); + gnttab_end_access(dev->ring_ref); + + free_page(dev->tx); + + } + + /* Cleanup memory usage */ + if(dev->respbuf) { + free(dev->respbuf); + } + if(dev->bepath) { + free(dev->bepath); + } + if(dev->nodename) { + free(dev->nodename); + } + free(dev); +} + +int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_t length) +{ + int i; + tpmif_tx_request_t* tx = NULL; + /* Error Checking */ + if(dev == NULL || dev->state != XenbusStateConnected) { + TPMFRONT_ERR("Tried to send message through disconnected frontend\n"); + return -1; + } + +#ifdef TPMFRONT_PRINT_DEBUG + TPMFRONT_DEBUG("Sending Msg to backend size=%u", (unsigned int) length); + for(i = 0; i < length; ++i) { + if(!(i % 30)) { + TPMFRONT_DEBUG_MORE("\n"); + } + TPMFRONT_DEBUG_MORE("%02X ", msg[i]); + } + TPMFRONT_DEBUG_MORE("\n"); +#endif + + /* Copy to shared pages now */ + for(i = 0; length > 0 && i < TPMIF_TX_RING_SIZE; ++i) { + /* Share the page */ + tx = &dev->tx->ring[i].req; + tx->unused = 0; + tx->addr = virt_to_mach(dev->pages[i]); + tx->ref = gnttab_grant_access(dev->bedomid, virt_to_mfn(dev->pages[i]), 0); + /* Copy the bits to the page */ + tx->size = length > PAGE_SIZE ? PAGE_SIZE : length; + memcpy(dev->pages[i], &msg[i * PAGE_SIZE], tx->size); + + /* Update counters */ + length -= tx->size; + } + dev->waiting = 1; + dev->resplen = 0; +#ifdef HAVE_LIBC + if(dev->fd >= 0) { + files[dev->fd].read = 0; + files[dev->fd].tpmfront.respgot = 0; + files[dev->fd].tpmfront.offset = 0; + } +#endif + notify_remote_via_evtchn(dev->evtchn); + return 0; +} +int tpmfront_recv(struct tpmfront_dev* dev, uint8_t** msg, size_t *length) +{ + tpmif_tx_request_t* tx; + int i; + if(dev == NULL || dev->state != XenbusStateConnected) { + TPMFRONT_ERR("Tried to receive message from disconnected frontend\n"); + return -1; + } + /*Wait for the response */ + wait_event(dev->waitq, (!dev->waiting)); + + /* Initialize */ + *msg = NULL; + *length = 0; + + /* special case, just quit */ + tx = &dev->tx->ring[0].req; + if(tx->size == 0 ) { + goto quit; + } + /* Get the total size */ + tx = &dev->tx->ring[0].req; + for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { + tx = &dev->tx->ring[i].req; + *length += tx->size; + } + /* Alloc the buffer */ + if(dev->respbuf) { + free(dev->respbuf); + } + *msg = dev->respbuf = malloc(*length); + dev->resplen = *length; + /* Copy the bits */ + tx = &dev->tx->ring[0].req; + for(i = 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { + tx = &dev->tx->ring[i].req; + memcpy(&(*msg)[i * PAGE_SIZE], dev->pages[i], tx->size); + gnttab_end_access(tx->ref); + tx->ref = 0; + } +#ifdef TPMFRONT_PRINT_DEBUG + TPMFRONT_DEBUG("Received response from backend size=%u", (unsigned int) *length); + for(i = 0; i < *length; ++i) { + if(!(i % 30)) { + TPMFRONT_DEBUG_MORE("\n"); + } + TPMFRONT_DEBUG_MORE("%02X ", (*msg)[i]); + } + TPMFRONT_DEBUG_MORE("\n"); +#endif +#ifdef HAVE_LIBC + if(dev->fd >= 0) { + files[dev->fd].tpmfront.respgot = 1; + } +#endif +quit: + return 0; +} + +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, uint8_t** resp, size_t* resplen) +{ + int rc; + if((rc = tpmfront_send(dev, req, reqlen))) { + return rc; + } + if((rc = tpmfront_recv(dev, resp, resplen))) { + return rc; + } + + return 0; +} + +#ifdef HAVE_LIBC +#include <errno.h> +int tpmfront_open(struct tpmfront_dev* dev) +{ + /* Silently prevent multiple opens */ + if(dev->fd != -1) { + return dev->fd; + } + + dev->fd = alloc_fd(FTYPE_TPMFRONT); + printk("tpmfront_open(%s) -> %d\n", dev->nodename, dev->fd); + files[dev->fd].tpmfront.dev = dev; + files[dev->fd].tpmfront.offset = 0; + files[dev->fd].tpmfront.respgot = 0; + return dev->fd; +} + +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count) +{ + int rc; + struct tpmfront_dev* dev; + dev = files[fd].tpmfront.dev; + + if(count == 0) { + return 0; + } + + /* Return an error if we are already processing a command */ + if(dev->waiting) { + errno = EINPROGRESS; + return -1; + } + /* Send the command now */ + if((rc = tpmfront_send(dev, buf, count)) != 0) { + errno = EIO; + return -1; + } + return count; +} + +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count) +{ + int rc; + uint8_t* dummybuf; + size_t dummysz; + struct tpmfront_dev* dev; + + dev = files[fd].tpmfront.dev; + + if(count == 0) { + return 0; + } + + /* get the response if we haven''t already */ + if(files[dev->fd].tpmfront.respgot == 0) { + if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) { + errno = EIO; + return -1; + } + } + + /* handle EOF case */ + if(files[dev->fd].tpmfront.offset >= dev->resplen) { + return 0; + } + + /* Compute the number of bytes and do the copy operation */ + if((rc = min(count, dev->resplen - files[dev->fd].tpmfront.offset)) != 0) { + memcpy(buf, dev->respbuf + files[dev->fd].tpmfront.offset, rc); + files[dev->fd].tpmfront.offset += rc; + } + + return rc; +} + +int tpmfront_posix_fstat(int fd, struct stat* buf) +{ + uint8_t* dummybuf; + size_t dummysz; + int rc; + struct tpmfront_dev* dev = files[fd].tpmfront.dev; + + /* If we have a response waiting, then read it now from the backend + * so we can get its length*/ + if(dev->waiting || (files[dev->fd].read == 1 && !files[dev->fd].tpmfront.respgot)) { + if ((rc = tpmfront_recv(dev, &dummybuf, &dummysz)) != 0) { + errno = EIO; + return -1; + } + } + + buf->st_mode = O_RDWR; + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_size = dev->resplen; + buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL); + + return 0; +} + + +#endif -- 1.7.9.5
George Dunlap
2012-Sep-28 10:16 UTC
Re: [PATCH 01/11] Add ioread/iowrite functions to mini-os
On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante <matthew.fioravante@jhuapl.edu> wrote:> This patch adds iowritexx() and ioreadxx() functions for interacting > with hardware memory to mini-os. The functions are available in a header > iorw.h > > Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > > diff --git a/extras/mini-os/arch/ia64/iorw.c b/extras/mini-os/arch/ia64/iorw.cIs there any reason to have the ia64 stuff? ia64 isn''t supported in Xen anymore, AFAIK. -George> new file mode 100644 > index 0000000..aa58807 > --- /dev/null > +++ b/extras/mini-os/arch/ia64/iorw.c > @@ -0,0 +1,48 @@ > +#include <mini-os/iorw.h> > +#include <mini-os/console.h> > + > +void iowrite8(volatile void* addr, uint8_t val) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > +} > +void iowrite16(volatile void* addr, uint16_t val) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > +} > +void iowrite32(volatile void* addr, uint32_t val) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > +} > +void iowrite64(volatile void* addr, uint64_t val) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > +} > + > +uint8_t ioread8(volatile void* addr) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > + return 0; > +} > +uint16_t ioread16(volatile void* addr) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > + return 0; > +} > +uint32_t ioread32(volatile void* addr) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > + return 0; > +} > +uint64_t ioread64(volatile void* addr) > +{ > + printk("iorw not implemented!!\n"); > + BUG(); > + return 0; > +} > diff --git a/extras/mini-os/arch/x86/iorw.c b/extras/mini-os/arch/x86/iorw.c > new file mode 100644 > index 0000000..3080769 > --- /dev/null > +++ b/extras/mini-os/arch/x86/iorw.c > @@ -0,0 +1,35 @@ > +#include <mini-os/iorw.h> > + > +void iowrite8(volatile void* addr, uint8_t val) > +{ > + *((volatile uint8_t*)addr) = val; > +} > +void iowrite16(volatile void* addr, uint16_t val) > +{ > + *((volatile uint16_t*)addr) = val; > +} > +void iowrite32(volatile void* addr, uint32_t val) > +{ > + *((volatile uint32_t*)addr) = val; > +} > +void iowrite64(volatile void* addr, uint64_t val) > +{ > + *((volatile uint64_t*)addr) = val; > +} > + > +uint8_t ioread8(volatile void* addr) > +{ > + return *((volatile uint8_t*) addr); > +} > +uint16_t ioread16(volatile void* addr) > +{ > + return *((volatile uint16_t*) addr); > +} > +uint32_t ioread32(volatile void* addr) > +{ > + return *((volatile uint32_t*) addr); > +} > +uint64_t ioread64(volatile void* addr) > +{ > + return *((volatile uint64_t*) addr); > +} > diff --git a/extras/mini-os/include/iorw.h b/extras/mini-os/include/iorw.h > new file mode 100644 > index 0000000..d5ec065 > --- /dev/null > +++ b/extras/mini-os/include/iorw.h > @@ -0,0 +1,16 @@ > +#ifndef MINIOS_IORW_H > +#define MINIOS_IORW_H > + > +#include <mini-os/types.h> > + > +void iowrite8(volatile void* addr, uint8_t val); > +void iowrite16(volatile void* addr, uint16_t val); > +void iowrite32(volatile void* addr, uint32_t val); > +void iowrite64(volatile void* addr, uint64_t val); > + > +uint8_t ioread8(volatile void* addr); > +uint16_t ioread16(volatile void* addr); > +uint32_t ioread32(volatile void* addr); > +uint64_t ioread64(volatile void* addr); > + > +#endif > -- > 1.7.9.5 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante <matthew.fioravante@jhuapl.edu> wrote:> This patch adds posix io support (read,write,lseek) to block devices > using blkfront. > > Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>There seems to be a lot of inconsistent use of whitespace in this one (i.e,. tabs vs spaces) -- but that seems to be true of mini-os as a whole, so it''s not too surprising. :-) It would be nice if new code at least could conform to the Xen style, which is no tabs, 4-space indentation. (I note that when big chunks of new code are added, as in blkfront.c, you do follow this convention.) (Unless Samuel thinks attempting to match the patchwork of style is more important...) -George> > diff --git a/extras/mini-os/blkfront.c b/extras/mini-os/blkfront.c > index 74b8b26..66c65c9 100644 > --- a/extras/mini-os/blkfront.c > +++ b/extras/mini-os/blkfront.c > @@ -392,6 +392,7 @@ void blkfront_aio(struct blkfront_aiocb *aiocbp, int write) > static void blkfront_aio_cb(struct blkfront_aiocb *aiocbp, int ret) > { > aiocbp->data = (void*) 1; > + aiocbp->aio_cb = NULL; > } > > void blkfront_io(struct blkfront_aiocb *aiocbp, int write) > @@ -547,9 +548,150 @@ moretodo: > #ifdef HAVE_LIBC > int blkfront_open(struct blkfront_dev *dev) > { > + /* Silently prevent multiple opens */ > + if(dev->fd != -1) { > + return dev->fd; > + } > dev->fd = alloc_fd(FTYPE_BLK); > printk("blk_open(%s) -> %d\n", dev->nodename, dev->fd); > files[dev->fd].blk.dev = dev; > + files[dev->fd].blk.offset = 0; > return dev->fd; > } > + > +int blkfront_posix_rwop(int fd, uint8_t* buf, size_t count, int write) > +{ > + struct blkfront_dev* dev = files[fd].blk.dev; > + off_t offset = files[fd].blk.offset; > + struct blkfront_aiocb aiocb; > + unsigned long long disksize = dev->info.sectors * dev->info.sector_size; > + unsigned int blocksize = dev->info.sector_size; > + > + int blknum; > + int blkoff; > + size_t bytes; > + int rc = 0; > + int alignedbuf = 0; > + uint8_t* copybuf = NULL; > + > + /* RW 0 bytes is just a NOP */ > + if(count == 0) { > + return 0; > + } > + /* Check for NULL buffer */ > + if( buf == NULL ) { > + errno = EFAULT; > + return -1; > + } > + > + /* Write mode checks */ > + if(write) { > + /*Make sure we have write permission */ > + if(dev->info.info & VDISK_READONLY || (dev->info.mode != O_RDWR && dev->info.mode != O_WRONLY)) { > + errno = EACCES; > + return -1; > + } > + /*Make sure disk is big enough for this write */ > + if(offset + count > disksize) { > + errno = ENOSPC; > + return -1; > + } > + } > + /* Read mode checks */ > + else > + { > + /*If the requested read is bigger than the disk, just > + * read as much as we can until the end */ > + if(offset + count > disksize) { > + count = offset >= disksize ? 0 : disksize - offset; > + } > + } > + /* Determine which block to start at and which offset inside of it */ > + blknum = offset / blocksize; > + blkoff = offset % blocksize; > + > + /* Optimization: We need to check if buf is aligned to the sector size. > + * This is somewhat tricky code. We have to add the blocksize - block offset > + * because the first block may be a partial block and then for every subsequent > + * block rw the buffer will be offset.*/ > + if(!((uintptr_t) (buf +(blocksize - blkoff)) & (dev->info.sector_size-1))) { > + alignedbuf = 1; > + } > + > + /* Setup aiocb block object */ > + aiocb.aio_dev = dev; > + aiocb.aio_nbytes = blocksize; > + aiocb.aio_offset = blknum * blocksize; > + aiocb.aio_cb = NULL; > + aiocb.data = NULL; > + > + /* If our buffer is unaligned or its aligned but we will need to rw a partial block > + * then a copy will have to be done */ > + if(!alignedbuf || blkoff != 0 || count % blocksize != 0) { > + copybuf = _xmalloc(blocksize, dev->info.sector_size); > + } > + > + rc = count; > + while(count > 0) { > + /* determine how many bytes to read/write from/to the current block buffer */ > + bytes = count > (blocksize - blkoff) ? blocksize - blkoff : count; > + > + /* read operation */ > + if(!write) { > + if (alignedbuf && bytes >= blocksize) { > + /* If aligned and were reading a whole block, just read right into buf */ > + aiocb.aio_buf = buf; > + blkfront_read(&aiocb); > + } else { > + /* If not then we have to do a copy */ > + aiocb.aio_buf = copybuf; > + blkfront_read(&aiocb); > + memcpy(buf, ©buf[blkoff], bytes); > + } > + } > + /* Write operation */ > + else { > + if(alignedbuf && bytes >= blocksize) { > + /* If aligned and were writing a whole block, just write directly from buf */ > + aiocb.aio_buf = buf; > + blkfront_write(&aiocb); > + } else { > + /* If not then we have to do a copy. */ > + aiocb.aio_buf = copybuf; > + /* If we''re writing a partial block, we need to read the current contents first > + * so we don''t overwrite the extra bits with garbage */ > + if(blkoff != 0 || bytes < blocksize) { > + blkfront_read(&aiocb); > + } > + memcpy(©buf[blkoff], buf, bytes); > + blkfront_write(&aiocb); > + } > + } > + /* Will start at beginning of all remaining blocks */ > + blkoff = 0; > + > + /* Increment counters and continue */ > + count -= bytes; > + buf += bytes; > + aiocb.aio_offset += blocksize; > + } > + > + free(copybuf); > + files[fd].blk.offset += rc; > + return rc; > + > +} > + > +int blkfront_posix_fstat(int fd, struct stat* buf) > +{ > + struct blkfront_dev* dev = files[fd].blk.dev; > + > + buf->st_mode = dev->info.mode; > + buf->st_uid = 0; > + buf->st_gid = 0; > + buf->st_size = dev->info.sectors * dev->info.sector_size; > + buf->st_atime = buf->st_mtime = buf->st_ctime = time(NULL); > + > + return 0; > +} > #endif > diff --git a/extras/mini-os/include/blkfront.h b/extras/mini-os/include/blkfront.h > index 724137e..3528af9 100644 > --- a/extras/mini-os/include/blkfront.h > +++ b/extras/mini-os/include/blkfront.h > @@ -28,7 +28,17 @@ struct blkfront_info > }; > struct blkfront_dev *init_blkfront(char *nodename, struct blkfront_info *info); > #ifdef HAVE_LIBC > +#include <sys/stat.h> > +/* POSIX IO functions: > + * use blkfront_open() to get a file descriptor to the block device > + * Don''t use the other blkfront posix functions here directly, instead use > + * read(), write(), lseek() and fstat() on the file descriptor > + */ > int blkfront_open(struct blkfront_dev *dev); > +int blkfront_posix_rwop(int fd, uint8_t* buf, size_t count, int write); > +#define blkfront_posix_write(fd, buf, count) blkfront_posix_rwop(fd, (uint8_t*)buf, count, 1) > +#define blkfront_posix_read(fd, buf, count) blkfront_posix_rwop(fd, (uint8_t*)buf, count, 0) > +int blkfront_posix_fstat(int fd, struct stat* buf); > #endif > void blkfront_aio(struct blkfront_aiocb *aiocbp, int write); > #define blkfront_aio_read(aiocbp) blkfront_aio(aiocbp, 0) > diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib.h > index 1af2717..d4641b6 100644 > --- a/extras/mini-os/include/lib.h > +++ b/extras/mini-os/include/lib.h > @@ -174,6 +174,7 @@ extern struct file { > } tap; > struct { > struct blkfront_dev *dev; > + off_t offset; > } blk; > struct { > struct kbdfront_dev *dev; > diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c > index a7d35d6..7ddbbf8 100644 > --- a/extras/mini-os/lib/sys.c > +++ b/extras/mini-os/lib/sys.c > @@ -289,6 +289,11 @@ int read(int fd, void *buf, size_t nbytes) > return ret * sizeof(union xenfb_in_event); > } > #endif > +#ifdef CONFIG_BLKFRONT > + case FTYPE_BLK: { > + return blkfront_posix_read(fd, buf, nbytes); > + } > +#endif > default: > break; > } > @@ -321,6 +326,10 @@ int write(int fd, const void *buf, size_t nbytes) > netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes); > return nbytes; > #endif > +#ifdef CONFIG_BLKFRONT > + case FTYPE_BLK: > + return blkfront_posix_write(fd, buf, nbytes); > +#endif > default: > break; > } > @@ -331,8 +340,37 @@ int write(int fd, const void *buf, size_t nbytes) > > off_t lseek(int fd, off_t offset, int whence) > { > - errno = ESPIPE; > - return (off_t) -1; > + switch(files[fd].type) { > +#ifdef CONFIG_BLKFRONT > + case FTYPE_BLK: > + switch (whence) { > + case SEEK_SET: > + files[fd].file.offset = offset; > + break; > + case SEEK_CUR: > + files[fd].file.offset += offset; > + break; > + case SEEK_END: > + { > + struct stat st; > + int ret; > + ret = fstat(fd, &st); > + if (ret) > + return -1; > + files[fd].file.offset = st.st_size + offset; > + break; > + } > + default: > + errno = EINVAL; > + return -1; > + } > + return files[fd].file.offset; > + break; > +#endif > + default: /* Not implemented on this FTYPE */ > + errno = ESPIPE; > + return (off_t) -1; > + } > } > > int fsync(int fd) { > @@ -445,6 +483,10 @@ int fstat(int fd, struct stat *buf) > buf->st_ctime = time(NULL); > return 0; > } > +#ifdef CONFIG_BLKFRONT > + case FTYPE_BLK: > + return blkfront_posix_fstat(fd, buf); > +#endif > default: > break; > } > -- > 1.7.9.5 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
George Dunlap
2012-Sep-28 10:48 UTC
Re: [PATCH 03/11] Add endian, byteswap, and wordsize macros to mini-os
On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante <matthew.fioravante@jhuapl.edu> wrote:> This patch addes byte swapping macros and endian support to mini-os. > > Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> >[snip]> diff --git a/extras/mini-os/include/byteswap.h b/extras/mini-os/include/byteswap.h > index 46821ae..992c8bd 100644 > --- a/extras/mini-os/include/byteswap.h > +++ b/extras/mini-os/include/byteswap.h > @@ -4,30 +4,36 @@ > /* Unfortunately not provided by newlib. */ > > #include <mini-os/types.h> > -static inline uint16_t bswap_16(uint16_t x) > -{ > - return > - ((((x) & 0xff00) >> 8) | (((x) & 0xff) << 8)); > -} > - > -static inline uint32_t bswap_32(uint32_t x) > -{ > - return > - ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | > - (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)); > -} > - > -static inline uint64_t bswap_64(uint64_t x) > -{ > - return > - ((((x) & 0xff00000000000000ULL) >> 56) | > - (((x) & 0x00ff000000000000ULL) >> 40) | > - (((x) & 0x0000ff0000000000ULL) >> 24) | > - (((x) & 0x000000ff00000000ULL) >> 8) | > - (((x) & 0x00000000ff000000ULL) << 8) | > - (((x) & 0x0000000000ff0000ULL) << 24) | > - (((x) & 0x000000000000ff00ULL) << 40) | > - (((x) & 0x00000000000000ffULL) << 56)); > -} > + > +#define bswap_16(x) ((uint16_t)( \ > + (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ > + (((uint16_t)(x) & (uint16_t)0xff00U) >> 8))) > + > +/* Use gcc optimized versions if they exist */ > +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) > +#define bswap_32(v) __builtin_bswap32(v) > +#define bswap_64(v) __builtin_bswap64(v) > +#else > + > +#define bswap_32(x) ((uint32_t)( \ > + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ > + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ > + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ > + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24))) > + > +#define bswap_64(x) ((uint64_t)( \ > + (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ > + (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ > + (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ > + (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ > + (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ > + (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ > + (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ > + (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56))) > + > +#endifI think it would be worth adding to the commit message your rationale for changing from static inline to #defines, which you gave in response to Samuel in the last iteration of this patch. [snip]> diff --git a/extras/mini-os/include/ia64/arch_endian.h b/extras/mini-os/include/ia64/arch_endian.h > new file mode 100644 > index 0000000..0771683 > --- /dev/null > +++ b/extras/mini-os/include/ia64/arch_endian.h > @@ -0,0 +1,7 @@ > +#ifndef ARCH_ENDIAN_H > +#error "Do not include arch_endian by itself, include endian.h" > +#else > + > +#define __BYTE_ORDER __LITTLE_ENDIAN > + > +#endif > diff --git a/extras/mini-os/include/ia64/arch_wordsize.h b/extras/mini-os/include/ia64/arch_wordsize.h > new file mode 100644 > index 0000000..1b5a00f > --- /dev/null > +++ b/extras/mini-os/include/ia64/arch_wordsize.h > @@ -0,0 +1 @@ > +#define __WORDSIZE 64Again, is there a reason to include the ia64 files? -George
On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante <matthew.fioravante@jhuapl.edu> wrote:> This patch adds a CONFIG_XC option to mini-os, to allow conditional > support for libxc for mini-os domains. > > Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>Hmm... Samuel said, "Apart from that, Acked-by:", but you didn''t address the "that" that he mentioned. In that circumstance, I don''t think addding the "Acked-by" to the commit message is really appropriate -- it implies that the patch was approved as-is, when in fact he was only saying that he agreed that these changes were all right, but that perhaps there needed to be more. Can you address his question? -George> > diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile > index c425f76..b4236e8 100644 > --- a/extras/mini-os/Makefile > +++ b/extras/mini-os/Makefile > @@ -27,6 +27,7 @@ CONFIG_FBFRONT ?= y > CONFIG_KBDFRONT ?= y > CONFIG_CONSFRONT ?= y > CONFIG_XENBUS ?= y > +CONFIG_XC ?=y > CONFIG_LWIP ?= $(lwip) > > # Export config items as compiler directives > diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c > index 7ddbbf8..6cb97b1 100644 > --- a/extras/mini-os/lib/sys.c > +++ b/extras/mini-os/lib/sys.c > @@ -397,6 +397,7 @@ int close(int fd) > return res; > } > #endif > +#ifdef CONFIG_XC > case FTYPE_XC: > minios_interface_close_fd(fd); > return 0; > @@ -406,6 +407,7 @@ int close(int fd) > case FTYPE_GNTMAP: > minios_gnttab_close_fd(fd); > return 0; > +#endif > #ifdef CONFIG_NETFRONT > case FTYPE_TAP: > shutdown_netfront(files[fd].tap.dev); > @@ -1195,10 +1197,13 @@ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset > > if (fd == -1) > return map_zero(n, 1); > +#ifdef CONFIG_XC > else if (files[fd].type == FTYPE_XC) { > unsigned long zero = 0; > return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, NULL, 0); > - } else if (files[fd].type == FTYPE_MEM) { > + } > +#endif > + else if (files[fd].type == FTYPE_MEM) { > unsigned long first_mfn = offset >> PAGE_SHIFT; > return map_frames_ex(&first_mfn, n, 0, 1, 1, DOMID_IO, NULL, _PAGE_PRESENT|_PAGE_RW); > } else ASSERT(0); > -- > 1.7.9.5 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Sep-28 13:57 UTC
Re: [PATCH 01/11] Add ioread/iowrite functions to mini-os
On 09/28/2012 06:16 AM, George Dunlap wrote:> On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante > <matthew.fioravante@jhuapl.edu> wrote: >> This patch adds iowritexx() and ioreadxx() functions for interacting >> with hardware memory to mini-os. The functions are available in a header >> iorw.h >> >> Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> >> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> >> >> diff --git a/extras/mini-os/arch/ia64/iorw.c b/extras/mini-os/arch/ia64/iorw.c > Is there any reason to have the ia64 stuff? ia64 isn''t supported in > Xen anymore, AFAIK.Maybe not. But until ia64 support is removed from mini-os the function bodies should exist so stuff will compile.> -George > >> new file mode 100644 >> index 0000000..aa58807 >> --- /dev/null >> +++ b/extras/mini-os/arch/ia64/iorw.c >> @@ -0,0 +1,48 @@ >> +#include <mini-os/iorw.h> >> +#include <mini-os/console.h> >> + >> +void iowrite8(volatile void* addr, uint8_t val) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> +} >> +void iowrite16(volatile void* addr, uint16_t val) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> +} >> +void iowrite32(volatile void* addr, uint32_t val) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> +} >> +void iowrite64(volatile void* addr, uint64_t val) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> +} >> + >> +uint8_t ioread8(volatile void* addr) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> + return 0; >> +} >> +uint16_t ioread16(volatile void* addr) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> + return 0; >> +} >> +uint32_t ioread32(volatile void* addr) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> + return 0; >> +} >> +uint64_t ioread64(volatile void* addr) >> +{ >> + printk("iorw not implemented!!\n"); >> + BUG(); >> + return 0; >> +} >> diff --git a/extras/mini-os/arch/x86/iorw.c b/extras/mini-os/arch/x86/iorw.c >> new file mode 100644 >> index 0000000..3080769 >> --- /dev/null >> +++ b/extras/mini-os/arch/x86/iorw.c >> @@ -0,0 +1,35 @@ >> +#include <mini-os/iorw.h> >> + >> +void iowrite8(volatile void* addr, uint8_t val) >> +{ >> + *((volatile uint8_t*)addr) = val; >> +} >> +void iowrite16(volatile void* addr, uint16_t val) >> +{ >> + *((volatile uint16_t*)addr) = val; >> +} >> +void iowrite32(volatile void* addr, uint32_t val) >> +{ >> + *((volatile uint32_t*)addr) = val; >> +} >> +void iowrite64(volatile void* addr, uint64_t val) >> +{ >> + *((volatile uint64_t*)addr) = val; >> +} >> + >> +uint8_t ioread8(volatile void* addr) >> +{ >> + return *((volatile uint8_t*) addr); >> +} >> +uint16_t ioread16(volatile void* addr) >> +{ >> + return *((volatile uint16_t*) addr); >> +} >> +uint32_t ioread32(volatile void* addr) >> +{ >> + return *((volatile uint32_t*) addr); >> +} >> +uint64_t ioread64(volatile void* addr) >> +{ >> + return *((volatile uint64_t*) addr); >> +} >> diff --git a/extras/mini-os/include/iorw.h b/extras/mini-os/include/iorw.h >> new file mode 100644 >> index 0000000..d5ec065 >> --- /dev/null >> +++ b/extras/mini-os/include/iorw.h >> @@ -0,0 +1,16 @@ >> +#ifndef MINIOS_IORW_H >> +#define MINIOS_IORW_H >> + >> +#include <mini-os/types.h> >> + >> +void iowrite8(volatile void* addr, uint8_t val); >> +void iowrite16(volatile void* addr, uint16_t val); >> +void iowrite32(volatile void* addr, uint32_t val); >> +void iowrite64(volatile void* addr, uint64_t val); >> + >> +uint8_t ioread8(volatile void* addr); >> +uint16_t ioread16(volatile void* addr); >> +uint32_t ioread32(volatile void* addr); >> +uint64_t ioread64(volatile void* addr); >> + >> +#endif >> -- >> 1.7.9.5 >> >> >> _______________________________________________ >> Xen-devel mailing list >> Xen-devel@lists.xen.org >> http://lists.xen.org/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
On 09/28/2012 07:18 AM, George Dunlap wrote:> On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante > <matthew.fioravante@jhuapl.edu> wrote: >> This patch adds a CONFIG_XC option to mini-os, to allow conditional >> support for libxc for mini-os domains. >> >> Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> >> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > Hmm... Samuel said, "Apart from that, Acked-by:", but you didn''t > address the "that" that he mentioned. In that circumstance, I don''t > think addding the "Acked-by" to the commit message is really > appropriate -- it implies that the patch was approved as-is, when in > fact he was only saying that he agreed that these changes were all > right, but that perhaps there needed to be more. > > Can you address his question?I''ll look into it. I assumed Acked-by in the message meant it was officially acked. Sorry about that.> -George > >> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile >> index c425f76..b4236e8 100644 >> --- a/extras/mini-os/Makefile >> +++ b/extras/mini-os/Makefile >> @@ -27,6 +27,7 @@ CONFIG_FBFRONT ?= y >> CONFIG_KBDFRONT ?= y >> CONFIG_CONSFRONT ?= y >> CONFIG_XENBUS ?= y >> +CONFIG_XC ?=y >> CONFIG_LWIP ?= $(lwip) >> >> # Export config items as compiler directives >> diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c >> index 7ddbbf8..6cb97b1 100644 >> --- a/extras/mini-os/lib/sys.c >> +++ b/extras/mini-os/lib/sys.c >> @@ -397,6 +397,7 @@ int close(int fd) >> return res; >> } >> #endif >> +#ifdef CONFIG_XC >> case FTYPE_XC: >> minios_interface_close_fd(fd); >> return 0; >> @@ -406,6 +407,7 @@ int close(int fd) >> case FTYPE_GNTMAP: >> minios_gnttab_close_fd(fd); >> return 0; >> +#endif >> #ifdef CONFIG_NETFRONT >> case FTYPE_TAP: >> shutdown_netfront(files[fd].tap.dev); >> @@ -1195,10 +1197,13 @@ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset >> >> if (fd == -1) >> return map_zero(n, 1); >> +#ifdef CONFIG_XC >> else if (files[fd].type == FTYPE_XC) { >> unsigned long zero = 0; >> return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, NULL, 0); >> - } else if (files[fd].type == FTYPE_MEM) { >> + } >> +#endif >> + else if (files[fd].type == FTYPE_MEM) { >> unsigned long first_mfn = offset >> PAGE_SHIFT; >> return map_frames_ex(&first_mfn, n, 0, 1, 1, DOMID_IO, NULL, _PAGE_PRESENT|_PAGE_RW); >> } else ASSERT(0); >> -- >> 1.7.9.5 >> >> >> _______________________________________________ >> Xen-devel mailing list >> Xen-devel@lists.xen.org >> http://lists.xen.org/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
This patch adds a CONFIG_XC option to mini-os, to allow conditional support for libxc for mini-os domains. Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> --- * Disable linking against libxc if its disabled diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile index c425f76..2422db3 100644 --- a/extras/mini-os/Makefile +++ b/extras/mini-os/Makefile @@ -27,6 +27,7 @@ CONFIG_FBFRONT ?= y CONFIG_KBDFRONT ?= y CONFIG_CONSFRONT ?= y CONFIG_XENBUS ?= y +CONFIG_XC ?=y CONFIG_LWIP ?= $(lwip) # Export config items as compiler directives @@ -144,7 +145,9 @@ endif OBJS := $(filter-out $(OBJ_DIR)/lwip%.o $(LWO), $(OBJS)) ifeq ($(libc),y) +ifeq ($(CONFIG_XC),y) APP_LDLIBS += -L$(XEN_ROOT)/stubdom/libxc-$(XEN_TARGET_ARCH) -whole-archive -lxenguest -lxenctrl -no-whole-archive +endif APP_LDLIBS += -lpci APP_LDLIBS += -lz APP_LDLIBS += -lm diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c index 7ddbbf8..6cb97b1 100644 --- a/extras/mini-os/lib/sys.c +++ b/extras/mini-os/lib/sys.c @@ -397,6 +397,7 @@ int close(int fd) return res; } #endif +#ifdef CONFIG_XC case FTYPE_XC: minios_interface_close_fd(fd); return 0; @@ -406,6 +407,7 @@ int close(int fd) case FTYPE_GNTMAP: minios_gnttab_close_fd(fd); return 0; +#endif #ifdef CONFIG_NETFRONT case FTYPE_TAP: shutdown_netfront(files[fd].tap.dev); @@ -1195,10 +1197,13 @@ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset if (fd == -1) return map_zero(n, 1); +#ifdef CONFIG_XC else if (files[fd].type == FTYPE_XC) { unsigned long zero = 0; return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, NULL, 0); - } else if (files[fd].type == FTYPE_MEM) { + } +#endif + else if (files[fd].type == FTYPE_MEM) { unsigned long first_mfn = offset >> PAGE_SHIFT; return map_frames_ex(&first_mfn, n, 0, 1, 1, DOMID_IO, NULL, _PAGE_PRESENT|_PAGE_RW); } else ASSERT(0); -- 1.7.9.5
Also will note that I tested this change against c-stubdom with a libxc function. It fails to link when CONFIG_XC=n so the change works. On 09/28/2012 11:24 AM, Matthew Fioravante wrote:> This patch adds a CONFIG_XC option to mini-os, to allow conditional > support for libxc for mini-os domains. > > Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > --- > * Disable linking against libxc if its disabled > > diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile > index c425f76..2422db3 100644 > --- a/extras/mini-os/Makefile > +++ b/extras/mini-os/Makefile > @@ -27,6 +27,7 @@ CONFIG_FBFRONT ?= y > CONFIG_KBDFRONT ?= y > CONFIG_CONSFRONT ?= y > CONFIG_XENBUS ?= y > +CONFIG_XC ?=y > CONFIG_LWIP ?= $(lwip) > > # Export config items as compiler directives > @@ -144,7 +145,9 @@ endif > OBJS := $(filter-out $(OBJ_DIR)/lwip%.o $(LWO), $(OBJS)) > > ifeq ($(libc),y) > +ifeq ($(CONFIG_XC),y) > APP_LDLIBS += -L$(XEN_ROOT)/stubdom/libxc-$(XEN_TARGET_ARCH) -whole-archive -lxenguest -lxenctrl -no-whole-archive > +endif > APP_LDLIBS += -lpci > APP_LDLIBS += -lz > APP_LDLIBS += -lm > diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c > index 7ddbbf8..6cb97b1 100644 > --- a/extras/mini-os/lib/sys.c > +++ b/extras/mini-os/lib/sys.c > @@ -397,6 +397,7 @@ int close(int fd) > return res; > } > #endif > +#ifdef CONFIG_XC > case FTYPE_XC: > minios_interface_close_fd(fd); > return 0; > @@ -406,6 +407,7 @@ int close(int fd) > case FTYPE_GNTMAP: > minios_gnttab_close_fd(fd); > return 0; > +#endif > #ifdef CONFIG_NETFRONT > case FTYPE_TAP: > shutdown_netfront(files[fd].tap.dev); > @@ -1195,10 +1197,13 @@ void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset > > if (fd == -1) > return map_zero(n, 1); > +#ifdef CONFIG_XC > else if (files[fd].type == FTYPE_XC) { > unsigned long zero = 0; > return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, NULL, 0); > - } else if (files[fd].type == FTYPE_MEM) { > + } > +#endif > + else if (files[fd].type == FTYPE_MEM) { > unsigned long first_mfn = offset >> PAGE_SHIFT; > return map_frames_ex(&first_mfn, n, 0, 1, 1, DOMID_IO, NULL, _PAGE_PRESENT|_PAGE_RW); > } else ASSERT(0);_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
George Dunlap
2012-Sep-28 15:39 UTC
Re: [PATCH 01/11] Add ioread/iowrite functions to mini-os
On 28/09/12 14:57, Matthew Fioravante wrote:> On 09/28/2012 06:16 AM, George Dunlap wrote: >> On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante >> <matthew.fioravante@jhuapl.edu> wrote: >>> This patch adds iowritexx() and ioreadxx() functions for interacting >>> with hardware memory to mini-os. The functions are available in a header >>> iorw.h >>> >>> Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> >>> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> >>> >>> diff --git a/extras/mini-os/arch/ia64/iorw.c b/extras/mini-os/arch/ia64/iorw.c >> Is there any reason to have the ia64 stuff? ia64 isn''t supported in >> Xen anymore, AFAIK. > Maybe not. But until ia64 support is removed from mini-os the function > bodies should exist so stuff will compile.Ah, right. :-) Then: Reviewed-by: George Dunlap <george.dunlap@eu.citrix.com>
Ian Campbell
2012-Oct-02 09:10 UTC
Re: [PATCH 01/11] Add ioread/iowrite functions to mini-os
On Fri, 2012-09-28 at 14:57 +0100, Matthew Fioravante wrote:> On 09/28/2012 06:16 AM, George Dunlap wrote: > > On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante > > <matthew.fioravante@jhuapl.edu> wrote: > >> This patch adds iowritexx() and ioreadxx() functions for interacting > >> with hardware memory to mini-os. The functions are available in a header > >> iorw.h > >> > >> Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > >> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > >> > >> diff --git a/extras/mini-os/arch/ia64/iorw.c b/extras/mini-os/arch/ia64/iorw.c > > Is there any reason to have the ia64 stuff? ia64 isn''t supported in > > Xen anymore, AFAIK. > Maybe not. But until ia64 support is removed from mini-os the function > bodies should exist so stuff will compile.I thought I had dropped all the remnants of ia64 in mini-os in commit 25882:485e6db28b93 "tools: drop ia64 support". Let me know if you think I''ve missed something, but:> >> new file mode 100644 > >> index 0000000..aa58807 > >> --- /dev/null > >> +++ b/extras/mini-os/arch/ia64/iorw.c$ ls extras/mini-os/arch/ia64/iorw.c ls: cannot access extras/mini-os/arch/ia64/iorw.c: No such file or directory I think perhaps you just need to rebase? Ian.
Ian Campbell
2012-Oct-02 10:49 UTC
Re: [PATCH 04/11] Disable the mfn_is_ram() check, it doesn''t work correctly on all systems
On Thu, 2012-09-27 at 18:09 +0100, Matthew Fioravante wrote:> This patch disables the mfn_is_ram check in mini-os. The current check > is insufficient and fails on some systems with larger than 4gb memory. > > Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> > Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org>Further down the thread with the Ack Samuel said: We can probably just remove the check in __do_ioremap, which AFAIK is the only call. since this function is a bit pointless now.> > diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c > index 80aceac..5813a08 100644 > --- a/extras/mini-os/arch/x86/mm.c > +++ b/extras/mini-os/arch/x86/mm.c > @@ -850,6 +850,8 @@ unsigned long alloc_contig_pages(int order, unsigned int addr_bits) > static long system_ram_end_mfn; > int mfn_is_ram(unsigned long mfn) > { > + /* This is broken on systems with large ammounts of ram. Always return 0 for now */ > + return 0; > /* very crude check if a given MFN is memory or not. Probably should > * make this a little more sophisticated ;) */ > return (mfn <= system_ram_end_mfn) ? 1 : 0;
Ian Campbell
2012-Oct-02 10:57 UTC
Re: [PATCH 08/11] add tpmfront, tpm_tis, and tpmback drivers to mini-os
> diff --git a/extras/mini-os/include/tpm_tis.h b/extras/mini-os/include/tpm_tis.h > new file mode 100644 > index 0000000..b463cea > --- /dev/null > +++ b/extras/mini-os/include/tpm_tis.h > @@ -0,0 +1,74 @@ > +/* > + * Copyright (c) 2010-2012 United States Government, as represented by > + * the Secretary of Defense. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation; or, when distributed > + * separately from the Linux kernel or incorporated into other > + * software packages, subject to the following license: > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this source file (the "Software"), to deal in the Software without > + * restriction, including without limitation the rights to use, copy, modify, > + * merge, publish, distribute, sublicense, and/or sell copies of the Software, > + * and to permit persons to whom the Software is furnished to do so, subject to > + * the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + * > + * Based upon the files: > + * drivers/char/tpm/tpm_tis.c > + * drivers/char/tpm/tpm.c > + * from the Linux kernel, which are Copyright (C) 2006 IBM CorporationGiven that then I don''t think you have the authority to dual license code owned by IBM as GPL or the MIT style thing above -- these files are subject to the licensing terms of those original files (which looks to be GPL v2 only). It might be acceptable to have a GPL header as the primary followed by a "modifications by Matthew Fioravante/US Gov/Secretary Defense are also licensed under... .MIT thing ...." but I''d want to see a second opinion on that I think. I didn''t check all the other licensing thoroughly but I expect similar comments will apply elsewhere too. Ian.
Ian Jackson
2012-Oct-02 11:08 UTC
Re: [PATCH 08/11] add tpmfront, tpm_tis, and tpmback drivers to mini-os
Ian Campbell writes ("Re: [Xen-devel] [PATCH 08/11] add tpmfront, tpm_tis, and tpmback drivers to mini-os"):> > diff --git a/extras/mini-os/include/tpm_tis.h b/extras/mini-os/include/tpm_tis.h > > new file mode 100644 > > index 0000000..b463cea > > --- /dev/null > > +++ b/extras/mini-os/include/tpm_tis.h > > @@ -0,0 +1,74 @@ > > +/* > > + * Copyright (c) 2010-2012 United States Government, as represented by > > + * the Secretary of Defense. All rights reserved. > > + * > > + * This program is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU General Public License version 2 > > + * as published by the Free Software Foundation; or, when distributed > > + * separately from the Linux kernel or incorporated into other > > + * software packages, subject to the following license: > > + * > > + * Permission is hereby granted, free of charge, to any person > > + * obtaining a copy of this source file (the "Software"), to deal[ MIT licence continues ] ...> > + * Based upon the files: > > + * drivers/char/tpm/tpm_tis.c > > + * drivers/char/tpm/tpm.c > > + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation > > Given that then I don''t think you have the authority to dual license > code owned by IBM as GPL or the MIT style thing above -- these files are > subject to the licensing terms of those original files (which looks to > be GPL v2 only).Indeed so. This is totally forbidden, I''m afraid. Are you sure you know what you are doing with the licensing here ? Do you have anyone nearby who could help you with this ? The basic principle is that the existing source file licence must remain unchanged.> It might be acceptable to have a GPL header as the primary followed by a > "modifications by Matthew Fioravante/US Gov/Secretary Defense are also > licensed under... .MIT thing ...." but I''d want to see a second opinion > on that I think.This is in theory possible but in practice not a good idea. Ian.
Matthew Fioravante
2012-Oct-02 14:17 UTC
Re: [PATCH 08/11] add tpmfront, tpm_tis, and tpmback drivers to mini-os
On 10/02/2012 06:57 AM, Ian Campbell wrote:>> diff --git a/extras/mini-os/include/tpm_tis.h b/extras/mini-os/include/tpm_tis.h >> new file mode 100644 >> index 0000000..b463cea >> --- /dev/null >> +++ b/extras/mini-os/include/tpm_tis.h >> @@ -0,0 +1,74 @@ >> +/* >> + * Copyright (c) 2010-2012 United States Government, as represented by >> + * the Secretary of Defense. All rights reserved. >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License version 2 >> + * as published by the Free Software Foundation; or, when distributed >> + * separately from the Linux kernel or incorporated into other >> + * software packages, subject to the following license: >> + * >> + * Permission is hereby granted, free of charge, to any person obtaining a copy >> + * of this source file (the "Software"), to deal in the Software without >> + * restriction, including without limitation the rights to use, copy, modify, >> + * merge, publish, distribute, sublicense, and/or sell copies of the Software, >> + * and to permit persons to whom the Software is furnished to do so, subject to >> + * the following conditions: >> + * >> + * The above copyright notice and this permission notice shall be included in >> + * all copies or substantial portions of the Software. >> + * >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE >> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS >> + * IN THE SOFTWARE. >> + * >> + * Based upon the files: >> + * drivers/char/tpm/tpm_tis.c >> + * drivers/char/tpm/tpm.c >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation > Given that then I don''t think you have the authority to dual license > code owned by IBM as GPL or the MIT style thing above -- these files are > subject to the licensing terms of those original files (which looks to > be GPL v2 only). > > It might be acceptable to have a GPL header as the primary followed by a > "modifications by Matthew Fioravante/US Gov/Secretary Defense are also > licensed under... .MIT thing ...." but I''d want to see a second opinion > on that I think. > > I didn''t check all the other licensing thoroughly but I expect similar > comments will apply elsewhere too.As far as I understand (I''m in no way a copyright lawyer), there is a difference between copyright and license. What this is trying to convey is that the changes are copyrighted by the US Govt and the license being offered is GPLv2.> Ian. > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Oct-02 14:20 UTC
Re: [PATCH 04/11] Disable the mfn_is_ram() check, it doesn''t work correctly on all systems
On 10/02/2012 06:49 AM, Ian Campbell wrote:> On Thu, 2012-09-27 at 18:09 +0100, Matthew Fioravante wrote: >> This patch disables the mfn_is_ram check in mini-os. The current check >> is insufficient and fails on some systems with larger than 4gb memory. >> >> Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> >> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> > Further down the thread with the Ack Samuel said: > We can probably just remove the check in __do_ioremap, which > AFAIK is the only call. > > since this function is a bit pointless now.I think its a question of whether or not we want to leave it for someone to implement correctly later (by getting the memory map from the hypervisor/ doing e820 calls) or get rid of it entirely. Since its only purpose seems to be for preventing mini-os devs from making logical errors I''d be more inclined to just get rid of it. Do you all agree? If so I can send a new patch with it taken out.> >> diff --git a/extras/mini-os/arch/x86/mm.c b/extras/mini-os/arch/x86/mm.c >> index 80aceac..5813a08 100644 >> --- a/extras/mini-os/arch/x86/mm.c >> +++ b/extras/mini-os/arch/x86/mm.c >> @@ -850,6 +850,8 @@ unsigned long alloc_contig_pages(int order, unsigned int addr_bits) >> static long system_ram_end_mfn; >> int mfn_is_ram(unsigned long mfn) >> { >> + /* This is broken on systems with large ammounts of ram. Always return 0 for now */ >> + return 0; >> /* very crude check if a given MFN is memory or not. Probably should >> * make this a little more sophisticated ;) */ >> return (mfn <= system_ram_end_mfn) ? 1 : 0; >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Matthew Fioravante
2012-Oct-02 14:23 UTC
Re: [PATCH 01/11] Add ioread/iowrite functions to mini-os
On 10/02/2012 05:10 AM, Ian Campbell wrote:> On Fri, 2012-09-28 at 14:57 +0100, Matthew Fioravante wrote: >> On 09/28/2012 06:16 AM, George Dunlap wrote: >>> On Thu, Sep 27, 2012 at 6:09 PM, Matthew Fioravante >>> <matthew.fioravante@jhuapl.edu> wrote: >>>> This patch adds iowritexx() and ioreadxx() functions for interacting >>>> with hardware memory to mini-os. The functions are available in a header >>>> iorw.h >>>> >>>> Signed-off-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu> >>>> Acked-by: Samuel Thibault <samuel.thibault@ens-lyon.org> >>>> >>>> diff --git a/extras/mini-os/arch/ia64/iorw.c b/extras/mini-os/arch/ia64/iorw.c >>> Is there any reason to have the ia64 stuff? ia64 isn''t supported in >>> Xen anymore, AFAIK. >> Maybe not. But until ia64 support is removed from mini-os the function >> bodies should exist so stuff will compile. > I thought I had dropped all the remnants of ia64 in mini-os in commit > 25882:485e6db28b93 "tools: drop ia64 support". Let me know if you think > I''ve missed something, but: > >>>> new file mode 100644 >>>> index 0000000..aa58807 >>>> --- /dev/null >>>> +++ b/extras/mini-os/arch/ia64/iorw.c > $ ls extras/mini-os/arch/ia64/iorw.c > ls: cannot access extras/mini-os/arch/ia64/iorw.c: No such file or directory > > I think perhaps you just need to rebase?Sorry about that, I missed that entirely. These patches were written a long time ago when ia64 was still in and since iorw.c never existed in the first place the patch just happily added it. Anyway, its been removed.> Ian. >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Ian Campbell
2012-Oct-02 14:44 UTC
Re: [PATCH 08/11] add tpmfront, tpm_tis, and tpmback drivers to mini-os
On Tue, 2012-10-02 at 15:17 +0100, Matthew Fioravante wrote:> On 10/02/2012 06:57 AM, Ian Campbell wrote: > >> diff --git a/extras/mini-os/include/tpm_tis.h b/extras/mini-os/include/tpm_tis.h > >> new file mode 100644 > >> index 0000000..b463cea > >> --- /dev/null > >> +++ b/extras/mini-os/include/tpm_tis.h > >> @@ -0,0 +1,74 @@ > >> +/* > >> + * Copyright (c) 2010-2012 United States Government, as represented by > >> + * the Secretary of Defense. All rights reserved. > >> + * > >> + * This program is free software; you can redistribute it and/or > >> + * modify it under the terms of the GNU General Public License version 2 > >> + * as published by the Free Software Foundation; or, when distributed > >> + * separately from the Linux kernel or incorporated into other > >> + * software packages, subject to the following license: > >> + * > >> + * Permission is hereby granted, free of charge, to any person obtaining a copy > >> + * of this source file (the "Software"), to deal in the Software without > >> + * restriction, including without limitation the rights to use, copy, modify, > >> + * merge, publish, distribute, sublicense, and/or sell copies of the Software, > >> + * and to permit persons to whom the Software is furnished to do so, subject to > >> + * the following conditions: > >> + * > >> + * The above copyright notice and this permission notice shall be included in > >> + * all copies or substantial portions of the Software. > >> + * > >> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > >> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > >> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > >> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > >> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > >> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > >> + * IN THE SOFTWARE. > >> + * > >> + * Based upon the files: > >> + * drivers/char/tpm/tpm_tis.c > >> + * drivers/char/tpm/tpm.c > >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporation > > Given that then I don''t think you have the authority to dual license > > code owned by IBM as GPL or the MIT style thing above -- these files are > > subject to the licensing terms of those original files (which looks to > > be GPL v2 only). > > > > It might be acceptable to have a GPL header as the primary followed by a > > "modifications by Matthew Fioravante/US Gov/Secretary Defense are also > > licensed under... .MIT thing ...." but I''d want to see a second opinion > > on that I think. > > > > I didn''t check all the other licensing thoroughly but I expect similar > > comments will apply elsewhere too. > As far as I understand (I''m in no way a copyright lawyer), there is a > difference between copyright and license. What this is trying to convey > is that the changes are copyrighted by the US Govt and the license being > offered is GPLv2.The license which your header offers is not the GPLv2 though -- it says GPLv2 or MIT license, specifically it says: "; or, when distributed separately from the Linux kernel or incorporated into other software packages, subject to the following license: <MIT license>". If that is not your intention then you have written the wrong thing in your header. Perhaps you would find the "How to Apply These Terms to Your New Programs" bit of http://www.gnu.org/licenses/gpl-2.0.html useful? Ian.