sval xh_kern_prog_ex(struct cpu_thread* thread, uval addr) { uval32 ins; struct thread_control_area *tca = get_tca(); sval ret = 0; uval srr1 = tca->srr1; if (! (srr1 & (1ULL << (63-45)))) goto abort; struct vm_class *vmc = find_kernel_vmc(thread, addr); if (!vmc) goto abort; union ptel pte; uval laddr = vmc_xlate(vmc, addr, &pte); if (laddr == INVALID_LOGICAL_ADDRESS) goto abort; uval pa = logical_to_physical_address(thread->cpu->os, laddr, sizeof(uval32)); if (pa == INVALID_PHYSICAL_ADDRESS) goto abort; ins = *(uval32*)pa; ret = decode_spr_ins(thread, addr, ins); if (ret == 0) return -1; abort: return insert_exception(thread, EXC_V_DEBUG); }
sval xh_ext(struct cpu_thread *thread) { struct thread_control_area *tca = get_tca(); hprintf("Inserting external exception\n"); thread->vstate.thread_mode &= ~VSTATE_PENDING_EXT; tca->vstate &= ~VSTATE_PENDING_EXT; return insert_exception(thread, EXC_V_EXT); }
sval insert_debug_exception(struct cpu_thread *thread, uval dbgflag) { struct thread_control_area *tca = get_tca(); if (thread->vregs->debug & V_DEBUG_FLAG) { thread->vregs->debug |= dbgflag; /* Increment to the next instruction */ tca->srr0 += sizeof(uval32); return thread->vregs->active_vsave; } return insert_exception(thread, EXC_V_DEBUG); }
sval xh_kern_pgflt(struct cpu_thread* thr, uval type, struct vexc_save_regs *vr) { struct vm_class *vmc = NULL; uval orig_addr; struct thread_control_area *tca = get_tca(); if (type == 1) { orig_addr = mfdar(); } else { orig_addr = tca->srr0; } if (thr->vstate.thread_mode & VSTATE_KERN_MODE) { vmc = find_kernel_vmc(thr, orig_addr); } if (!vmc) { vmc = find_app_vmc(thr, orig_addr); } if (!vmc) { hprintf("No vm_class for 0x%lx\n", orig_addr); breakpoint(); return insert_debug_exception(thr, V_DEBUG_MEM_FAULT); } uval addr = ALIGN_DOWN(orig_addr, PGSIZE); union ptel pte = { .word = 0 }; uval la = vmc_xlate(vmc, addr, &pte); uval ra; uval vsid; if (la == INVALID_LOGICAL_ADDRESS) { /* If logical address is invalid, and pte is non-zero, then * pte contains physical address */ if (pte.word == 0) { goto reflect; } ra = pte.bits.rpn << LOG_PGSIZE; } else { ra = logical_to_physical_address(thr->cpu->os, la, PGSIZE); } vsid = vmc_class_vsid(thr, vmc, addr); pte.bits.rpn = ra >> LOG_PGSIZE; sval ret = insert_ea_map(thr, vsid, addr, pte); if (ret == H_Success) { return vr->reg_gprs[3]; } reflect: thr->vregs->v_dar = orig_addr; thr->vregs->v_dsisr = mfdsisr(); assert(thr->vregs->exception_vectors[EXC_V_PGFLT], "no pgflt vector defined\n"); return insert_exception(thr, EXC_V_PGFLT); } sval xh_kern_slb(struct cpu_thread* thread, uval type, struct vexc_save_regs *vr) { struct vm_class *vmc = NULL; struct thread_control_area *tca = get_tca(); uval addr; if (type == 1) { addr = mfdar(); } else { addr = tca->srr0; } uval seg_base = ALIGN_DOWN(addr, SEGMENT_SIZE); uval lp = LOG_PGSIZE; /* FIXME: get large page size */ uval l = 1; uval spot; if (thread->vstate.thread_mode & VSTATE_KERN_MODE) { vmc = find_kernel_vmc(thread, addr); } if (!vmc) { vmc = find_app_vmc(thread, addr); } if (!vmc) { hprintf("No vm_class for 0x%lx\n", addr); return insert_debug_exception(thread, V_DEBUG_MEM_FAULT); } uval vsid = vmc_class_vsid(thread, vmc, addr); #ifdef FORCE_4K_PAGES lp = 12; l = 0; spot = slb_insert(seg_base, 0, 0, 1, vsid, thread->slb_entries); #else spot = slb_insert(ea, 1, SELECT_LG, 1, vsid, thread->slb_entries); #endif return vr->reg_gprs[3]; } uval xh_syscall(uval a1, uval a2, uval a3, uval a4, uval a5, uval a6, uval a7, uval a8, uval a9, uval a10) { struct thread_control_area* tca = (struct thread_control_area*)mfr13(); struct cpu_thread* thread = tca->active_thread; hcall_fn_t hcall_fn; const hcall_vec_t* vec = (const hcall_vec_t*)hca.hcall_vector; thread->return_args = tca->save_area; a1 >>= 2; if (a1 >= hca.hcall_vector_len && a1 - 0x1800 < hca.hcall_6000_vector_len) { vec = (const hcall_vec_t*)hca.hcall_6000_vector; a1 -= 0x1800; } hcall_fn = *(const hcall_fn_t*)&vec[a1]; return hcall_fn(thread, a2, a3, a4, a5, a6, a7, a8, a9, a10); } extern void insert_dec_exception(void); extern void insert_ext_exception(void); inline void set_v_msr(struct cpu_thread* thr, uval val) { struct thread_control_area *tca = get_tca(); if ((val ^ thr->vregs->v_msr) & MSR_PR) { if (val & MSR_PR) { vmc_exit_kernel(thr); thr->vstate.thread_mode &= ~VSTATE_KERN_MODE; } else { vmc_enter_kernel(thr); thr->vstate.thread_mode |= VSTATE_KERN_MODE; } tca->vstate = thr->vstate.thread_mode; } thr->vregs->v_msr = (val & ~(MSR_HV|(MSR_SF>>2))) | MSR_AM; if (! (val & MSR_EE)) { return; } assert(get_tca()->restore_fn == NULL, "Exception delivery already pending.\n"); if (thr->vstate.thread_mode & VSTATE_PENDING_EXT) { get_tca()->restore_fn = insert_ext_exception; } else if (thr->vstate.thread_mode & VSTATE_PENDING_DEC) { get_tca()->restore_fn = insert_dec_exception; } } static inline void mtgpr(struct cpu_thread* thr, uval gpr, uval val) { switch (gpr) { case 14 ... 31: thr->reg_gprs[gpr] = val; break; case 0 ... 13: get_tca()->save_area->reg_gprs[gpr] = val; break; } } static inline uval mfgpr(struct cpu_thread* thr, uval gpr) { uval val; switch (gpr) { case 14 ... 31: val = thr->reg_gprs[gpr]; break; case 0 ... 13: val = get_tca()->save_area->reg_gprs[gpr]; break; } return val; }
void read_patterns(char *hyph_patterns) { FILE *patfile; int i, lineno = 0, h, patlen, exclen, maxpatlen = 0, pairs; char *syl; unsigned char *exception; unsigned char syllable[MAXPAT]; int hyf[MAXPAT]; struct pattern *p; patfile = fopen(hyph_patterns, "r"); if (patfile==NULL) { fprintf(stderr, "Can not open %s for read\n", hyph_patterns); exit(1); } /* the following structure is assumed for the hyphenation patterns: % comment ... % comment \patterns{ pattern pattern ... pattern } */ /* we assume that all pointers *entry[] and *tail[] are NULL */ while (fgets(linep, LINE_LENGTH, patfile)) { lineno++; if (*linep == '%' || *linep == '\\') continue; if (*linep == '}') break; pairs = 0; h = 0; hyf[0] = 0; for (i = 0; line[i] != '\n'; i++) { if (line[i]=='^') { /* Richard Verhoeven */ /* ^^?? -> 0x?? */ #define XTON(X) ((X)>'9'? ((X)-'a'+10):(X)-'0') if (line[i+1]=='^' && isxdigit(line[i+2]) && isxdigit(line[i+3])) { i+=3; line[i]=XTON(line[i-1])*16+XTON(line[i]); } } if (internal[line[i]] >= 0) { syllable[h++] = line[i]; hyf[h] = 0; } else if (isdigit(line[i])) { pairs++; if (pairs > MAXHYFS) { fprintf(stderr, "more than %d hyphens in %s", MAXHYFS, linep); continue; } hyf[h] = (line[i] - '0'); } } syllable[h] = '\0'; if (logging & INPUT) { showhyfs(syllable, hyf); putchar('\n'); } patlen = strlen((char *) syllable); if (patterns_left == 0) { pattern_space = (struct pattern *) calloc(PATTERN_CHUNK, sizeof(struct pattern)); if (pattern_space == NULL) { fprintf(stderr, "Out of pattern space\n"); exit(1); } patterns_left = PATTERN_CHUNK; pattern_bytes+= PATTERN_CHUNK; pattern_space_left = pattern_space; } /* pattern plus \0 minus two first letters */ if (max(patlen+1-2, 1) > text_left) { text_space = (unsigned char *) calloc(TEXT_CHUNK, sizeof(unsigned char)); if (text_space == NULL) { fprintf(stderr, "Out of space\n"); exit(1); } text_left = TEXT_CHUNK; text_bytes+= TEXT_CHUNK; text_space_left = text_space; } i = key(syllable); if (i < 0) { fprintf(stderr, "Invalid pattern: %s in line %d\n", linep, lineno); exit(1); } p = pattern_space_left++; patterns_left--; pattern_cnt++; if (entry[i] == NULL) entry[i] = p; else tail[i]->next = p; tail[i] = p; p->next = NULL; p->name = text_space_left; if (patlen > 2) { strcpy((char *) text_space_left, (char *) syllable+2); text_space_left+=(patlen+1-2); text_left-=(patlen+1-2); if (patlen+1 > MAXHYFS) { fprintf(stderr, "Can not store more than %d hyf's\n", MAXHYFS); exit(1); } } else { *text_space_left++ = '\0'; text_left-=1; } packhyfs(patlen, hyf, &p->hyfens); maxpatlen = max(maxpatlen, patlen); } /* now read exceptions */ for (i=0; i<EXCEPTIONS; i++) exc[i] = (unsigned char *) NULL; linep = line; while (fgets(linep, LINE_LENGTH, patfile)) { lineno++; if (*linep == '%' || *linep == '\\') continue; if (*linep == '}') break; exclen = strlen(linep); /* including newline */ /* get enough text space */ if (exclen > text_left) { text_space = (unsigned char *) calloc((size_t) TEXT_CHUNK, sizeof(unsigned char)); if (text_space == NULL) { fprintf(stderr, "Out of space\n"); exit(1); } text_left = TEXT_CHUNK; text_bytes+= TEXT_CHUNK; text_space_left = text_space; } exception = text_space_left; strncpy((unsigned char *) text_space_left, (unsigned char *) linep, exclen - 1); text_space_left+=exclen-1; *text_space_left++='\0'; text_left-=exclen; insert_exception(exception); } fclose(patfile); if (logging & STATS) { int maximum, N, count, average, M; unsigned char a, b; float sum; void syllabe(int, unsigned char *, unsigned char *); printf("Loaded %d patterns. Maximum pattern length %d\n", pattern_cnt, maxpatlen); patterns_left*=sizeof(struct pattern); pattern_bytes*=sizeof(struct pattern); printf("Memory consumption:\n"); printf("patterns : %d bytes (%d unused)\n", pattern_bytes, patterns_left); printf("syllables: %d bytes (%d unused)\n", text_bytes, text_left); sum = maximum = N = 0; for (i = 0; i < MAX_KEY; i++) { if (entry[i] == NULL) continue; for (count = 0, p = entry[i]; p != NULL; p=p->next) count++; if (count > maximum) { maximum = count; M = i; } sum+=count; N++; } printf("syllables %d average %5.1f\n", N, ((float) sum/N)); syllabe(M, &a, &b); printf("maximum of patterns %d (%c%c)\n", maximum, a, b); # ifdef DEBUGG p = entry[M]; count = 0; while (p != NULL) { syllable[0] = a; syllable[1] = b; strcat(syllable, p->name); unpackhyfs(strlen(syllable), hyf, p->hyfens); printf("<"); showhyfs(syllable, hyf); printf(">, "); if (++count % 5 == 0) putchar('\n'); p = p->next; } putchar('\n'); # endif } }