Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / board-qemu / llfw / stage2.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2011 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <stdint.h>
14 #include <xvect.h>
15 #include <hw.h>
16 #include <stdio.h>
17 #include <romfs.h>
18 #include "memmap.h"
19 #include "stage2.h"
20 #include <termctrl.h>
21 #include "product.h"
22 #include "calculatecrc.h"
23 #include <cpu.h>
24 #include <libelf.h>
25 #include <string.h>
26 #include "../lib/libhvcall/libhvcall.h"
27
28 #define DEBUG(fmt...)
29 //#define DEBUG(fmt...) printf(fmt)
30
31 uint64_t gVecNum;
32
33 uint64_t exception_stack_frame;
34
35 typedef void (*pInterruptFunc_t) (void);
36
37 pInterruptFunc_t vectorTable[0x2E << 1];
38
39 extern void proceedInterrupt(void);
40
41 /* Prototypes for functions of this file */
42 void c_interrupt(uint64_t vecNum);
43 void set_exceptionVector(int num, void *func);
44 void early_c_entry(uint64_t start_addr, uint64_t fdt_addr);
45
46
47 static void exception_forward(void)
48 {
49         uint64_t val;
50
51         if (*(uint64_t *) XVECT_M_HANDLER) {
52                 proceedInterrupt();
53         }
54
55         printf("\r\n exception %llx ", gVecNum);
56         asm volatile ("mfsrr0   %0":"=r" (val):);
57         printf("\r\nSRR0 = %08llx%08llx ", val >> 32, val);
58         asm volatile ("mfsrr1   %0":"=r" (val):);
59         printf(" SRR1 = %08llx%08llx ", val >> 32, val);
60
61         asm volatile ("mfsprg   %0,2":"=r" (val):);
62         printf("\r\nSPRG2 = %08llx%08llx ", val >> 32, val);
63         asm volatile ("mfsprg   %0,3":"=r" (val):);
64         printf(" SPRG3 = %08llx%08llx \r\n", val >> 32, val);
65         while (1);
66 }
67
68 void c_interrupt(uint64_t vecNum)
69 {
70         gVecNum = vecNum;
71         if (vectorTable[vecNum >> 7]) {
72                 vectorTable[vecNum >> 7] ();
73         } else {
74                 exception_forward();
75         }
76 }
77
78 void set_exceptionVector(int num, void *func)
79 {
80         vectorTable[num >> 7] = (pInterruptFunc_t) func;
81 }
82
83 static void load_file(uint64_t destAddr, char *name, uint64_t maxSize,
84                       uint64_t romfs_base)
85 {
86         uint64_t cnt;
87         struct romfs_lookup_t fileInfo;
88         int rc;
89
90         rc = c_romfs_lookup(name, romfs_base, &fileInfo);
91         if (rc) {
92                 printf("Cannot find romfs file %s\n", name);
93                 return;
94         }
95         DEBUG("Found romfs file %s\n", name);
96         if (maxSize) {
97                 cnt = maxSize;
98         } else {
99                 cnt = fileInfo.size_data;
100         }
101         memcpy((void *)destAddr, (void *)fileInfo.addr_data, cnt);
102         flush_cache((void *) destAddr, fileInfo.size_data);
103 }
104
105 extern void print_version(void);
106
107 /***************************************************************************
108  * Function: early_c_entry
109  * Input   : start_addr
110  *
111  * Description:
112  **************************************************************************/
113 void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
114 {
115         struct romfs_lookup_t fileInfo;
116         void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
117         uint64_t *boot_info;
118         uint64_t romfs_base, paflof_base;
119         // romfs header values
120         // struct stH *header = (struct stH *) (start_addr + 0x28);
121         // uint64_t flashlen = header->flashlen;
122         unsigned long ofw_addr[2];
123         int rc;
124         extern char __executable_start;
125         extern char __etext;
126
127         /*
128          * If we run on a broken environment, we need to patch our own sc 1
129          * calls to be able to trap hypercalls. This does not cover RTAS or
130          * any payload we will load yet.
131          */
132         if (patch_broken_sc1(&__executable_start, &__etext, NULL)) {
133                 /* We are running in PR KVM on top of pHyp. Print all output
134                    we missed to print so far again to fake identical behavior */
135                 printf("\n\r\nSLOF");
136                 print_version();
137         }
138
139         if (fdt_addr == 0) {
140                 puts("ERROR: Flatten device tree not available!");
141         }
142
143         /* Hack: Determine base for "ROM filesystem" in memory...
144          * QEMU loads the FDT at the top of the available RAM, so we place
145          * the ROMFS just underneath. */
146         romfs_base = (fdt_addr - 0x410000) & ~0xffffLL;
147         memcpy((char *)romfs_base, 0, 0x400000);
148
149         exception_stack_frame = 0;
150
151         printf(" Press \"s\" to enter Open Firmware.\r\n\r\n");
152
153         DEBUG("  [c_romfs_lookup at %p]\n", c_romfs_lookup);
154         rc = c_romfs_lookup("bootinfo", romfs_base, &fileInfo);
155         if (rc)
156                 printf("  !!! roomfs lookup(bootinfo) = %d\n", rc);
157         boot_info = (uint64_t *) fileInfo.addr_data;
158         boot_info[1] = start_addr;
159         load_file(0x100, "xvect", 0, romfs_base);
160         rc = c_romfs_lookup("ofw_main", romfs_base, &fileInfo);
161         if (rc)
162                 printf("  !!! roomfs lookup(bootinfo) = %d\n", rc);
163
164         DEBUG("  [ofw_main addr hdr  0x%lx]\n", fileInfo.addr_header);
165         DEBUG("  [ofw_main addr data 0x%lx]\n", fileInfo.addr_data);
166         DEBUG("  [ofw_main size data 0x%lx]\n", fileInfo.size_data);
167         DEBUG("  [ofw_main flags     0x%lx]\n", fileInfo.flags);
168         DEBUG("  [hdr: 0x%08lx 0x%08lx]\n  [     0x%08lx 0x%08lx]\n",
169                ((uint64_t *)fileInfo.addr_header)[0],
170                ((uint64_t *)fileInfo.addr_header)[1],
171                ((uint64_t *)fileInfo.addr_header)[2],
172                ((uint64_t *)fileInfo.addr_header)[3]);
173
174         /* Assume that paflof and SNK need ca. 31 MiB RAM right now.
175          * TODO: Use value from ELF file instead */
176         paflof_base = romfs_base - 0x1F00000 + 0x100;
177         if ((int64_t)paflof_base <= 0LL) {
178                 puts("ERROR: Not enough memory for Open Firmware");
179         }
180         rc = elf_load_file_to_addr((void *)fileInfo.addr_data, (void*)paflof_base,
181                                    ofw_addr, NULL, flush_cache);
182         DEBUG("  [load_elf_file returned %d]\n", rc);
183
184         ofw_start =
185             (void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
186             &ofw_addr;
187         // re-enable the cursor
188         printf("%s%s", TERM_CTRL_RESET, TERM_CTRL_CRSON);
189         DEBUG("  [ofw_start=%p ofw_addr=0x%lx]\n", ofw_start, ofw_addr[0]);
190         ofw_addr[1] = ofw_addr[0];
191         /* Call the Open Firmware layer with ePAPR-style calling conventions:
192          * r3 = R3 Effective address of the device tree image. Note: this
193          *      address must be 8-byte aligned in memory.
194          * r4 = implementation dependent, we use it for ROMFS base address
195          * r5 = 0
196          * r6 = 0x65504150 -- ePAPR magic value-to distinguish from
197          *      non-ePAPR-compliant firmware
198          * r7 = size of Initially Mapped Area
199          *      (right now we assume everything from 0 to the FDT is the IMA)
200          */
201         asm volatile("isync; sync;" : : : "memory");
202         ofw_start(fdt_addr, romfs_base, 0, 0x65504150, fdt_addr);
203         asm volatile("isync; sync;" : : : "memory");
204         // never return
205 }