sparc64.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * QEMU Sun4u/Sun4v System Emulator common routines
  3. *
  4. * Copyright (c) 2005 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "cpu.h"
  26. #include "hw/boards.h"
  27. #include "hw/sparc/sparc64.h"
  28. #include "qemu/timer.h"
  29. #include "sysemu/reset.h"
  30. #include "trace.h"
  31. #define TICK_MAX 0x7fffffffffffffffULL
  32. static void cpu_kick_irq(SPARCCPU *cpu)
  33. {
  34. CPUState *cs = CPU(cpu);
  35. CPUSPARCState *env = &cpu->env;
  36. cs->halted = 0;
  37. cpu_check_irqs(env);
  38. qemu_cpu_kick(cs);
  39. }
  40. void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level)
  41. {
  42. SPARCCPU *cpu = opaque;
  43. CPUSPARCState *env = &cpu->env;
  44. CPUState *cs;
  45. if (level) {
  46. if (!(env->ivec_status & 0x20)) {
  47. trace_sparc64_cpu_ivec_raise_irq(irq);
  48. cs = CPU(cpu);
  49. cs->halted = 0;
  50. env->interrupt_index = TT_IVEC;
  51. env->ivec_status |= 0x20;
  52. env->ivec_data[0] = (0x1f << 6) | irq;
  53. env->ivec_data[1] = 0;
  54. env->ivec_data[2] = 0;
  55. cpu_interrupt(cs, CPU_INTERRUPT_HARD);
  56. }
  57. } else {
  58. if (env->ivec_status & 0x20) {
  59. trace_sparc64_cpu_ivec_lower_irq(irq);
  60. cs = CPU(cpu);
  61. env->ivec_status &= ~0x20;
  62. cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
  63. }
  64. }
  65. }
  66. typedef struct ResetData {
  67. SPARCCPU *cpu;
  68. uint64_t prom_addr;
  69. } ResetData;
  70. static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
  71. QEMUBHFunc *cb, uint32_t frequency,
  72. uint64_t disabled_mask, uint64_t npt_mask)
  73. {
  74. CPUTimer *timer = g_new0(CPUTimer, 1);
  75. timer->name = name;
  76. timer->frequency = frequency;
  77. timer->disabled_mask = disabled_mask;
  78. timer->npt_mask = npt_mask;
  79. timer->disabled = 1;
  80. timer->npt = 1;
  81. timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  82. timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu);
  83. return timer;
  84. }
  85. static void cpu_timer_reset(CPUTimer *timer)
  86. {
  87. timer->disabled = 1;
  88. timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  89. timer_del(timer->qtimer);
  90. }
  91. static void main_cpu_reset(void *opaque)
  92. {
  93. ResetData *s = (ResetData *)opaque;
  94. CPUSPARCState *env = &s->cpu->env;
  95. static unsigned int nr_resets;
  96. cpu_reset(CPU(s->cpu));
  97. cpu_timer_reset(env->tick);
  98. cpu_timer_reset(env->stick);
  99. cpu_timer_reset(env->hstick);
  100. env->gregs[1] = 0; /* Memory start */
  101. env->gregs[2] = current_machine->ram_size; /* Memory size */
  102. env->gregs[3] = 0; /* Machine description XXX */
  103. if (nr_resets++ == 0) {
  104. /* Power on reset */
  105. env->pc = s->prom_addr + 0x20ULL;
  106. } else {
  107. env->pc = s->prom_addr + 0x40ULL;
  108. }
  109. env->npc = env->pc + 4;
  110. }
  111. static void tick_irq(void *opaque)
  112. {
  113. SPARCCPU *cpu = opaque;
  114. CPUSPARCState *env = &cpu->env;
  115. CPUTimer *timer = env->tick;
  116. if (timer->disabled) {
  117. trace_sparc64_cpu_tick_irq_disabled();
  118. return;
  119. } else {
  120. trace_sparc64_cpu_tick_irq_fire();
  121. }
  122. env->softint |= SOFTINT_TIMER;
  123. cpu_kick_irq(cpu);
  124. }
  125. static void stick_irq(void *opaque)
  126. {
  127. SPARCCPU *cpu = opaque;
  128. CPUSPARCState *env = &cpu->env;
  129. CPUTimer *timer = env->stick;
  130. if (timer->disabled) {
  131. trace_sparc64_cpu_stick_irq_disabled();
  132. return;
  133. } else {
  134. trace_sparc64_cpu_stick_irq_fire();
  135. }
  136. env->softint |= SOFTINT_STIMER;
  137. cpu_kick_irq(cpu);
  138. }
  139. static void hstick_irq(void *opaque)
  140. {
  141. SPARCCPU *cpu = opaque;
  142. CPUSPARCState *env = &cpu->env;
  143. CPUTimer *timer = env->hstick;
  144. if (timer->disabled) {
  145. trace_sparc64_cpu_hstick_irq_disabled();
  146. return;
  147. } else {
  148. trace_sparc64_cpu_hstick_irq_fire();
  149. }
  150. env->softint |= SOFTINT_STIMER;
  151. cpu_kick_irq(cpu);
  152. }
  153. static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
  154. {
  155. return muldiv64(cpu_ticks, NANOSECONDS_PER_SECOND, frequency);
  156. }
  157. static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
  158. {
  159. return muldiv64(timer_ticks, frequency, NANOSECONDS_PER_SECOND);
  160. }
  161. void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
  162. {
  163. uint64_t real_count = count & ~timer->npt_mask;
  164. uint64_t npt_bit = count & timer->npt_mask;
  165. int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
  166. cpu_to_timer_ticks(real_count, timer->frequency);
  167. trace_sparc64_cpu_tick_set_count(timer->name, real_count,
  168. timer->npt ? "disabled" : "enabled",
  169. timer);
  170. timer->npt = npt_bit ? 1 : 0;
  171. timer->clock_offset = vm_clock_offset;
  172. }
  173. uint64_t cpu_tick_get_count(CPUTimer *timer)
  174. {
  175. uint64_t real_count = timer_to_cpu_ticks(
  176. qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset,
  177. timer->frequency);
  178. trace_sparc64_cpu_tick_get_count(timer->name, real_count,
  179. timer->npt ? "disabled" : "enabled",
  180. timer);
  181. if (timer->npt) {
  182. real_count |= timer->npt_mask;
  183. }
  184. return real_count;
  185. }
  186. void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
  187. {
  188. int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  189. uint64_t real_limit = limit & ~timer->disabled_mask;
  190. timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
  191. int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
  192. timer->clock_offset;
  193. if (expires < now) {
  194. expires = now + 1;
  195. }
  196. trace_sparc64_cpu_tick_set_limit(timer->name, real_limit,
  197. timer->disabled ? "disabled" : "enabled",
  198. timer, limit,
  199. timer_to_cpu_ticks(
  200. now - timer->clock_offset,
  201. timer->frequency
  202. ),
  203. timer_to_cpu_ticks(
  204. expires - now, timer->frequency
  205. ));
  206. if (!real_limit) {
  207. trace_sparc64_cpu_tick_set_limit_zero(timer->name);
  208. timer_del(timer->qtimer);
  209. } else if (timer->disabled) {
  210. timer_del(timer->qtimer);
  211. } else {
  212. timer_mod(timer->qtimer, expires);
  213. }
  214. }
  215. SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr)
  216. {
  217. SPARCCPU *cpu;
  218. CPUSPARCState *env;
  219. ResetData *reset_info;
  220. uint32_t tick_frequency = 100 * 1000000;
  221. uint32_t stick_frequency = 100 * 1000000;
  222. uint32_t hstick_frequency = 100 * 1000000;
  223. cpu = SPARC_CPU(cpu_create(cpu_type));
  224. qdev_init_gpio_in_named(DEVICE(cpu), sparc64_cpu_set_ivec_irq,
  225. "ivec-irq", IVEC_MAX);
  226. env = &cpu->env;
  227. env->tick = cpu_timer_create("tick", cpu, tick_irq,
  228. tick_frequency, TICK_INT_DIS,
  229. TICK_NPT_MASK);
  230. env->stick = cpu_timer_create("stick", cpu, stick_irq,
  231. stick_frequency, TICK_INT_DIS,
  232. TICK_NPT_MASK);
  233. env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
  234. hstick_frequency, TICK_INT_DIS,
  235. TICK_NPT_MASK);
  236. reset_info = g_new0(ResetData, 1);
  237. reset_info->cpu = cpu;
  238. reset_info->prom_addr = prom_addr;
  239. qemu_register_reset(main_cpu_reset, reset_info);
  240. return cpu;
  241. }