sparc64.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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/char/serial.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. void cpu_check_irqs(CPUSPARCState *env)
  33. {
  34. CPUState *cs;
  35. uint32_t pil = env->pil_in |
  36. (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER));
  37. /* We should be holding the BQL before we mess with IRQs */
  38. g_assert(qemu_mutex_iothread_locked());
  39. /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
  40. if (env->ivec_status & 0x20) {
  41. return;
  42. }
  43. cs = env_cpu(env);
  44. /* check if TM or SM in SOFTINT are set
  45. setting these also causes interrupt 14 */
  46. if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) {
  47. pil |= 1 << 14;
  48. }
  49. /* The bit corresponding to psrpil is (1<< psrpil), the next bit
  50. is (2 << psrpil). */
  51. if (pil < (2 << env->psrpil)) {
  52. if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
  53. trace_sparc64_cpu_check_irqs_reset_irq(env->interrupt_index);
  54. env->interrupt_index = 0;
  55. cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
  56. }
  57. return;
  58. }
  59. if (cpu_interrupts_enabled(env)) {
  60. unsigned int i;
  61. for (i = 15; i > env->psrpil; i--) {
  62. if (pil & (1 << i)) {
  63. int old_interrupt = env->interrupt_index;
  64. int new_interrupt = TT_EXTINT | i;
  65. if (unlikely(env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt
  66. && ((cpu_tsptr(env)->tt & 0x1f0) == TT_EXTINT))) {
  67. trace_sparc64_cpu_check_irqs_noset_irq(env->tl,
  68. cpu_tsptr(env)->tt,
  69. new_interrupt);
  70. } else if (old_interrupt != new_interrupt) {
  71. env->interrupt_index = new_interrupt;
  72. trace_sparc64_cpu_check_irqs_set_irq(i, old_interrupt,
  73. new_interrupt);
  74. cpu_interrupt(cs, CPU_INTERRUPT_HARD);
  75. }
  76. break;
  77. }
  78. }
  79. } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
  80. trace_sparc64_cpu_check_irqs_disabled(pil, env->pil_in, env->softint,
  81. env->interrupt_index);
  82. env->interrupt_index = 0;
  83. cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
  84. }
  85. }
  86. static void cpu_kick_irq(SPARCCPU *cpu)
  87. {
  88. CPUState *cs = CPU(cpu);
  89. CPUSPARCState *env = &cpu->env;
  90. cs->halted = 0;
  91. cpu_check_irqs(env);
  92. qemu_cpu_kick(cs);
  93. }
  94. void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level)
  95. {
  96. SPARCCPU *cpu = opaque;
  97. CPUSPARCState *env = &cpu->env;
  98. CPUState *cs;
  99. if (level) {
  100. if (!(env->ivec_status & 0x20)) {
  101. trace_sparc64_cpu_ivec_raise_irq(irq);
  102. cs = CPU(cpu);
  103. cs->halted = 0;
  104. env->interrupt_index = TT_IVEC;
  105. env->ivec_status |= 0x20;
  106. env->ivec_data[0] = (0x1f << 6) | irq;
  107. env->ivec_data[1] = 0;
  108. env->ivec_data[2] = 0;
  109. cpu_interrupt(cs, CPU_INTERRUPT_HARD);
  110. }
  111. } else {
  112. if (env->ivec_status & 0x20) {
  113. trace_sparc64_cpu_ivec_lower_irq(irq);
  114. cs = CPU(cpu);
  115. env->ivec_status &= ~0x20;
  116. cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
  117. }
  118. }
  119. }
  120. typedef struct ResetData {
  121. SPARCCPU *cpu;
  122. uint64_t prom_addr;
  123. } ResetData;
  124. static CPUTimer *cpu_timer_create(const char *name, SPARCCPU *cpu,
  125. QEMUBHFunc *cb, uint32_t frequency,
  126. uint64_t disabled_mask, uint64_t npt_mask)
  127. {
  128. CPUTimer *timer = g_malloc0(sizeof(CPUTimer));
  129. timer->name = name;
  130. timer->frequency = frequency;
  131. timer->disabled_mask = disabled_mask;
  132. timer->npt_mask = npt_mask;
  133. timer->disabled = 1;
  134. timer->npt = 1;
  135. timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  136. timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cb, cpu);
  137. return timer;
  138. }
  139. static void cpu_timer_reset(CPUTimer *timer)
  140. {
  141. timer->disabled = 1;
  142. timer->clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  143. timer_del(timer->qtimer);
  144. }
  145. static void main_cpu_reset(void *opaque)
  146. {
  147. ResetData *s = (ResetData *)opaque;
  148. CPUSPARCState *env = &s->cpu->env;
  149. static unsigned int nr_resets;
  150. cpu_reset(CPU(s->cpu));
  151. cpu_timer_reset(env->tick);
  152. cpu_timer_reset(env->stick);
  153. cpu_timer_reset(env->hstick);
  154. env->gregs[1] = 0; /* Memory start */
  155. env->gregs[2] = ram_size; /* Memory size */
  156. env->gregs[3] = 0; /* Machine description XXX */
  157. if (nr_resets++ == 0) {
  158. /* Power on reset */
  159. env->pc = s->prom_addr + 0x20ULL;
  160. } else {
  161. env->pc = s->prom_addr + 0x40ULL;
  162. }
  163. env->npc = env->pc + 4;
  164. }
  165. static void tick_irq(void *opaque)
  166. {
  167. SPARCCPU *cpu = opaque;
  168. CPUSPARCState *env = &cpu->env;
  169. CPUTimer *timer = env->tick;
  170. if (timer->disabled) {
  171. trace_sparc64_cpu_tick_irq_disabled();
  172. return;
  173. } else {
  174. trace_sparc64_cpu_tick_irq_fire();
  175. }
  176. env->softint |= SOFTINT_TIMER;
  177. cpu_kick_irq(cpu);
  178. }
  179. static void stick_irq(void *opaque)
  180. {
  181. SPARCCPU *cpu = opaque;
  182. CPUSPARCState *env = &cpu->env;
  183. CPUTimer *timer = env->stick;
  184. if (timer->disabled) {
  185. trace_sparc64_cpu_stick_irq_disabled();
  186. return;
  187. } else {
  188. trace_sparc64_cpu_stick_irq_fire();
  189. }
  190. env->softint |= SOFTINT_STIMER;
  191. cpu_kick_irq(cpu);
  192. }
  193. static void hstick_irq(void *opaque)
  194. {
  195. SPARCCPU *cpu = opaque;
  196. CPUSPARCState *env = &cpu->env;
  197. CPUTimer *timer = env->hstick;
  198. if (timer->disabled) {
  199. trace_sparc64_cpu_hstick_irq_disabled();
  200. return;
  201. } else {
  202. trace_sparc64_cpu_hstick_irq_fire();
  203. }
  204. env->softint |= SOFTINT_STIMER;
  205. cpu_kick_irq(cpu);
  206. }
  207. static int64_t cpu_to_timer_ticks(int64_t cpu_ticks, uint32_t frequency)
  208. {
  209. return muldiv64(cpu_ticks, NANOSECONDS_PER_SECOND, frequency);
  210. }
  211. static uint64_t timer_to_cpu_ticks(int64_t timer_ticks, uint32_t frequency)
  212. {
  213. return muldiv64(timer_ticks, frequency, NANOSECONDS_PER_SECOND);
  214. }
  215. void cpu_tick_set_count(CPUTimer *timer, uint64_t count)
  216. {
  217. uint64_t real_count = count & ~timer->npt_mask;
  218. uint64_t npt_bit = count & timer->npt_mask;
  219. int64_t vm_clock_offset = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
  220. cpu_to_timer_ticks(real_count, timer->frequency);
  221. trace_sparc64_cpu_tick_set_count(timer->name, real_count,
  222. timer->npt ? "disabled" : "enabled",
  223. timer);
  224. timer->npt = npt_bit ? 1 : 0;
  225. timer->clock_offset = vm_clock_offset;
  226. }
  227. uint64_t cpu_tick_get_count(CPUTimer *timer)
  228. {
  229. uint64_t real_count = timer_to_cpu_ticks(
  230. qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->clock_offset,
  231. timer->frequency);
  232. trace_sparc64_cpu_tick_get_count(timer->name, real_count,
  233. timer->npt ? "disabled" : "enabled",
  234. timer);
  235. if (timer->npt) {
  236. real_count |= timer->npt_mask;
  237. }
  238. return real_count;
  239. }
  240. void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
  241. {
  242. int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  243. uint64_t real_limit = limit & ~timer->disabled_mask;
  244. timer->disabled = (limit & timer->disabled_mask) ? 1 : 0;
  245. int64_t expires = cpu_to_timer_ticks(real_limit, timer->frequency) +
  246. timer->clock_offset;
  247. if (expires < now) {
  248. expires = now + 1;
  249. }
  250. trace_sparc64_cpu_tick_set_limit(timer->name, real_limit,
  251. timer->disabled ? "disabled" : "enabled",
  252. timer, limit,
  253. timer_to_cpu_ticks(
  254. now - timer->clock_offset,
  255. timer->frequency
  256. ),
  257. timer_to_cpu_ticks(
  258. expires - now, timer->frequency
  259. ));
  260. if (!real_limit) {
  261. trace_sparc64_cpu_tick_set_limit_zero(timer->name);
  262. timer_del(timer->qtimer);
  263. } else if (timer->disabled) {
  264. timer_del(timer->qtimer);
  265. } else {
  266. timer_mod(timer->qtimer, expires);
  267. }
  268. }
  269. SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr)
  270. {
  271. SPARCCPU *cpu;
  272. CPUSPARCState *env;
  273. ResetData *reset_info;
  274. uint32_t tick_frequency = 100 * 1000000;
  275. uint32_t stick_frequency = 100 * 1000000;
  276. uint32_t hstick_frequency = 100 * 1000000;
  277. cpu = SPARC_CPU(cpu_create(cpu_type));
  278. qdev_init_gpio_in_named(DEVICE(cpu), sparc64_cpu_set_ivec_irq,
  279. "ivec-irq", IVEC_MAX);
  280. env = &cpu->env;
  281. env->tick = cpu_timer_create("tick", cpu, tick_irq,
  282. tick_frequency, TICK_INT_DIS,
  283. TICK_NPT_MASK);
  284. env->stick = cpu_timer_create("stick", cpu, stick_irq,
  285. stick_frequency, TICK_INT_DIS,
  286. TICK_NPT_MASK);
  287. env->hstick = cpu_timer_create("hstick", cpu, hstick_irq,
  288. hstick_frequency, TICK_INT_DIS,
  289. TICK_NPT_MASK);
  290. reset_info = g_malloc0(sizeof(ResetData));
  291. reset_info->cpu = cpu;
  292. reset_info->prom_addr = prom_addr;
  293. qemu_register_reset(main_cpu_reset, reset_info);
  294. return cpu;
  295. }