Annotation of qemu/roms/qemu-palcode/init.c, revision 1.1.1.1

1.1       root        1: /* Initialization of the system and the HWRPB.
                      2: 
                      3:    Copyright (C) 2011 Richard Henderson
                      4: 
                      5:    This file is part of QEMU PALcode.
                      6: 
                      7:    This program is free software; you can redistribute it and/or modify
                      8:    it under the terms of the GNU General Public License as published by
                      9:    the Free Software Foundation; either version 2 of the License or
                     10:    (at your option) any later version.
                     11: 
                     12:    This program is distributed in the hope that it will be useful,
                     13:    but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the text
                     15:    of the GNU General Public License for more details.
                     16: 
                     17:    You should have received a copy of the GNU General Public License
                     18:    along with this program; see the file COPYING.  If not see
                     19:    <http://www.gnu.org/licenses/>.  */
                     20: 
                     21: #include <string.h>
                     22: #include <stddef.h>
                     23: #include "hwrpb.h"
                     24: #include "osf.h"
                     25: #include "ioport.h"
                     26: #include "uart.h"
                     27: #include "protos.h"
                     28: #include SYSTEM_H
                     29: 
                     30: #define PAGE_SHIFT     13
                     31: #define PAGE_SIZE      (1ul << PAGE_SHIFT)
                     32: #define PAGE_OFFSET    0xfffffc0000000000UL
                     33: 
                     34: #define VPTPTR         0xfffffffe00000000UL
                     35: 
                     36: #define PA(VA)         ((unsigned long)(VA) & 0xfffffffffful)
                     37: #define VA(PA)         ((void *)(PA) + PAGE_OFFSET)
                     38: 
                     39: #define HZ     1024
                     40: 
                     41: struct hwrpb_combine {
                     42:   struct hwrpb_struct hwrpb;
                     43:   struct percpu_struct processor;
                     44:   struct memdesc_struct md;
                     45:   struct memclust_struct mc[2];
                     46:   struct crb_struct crb;
                     47:   struct procdesc_struct proc_dispatch;
                     48:   struct procdesc_struct proc_fixup;
                     49: };
                     50: 
                     51: extern char stack[PAGE_SIZE] __attribute__((section(".sbss")));
                     52: extern char _end[] __attribute__((visibility("hidden"), nocommon));
                     53: 
                     54: struct pcb_struct pcb __attribute__((section(".sbss")));
                     55: 
                     56: static unsigned long page_dir[1024] __attribute__((aligned(PAGE_SIZE)));
                     57: 
                     58: /* The HWRPB must be aligned because it is exported at INIT_HWRPB.  */
                     59: struct hwrpb_combine hwrpb __attribute__((aligned(PAGE_SIZE)));
                     60: 
                     61: void *last_alloc;
                     62: bool have_vga;
                     63: 
                     64: static void *
                     65: alloc (unsigned long size, unsigned long align)
                     66: {
                     67:   void *p = (void *)(((unsigned long)last_alloc + align - 1) & ~(align - 1));
                     68:   last_alloc = p + size;
                     69:   return memset (p, 0, size);
                     70: }
                     71: 
                     72: static inline unsigned long
                     73: pt_index(unsigned long addr, int level)
                     74: {
                     75:   return (addr >> (PAGE_SHIFT + (10 * level))) & 0x3ff;
                     76: }
                     77: 
                     78: static inline unsigned long
                     79: build_pte (void *page)
                     80: {
                     81:   unsigned long bits;
                     82: 
                     83:   bits = PA((unsigned long)page) << (32 - PAGE_SHIFT);
                     84:   bits += _PAGE_VALID | _PAGE_KRE | _PAGE_KWE;
                     85: 
                     86:   return bits;
                     87: }
                     88: 
                     89: static inline void *
                     90: pte_page (unsigned long pte)
                     91: {
                     92:   return VA(pte >> 32 << PAGE_SHIFT);
                     93: }
                     94: 
                     95: static void
                     96: set_pte (unsigned long addr, void *page)
                     97: {
                     98:   unsigned long *pt = page_dir;
                     99:   unsigned long index;
                    100: 
                    101:   index = pt_index(addr, 2);
                    102:   if (pt[index] != 0)
                    103:     pt = pte_page (pt[index]);
                    104:   else
                    105:     {
                    106:       unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
                    107:       pt[index] = build_pte (npt);
                    108:       pt = npt;
                    109:     }
                    110: 
                    111:   index = pt_index(addr, 1);
                    112:   if (pt[index] != 0)
                    113:     pt = pte_page (pt[index]);
                    114:   else
                    115:     {
                    116:       unsigned long *npt = alloc(PAGE_SIZE, PAGE_SIZE);
                    117:       pt[index] = build_pte (npt);
                    118:       pt = npt;
                    119:     }
                    120: 
                    121:   index = pt_index(addr, 0);
                    122:   pt[index] = build_pte (page);
                    123: }
                    124: 
                    125: static void
                    126: init_page_table(void)
                    127: {
                    128:   /* Install the self-reference for the virtual page table base register.  */
                    129:   page_dir[pt_index(VPTPTR, 2)] = build_pte(page_dir);
                    130: 
                    131:   set_pte ((unsigned long)INIT_HWRPB, &hwrpb);
                    132:   
                    133:   /* ??? SRM maps some amount of memory at 0x20000000 for use by programs
                    134:      started from the console prompt.  Including the bootloader.  While
                    135:      we're emulating MILO, don't bother as we jump straight to the kernel
                    136:      loaded into KSEG.  */
                    137: }
                    138: 
                    139: static void
                    140: init_hwrpb (unsigned long memsize)
                    141: {
                    142:   unsigned long pal_pages;
                    143:   unsigned long amask;
                    144:   
                    145:   hwrpb.hwrpb.phys_addr = PA(&hwrpb);
                    146: 
                    147:   /* Yes, the 'HWRPB' magic is in big-endian byte ordering.  */
                    148:   hwrpb.hwrpb.id = ( (long)'H' << 56
                    149:                   | (long)'W' << 48
                    150:                   | (long)'R' << 40
                    151:                   | (long)'P' << 32
                    152:                   | (long)'B' << 24);
                    153: 
                    154:   hwrpb.hwrpb.size = sizeof(struct hwrpb_struct);
                    155: 
                    156:   ((int *)hwrpb.hwrpb.ssn)[0] = ( 'Q' << 0
                    157:                                | 'E' << 8
                    158:                                | 'M' << 16
                    159:                                | 'U' << 24);
                    160: 
                    161:   amask = ~__builtin_alpha_amask(-1);
                    162:   switch (__builtin_alpha_implver())
                    163:     {
                    164:     case 0: /* EV4 */
                    165:       hwrpb.hwrpb.cpuid = EV4_CPU;
                    166:       hwrpb.hwrpb.max_asn = 63;
                    167:       break;
                    168: 
                    169:     case 1: /* EV5 */
                    170:       hwrpb.hwrpb.cpuid
                    171:        = ((amask & 0x101) == 0x101 ? PCA56_CPU         /* MAX+BWX */
                    172:           : amask & 1 ? EV56_CPU                       /* BWX */
                    173:           : EV5_CPU);
                    174:       hwrpb.hwrpb.max_asn = 127;
                    175:       break;
                    176: 
                    177:     case 2: /* EV6 */
                    178:       hwrpb.hwrpb.cpuid = (amask & 4 ? EV67_CPU : EV6_CPU);  /* CIX */
                    179:       hwrpb.hwrpb.max_asn = 255;
                    180:       break;
                    181:     }
                    182: 
                    183:   hwrpb.hwrpb.pagesize = PAGE_SIZE;
                    184:   hwrpb.hwrpb.pa_bits = 40;
                    185:   hwrpb.hwrpb.sys_type = SYS_TYPE;
                    186:   hwrpb.hwrpb.sys_variation = SYS_VARIATION;
                    187:   hwrpb.hwrpb.sys_revision = SYS_REVISION;
                    188:   hwrpb.processor.type = hwrpb.hwrpb.cpuid;
                    189: 
                    190:   hwrpb.hwrpb.intr_freq = HZ * 4096;
                    191:   hwrpb.hwrpb.cycle_freq = 250000000;  /* QEMU architects 250MHz.  */
                    192: 
                    193:   hwrpb.hwrpb.vptb = VPTPTR;
                    194: 
                    195:   hwrpb.hwrpb.nr_processors = 1;
                    196:   hwrpb.hwrpb.processor_size = sizeof(struct percpu_struct);
                    197:   hwrpb.hwrpb.processor_offset = offsetof(struct hwrpb_combine, processor);
                    198: 
                    199:   hwrpb.hwrpb.mddt_offset = offsetof(struct hwrpb_combine, md);
                    200:   hwrpb.md.numclusters = 2;
                    201: 
                    202:   pal_pages = (PA(last_alloc) + PAGE_SIZE - 1) >> PAGE_SHIFT;
                    203: 
                    204:   hwrpb.mc[0].numpages = pal_pages;
                    205:   hwrpb.mc[0].usage = 1;
                    206:   hwrpb.mc[1].start_pfn = pal_pages;
                    207:   hwrpb.mc[1].numpages = (memsize >> PAGE_SHIFT) - pal_pages;
                    208: 
                    209:   hwrpb.hwrpb.crb_offset = offsetof(struct hwrpb_combine, crb);
                    210:   hwrpb.crb.dispatch_va = &hwrpb.proc_dispatch;
                    211:   hwrpb.crb.dispatch_pa = PA(&hwrpb.proc_dispatch);
                    212:   hwrpb.crb.fixup_va = &hwrpb.proc_fixup;
                    213:   hwrpb.crb.fixup_pa = PA(&hwrpb.proc_fixup);
                    214:   hwrpb.crb.map_entries = 1;
                    215:   hwrpb.crb.map_pages = 1;
                    216:   hwrpb.crb.map[0].va = &hwrpb;
                    217:   hwrpb.crb.map[0].pa = PA(&hwrpb);
                    218:   hwrpb.crb.map[0].count = 1;
                    219: 
                    220:   /* See crb.c for how we match the VMS calling conventions to Unix.  */
                    221:   hwrpb.proc_dispatch.address = (unsigned long)crb_dispatch;
                    222:   hwrpb.proc_fixup.address = (unsigned long)crb_fixup;
                    223: 
                    224:   hwrpb_update_checksum(&hwrpb.hwrpb);
                    225: }
                    226: 
                    227: static void
                    228: init_pcb (void)
                    229: {
                    230:   pcb.ksp = (unsigned long)stack + sizeof(stack);
                    231:   pcb.ptbr = PA(page_dir) >> PAGE_SHIFT;
                    232:   pcb.flags = 1; /* FEN */
                    233: }
                    234: 
                    235: static void
                    236: init_i8259 (void)
                    237: {
                    238:   /* ??? MILO initializes the PIC as edge triggered; I do not know how SRM
                    239:      initializes them.  However, Linux seems to expect that these are level
                    240:      triggered.  That may be a kernel bug, but level triggers are more
                    241:      reliable anyway so lets go with that.  */
                    242: 
                    243:   /* Initialize the slave PIC.  */
                    244:   outb(0x11, PORT_PIC2_CMD);   /* ICW1: edge trigger, cascade, ICW4 req */
                    245:   outb(0x08, PORT_PIC2_DATA);  /* ICW2: irq offset = 8 */
                    246:   outb(0x02, PORT_PIC2_DATA);  /* ICW3: slave ID 2 */
                    247:   outb(0x01, PORT_PIC2_DATA);  /* ICW4: not special nested, normal eoi */
                    248: 
                    249:   /* Initialize the master PIC.  */
                    250:   outb(0x11, PORT_PIC1_CMD);   /* ICW1 */
                    251:   outb(0x00, PORT_PIC1_DATA);  /* ICW2: irq offset = 0 */
                    252:   outb(0x04, PORT_PIC1_DATA);  /* ICW3: slave control INTC2 */
                    253:   outb(0x01, PORT_PIC1_DATA);  /* ICW4 */
                    254: 
                    255:   /* Initialize level triggers.  The CY82C693UB that's on real alpha
                    256:      hardware doesn't have this; this is a PIIX extension.  However,
                    257:      QEMU doesn't implement regular level triggers.  */
                    258:   outb(0xff, PORT_PIC2_ELCR);
                    259:   outb(0xff, PORT_PIC1_ELCR);
                    260: 
                    261:   /* Disable all interrupts.  */
                    262:   outb(0xff, PORT_PIC2_DATA);
                    263:   outb(0xff, PORT_PIC1_DATA);
                    264: 
                    265:   /* Non-specific EOI, clearing anything the might be pending.  */
                    266:   outb(0x20, PORT_PIC2_CMD);
                    267:   outb(0x20, PORT_PIC1_CMD);
                    268: }
                    269: 
                    270: void
                    271: do_start(unsigned long memsize, void (*kernel_entry)(void), long cpus)
                    272: {
                    273:   last_alloc = _end;
                    274: 
                    275:   init_page_table();
                    276:   init_hwrpb(memsize);
                    277:   init_pcb();
                    278:   init_i8259();
                    279:   uart_init();
                    280:   ps2port_setup();
                    281:   pci_setup();
                    282:   vgahw_init();
                    283: 
                    284:   {
                    285:     register int variant __asm__("$16") = 2;   /* OSF/1 PALcode */
                    286:     register void (*pc)(void) __asm__("$17");
                    287:     register unsigned long pa_pcb __asm__("$18");
                    288:     register unsigned long vptptr __asm__("$19");
                    289: 
                    290:     pc = (kernel_entry ? kernel_entry : do_console);
                    291:     pa_pcb = PA(&pcb);
                    292:     vptptr = VPTPTR;
                    293:     asm("call_pal 0x0a" : : "r"(variant), "r"(pc), "r"(pa_pcb), "r"(vptptr));
                    294:   }
                    295:   __builtin_unreachable ();
                    296: }
                    297: 
                    298: void
                    299: do_start_wait(void)
                    300: {
                    301:   while (1)
                    302:     {
                    303:       // WtInt with interrupts off.  Rely on the fact that QEMU will
                    304:       // un-halt the CPU when an interrupt arrives.
                    305:       asm("lda $16,-1\n\tcall_pal 0x3e" : : : "$0", "$16");
                    306: 
                    307:       // FIXME do something with the IPI.
                    308:     }
                    309: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.