serial.c 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2022 - Google LLC
  4. */
  5. #include <nvhe/pkvm.h>
  6. #include <nvhe/spinlock.h>
  7. static void (*__hyp_putc)(char c);
  8. static inline void __hyp_putx4(unsigned int x)
  9. {
  10. x &= 0xf;
  11. if (x <= 9)
  12. x += '0';
  13. else
  14. x += ('a' - 0xa);
  15. __hyp_putc(x);
  16. }
  17. static inline void __hyp_putx4n(unsigned long x, int n)
  18. {
  19. int i = n >> 2;
  20. __hyp_putc('0');
  21. __hyp_putc('x');
  22. while (i--)
  23. __hyp_putx4(x >> (4 * i));
  24. __hyp_putc('\n');
  25. __hyp_putc('\r');
  26. }
  27. static inline bool hyp_serial_enabled(void)
  28. {
  29. /* Paired with __pkvm_register_serial_driver()'s cmpxchg */
  30. return !!smp_load_acquire(&__hyp_putc);
  31. }
  32. void hyp_puts(const char *s)
  33. {
  34. if (!hyp_serial_enabled())
  35. return;
  36. while (*s)
  37. __hyp_putc(*s++);
  38. __hyp_putc('\n');
  39. __hyp_putc('\r');
  40. }
  41. void hyp_putx64(u64 x)
  42. {
  43. if (hyp_serial_enabled())
  44. __hyp_putx4n(x, 64);
  45. }
  46. void hyp_putc(char c)
  47. {
  48. if (hyp_serial_enabled())
  49. __hyp_putc(c);
  50. }
  51. int __pkvm_register_serial_driver(void (*cb)(char))
  52. {
  53. /*
  54. * Paired with smp_load_acquire(&__hyp_putc) in
  55. * hyp_serial_enabled(). Ensure memory stores hapenning during a pKVM
  56. * module init are observed before executing the callback.
  57. */
  58. return cmpxchg_release(&__hyp_putc, NULL, cb) ? -EBUSY : 0;
  59. }