Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

WZENC1 - Model of Bus Mastering PCI AES256 accelerator for QEMU

19 views
Skip to first unread message

wzab

unread,
Jun 17, 2011, 2:16:09 PM6/17/11
to
Archive-name: qemu-wzab-enc1
Submitted-by: wz...@ise.pw.edu.pl (Wojciech M. Zabolotny)

The attached sources implement a simple model of Bus Mastering
crypto accelerator for QEMU.
The design is mainly supposed to be a didactical aid for students
learning how to write device drivers.

The sources consist of the following files:
1. drv_enc1.c - driver for the ADC written for kernel 2.6.37.2 (works
also with kernel used in Knoppix 6.4.4)
2. Makefile - the makefile used to compile the driver
3. user_enc1.c - sample program working with driver drv_enc1, showing
operation of the device.
You should compile it with:
$gcc -o user_enc1 user_enc1.c
4. qemu.patch - Patch showing how to modify the Makefile.target file
in qemu 0.14.0 sources.
Additionally you should add two other files to the qemu-0.14.0/hw directory:
5. wzab_enc1.c - this is the main file implementing the model of WZENC1
You should copy it to the qemu-0.14.0/hw directory
6. wzab_enc1.h - this is the header file with registers' structure,
commands and errors code.
You should copy it to the qemu-0.14.0/hw directory,
but you should also copy it (or create the symlink to it)
to the directory in which you will compile drv_enc1.c
and user_enc1.c

Explanation how the modelled device works is given in the begining of the
wzab_enc1.c file.
All sources are free. They are licensed according to GPL v2 license or
according to QEMU license. If license terms are not given, please consider
this source as PUBLIC DOMAIN.

Wojciech M. Zabolotny
wzab<at>ise.pw.edu.pl

#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.11).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh07737
# Made on 2011-06-17 20:04 CEST by <wzab@wzlaphp>.
# Source directory was `/home/wzab/qemu_ster/enc1'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 10132 -rw-r--r-- drv_enc1.c
# 177 -rw-r--r-- Makefile
# 658 -rw-r--r-- qemu.patch
# 3148 -rw-r--r-- user_enc1.c
# 11831 -rw-r--r-- wzab_enc1.c
# 530 -rw-r--r-- wzab_enc1.h
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false

for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done

if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done

if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'

else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU `touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= drv_enc1.c ==============
if test -n "${keep_file}" && test -f 'drv_enc1.c'
then
${echo} "x - SKIPPING drv_enc1.c (file already exists)"
else
${echo} "x - extracting drv_enc1.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'drv_enc1.c' &&
/* Quick and dirty WZENC1 device driver
X * This driver only allows to check, that the simulated
X * WZENC1 core works correctly.
X * Most functionality is simply passed to the user space
X * allowing you to use WZENC1 to completely crash your emulated
X * machine :-(.
X * This driver also does not allow to control multiple
X * instances of WZENC1
X *
X * Copyright (C) 2011 by Wojciech M. Zabolotny
X * wzab<at>ise.pw.edu.pl
X * Significantly based on multiple drivers included in
X * sources of Linux
X * Therefore this saource is licensed under GPL v2
X */
X
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL v2");
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include "wzab_enc1.h"
X
//PCI IDs below are not registred! Use only for experiments!
#define PCI_VENDOR_ID_WZAB 0xabba
#define PCI_DEVICE_ID_WZAB_WZENC1 0x231
X
X
static DEFINE_PCI_DEVICE_TABLE(tst1_pci_tbl) = {
X {PCI_VENDOR_ID_WZAB, PCI_DEVICE_ID_WZAB_WZENC1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
X {0,}
};
MODULE_DEVICE_TABLE(pci, tst1_pci_tbl);
X
#define SUCCESS 0
#define DEVICE_NAME "wzab_enc1"
X
//Global variables used to store information about WZENC1
//This must be changed, if we'd like to handle multiple WZENC1 instances
int irq=0; //IRQ used by WZENC1
int phys_addr = 0; //Physical address of register memory
volatile uint32_t * fmem=NULL; //Pointer to registers area
volatile void * fdata=NULL; //Pointer to data buffer
X
void cleanup_tst1( void );
void cleanup_tst1( void );
int init_tst1( void );
static int tst1_open(struct inode *inode, struct file *file);
static int tst1_release(struct inode *inode, struct file *file);
ssize_t tst1_read(struct file *filp,
X char __user *buf,size_t count, loff_t *off);
ssize_t tst1_write(struct file *filp,
X const char __user *buf,size_t count, loff_t *off);
loff_t tst1_llseek(struct file *filp, loff_t off, int origin);
X
int tst1_mmap(struct file *filp, struct vm_area_struct *vma);
X
dev_t my_dev=0;
struct cdev * my_cdev = NULL;
static struct class *class_my_tst = NULL;
X
/* Queue for reading process */
DECLARE_WAIT_QUEUE_HEAD (readqueue);
X
/* Interrupt service routine */
irqreturn_t tst1_irq(int irq, void * dev_id)
{
X // First we check if our device requests interrupt
X //printk("<1>I'm in interrupt!\n");
X volatile uint32_t status; //Must be volatile to ensure 32-bit access!
X volatile WzEnc1Regs * regs;
X regs = (volatile WzEnc1Regs *) fmem;
X status = regs->Status;
X if(status & 0x8000) {
X //Yes, this is our device
X //Block interrupts, they will be turned on by the reading process
X regs->Ctrl = ENC1_CMD_DISIRQ;
X //Wake up the reading process
X wake_up_interruptible(&readqueue);
X return IRQ_HANDLED;
X }
X return IRQ_NONE; //Our device does not request interrupt
};
X
X
struct file_operations Fops = {
X .owner = THIS_MODULE,
X .read=tst1_read, /* read */
X .write=tst1_write, /* write */
X .open=tst1_open,
X .release=tst1_release, /* a.k.a. close */
X .llseek=no_llseek,
X .mmap=tst1_mmap
};
X
/* Cleanup resources */
void tst1_remove(struct pci_dev *pdev )
{
X if(my_dev && class_my_tst) {
X device_destroy(class_my_tst,my_dev);
X }
X if(fdata) free_pages((unsigned long)fdata,2);
X if(fmem) iounmap(fmem);
X if(my_cdev) cdev_del(my_cdev);
X my_cdev=NULL;
X unregister_chrdev_region(my_dev, 1);
X if(class_my_tst) {
X class_destroy(class_my_tst);
X class_my_tst=NULL;
X }
X pci_release_regions(pdev);
X pci_disable_device(pdev);
X //printk("<1>drv_tst1 removed!\n");
}
X
static int tst1_open(struct inode *inode,
X struct file *file)
{
X int res=0;
X nonseekable_open(inode, file);
X res=request_irq(irq,tst1_irq,0,DEVICE_NAME,NULL); //Should be changed for multiple WZENC1s
X if(res) {
X printk (KERN_INFO "wzab_tst1: I can't connect irq %i error: %d\n", irq,res);
X irq = -1;
X }
X return SUCCESS;
}
X
static int tst1_release(struct inode *inode,
X struct file *file)
{
X WzEnc1Regs * volatile regs;
X regs = (volatile WzEnc1Regs *) fmem;
#ifdef DEBUG
X printk ("<1>device_release(%p,%p)\n", inode, file);
#endif
X regs->Ctrl = ENC1_CMD_DISIRQ; //Disable IRQ
X if(irq>=0) free_irq(irq,NULL); //Free interrupt
X return SUCCESS;
}
X
static inline uint32_t read_status(void)
{
X volatile WzEnc1Regs * regs;
X volatile uint32_t status;
X regs = (volatile WzEnc1Regs *) fmem;
X status = regs->Status;
X return status;
}
X
ssize_t tst1_read(struct file *filp,
X char __user *buf,size_t count, loff_t *off)
{
X uint32_t val;
X if (count != 4) return -EINVAL; //Only 4-byte accesses allowed
X {
X ssize_t res;
X //Interrupts are on, so we should sleep and wait for interrupt
X res=wait_event_interruptible(readqueue,read_status() & 0x8000);
X if(res) return res; //Signal received!
X }
X //Read pointers
X val = read_status();
X if(__copy_to_user(buf,&val,4)) return -EFAULT;
X return 4;
}
X
ssize_t tst1_write(struct file *filp,
X const char __user *buf,size_t count, loff_t *off)
{
X //uint32_t val;
X if (count != 4) return -EINVAL; //Only 4-byte access allowed
X //__copy_from_user(&val,buf,4);
X //Write is not used at all!
X return 4;
}
X
X
void tst1_vma_open (struct vm_area_struct * area)
{ }
X
void tst1_vma_close (struct vm_area_struct * area)
{ }
X
static struct vm_operations_struct tst1_vm_ops = {
X .open=tst1_vma_open,
X .close=tst1_vma_close,
};
X
int tst1_mmap(struct file *filp,
X struct vm_area_struct *vma)
{
X unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
X if(off==0) {
X //Mapping of registers
X unsigned long physical = phys_addr;
X unsigned long vsize = vma->vm_end - vma->vm_start;
X unsigned long psize = 0x1000; //One page is enough
X //printk("<1>start mmap of registers\n");
X if(vsize>psize)
X return -EINVAL;
X remap_pfn_range(vma,vma->vm_start, physical >> PAGE_SHIFT , vsize, vma->vm_page_prot);
X if (vma->vm_ops)
X return -EINVAL; //It should never happen
X vma->vm_ops = &tst1_vm_ops;
X tst1_vma_open(vma); //This time no open(vma) was called
X //printk("<1>mmap of registers succeeded!\n");
X return 0;
X } else {
X //Mapping of buffer
X //In the newest kernel we may use remap_pfn_range to map RAM.
X unsigned long physical = virt_to_phys(fdata);
X unsigned long vsize = vma->vm_end - vma->vm_start;
X unsigned long psize = 4*4096; //4 pages of buffer!
X //printk("<1>start mmap of buffers\n");
X if(vsize>psize)
X return -EINVAL;
X remap_pfn_range(vma,vma->vm_start, physical >> PAGE_SHIFT , vsize, vma->vm_page_prot);
X if (vma->vm_ops)
X return -EINVAL; //It should never happen
X vma->vm_ops = &tst1_vm_ops;
X tst1_vma_open(vma); //This time no open(vma) was called
X //printk("<1>mmap of buffers succeeded!\n");
X return 0;
X }
}
X
static int __devinit tst1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
X unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
X int res = 0;
X res = pci_enable_device(pdev);
X if (res) {
X dev_err(&pdev->dev, "Can't enable PCI device, aborting\n");
X res = -ENODEV;
X goto err1;
X }
X mmio_start = pci_resource_start(pdev, 0);
X mmio_end = pci_resource_end(pdev, 0);
X mmio_flags = pci_resource_flags(pdev, 0);
X mmio_len = pci_resource_len(pdev, 0);
X irq = pdev->irq;
X //printk("<1> mmio_start=%x, mmio_end=%x, mmio_len=%x, irq=%d\n",mmio_start,mmio_end,mmio_len,irq);
X /* make sure PCI base addr 1 is MMIO */
X if (!(mmio_flags & IORESOURCE_MEM)) {
X dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
X res = -ENODEV;
X goto err1;
X }
X res = pci_request_regions(pdev, DEVICE_NAME);
X if (res)
X goto err1;
X pci_set_master(pdev);
X class_my_tst = class_create(THIS_MODULE, "my_tst");
X if (IS_ERR(class_my_tst)) {
X printk(KERN_ERR "Error creating my_tst class.\n");
X res=PTR_ERR(class_my_tst);
X goto err1;
X }
X /* Alocate device number */
X res=alloc_chrdev_region(&my_dev, 0, 1, DEVICE_NAME);
X if(res) {
X printk ("<1>Alocation of the device number for %s failed\n",
X DEVICE_NAME);
X goto err1;
X };
X my_cdev = cdev_alloc( );
X if(my_cdev == NULL) {
X printk ("<1>Allocation of cdev for %s failed\n",
X DEVICE_NAME);
X goto err1;
X }
X my_cdev->ops = &Fops;
X my_cdev->owner = THIS_MODULE;
X /* Add character device */
X res=cdev_add(my_cdev, my_dev, 1);
X if(res) {
X printk ("<1>Registration of the device number for %s failed\n",
X DEVICE_NAME);
X goto err1;
X };
X /* Create pointer needed to access registers */
X phys_addr = mmio_start; //Save start address for further mapping
X fmem = ioremap(mmio_start, mmio_len); //One page should be enough
X if(!fmem) {
X printk ("<1>Mapping of memory for %s registers failed\n",
X DEVICE_NAME);
X res= -ENOMEM;
X goto err1;
X }
X /* Create pointer needed to access ADC data */
X fdata = (void *) __get_free_pages(GFP_KERNEL, 2);
X if(!fdata) {
X printk ("<1>Mapping of memory for %s data failed\n",
X DEVICE_NAME);
X res= -ENOMEM;
X goto err1;
X }
X /* Write physical addresses of buffer pages to registers */
X {
X int i;
X WzEnc1Regs * volatile regs;
X regs = (volatile WzEnc1Regs *) fmem;
X for(i=0;i<4;i++) {
X regs->Pages[i].PhysAddr = virt_to_phys(fdata+4096*i);
X regs->Pages[i].Length = 0;
X regs->Pages[i].Offset = 0;
X }
X }
X device_create(class_my_tst,NULL,my_dev,NULL,"my_enc%d",MINOR(my_dev));
X printk ("<1>%s The major device number is %d.\n",
X "Registeration is a success.",
X MAJOR(my_dev));
X return 0;
X err1:
X return res;
}
X
static struct pci_driver tst1_pci_driver = {
X .name = DEVICE_NAME,
X .id_table = tst1_pci_tbl,
X .probe = tst1_probe,
X .remove = __devexit_p(tst1_remove),
};
X
static int __init tst1_init_module(void)
{
X /* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
X // printk(version);
#endif
X return pci_register_driver(&tst1_pci_driver);
}
X
X
static void __exit tst1_cleanup_module(void)
{
X pci_unregister_driver(&tst1_pci_driver);
}
X
X
module_init(tst1_init_module);
module_exit(tst1_cleanup_module);
X
SHAR_EOF
(set 20 11 06 17 19 34 18 'drv_enc1.c'
eval "${shar_touch}") && \
chmod 0644 'drv_enc1.c'
if test $? -ne 0
then ${echo} "restore of drv_enc1.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'drv_enc1.c': 'MD5 check failed'
) << \SHAR_EOF
ea17e3899be4b367ec00ab89df3563ce drv_enc1.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'drv_enc1.c'` -ne 10132 && \
${echo} "restoration warning: size of 'drv_enc1.c' is not 10132"
fi
fi
# ============= Makefile ==============
if test -n "${keep_file}" && test -f 'Makefile'
then
${echo} "x - SKIPPING Makefile (file already exists)"
else
${echo} "x - extracting Makefile (text)"
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
ifneq ($(KERNELRELEASE),)
X obj-m := drv_tst1.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
X $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
SHAR_EOF
(set 20 11 04 12 22 11 57 'Makefile'
eval "${shar_touch}") && \
chmod 0644 'Makefile'
if test $? -ne 0
then ${echo} "restore of Makefile failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'Makefile': 'MD5 check failed'
) << \SHAR_EOF
b97d817bf5e5ab14128af9f253366792 Makefile
SHAR_EOF
else
test `LC_ALL=C wc -c < 'Makefile'` -ne 177 && \
${echo} "restoration warning: size of 'Makefile' is not 177"
fi
fi
# ============= qemu.patch ==============
if test -n "${keep_file}" && test -f 'qemu.patch'
then
${echo} "x - SKIPPING qemu.patch (file already exists)"
else
${echo} "x - extracting qemu.patch (text)"
sed 's/^X//' << 'SHAR_EOF' > 'qemu.patch' &&
*** Makefile.target 2011-02-16 15:44:04.000000000 +0100
--- /home/wzab/qemu_ster/qemu-0.14.0/Makefile.target 2011-06-17 20:02:07.000000000 +0200
***************
*** 1,5 ****
--- 1,6 ----
X # -*- Mode: makefile -*-
X
+ LIBS += -lmcrypt
X GENERATED_HEADERS = config-target.h
X CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
X CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
***************
*** 213,218 ****
--- 214,220 ----
X
X # Hardware support
X obj-i386-y += vga.o
+ obj-i386-y += wzab_enc1.o
X obj-i386-y += mc146818rtc.o i8259.o pc.o
X obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
X obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
SHAR_EOF
(set 20 11 06 17 20 02 47 'qemu.patch'
eval "${shar_touch}") && \
chmod 0644 'qemu.patch'
if test $? -ne 0
then ${echo} "restore of qemu.patch failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'qemu.patch': 'MD5 check failed'
) << \SHAR_EOF
d58c6179c4eae1e869cc943e4e038d61 qemu.patch
SHAR_EOF
else
test `LC_ALL=C wc -c < 'qemu.patch'` -ne 658 && \
${echo} "restoration warning: size of 'qemu.patch' is not 658"
fi
fi
# ============= user_enc1.c ==============
if test -n "${keep_file}" && test -f 'user_enc1.c'
then
${echo} "x - SKIPPING user_enc1.c (file already exists)"
else
${echo} "x - extracting user_enc1.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'user_enc1.c' &&
/*
X This is a very simple program showing functionality of the WZENC1 device model
*/
#include<stdio.h>
#include<sys/types.h>
#include<stdint.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<fcntl.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include "wzab_enc1.h"
X
unsigned char key1[]="01234567abcdefgh01234567hgfedcba";
unsigned char iv1[]="dferrtertertrtr34gfdfge3t3434334";
unsigned char text1[]="This is a secret message. We will encrypt it and later decrypt it back to show operation of WZENC1.";
unsigned char text2[]="This is the second segment of our top secret message. It will be passed through the second page.";
X
WzEnc1Regs * volatile regs = NULL;
int plik = -1;
volatile uint32_t * devm1;
volatile unsigned char * devm2;
X
void print_char(unsigned char c)
{
X if((c>27) && (c<128)) {
X printf("%c",c);
X } else {
X printf("<%2.2x>",(int)c);
X }
}
void print_texts()
{
X int i;
X for(i=0;i<sizeof(text1);i++) print_char(text1[i]);
X for(i=0;i<sizeof(text2);i++) print_char(text2[i]);
}
X
void encrypt_or_decrypt(int operation)
{
X uint32_t status;
X //Clear and unamsk interrupt
X regs->Ctrl = ENC1_CMD_ACKIRQ;
X //Initialize the key
X memcpy((void *)&devm2[0],key1,32);
X //Initialize the IV
X memcpy((void *)&devm2[4096],iv1,32);
X //Select encryption or encryption
X if(operation)
X regs->Ctrl = ENC1_CMD_ENCR;
X else
X regs->Ctrl = ENC1_CMD_DECR;
X //Prepare data
X regs->Pages[0].Offset=0;
X regs->Pages[0].Length=sizeof(text1);
X memcpy((void *)&devm2[0],text1,sizeof(text1));
X regs->Pages[1].Offset=0;
X regs->Pages[1].Length=sizeof(text2);
X memcpy((void *)&devm2[0x1000],text2,sizeof(text2));
X regs->Pages[2].Length=0; //No data on page 2
X regs->Ctrl = ENC1_CMD_DATA;
X //Read - wait until ready
X printf("waiting for IRQ\n");
X fflush(stdout);
X if(read(plik,&status,4)!=4) exit(1);
X printf("received IRQ, status %x\n", status);
X fflush(stdout);
X //Save processed data
X memcpy(text1,(void *)devm2,sizeof(text1));
X memcpy(text2,(void *)&devm2[0x1000],sizeof(text2));
X //Free WZENC1
X regs->Ctrl = ENC1_CMD_STOP;
}
X
int main()
{
X unsigned long val;
X int i;
X printf("I'm trying to open our device!\n");
X fflush(stdout);
X plik=open("/dev/my_enc0", O_RDWR);
X if(plik==-1)
X {
X printf("I can't open device!\n");
X fflush(stdout);
X exit(1);
X }
X printf("Device opened!\n");
X fflush(stdout);
X //Map registers (in fact it should not be necessary!
X devm1 = (uint32_t *) mmap(0,0x1000,PROT_READ | PROT_WRITE,MAP_SHARED,
X plik,0x0000000);
X if(devm1 == (void *) -1l)
X {
X perror("I can't map registers\n");
X }
X regs = (volatile WzEnc1Regs *) devm1;
X //Map data buffer
X devm2 = (unsigned char *) mmap(0,0x4000,PROT_READ | PROT_WRITE,MAP_SHARED,
X plik,0x0001000);
X if(devm2 == (void *) -1l)
X {
X perror("I can't map data buffer!\n");
X }
X printf("Memory mapped: regs: %x buffer: %x\n",devm1, devm2);
X print_texts(); //Print original text
X fflush(stdout);
X encrypt_or_decrypt(1);
X print_texts(); //Print encrypted text
X fflush(stdout);
X encrypt_or_decrypt(0);
X print_texts(); //Print decrypted text
X fflush(stdout);
}
SHAR_EOF
(set 20 11 06 17 19 53 13 'user_enc1.c'
eval "${shar_touch}") && \
chmod 0644 'user_enc1.c'
if test $? -ne 0
then ${echo} "restore of user_enc1.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'user_enc1.c': 'MD5 check failed'
) << \SHAR_EOF
6b5a2aa0c63f5769f4441c38e2c75c84 user_enc1.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'user_enc1.c'` -ne 3148 && \
${echo} "restoration warning: size of 'user_enc1.c' is not 3148"
fi
fi
# ============= wzab_enc1.c ==============
if test -n "${keep_file}" && test -f 'wzab_enc1.c'
then
${echo} "x - SKIPPING wzab_enc1.c (file already exists)"
else
${echo} "x - extracting wzab_enc1.c (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wzab_enc1.c' &&
/*
X * QEMU - AES256 cryptographic engine WZENC1 emulation
X *
X * Copyright Wojciech M. Zabolotny ( wz...@ise.pw.edu.pl ) 17.06.2011
X *
X * Permission is hereby granted, free of charge, to any person obtaining a copy
X * of this software and associated documentation files (the "Software"), to deal
X * in the Software without restriction, including without limitation the rights
X * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
X * copies of the Software, and to permit persons to whom the Software is
X * furnished to do so, subject to the following conditions:
X *
X * The above copyright notice and this permission notice shall be included in
X * all copies or substantial portions of the Software.
X *
X * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
X * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
X * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
X * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
X * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
X * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
X * THE SOFTWARE.
X */
X
//#define DEBUG_wzab1 1
X
//PCI IDs below are not registred! Use only for experiments!
#define PCI_VENDOR_ID_WZAB 0xabba
#define PCI_DEVICE_ID_WZAB_WZENC1 0x0231
X
//Simulated processing time
#define ENC1_PROCESSING_TIME 5000000
X
#include "hw.h"
#include "pci.h"
#include <mcrypt.h>
#include "qemu-timer.h"
#include "wzab_enc1.h"
X
/*
X Description of functionalities.
X The emulated hardware is able to perform encryption/decryption using AES256 algorithm.
X It is a PCI device with memory mapped registers.
X Register definitions are provided in "wzab_enc1.h" file
X The data transfer is fulfilled using bus-mastering DMA
X
X Registers (all 32-bit):
X Ctrl - offset 0
X Status - offset 1
X Pages[4] - starting from offset 2
X 4 sets of registers describing pages used to transfer data
X each set contains:
X PhysAddr register - physical address of the begining of the page
X Offset register - start address of the encrypted/decrypted content on the page
X Length register - length (in bytes) of the encrypted/decrypted content on the page
X length should be equal to N*B where B is length of the block
X in the cipher (in case of AES256 - 32 bytes).
X
X It is relatively easy to modify the model to use more pages.
X The model should be used as follows:
X 1) Initialization of the core
X a) Key should be stored in the first 32 bytes of page pointed by Pages[0].PhysAddr
X b) Initialization vector should be stored in the first 32 bytes of page
X pointed by Pages[1].PhysAddr (Offset registers are not used)
X c) Write ENC1_CMD_ENCR to Ctrl to initialize core for encryption or
X write ENC1_CMD_DECR to Ctrl to initialize core for decryption
X 2) Processing of data
X a) Data should be stored in buffers located on up to 4 pages, described
X by registers PhysAddr, Offset, Length in Pages register sets.
X b) Processing ends either after 4 pages are processed or after first
X page with Length set to 0 is found.
X c) When data are written to buffers and Pages registers are set, write
X the ENC1_CMD_DATA command to Ctrl
X 3) After all data are encrypted or decrypted, the core requests interrupt.
X a) The interrupt may be masked by writing ENC1_CMD_DISIRQ to Ctrl
X b) The interrupt may be unmasked by writing ENC1_CMD_ENAIRQ to Ctrl
X c) After the interrupt is serviced, it should be acknowledged by writing
X ENC1_CMD_ACKIRQ to Ctrl
X 4) If data do not fit in 4 pages, step (3) may be repeated until all data are
X processed.
X 5) After all data are processed, write ENC1_CMD_STOP to Ctrl to free the core
X 6) Following errors are detected:
X a) Attempt to use non-initialized (see step 1) core - ENC1_ERR_NOTINIT
X b) Attempt to start next processing when previous is not finished
X ENC1_ERR_BUSY
X 7) Errors are reported via Status register. The bits of this register
X have following meaning:
X a) 31st - Interrupt is pending
X b) 30th - Interrupt is masked
X c) 28th - Core is busy
X d) 15th-0th - Error code
*/
X
//Some prototypes...
uint32_t wz_enc1_mem_readl(void *opaque, target_phys_addr_t addr);
void wz_enc1_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val);
int wz_enc1_init (PCIBus *bus);
X
typedef struct WzEnc1State {
X PCIDevice dev;
X union {
X WzEnc1Regs r;
X uint32_t u32[sizeof(WzEnc1Regs)/sizeof(uint32_t)];
X } regs;
X uint32_t wz_enc1_mmio_io_addr;
X uint32_t irq_pending;
X uint32_t irq_mask;
X uint8_t Error;
X uint8_t Working;
X MCRYPT td;
X uint8_t enc_ndec;
X QEMUTimer * timer;
} WzEnc1State;
X
static void wz_enc1_reset (WzEnc1State *s)
{
X memset((void *)s->regs.u32,0,sizeof(s->regs.u32));
#ifdef DEBUG_wzab1
X printf("wzab_tst1 reset!\n");
#endif
}
X
/* called for read accesses to our register memory area */
uint32_t wz_enc1_mem_readl(void *opaque, target_phys_addr_t addr)
{
X int i_addr;
#ifdef DEBUG_wzab1
X printf("Memory read: address %x\n ", (unsigned int) addr);
#endif
X WzEnc1State *s = opaque;
X if(addr>=sizeof(WzEnc1Regs)){
X //Read above registers area - return "0xbada4ea" to show it
X return 0xbada4ea;
X } else if (addr == offsetof(WzEnc1Regs, Status)) {
X //Reading of the Status - synthesize the correct value
X uint32_t res = s->Error & 0xffff ; //Lower 16 bits!
X if (s->Working) res |= 0x1000;
X if (s->irq_pending) res |= 0x8000;
X if (s->irq_mask) res |= 0x4000;
#ifdef DEBUG_wzab1
X printf("Status=%d\n",res);
#endif
X return res;
X }else {
X i_addr = addr/4;
X //Read the register
X return s->regs.u32[i_addr];
X }
}
X
char cipher[] = "rijndael-256";
char cipher_mode[] = "cbc";
X
/* called for write accesses to our register memory area */
void wz_enc1_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
X WzEnc1State *s = opaque;
X int i_addr;
#ifdef DEBUG_wzab1
X printf("wzab1: zapis pod adres = 0x%08x, 0x%08x\n", (unsigned int) addr, val);
#endif
X /* Check which register is accessed */
X if(addr>=sizeof(WzEnc1Regs)){
X //Write above registers area - ignore it!
X } else {
X i_addr = addr/4;
X //Write the value
X s->regs.u32[i_addr]=val;
X //Interprete its special meaning
X if (addr==offsetof(WzEnc1Regs,Ctrl)) {
X //Write to control register - we need to check what operation is required
X switch(val) {
X case ENC1_CMD_DECR:
X case ENC1_CMD_ENCR: {
X //required initialization of the encryption engine
X //key and IV provided
X uint8_t key[32];
X uint8_t iv[32];
X s->td = mcrypt_module_open(cipher, NULL, cipher_mode, NULL);
X if(s->td == NULL) {
X printf("Initialization A of mcrypt impossible!\n");
X exit(1);
X }
X if (val==ENC1_CMD_ENCR) {
X s->enc_ndec = 1; //We will encrypt data
X } else {
X s->enc_ndec = 0; //We will decrypt data
X }
X cpu_physical_memory_read(s->regs.r.Pages[0].PhysAddr,key,32);
X cpu_physical_memory_read(s->regs.r.Pages[1].PhysAddr,iv,32);
X if(mcrypt_generic_init(s->td,(void*)key,32,(void*)iv)<0){
X printf("Initialization B of mcrypt impossible!\n");
X exit(1);
X }
X break;
X }
X case ENC1_CMD_DATA:
X //next set of data provided, no reinitialization of encryption engine
X if(s->td == NULL) {
X //Error - hardware not initialized
X s->Error = ENC1_ERR_NOTINIT; //Error hardware not initialized
X s->irq_pending = 1;
X if(s->irq_mask==0) qemu_irq_raise(s->dev.irq[0]);
X } else if(s->Working) {
X //Error - engine is still busy!
X s->Error = ENC1_ERR_BUSY; //Error!
X s->irq_pending = 1;
X if(s->irq_mask==0) qemu_irq_raise(s->dev.irq[0]);
X } else {
X //Normal operation - submit data to processing
X s->Working = 0x1;
X qemu_mod_timer(s->timer,qemu_get_clock(vm_clock)+ENC1_PROCESSING_TIME);
X }
X break;
X case ENC1_CMD_STOP:
X //End of encryption!
X mcrypt_generic_deinit(s->td);
X mcrypt_module_close(s->td);
X s->td = NULL;
X s->irq_pending = 0;
X s->irq_mask = 0;
X qemu_irq_lower(s->dev.irq[0]);
X break;
X case ENC1_CMD_ACKIRQ:
X //Confirm reception of interrupt (and unmask it)
X s->irq_pending = 0;
X s->irq_mask = 0;
X qemu_irq_lower(s->dev.irq[0]);
X break;
X case ENC1_CMD_DISIRQ:
X //Mask interrupt
X s->irq_mask = 1;
X qemu_irq_lower(s->dev.irq[0]);
X break;
X case ENC1_CMD_ENAIRQ:
X //Unmask interrupt
X s->irq_mask = 0;
X if(s->irq_pending) qemu_irq_raise(s->dev.irq[0]);
X break;
X }
X }
X }
}
X
/* The procedure below performs the real encryption, after simulated processing time is expired */
static void wzab1_tick(void *opaque)
{
X WzEnc1State * s = opaque;
X //Encrypt the data
X {
X uint8_t block[32];
X int p;
X for(p=0;p<WZENC1_NOF_PAGES;p++) {
X //Loop through all pages
X int i;
X int j = s->regs.r.Pages[p].PhysAddr + s->regs.r.Pages[p].Offset;
X int len = s->regs.r.Pages[p].Length ;
X if(!len) break; //Page with Length=0 is found
X for(i=0; i<len ; i+=32) {
X //Read data from page to processing buffer
X cpu_physical_memory_read(j+i,block,32);
X if (s->enc_ndec) {
X //Encrypt data
X mcrypt_generic (s->td, block, 32);
X } else {
X //Decrypt data
X mdecrypt_generic (s->td, block, 32);
X }
X //Write processed data back
X cpu_physical_memory_write(j+i,block,32);
X }
X }
X }
#ifdef DEBUG_wzab1
X printf("Data processed - request IRQ!\n");
#endif
X s->Working = 0;
X s->irq_pending = 1;
X if(s->irq_mask==0) qemu_irq_raise(s->dev.irq[0]);
}
X
X
static void wz_enc1_map (PCIDevice *pci_dev, int region_num,
X pcibus_t addr, pcibus_t size, int type)
{
X WzEnc1State *s = DO_UPCAST (WzEnc1State, dev, pci_dev);
X
X (void) region_num;
X (void) size;
X (void) type;
X
X cpu_register_physical_memory(addr,size,s->wz_enc1_mmio_io_addr);
}
X
X
/* We handle only 32-bit accesses! */
CPUReadMemoryFunc * const wz_enc1_mmio_read[3] = {
X NULL,
X NULL,
X wz_enc1_mem_readl,
};
X
/* We handle only 32-bit accesses! */
CPUWriteMemoryFunc * const wz_enc1_mmio_write[3] = {
X NULL,
X NULL,
X wz_enc1_mem_writel,
};
X
//Sorry, but the state description below is not complete!
//You are free to fix it!
static const VMStateDescription vmstate_wz_enc1 = {
X .name = "wz_enc1",
X .version_id = 2,
X .minimum_version_id = 2,
X .minimum_version_id_old = 2,
X .fields = (VMStateField []) {
X VMSTATE_PCI_DEVICE(dev, WzEnc1State),
X VMSTATE_TIMER(timer,WzEnc1State),
X VMSTATE_END_OF_LIST()
X }
};
X
static void wz_enc1_on_reset (void *opaque)
{
X WzEnc1State *s = opaque;
X wz_enc1_reset (s);
}
X
static int wz_enc1_initfn (PCIDevice *dev)
{
X WzEnc1State *s = DO_UPCAST (WzEnc1State, dev, dev);
X uint8_t *c = s->dev.config;
X //Set values in the configuration space
X pci_config_set_vendor_id (c, PCI_VENDOR_ID_WZAB);
X pci_config_set_device_id (c, PCI_DEVICE_ID_WZAB_WZENC1);
X pci_config_set_class (c, PCI_CLASS_OTHERS);
X
X /* TODO: RST# value should be 0. */
X c[PCI_INTERRUPT_PIN] = 1;
X //Register memory mapped registers
X s->wz_enc1_mmio_io_addr = cpu_register_io_memory(wz_enc1_mmio_read, wz_enc1_mmio_write,
X s, DEVICE_LITTLE_ENDIAN);
X pci_register_bar (&s->dev, 0, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY, wz_enc1_map);
X qemu_register_reset (wz_enc1_on_reset, s);
X //Register timer used to simulate processing time
X s->timer = qemu_new_timer(vm_clock, wzab1_tick, s);
X wz_enc1_reset (s);
X return 0;
}
X
int wz_enc1_init (PCIBus *bus)
{
X pci_create_simple (bus, -1, "WZENC1");
X return 0;
}
X
static PCIDeviceInfo wz_enc1_info = {
X .qdev.name = "WZENC1",
X .qdev.desc = "WZENC1 - Model of AES32 crypto-engine",
X .qdev.size = sizeof (WzEnc1State),
X .qdev.vmsd = &vmstate_wz_enc1,
X .init = wz_enc1_initfn,
};
X
static void wz_enc1_register (void)
{
X pci_qdev_register (&wz_enc1_info);
}
X
device_init (wz_enc1_register);
X
SHAR_EOF
(set 20 11 06 17 18 38 45 'wzab_enc1.c'
eval "${shar_touch}") && \
chmod 0644 'wzab_enc1.c'
if test $? -ne 0
then ${echo} "restore of wzab_enc1.c failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wzab_enc1.c': 'MD5 check failed'
) << \SHAR_EOF
0fc905247a624faf3236d2e66492d460 wzab_enc1.c
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wzab_enc1.c'` -ne 11831 && \
${echo} "restoration warning: size of 'wzab_enc1.c' is not 11831"
fi
fi
# ============= wzab_enc1.h ==============
if test -n "${keep_file}" && test -f 'wzab_enc1.h'
then
${echo} "x - SKIPPING wzab_enc1.h (file already exists)"
else
${echo} "x - extracting wzab_enc1.h (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wzab_enc1.h' &&
//Definitions of 32-bit registers
#define WZENC1_NOF_PAGES 4
typedef struct WzEnc1Page {
X uint32_t PhysAddr;
X uint32_t Offset;
X uint32_t Length;
} WzEnc1Page;
X
typedef struct WzEnc1Regs {
X uint32_t Ctrl;
X uint32_t Status;
X WzEnc1Page Pages[WZENC1_NOF_PAGES];
} WzEnc1Regs;
X
X
//Commands
#define ENC1_CMD_DECR 1
#define ENC1_CMD_ENCR 2
#define ENC1_CMD_DATA 3
#define ENC1_CMD_STOP 4
#define ENC1_CMD_ENAIRQ 5
#define ENC1_CMD_DISIRQ 6
#define ENC1_CMD_ACKIRQ 7
X
//Errors
#define ENC1_ERR_NOTINIT 1
#define ENC1_ERR_BUSY 2
X
X
SHAR_EOF
(set 20 11 06 16 13 16 00 'wzab_enc1.h'
eval "${shar_touch}") && \
chmod 0644 'wzab_enc1.h'
if test $? -ne 0
then ${echo} "restore of wzab_enc1.h failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wzab_enc1.h': 'MD5 check failed'
) << \SHAR_EOF
1bfb98c4cf516aaa9e539570047bd7bc wzab_enc1.h
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wzab_enc1.h'` -ne 530 && \
${echo} "restoration warning: size of 'wzab_enc1.h' is not 530"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0

0 new messages