void UASM_i_LA(u32 **buf, unsigned int rs, long addr) { UASM_i_LA_mostly(buf, rs, addr); if (uasm_rel_lo(addr)) { if (!uasm_in_compat_space_p(addr)) uasm_i_daddiu(buf, rs, rs, uasm_rel_lo(addr)); else uasm_i_addiu(buf, rs, rs, uasm_rel_lo(addr)); } }
void UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr) { if (!uasm_in_compat_space_p(addr)) { uasm_i_lui(buf, rs, uasm_rel_highest(addr)); if (uasm_rel_higher(addr)) uasm_i_daddiu(buf, rs, rs, uasm_rel_higher(addr)); if (uasm_rel_hi(addr)) { uasm_i_dsll(buf, rs, rs, 16); uasm_i_daddiu(buf, rs, rs, uasm_rel_hi(addr)); uasm_i_dsll(buf, rs, rs, 16); } else uasm_i_dsll32(buf, rs, rs, 0); } else uasm_i_lui(buf, rs, uasm_rel_hi(addr)); }
/* * BVADDR is the faulting address, PTR is scratch. * PTR will hold the pgd for vmalloc. */ static __init void build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, unsigned int bvaddr, unsigned int ptr) { long swpd = (long)swapper_pg_dir; #ifdef MODULE_START long modd = (long)module_pg_dir; uasm_l_module_alloc(l, *p); /* * Assumption: * VMALLOC_START >= 0xc000000000000000UL * MODULE_START >= 0xe000000000000000UL */ UASM_i_SLL(p, ptr, bvaddr, 2); uasm_il_bgez(p, r, ptr, label_vmalloc); if (uasm_in_compat_space_p(MODULE_START) && !uasm_rel_lo(MODULE_START)) { uasm_i_lui(p, ptr, uasm_rel_hi(MODULE_START)); /* delay slot */ } else { /* unlikely configuration */ uasm_i_nop(p); /* delay slot */ UASM_i_LA(p, ptr, MODULE_START); } uasm_i_dsubu(p, bvaddr, bvaddr, ptr); if (uasm_in_compat_space_p(modd) && !uasm_rel_lo(modd)) { uasm_il_b(p, r, label_vmalloc_done); uasm_i_lui(p, ptr, uasm_rel_hi(modd)); } else { UASM_i_LA_mostly(p, ptr, modd); uasm_il_b(p, r, label_vmalloc_done); if (uasm_in_compat_space_p(modd)) uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(modd)); else uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(modd)); } uasm_l_vmalloc(l, *p); if (uasm_in_compat_space_p(MODULE_START) && !uasm_rel_lo(MODULE_START) && MODULE_START << 32 == VMALLOC_START) uasm_i_dsll32(p, ptr, ptr, 0); /* typical case */ else UASM_i_LA(p, ptr, VMALLOC_START); #else uasm_l_vmalloc(l, *p); UASM_i_LA(p, ptr, VMALLOC_START); #endif uasm_i_dsubu(p, bvaddr, bvaddr, ptr); if (uasm_in_compat_space_p(swpd) && !uasm_rel_lo(swpd)) { uasm_il_b(p, r, label_vmalloc_done); uasm_i_lui(p, ptr, uasm_rel_hi(swpd)); } else { UASM_i_LA_mostly(p, ptr, swpd); uasm_il_b(p, r, label_vmalloc_done); if (uasm_in_compat_space_p(swpd)) uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(swpd)); else uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd)); } }