QEMUのEduデバイスでの64ビット値に対するIOアクセスの問題

QEMUのEduデバイスでの64ビット値に対するIOアクセスの問題

現在、デバイスドライバを作成しています。教育機器qemu(RISC-V)から。したがって、質問、すでに一つがあることを確認しました。デバイスドライバそのような機器の場合。

~によるとEduデバイスドキュメントのこの行これは、アドレス> = 0x80がサイズ== 4またはサイズ== 8アクセスを許可することを意味します。これらの制約を図に示します。ここはedu_mmio_read()そしてここはedu_mmio_write()Eduデバイスのソースコードから。

内部にドライバーコード、およびの場合、read()8write()バイトではなく4バイトサイズの読み取り/書き込み値のみを処理するようです。したがって、8バイトの値の読み書きをサポートするために、これら2つの関数に新しいものを追加しました。

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    ssize_t ret;
    u32 kbuf32;
    u64 kbuf64;

    if (*off % 4 || len == 0) {
        ret = 0;
    } else {
        switch (len)
        {
        case 4:
            kbuf32 = ioread32(mmio + *off);
            if (copy_to_user(buf, (void *)&kbuf32, len)) {
                ret = -EFAULT;
            } else {
                ret = 4;
                (*off)++;
            }
            break;
        
        case 8:
            kbuf64 = ioread64(mmio + *off);
            if (copy_to_user(buf, (void *)&kbuf64, len)) {
                ret = -EFAULT;
            } else {
                ret = 8;
                (*off)++;
            }
            break;

        default:
            ret = -EFAULT;
            break;
        }
    }
    return ret;
}


static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
    ssize_t ret;
    u32 kbuf32; /* for size == 4 */
    u64 kbuf64; /* for size == 8 */
    
    ret = len;

    if (!(*off % 4)) {
        switch (len) {
        case 4:
            /* copy buf to kbuf32 */
            if (copy_from_user((void *)&kbuf32, buf, len)) {
                ret = -EFAULT;
            } else {
                iowrite32(kbuf32, mmio + *off);
            }
            break;
        
        case 8:
            if (copy_from_user((void *)&kbuf64, buf, len)) {
                ret = -EFAULT;
            } else {
                iowrite64(kbuf64, mmio + *off);
            }
            break;
        
        default:
            ret = -EFAULT;
            break;
        }
    }
    return ret;
}

私のユーザーモードテストコードは次のことを行います。

// open the device - succeed
// fd2 - the file descriptor representing the opened edu device

uint64_t val64 = 0x8b320000; // a random 64-bit value
unsigned long ret = -1; // retval

// write val64 to 0x80
lseek(fd2, 0x80, SEEK_SET); // seek to address 0x80 - dma.src in edu device source code (line 281)
ret = write(fd2, &val64, sizeof(uint64_t));
if(ret == -1) printf("write to dma src failed\n");
else printf("written %llx to dma src\n", val64);

// reset val64
val64 = 0;

// read what we have just written (sanity check)
lseek(fd2, 0x80, SEEK_SET);
ret = read(fd2, &ret64, sizeof(uint64_t));
if(ret == -1) printf("read from dma src failed\n");
else printf("sanity check: read dma src and we get - %llx\n", ret64);

ちなみに、ユーザーモードコードをテストすると、アドレスに値が書き込まれますが、0x80読み取ることはできません。いくつかのprintfステートメントを追加し、read()次のコード行に対応するエラーが発生したことを確認しました。

kbuf64 = ioread64(mmio + *off);

私はこれを見つけましたページIOアクセス機能の違いについて話し、に置き換えioread64()ましたが、readq()まだ問題は解決されませんでした。kbuf64 = ioread64(mmio + *off);実行中にコードの実行が停止します。追加も試しましたが、#define CONFIG_64BITまだエラーは解決されませんでした。

その後、Ctrl + Cを押してもユーザーモードコードを停止できません。私ができることは、QEMUを停止してCtrl + Aを押してからXを押して再起動することでした。

4バイト値の場合ioread32()と一緒に読み取りまたは書き込みを使用できますiowrite32()

何が間違ってエラーが発生したのかわかりますかioread64()

関連情報