Атомарная модификация 4байтов для SMP (x86)

Тема в разделе "WASM.ASSEMBLER", создана пользователем 7mm, 17 июн 2011.

  1. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Нужно обеспечить операцию атомарной модификации 4х байтов в случае SMP системы на базе x86 в режиме ядра. По терминологии Intel, это "Cross-Modifying Code".

    Смущает вот что:

    Т.е. получается, что LOCK префикс в случае модификации кода бесполезен?
     
  2. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    7mm
    Не бесполезен, но модифицируемые инструкции, могут быть уже выбраны на исполнение. Поэтому блокировать или не блокировать шину — не важно, т.к. поздно уже. Аналогично с доступом к таблицам страниц, т.к. их данные грузятся в TLB.
    Собственно, как писать кросс-модифицируемый код, описано там же.
     
  3. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    l_inc
    Вот поясните, если я ошибаюсь. Допустим, на одном процессоре я пишу 4 байта, которые лежат на границе линии кеша или страниц -- т.е. это получается будет однозначно не атомарная операция. А вот где-то в этот момент второй процессор делает предвыборку команд, и не получится ли так, что у него будут частично-обновлённые данные?

    И второй вопрос, если я модифицировал код, который лежит где-то в памяти и также закеширован некоторыми процессорами, будет ли осуществлена инвалидация их кешей после записи (после снятия LOCK) ?..
     
  4. 100gold

    100gold New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2010
    Сообщения:
    165
    Кажется префикс lock блокирует шину на время выполнения всей инструкции, т.е. как бы не лежали 4 байта - вся разница будет во времени блокирования (в случае пересечения границы просто "надолго" память будет недоступна).
     
  5. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    100gold
    Да, похоже так и будет. Но всё-таки, достаточно ли указать префикс LOCK перед операцией модификации 4х байтов для SMP, или же нужно делать что-то дополнительно?..
     
  6. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Вот так вопрос задам. В линуксе есть такой кодес:
    Код (Text):
    1. 14 /*
    2. 15  * Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
    3. 16  * Since this is generally used to protect other memory information, we
    4. 17  * use "asm volatile" and "memory" clobbers to prevent gcc from moving
    5. 18  * information around.
    6. 19  */
    7. 20 #define __xchg(x, ptr, size)                                            \
    8. 21 ({                                                                      \
    9. 22         __typeof(*(ptr)) __x = (x);                                     \
    10. 23         switch (size) {                                                 \
    11. 24         case 1:                                                         \
    12. 25         {                                                               \
    13. 26                 volatile u8 *__ptr = (volatile u8 *)(ptr);              \
    14. 27                 asm volatile("xchgb %0,%1"                              \
    15. 28                              : "=q" (__x), "+m" (*__ptr)                \
    16. 29                              : "0" (__x)                                \
    17. 30                              : "memory");                               \
    18. 31                 break;                                                  \
    19. 32         }                                                               \
    20. 33         case 2:                                                         \
    21. 34         {                                                               \
    22. 35                 volatile u16 *__ptr = (volatile u16 *)(ptr);            \
    23. 36                 asm volatile("xchgw %0,%1"                              \
    24. 37                              : "=r" (__x), "+m" (*__ptr)                \
    25. 38                              : "0" (__x)                                \
    26. 39                              : "memory");                               \
    27. 40                 break;                                                  \
    28. 41         }                                                               \
    29. 42         case 4:                                                         \
    30. 43         {                                                               \
    31. 44                 volatile u32 *__ptr = (volatile u32 *)(ptr);            \
    32. 45                 asm volatile("xchgl %0,%1"                              \
    33. 46                              : "=r" (__x), "+m" (*__ptr)                \
    34. 47                              : "0" (__x)                                \
    35. 48                              : "memory");                               \
    36. 49                 break;                                                  \
    37. 50         }                                                               \
    38. 51         case 8:                                                         \
    39. 52         {                                                               \
    40. 53                 volatile u64 *__ptr = (volatile u64 *)(ptr);            \
    41. 54                 asm volatile("xchgq %0,%1"                              \
    42. 55                              : "=r" (__x), "+m" (*__ptr)                \
    43. 56                              : "0" (__x)                                \
    44. 57                              : "memory");                               \
    45. 58                 break;                                                  \
    46. 59         }                                                               \
    47. 60         default:                                                        \
    48. 61                 __xchg_wrong_size();                                    \
    49. 62         }                                                               \
    50. 63         __x;                                                            \
    51. 64 })
    52. 65
    53. 66 #define xchg(ptr, v)                                                    \
    54. 67         __xchg((v), (ptr), sizeof(*ptr))
    Допустимо ли использовать вот этот самый xchg(ptr, v) в случае с SMP для модификации 4х байтов:

    Код (Text):
    1. typedef struct {
    2.          u8 type;
    3.          s32 imm32;
    4. } __attribute__((packed)) x86_call_t;
    5.  
    6. int x86_fixup_call(x86_call_t * pcall, void * handler)
    7. {
    8.          s32 imm32 = (...);
    9.          ...
    10.          xchg(&pcall->imm32, imm32);
    11.          ...
    12. }
    Подскажите, кто знает?..
     
  7. dinoweb

    dinoweb Дмитрий

    Публикаций:
    0
    Регистрация:
    12 окт 2005
    Сообщения:
    129
    Адрес:
    Россия. Красноярск
    Насколько я понимаю, допустимо.

    Добавлю, что если будет необходимость сразу-же исполнить изменённый код в этом-же потоке, то можно выполнить команду cpuid, это сбросит уже загруженные на исполнение инструкции.
     
  8. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    http://wasm.ru/forum/viewtopic.php?id=37370&p=2
    #28

    l_inc
    При записи в текущий сегмент кода очередь команд сбрасывается в современных камнях. Поэтому нельзя обмануть процессор модификацией следующей инструкции из текущей.
     
  9. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    klzlk
    Возможно, Вы не заметили, но речь не о самомодифицирующемся коде, а о кроссмодифицируемом. Так что вполне можно обмануть процессор.
     
  10. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    l_inc
    Хм и в правду, это вы про перекрёстный код говорите. В таком случае вполне возможно.
     
  11. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    dinoweb
    Нет, речь о корректной работе других камней после модификации общего кода.

    2All
    Итак, вердикт каков? Есть чем подтвердить/опровергнуть? Боюсь, отловить потенциальный баг будет ой-как не просто...
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    7mm
    Сам жду снегурочку с вердиктом. :) Тоже интересно.
     
  13. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Кстати, как вариант, наверняка можно создать копию страницы, модифицировать её и затем изменить запись PTE... Единственное, что тут может быть не так, если целевые байты лежат на границе страниц -- тогда нужно будет менять сразу 2 записи PTE, а это уже будет никак не атомарно :dntknw:
     
  14. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Kernel's `stop_machine` matters!