Annotation of qemu/roms/qemu-palcode/init.c, revision 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.