···11-/*22- * linux/arch/sparc64/mm/extable.c33- */44-55-#include <linux/config.h>66-#include <linux/module.h>77-#include <asm/uaccess.h>88-99-extern const struct exception_table_entry __start___ex_table[];1010-extern const struct exception_table_entry __stop___ex_table[];1111-1212-void sort_extable(struct exception_table_entry *start,1313- struct exception_table_entry *finish)1414-{1515-}1616-1717-/* Caller knows they are in a range if ret->fixup == 0 */1818-const struct exception_table_entry *1919-search_extable(const struct exception_table_entry *start,2020- const struct exception_table_entry *last,2121- unsigned long value)2222-{2323- const struct exception_table_entry *walk;2424-2525- /* Single insn entries are encoded as:2626- * word 1: insn address2727- * word 2: fixup code address2828- *2929- * Range entries are encoded as:3030- * word 1: first insn address3131- * word 2: 03232- * word 3: last insn address + 4 bytes3333- * word 4: fixup code address3434- *3535- * See asm/uaccess.h for more details.3636- */3737-3838- /* 1. Try to find an exact match. */3939- for (walk = start; walk <= last; walk++) {4040- if (walk->fixup == 0) {4141- /* A range entry, skip both parts. */4242- walk++;4343- continue;4444- }4545-4646- if (walk->insn == value)4747- return walk;4848- }4949-5050- /* 2. Try to find a range match. */5151- for (walk = start; walk <= (last - 1); walk++) {5252- if (walk->fixup)5353- continue;5454-5555- if (walk[0].insn <= value && walk[1].insn > value)5656- return walk;5757-5858- walk++;5959- }6060-6161- return NULL;6262-}6363-6464-/* Special extable search, which handles ranges. Returns fixup */6565-unsigned long search_extables_range(unsigned long addr, unsigned long *g2)6666-{6767- const struct exception_table_entry *entry;6868-6969- entry = search_exception_tables(addr);7070- if (!entry)7171- return 0;7272-7373- /* Inside range? Fix g2 and return correct fixup */7474- if (!entry->fixup) {7575- *g2 = (addr - entry->insn) / 4;7676- return (entry + 1)->fixup;7777- }7878-7979- return entry->fixup;8080-}
+5-64
arch/sparc64/mm/fault.c
···32323333#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))34343535-extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];3636-3735/*3836 * To debug kernel to catch accesses to certain virtual/physical addresses.3937 * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.···6769 : /* no outputs */6870 : "r" (lsubits), "i" (ASI_LSU_CONTROL)6971 : "memory");7070-}7171-7272-/* Nice, simple, prom library does all the sweating for us. ;) */7373-unsigned long __init prom_probe_memory (void)7474-{7575- register struct linux_mlist_p1275 *mlist;7676- register unsigned long bytes, base_paddr, tally;7777- register int i;7878-7979- i = 0;8080- mlist = *prom_meminfo()->p1275_available;8181- bytes = tally = mlist->num_bytes;8282- base_paddr = mlist->start_adr;8383-8484- sp_banks[0].base_addr = base_paddr;8585- sp_banks[0].num_bytes = bytes;8686-8787- while (mlist->theres_more != (void *) 0) {8888- i++;8989- mlist = mlist->theres_more;9090- bytes = mlist->num_bytes;9191- tally += bytes;9292- if (i >= SPARC_PHYS_BANKS-1) {9393- printk ("The machine has more banks than "9494- "this kernel can support\n"9595- "Increase the SPARC_PHYS_BANKS "9696- "setting (currently %d)\n",9797- SPARC_PHYS_BANKS);9898- i = SPARC_PHYS_BANKS-1;9999- break;100100- }101101-102102- sp_banks[i].base_addr = mlist->start_adr;103103- sp_banks[i].num_bytes = mlist->num_bytes;104104- }105105-106106- i++;107107- sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;108108- sp_banks[i].num_bytes = 0;109109-110110- /* Now mask all bank sizes on a page boundary, it is all we can111111- * use anyways.112112- */113113- for (i = 0; sp_banks[i].num_bytes != 0; i++)114114- sp_banks[i].num_bytes &= PAGE_MASK;115115-116116- return tally;11772}1187311974static void __kprobes unhandled_fault(unsigned long address,···193242static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,194243 unsigned int insn, unsigned long address)195244{196196- unsigned long g2;197245 unsigned char asi = ASI_P;198246199247 if ((!insn) && (regs->tstate & TSTATE_PRIV))···223273 }224274 }225275226226- g2 = regs->u_regs[UREG_G2];227227-228276 /* Is this in ex_table? */229277 if (regs->tstate & TSTATE_PRIV) {230230- unsigned long fixup;278278+ const struct exception_table_entry *entry;231279232280 if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {233281 if (insn & 0x2000)···236288237289 /* Look in asi.h: All _S asis have LS bit set */238290 if ((asi & 0x1) &&239239- (fixup = search_extables_range(regs->tpc, &g2))) {240240- regs->tpc = fixup;291291+ (entry = search_exception_tables(regs->tpc))) {292292+ regs->tpc = entry->fixup;241293 regs->tnpc = regs->tpc + 4;242242- regs->u_regs[UREG_G2] = g2;243294 return;244295 }245296 } else {···408461 }409462410463 up_read(&mm->mmap_sem);411411- goto fault_done;464464+ return;412465413466 /*414467 * Something tried to access memory that isn't in our memory map..···420473421474handle_kernel_fault:422475 do_kernel_fault(regs, si_code, fault_code, insn, address);423423-424424- goto fault_done;476476+ return;425477426478/*427479 * We ran out of memory, or some other thing happened to us that made···451505 /* Kernel mode? Handle exceptions or die */452506 if (regs->tstate & TSTATE_PRIV)453507 goto handle_kernel_fault;454454-455455-fault_done:456456- /* These values are no longer needed, clear them. */457457- set_thread_fault_code(0);458458- current_thread_info()->fault_address = 0;459508}
+130-129
arch/sparc64/mm/init.c
···2121#include <linux/seq_file.h>2222#include <linux/kprobes.h>2323#include <linux/cache.h>2424+#include <linux/sort.h>24252526#include <asm/head.h>2627#include <asm/system.h>···42414342extern void device_scan(void);44434545-struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];4444+#define MAX_BANKS 324545+4646+static struct linux_prom64_registers pavail[MAX_BANKS] __initdata;4747+static struct linux_prom64_registers pavail_rescan[MAX_BANKS] __initdata;4848+static int pavail_ents __initdata;4949+static int pavail_rescan_ents __initdata;5050+5151+static int cmp_p64(const void *a, const void *b)5252+{5353+ const struct linux_prom64_registers *x = a, *y = b;5454+5555+ if (x->phys_addr > y->phys_addr)5656+ return 1;5757+ if (x->phys_addr < y->phys_addr)5858+ return -1;5959+ return 0;6060+}6161+6262+static void __init read_obp_memory(const char *property,6363+ struct linux_prom64_registers *regs,6464+ int *num_ents)6565+{6666+ int node = prom_finddevice("/memory");6767+ int prop_size = prom_getproplen(node, property);6868+ int ents, ret, i;6969+7070+ ents = prop_size / sizeof(struct linux_prom64_registers);7171+ if (ents > MAX_BANKS) {7272+ prom_printf("The machine has more %s property entries than "7373+ "this kernel can support (%d).\n",7474+ property, MAX_BANKS);7575+ prom_halt();7676+ }7777+7878+ ret = prom_getproperty(node, property, (char *) regs, prop_size);7979+ if (ret == -1) {8080+ prom_printf("Couldn't get %s property from /memory.\n");8181+ prom_halt();8282+ }8383+8484+ *num_ents = ents;8585+8686+ /* Sanitize what we got from the firmware, by page aligning8787+ * everything.8888+ */8989+ for (i = 0; i < ents; i++) {9090+ unsigned long base, size;9191+9292+ base = regs[i].phys_addr;9393+ size = regs[i].reg_size;9494+9595+ size &= PAGE_MASK;9696+ if (base & ~PAGE_MASK) {9797+ unsigned long new_base = PAGE_ALIGN(base);9898+9999+ size -= new_base - base;100100+ if ((long) size < 0L)101101+ size = 0UL;102102+ base = new_base;103103+ }104104+ regs[i].phys_addr = base;105105+ regs[i].reg_size = size;106106+ }107107+ sort(regs, ents, sizeof(struct linux_prom64_registers),108108+ cmp_p64, NULL);109109+}4611047111unsigned long *sparc64_valid_addr_bitmap __read_mostly;48112···12721206 int i;1273120712741208#ifdef CONFIG_DEBUG_BOOTMEM12751275- prom_printf("bootmem_init: Scan sp_banks, ");12091209+ prom_printf("bootmem_init: Scan pavail, ");12761210#endif1277121112781212 bytes_avail = 0UL;12791279- for (i = 0; sp_banks[i].num_bytes != 0; i++) {12801280- end_of_phys_memory = sp_banks[i].base_addr +12811281- sp_banks[i].num_bytes;12821282- bytes_avail += sp_banks[i].num_bytes;12131213+ for (i = 0; i < pavail_ents; i++) {12141214+ end_of_phys_memory = pavail[i].phys_addr +12151215+ pavail[i].reg_size;12161216+ bytes_avail += pavail[i].reg_size;12831217 if (cmdline_memory_size) {12841218 if (bytes_avail > cmdline_memory_size) {12851219 unsigned long slack = bytes_avail - cmdline_memory_size;···12871221 bytes_avail -= slack;12881222 end_of_phys_memory -= slack;1289122312901290- sp_banks[i].num_bytes -= slack;12911291- if (sp_banks[i].num_bytes == 0) {12921292- sp_banks[i].base_addr = 0xdeadbeef;12241224+ pavail[i].reg_size -= slack;12251225+ if ((long)pavail[i].reg_size <= 0L) {12261226+ pavail[i].phys_addr = 0xdeadbeefUL;12271227+ pavail[i].reg_size = 0UL;12281228+ pavail_ents = i;12931229 } else {12941294- sp_banks[i+1].num_bytes = 0;12951295- sp_banks[i+1].base_addr = 0xdeadbeef;12301230+ pavail[i+1].reg_size = 0Ul;12311231+ pavail[i+1].phys_addr = 0xdeadbeefUL;12321232+ pavail_ents = i + 1;12961233 }12971234 break;12981235 }···13491280 /* Now register the available physical memory with the13501281 * allocator.13511282 */13521352- for (i = 0; sp_banks[i].num_bytes != 0; i++) {12831283+ for (i = 0; i < pavail_ents; i++) {13531284#ifdef CONFIG_DEBUG_BOOTMEM13541354- prom_printf("free_bootmem(sp_banks:%d): base[%lx] size[%lx]\n",13551355- i, sp_banks[i].base_addr, sp_banks[i].num_bytes);12851285+ prom_printf("free_bootmem(pavail:%d): base[%lx] size[%lx]\n",12861286+ i, pavail[i].phys_addr, pavail[i].reg_size);13561287#endif13571357- free_bootmem(sp_banks[i].base_addr, sp_banks[i].num_bytes);12881288+ free_bootmem(pavail[i].phys_addr, pavail[i].reg_size);13581289 }1359129013601291#ifdef CONFIG_BLK_DEV_INITRD···14031334 unsigned long alloc_bytes = 0UL;1404133514051336 if ((vstart & ~PAGE_MASK) || (vend & ~PAGE_MASK)) {14061406- prom_printf("kernel_map: Unaligned sp_banks[%lx:%lx]\n",13371337+ prom_printf("kernel_map: Unaligned physmem[%lx:%lx]\n",14071338 vstart, vend);14081339 prom_halt();14091340 }···14501381 return alloc_bytes;14511382}1452138314531453-extern struct linux_mlist_p1275 *prom_ptot_ptr;13841384+static struct linux_prom64_registers pall[MAX_BANKS] __initdata;13851385+static int pall_ents __initdata;13861386+14541387extern unsigned int kvmap_linear_patch[1];1455138814561389static void __init kernel_physical_mapping_init(void)14571390{14581458- struct linux_mlist_p1275 *p = prom_ptot_ptr;14591459- unsigned long mem_alloced = 0UL;13911391+ unsigned long i, mem_alloced = 0UL;1460139214611461- while (p) {13931393+ read_obp_memory("reg", &pall[0], &pall_ents);13941394+13951395+ for (i = 0; i < pall_ents; i++) {14621396 unsigned long phys_start, phys_end;1463139714641464- phys_start = p->start_adr;14651465- phys_end = phys_start + p->num_bytes;13981398+ phys_start = pall[i].phys_addr;13991399+ phys_end = phys_start + pall[i].reg_size;14661400 mem_alloced += kernel_map_range(phys_start, phys_end,14671401 PAGE_KERNEL);14681468-14691469- p = p->theres_more;14701402 }1471140314721404 printk("Allocated %ld bytes for kernel page tables.\n",···14951425}14961426#endif1497142714281428+unsigned long __init find_ecache_flush_span(unsigned long size)14291429+{14301430+ int i;14311431+14321432+ for (i = 0; i < pavail_ents; i++) {14331433+ if (pavail[i].reg_size >= size)14341434+ return pavail[i].phys_addr;14351435+ }14361436+14371437+ return ~0UL;14381438+}14391439+14981440/* paging_init() sets up the page tables */1499144115001442extern void cheetah_ecache_flush_init(void);···15171435void __init paging_init(void)15181436{15191437 unsigned long end_pfn, pages_avail, shift;15201520- unsigned long real_end;14381438+ unsigned long real_end, i;14391439+14401440+ /* Find available physical memory... */14411441+ read_obp_memory("available", &pavail[0], &pavail_ents);14421442+14431443+ phys_base = 0xffffffffffffffffUL;14441444+ for (i = 0; i < pavail_ents; i++)14451445+ phys_base = min(phys_base, pavail[i].phys_addr);14461446+14471447+ pfn_base = phys_base >> PAGE_SHIFT;14481448+14491449+ kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;14501450+ kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;1521145115221452 set_bit(0, mmu_context_bmap);15231453···16011507 device_scan();16021508}1603150916041604-/* Ok, it seems that the prom can allocate some more memory chunks16051605- * as a side effect of some prom calls we perform during the16061606- * boot sequence. My most likely theory is that it is from the16071607- * prom_set_traptable() call, and OBP is allocating a scratchpad16081608- * for saving client program register state etc.16091609- */16101610-static void __init sort_memlist(struct linux_mlist_p1275 *thislist)16111611-{16121612- int swapi = 0;16131613- int i, mitr;16141614- unsigned long tmpaddr, tmpsize;16151615- unsigned long lowest;16161616-16171617- for (i = 0; thislist[i].theres_more != 0; i++) {16181618- lowest = thislist[i].start_adr;16191619- for (mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++)16201620- if (thislist[mitr].start_adr < lowest) {16211621- lowest = thislist[mitr].start_adr;16221622- swapi = mitr;16231623- }16241624- if (lowest == thislist[i].start_adr)16251625- continue;16261626- tmpaddr = thislist[swapi].start_adr;16271627- tmpsize = thislist[swapi].num_bytes;16281628- for (mitr = swapi; mitr > i; mitr--) {16291629- thislist[mitr].start_adr = thislist[mitr-1].start_adr;16301630- thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;16311631- }16321632- thislist[i].start_adr = tmpaddr;16331633- thislist[i].num_bytes = tmpsize;16341634- }16351635-}16361636-16371637-void __init rescan_sp_banks(void)16381638-{16391639- struct linux_prom64_registers memlist[64];16401640- struct linux_mlist_p1275 avail[64], *mlist;16411641- unsigned long bytes, base_paddr;16421642- int num_regs, node = prom_finddevice("/memory");16431643- int i;16441644-16451645- num_regs = prom_getproperty(node, "available",16461646- (char *) memlist, sizeof(memlist));16471647- num_regs = (num_regs / sizeof(struct linux_prom64_registers));16481648- for (i = 0; i < num_regs; i++) {16491649- avail[i].start_adr = memlist[i].phys_addr;16501650- avail[i].num_bytes = memlist[i].reg_size;16511651- avail[i].theres_more = &avail[i + 1];16521652- }16531653- avail[i - 1].theres_more = NULL;16541654- sort_memlist(avail);16551655-16561656- mlist = &avail[0];16571657- i = 0;16581658- bytes = mlist->num_bytes;16591659- base_paddr = mlist->start_adr;16601660-16611661- sp_banks[0].base_addr = base_paddr;16621662- sp_banks[0].num_bytes = bytes;16631663-16641664- while (mlist->theres_more != NULL){16651665- i++;16661666- mlist = mlist->theres_more;16671667- bytes = mlist->num_bytes;16681668- if (i >= SPARC_PHYS_BANKS-1) {16691669- printk ("The machine has more banks than "16701670- "this kernel can support\n"16711671- "Increase the SPARC_PHYS_BANKS "16721672- "setting (currently %d)\n",16731673- SPARC_PHYS_BANKS);16741674- i = SPARC_PHYS_BANKS-1;16751675- break;16761676- }16771677-16781678- sp_banks[i].base_addr = mlist->start_adr;16791679- sp_banks[i].num_bytes = mlist->num_bytes;16801680- }16811681-16821682- i++;16831683- sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;16841684- sp_banks[i].num_bytes = 0;16851685-16861686- for (i = 0; sp_banks[i].num_bytes != 0; i++)16871687- sp_banks[i].num_bytes &= PAGE_MASK;16881688-}16891689-16901510static void __init taint_real_pages(void)16911511{16921692- struct sparc_phys_banks saved_sp_banks[SPARC_PHYS_BANKS];16931512 int i;1694151316951695- for (i = 0; i < SPARC_PHYS_BANKS; i++) {16961696- saved_sp_banks[i].base_addr =16971697- sp_banks[i].base_addr;16981698- saved_sp_banks[i].num_bytes =16991699- sp_banks[i].num_bytes;17001700- }15141514+ read_obp_memory("available", &pavail_rescan[0], &pavail_rescan_ents);1701151517021702- rescan_sp_banks();17031703-17041704- /* Find changes discovered in the sp_bank rescan and15161516+ /* Find changes discovered in the physmem available rescan and17051517 * reserve the lost portions in the bootmem maps.17061518 */17071707- for (i = 0; saved_sp_banks[i].num_bytes; i++) {15191519+ for (i = 0; i < pavail_ents; i++) {17081520 unsigned long old_start, old_end;1709152117101710- old_start = saved_sp_banks[i].base_addr;15221522+ old_start = pavail[i].phys_addr;17111523 old_end = old_start +17121712- saved_sp_banks[i].num_bytes;15241524+ pavail[i].reg_size;17131525 while (old_start < old_end) {17141526 int n;1715152717161716- for (n = 0; sp_banks[n].num_bytes; n++) {15281528+ for (n = 0; pavail_rescan_ents; n++) {17171529 unsigned long new_start, new_end;1718153017191719- new_start = sp_banks[n].base_addr;17201720- new_end = new_start + sp_banks[n].num_bytes;15311531+ new_start = pavail_rescan[n].phys_addr;15321532+ new_end = new_start +15331533+ pavail_rescan[n].reg_size;1721153417221535 if (new_start <= old_start &&17231536 new_end >= (old_start + PAGE_SIZE)) {17241724- set_bit (old_start >> 22,17251725- sparc64_valid_addr_bitmap);15371537+ set_bit(old_start >> 22,15381538+ sparc64_valid_addr_bitmap);17261539 goto do_next_page;17271540 }17281541 }
···8282/* Top-level page directory */8383extern pgd_t swapper_pg_dir[1024];84848585+extern void paging_init(void);8686+8587/* Page table for 0-4MB for everybody, on the Sparc this8688 * holds the same as on the i386.8789 */
+2-2
include/asm-sparc64/openprom.h
···186186};187187188188struct linux_prom64_registers {189189- long phys_addr;190190- long reg_size;189189+ unsigned long phys_addr;190190+ unsigned long reg_size;191191};192192193193struct linux_prom_irqs {
-14
include/asm-sparc64/oplib.h
···9595extern void prom_seek(int device_handle, unsigned int seek_hival,9696 unsigned int seek_lowval);97979898-/* Machine memory configuration routine. */9999-100100-/* This function returns a V0 format memory descriptor table, it has three101101- * entries. One for the total amount of physical ram on the machine, one102102- * for the amount of physical ram available, and one describing the virtual103103- * areas which are allocated by the prom. So, in a sense the physical104104- * available is a calculation of the total physical minus the physical mapped105105- * by the prom with virtual mappings.106106- *107107- * These lists are returned pre-sorted, this should make your life easier108108- * since the prom itself is way too lazy to do such nice things.109109- */110110-extern struct linux_mem_p1275 *prom_meminfo(void);111111-11298/* Miscellaneous routines, don't really fit in any category per se. */11399114100/* Reboot the machine with the command line passed. */
-17
include/asm-sparc64/page.h
···140140#define virt_to_phys __pa141141#define phys_to_virt __va142142143143-/* The following structure is used to hold the physical144144- * memory configuration of the machine. This is filled in145145- * probe_memory() and is later used by mem_init() to set up146146- * mem_map[]. We statically allocate SPARC_PHYS_BANKS of147147- * these structs, this is arbitrary. The entry after the148148- * last valid one has num_bytes==0.149149- */150150-151151-struct sparc_phys_banks {152152- unsigned long base_addr;153153- unsigned long num_bytes;154154-};155155-156156-#define SPARC_PHYS_BANKS 32157157-158158-extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];159159-160143#endif /* !(__ASSEMBLY__) */161144162145#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+3
include/asm-sparc64/pgtable.h
···341341extern pgd_t swapper_pg_dir[2048];342342extern pmd_t swapper_low_pmd_dir[2048];343343344344+extern void paging_init(void);345345+extern unsigned long find_ecache_flush_span(unsigned long size);346346+344347/* These do nothing with the way I have things setup. */345348#define mmu_lockarea(vaddr, len) (vaddr)346349#define mmu_unlockarea(vaddr, len) do { } while(0)
+6-18
include/asm-sparc64/uaccess.h
···7070 * with the main instruction path. This means when everything is well,7171 * we don't even have to jump over them. Further, they do not intrude7272 * on our cache or tlb entries.7373- *7474- * There is a special way how to put a range of potentially faulting7575- * insns (like twenty ldd/std's with now intervening other instructions)7676- * You specify address of first in insn and 0 in fixup and in the next7777- * exception_table_entry you specify last potentially faulting insn + 17878- * and in fixup the routine which should handle the fault.7979- * That fixup code will get8080- * (faulting_insn_address - first_insn_in_the_range_address)/48181- * in %g2 (ie. index of the faulting instruction in the range).8273 */83748484-struct exception_table_entry8585-{8686- unsigned insn, fixup;7575+struct exception_table_entry {7676+ unsigned int insn, fixup;8777};88788989-/* Special exable search, which handles ranges. Returns fixup */9090-unsigned long search_extables_range(unsigned long addr, unsigned long *g2);9191-9279extern void __ret_efault(void);8080+extern void __retl_efault(void);93819482/* Uh, these should become the main single-value transfer routines..9583 * They automatically use the right size if we just have the right···251263{252264 unsigned long ret = ___copy_from_user(to, from, size);253265254254- if (ret)266266+ if (unlikely(ret))255267 ret = copy_from_user_fixup(to, from, size);256268 return ret;257269}···267279{268280 unsigned long ret = ___copy_to_user(to, from, size);269281270270- if (ret)282282+ if (unlikely(ret))271283 ret = copy_to_user_fixup(to, from, size);272284 return ret;273285}···283295{284296 unsigned long ret = ___copy_in_user(to, from, size);285297286286- if (ret)298298+ if (unlikely(ret))287299 ret = copy_in_user_fixup(to, from, size);288300 return ret;289301}