Я пытаюсь выполнить некоторые записи в регистрах памяти из пространства пользователя (через пользовательский драйвер).Я хочу написать три 64-битных целых числа, и я инициализировал переменные "value_1, value_2 и value_3" для типа uint64_t.
Я должен использовать инструкцию gcc inline mov и работаю над ARM 64-bitархитектура на заказной версии Linux для встроенной системы.
Это мой код:
asm ( "MOV %[reg1], %[val1]\t\n"
"MOV %[reg2], %[val2]\t\n"
"MOV %[reg3], %[val3]\t\n"
:[reg1] "=&r" (*register_1),[arg2] "=&r" (*register_2), [arg3] "=&r" (*register_3)
:[val1] "r"(value_1),[val2] "r" (value_2), [val3] "r" (value_3)
);
Проблема странная ... Если я выполняю только два MOV, код работает.Если я выполню все три MOV, произойдет сбой всей системы, и мне придется перезагрузить всю систему.
даже незнакомец ... Если я положу "printf" хотя бы на нанососпит с 0 наносекундами между вторым и третьим MOV, код работает!
Я оглянулся, пытаясь найтиРешение и я также использую Clobber памяти:
asm ( "MOV %[reg1], %[val1]\t\n"
"MOV %[reg2], %[val2]\t\n"
"MOV %[reg3], %[val3]\t\n"
:[reg1] "=&r" (*register_1),[arg2] "=&r" (*register_2), [arg3] "=&r" (*register_3)
:[val1] "r"(value_1),[val2] "r" (value_2), [val3] "r" (value_3)
:"memory"
);
... не работает!
Я также использовал макрос барьер памяти между вторым и третьим MOV или вконец трех MOV:
asm volatile("": : :"memory")
.. не работает!
Кроме того, я попытался записать непосредственно в регистр с помощью указателей, и у меня было то же поведение: послево-вторых, напишите сбой системы ...
Кто-нибудь может предложить мне решение .. или скажите, неправильно ли я использую встроенный MOV gcc или барьер памяти?
----> БОЛЬШЕ ДЕТАЛЕЙ <----- </p>
Это мое основное:
int main()
{
int dev_fd;
volatile void * base_addr = NULL;
volatile uint64_t * reg1_addr = NULL;
volatile uint32_t * reg2_addr = NULL;
volatile uint32_t * reg3_addr = NULL;
dev_fd = open(MY_DEVICE, O_RDWR);
if (dev_fd < 0)
{
perror("Open call failed");
return -1;
}
base_addr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, xsmll_dev_fd, 0);
if (base_addr == MAP_FAILED)
{
perror("mmap operation failed");
return -1;
}
printf("BASE ADDRESS VIRT: 0x%p\n", base_addr);
/* Preparing the registers */
reg1_addr = base_addr + REG1_OFF;
reg2_addr = base_addr + REG2_OFF;
reg3_addr = base_addr + REG3_OFF;
uint64_t val_1 = 0xEEEEEEEE;
uint64_t val_2 = 0x00030010;
uint64_t val_3 = 0x01;
asm ( "str %[val1], %[reg1]\t\n"
"str %[val2], %[reg2]\t\n"
"str %[val3], %[reg3]\t\n"
:[reg1] "=&m" (*reg1_addr),[reg2] "=&m" (*reg2_addr), [reg3] "=&m" (*reg3_addr)
:[val1] "r"(val_1),[val2] "r" (val_2), [val3] "r" (val_3)
);
printf("--- END ---\n");
close(dev_fd);
return 0;
}
Это вывод компилятора относительно оператора asm(linaro..я кросс-компиляция):
400bfc: f90013a0 str x0, [x29,#32]
400c00: f94027a3 ldr x3, [x29,#72]
400c04: f94023a4 ldr x4, [x29,#64]
400c08: f9402ba5 ldr x5, [x29,#80]
400c0c: f9401ba0 ldr x0, [x29,#48]
400c10: f94017a1 ldr x1, [x29,#40]
400c14: f94013a2 ldr x2, [x29,#32]
400c18: f9000060 str x0, [x3]
400c1c: f9000081 str x1, [x4]
400c20: f90000a2 str x2, [x5]
Спасибо!