void jtag_reserve_syspage_addr(paddr_t jtag_syspage_addr) { // Save the address to be used later jtag_syspage_address = jtag_syspage_addr; // Reserve a block of memory to store the address of the system page alloc_ram(jtag_syspage_address, sizeof(syspage_paddr), 1); }
// Save writeable data section of ELF executables int rifs_save_elf32data(paddr32_t addr, union image_dirent *dir, int numboot) { Elf32_Phdr *phdr; // Make sure the number of bootable executables isn't greater than the max if(numboot >= RIFS_MAX_BOOTABLE) return(-1); // Read the ELF header if((phdr = rifs_readelf(addr))) { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("Found procnto Elf header\n"); kprintf("bootable exec data: offset %x, size %x\n", phdr->p_offset, phdr->p_filesz ); } // Increment the number of bootable images found and save the related info rifs_info->numboot++; rifs_info->elfinfo[numboot].offset = dir->file.offset + phdr->p_offset; rifs_info->elfinfo[numboot].size = phdr->p_filesz; // If the image is compressed, save the data if(shdr->flags1 & STARTUP_HDR_FLAGS1_COMPRESS_MASK) { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("Compressed image, store data\n"); } // Allocate storage space. // NOTE: We assume that the address will be the same everytime. // This should OK since the alloc_ram/find_ram algorithm is deterministic. rifs_info->elfinfo[numboot].data = alloc_ram(NULL_PADDR, rifs_info->elfinfo[numboot].size, sizeof(uint64_t)); // Save a copy of the data // NOTE: Use copy_memory to support mini-drivers copy_memory(rifs_info->elfinfo[numboot].data, shdr->image_paddr + shdr->startup_size + rifs_info->elfinfo[numboot].offset, rifs_info->elfinfo[numboot].size); } } else { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("Invalid ELF header\n"); } // Error reading ELF header return(-1); } return(0); }
void jtag_reserve_memory(paddr_t resmem_addr, size_t resmem_size, uint8_t resmem_flag) { void *p; // Reserve user specified block of memory alloc_ram(resmem_addr, resmem_size, 1); p = startup_memory_map(resmem_size, resmem_addr, PROT_READ|PROT_WRITE); // Determine if reserved memory should be cleared if(!resmem_flag) { memset(p, 0, resmem_size); } startup_memory_unmap(p); }
// Load a secondary (non-bootable) image files system int rifs_load_ifs2(void) { struct image_header *ifs2_hdr; ifs2_hdr = MAKE_1TO1_PTR(ifs2_paddr_dst); // Set the default source location of IFS2 if the user didn't specify if(!(rifs_flag & RIFS_FLAG_IFS2_SRC)) { // Look for 2nd IFS following directly after first IFS ifs2_paddr_src = shdr->imagefs_paddr + shdr->stored_size - shdr->startup_size; } if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("ifs2_paddr_src: 0x%X\r\n", ifs2_paddr_src); kprintf("ifs2_paddr_src (auto): 0x%X\r\n", shdr->imagefs_paddr + shdr->stored_size - shdr->startup_size); } // Reserve space for our 2nd IFS if it is a user specified location if(rifs_flag & RIFS_FLAG_IFS2_DST) { // Address must be on a 4K page boundary (handled by options parsing) alloc_ram(ifs2_paddr_dst, ifs2_size, 0x1000); } // Copy 2nd IFS to RAM copy_memory(ifs2_paddr_dst, ifs2_paddr_src, ifs2_size); // Save the restore info for the next boot with SDRAM in self-refresh if(rifs_flag & RIFS_FLAG_IFS2_RESTORE) { char sig[8] = RIFS_SIGNATURE; int i; // Initialize the signature for(i = 0; i < 8; i++) { rifs2_info->signature[i] = sig[i]; } // Save the image size to be used for the image checksum rifs2_info->image_size = ifs2_hdr->image_size; // Must initialize cksum to 0 before we can calculate cksum on data structure rifs2_info->cksum = 0; // Calculate the restore checksum such that a checksum will result in 0 rifs2_info->cksum = 0xFFFFFFFF & (0x100000000ULL - rifs_checksum(rifs2_info, sizeof(struct restore_ifs2_info))); } return(0); }
struct syspage_entry * cpu_alloc_syspage_memory(paddr32_t *cpupagep, paddr32_t *syspagep, unsigned spsize) { struct syspage_entry *sp = lsp.syspage.p; struct system_private_entry *private; unsigned size; unsigned cpsize; paddr32_t syspage_paddr; unsigned spacing; #define SP_OFFSET(field) PTR_DIFF(lsp.cpu.field.p, sp) #define INIT_ENTRY(_cpu, _field) \ sp->un._cpu._field.entry_size = lsp.cpu._cpu##_##_field.size; \ sp->un._cpu._field.entry_off = SP_OFFSET(_cpu##_##_field) spsize = ROUND(spsize, sizeof(uint64_t)); if (sp->num_cpu == 1) { spacing = sizeof(struct cpupage_entry); } else { /* * WARNING: we assume SMP processor has physical cache. * We allocate the cpupages in contiguous memory so that * the kernel's cpypageptr[] pointers point at virtually * contiguous mappings into the physical pages. * The user _cpupage_ptr is a different virtual address * where the same virtual address on each cpu maps the * different physical address for that cpu's cpupage. */ spacing = __PAGESIZE; spsize = ROUND(spsize, __PAGESIZE); } cpsize = sp->num_cpu * spacing; /* * Allocate the system page (and cpupage entries) and save it away. * The system page must be 4K aligned in a virtual system */ size = spsize + cpsize; syspage_paddr = alloc_ram(NULL_PADDR, size, lsp.system_private.p->pagesize); if (syspage_paddr == NULL_PADDR32) { crash("could not allocate 0x%l bytes for syspage/cpupage\n", size); } private = lsp.system_private.p;
// Load a secondary (non-bootable) image file system void load_ifs2_nonbootable(void) { // Set the location of IFS2 in RAM if the user didn't specify if(!(rifs_flag & RIFS_FLAG_IFS2_DST)) { // Find a default location to store our 2nd IFS (must by on a 4K page boundary) // NOTE: We assume that the address will be the same everytime. // This should OK since the alloc_ram/find_ram algorithm is deterministic. ifs2_paddr_dst = alloc_ram(NULL_PADDR, ifs2_size, 0x1000); } if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("ifs2_paddr_dst: 0x%X\r\n", ifs2_paddr_dst); } // Attempt to restore IFS2 if it is already in RAM if(!(rifs_flag & RIFS_FLAG_IFS2_RESTORE) || rifs_restore_ifs2() == -1) { // Normal (full) load of the non-bootable secondary IFS rifs_load_ifs2(); } }
uintptr_t load_elf32(paddr32_t addr) { Elf32_Ehdr hdr; Elf32_Phdr *phdr; Elf32_Phdr *phdr_start; int i; if((phdr_start = is_elf(&hdr, addr)) == NULL) { return(~0L); } if(!(shdr->flags1 & STARTUP_HDR_FLAGS1_VIRTUAL)) { phdr = phdr_start; for(i = 0; i < hdr.e_phnum; ++i, ++phdr) { switch(phdr->p_type) { case PT_LOAD: if(MAKE_1TO1_PTR(phdr->p_paddr) != (void *)phdr->p_vaddr) { alloc_ram(phdr->p_vaddr - shdr->paddr_bias, phdr->p_memsz, 1); memmove((void *)phdr->p_vaddr, MAKE_1TO1_PTR(addr + phdr->p_offset), phdr->p_filesz); memset((void *)(phdr->p_vaddr+phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz); } break; } } #ifdef __X86__ } else if(load_elf32mmu_4m(addr, &hdr, phdr_start)) { // Nothing to do #endif } else { load_elf32mmu(addr, &hdr, phdr_start); } startup_memory_unmap(phdr_start); return hdr.e_entry; }
// Restore a secondary (non-bootable) image files system int rifs_restore_ifs2(void) { struct image_header *ifs2_hdr; int status = 0; paddr32_t paddr; // Allocate memory for the restore IFS2 info. // NOTE: We assume that the address will be the same everytime. // This should OK since the alloc_ram/find_ram algorithm is deterministic. paddr = alloc_ram(NULL_PADDR, sizeof(struct restore_ifs2_info), sizeof(uint64_t)); rifs2_info = MAKE_1TO1_PTR(paddr); if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("Restore IFS2 searching for valid IFS in RAM...\n"); kprintf("rifs2_info PADDR = 0x%X\n", paddr); kprintf("rifs2_info ADDR = 0x%X\n", rifs2_info); } // Obtain a pointer to the IFS2 that *may* be in RAM. At this point, we still // don't know if it is valid or if it is safe to access this data structure. ifs2_hdr = MAKE_1TO1_PTR(ifs2_paddr_dst); // Determine if there is already an IFS2 in RAM and if the restore // information stored from the last boot is valid. if(check_ifs_signature(ifs2_hdr) == 0 && rifs_checksum(rifs2_info, sizeof(struct restore_ifs2_info)) == 0) { // At this point, we know that the IFS2 signature is valid and the // restore info is valid. We still can't be 100% sure that the IFS is // valid until we peform a checksum on the IFS2. if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("FOUND valid IFS2 signature and RIFS2 info in RAM.\n"); } // Determine if we should checksum the IFS if((rifs_flag & RIFS_FLAG_IFS2_CKSUM)) { // Checksum the entire IFS to make sure it hasn't been corrupted. if(rifs_checksum(ifs2_hdr, rifs2_info->image_size) != 0) { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("WARNING: Checksum failed on IFS2!\n"); } // Checksum failed - IFS is corrupt status = -1; } } else { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("WARNING: Skipped IFS2 checksum verification\n"); } } } else { // No IFS2 or invalid restore data status = -1; } if((status == -1) && (debug_flag > RIFS_DEBUG_LEVEL)) { kprintf("Restore IFS2 failed - Reload entire IFS2.\n"); } return(status); }
// Restore an IFS already stored in RAM (i.e. CPU was turned off, RAM was left in self-refresh) int rifs_restore_ifs(paddr32_t ifs_paddr) { paddr32_t paddr_dst, paddr_src; struct image_header *ifs_hdr; int status = 0; int i; paddr32_t paddr; // Allocate memory for the restore ifs info. // NOTE: We assume that the address will be the same everytime. // This should OK since the alloc_ram/find_ram algorithm is deterministic. paddr = alloc_ram(NULL_PADDR, sizeof(struct restore_ifs_info), sizeof(uint64_t)); rifs_info = MAKE_1TO1_PTR(paddr); // Obtain a pointer to the IFS that *may* be in RAM. At this point, we still // don't know if it is valid or if it is safe to access this data structure. ifs_hdr = MAKE_1TO1_PTR(ifs_paddr); if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("Restore IFS searching for valid IFS in RAM...\n"); kprintf("rifs_info PADDR = 0x%X\n", paddr); kprintf("rifs_info ADDR = 0x%X\n", rifs_info); } // Determine if there is already an IFS in RAM and if the restore // information stored from the last boot is valid. if(check_ifs_signature(ifs_hdr) == 0 && check_rifs_signature(rifs_info) == 0) { // At this point, we know that the IFS signature is valid and the // restore info is valid. We still can't be 100% sure that the IFS is // valid until we restore the IFS and peform a checksum. if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("FOUND valid IFS signature and RIFS info in RAM.\n"); kprintf("IFS pre checksum = 0x%X (should not be 0x0)\n", rifs_checksum(ifs_hdr, rifs_info->image_size)); } // Loop through all bootable executables in the image and restore only // the writeable data section to default/original values for(i = 0; i < rifs_info->numboot; i++) { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("bootable exec %d offset: 0x%X\r\n", i, rifs_info->elfinfo[i].offset); kprintf("bootable exec %d size: 0x%X\r\n", i, rifs_info->elfinfo[i].size); } // Determine location of the executable's data paddr_dst = shdr->image_paddr + shdr->startup_size + rifs_info->elfinfo[i].offset; // Determine if the image is compressed if(shdr->flags1 & STARTUP_HDR_FLAGS1_COMPRESS_MASK) { // Compressed image if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("Compressed image src = 0x%X\n", rifs_info->elfinfo[i].data); } // Copy over the previously saved data (dst & src both in the 1-to-1 mapping region) // NOTE: Use copy_memory to support mini-drivers copy_memory(paddr_dst, rifs_info->elfinfo[i].data, rifs_info->elfinfo[i].size); } else { // IFS in uncompressed, we can take the data directly from the source image paddr_src = shdr->imagefs_paddr + rifs_info->elfinfo[i].offset; if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("Uncompressed image paddr_src = 0x%X\n", paddr_src); } // Copy over data from the original image (dst in the 1-to-1 mapping region, src may be anywhere) copy_memory(paddr_dst, paddr_src, rifs_info->elfinfo[i].size); } } if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("IFS post checksum = 0x%X (should be 0x0)\n", rifs_checksum(ifs_hdr, rifs_info->image_size)); } // Determine if we should checksum the IFS if((rifs_flag & RIFS_FLAG_CKSUM)) { // Checksum the entire IFS to determine if it has been restored correctly and hasn't been corrupted. if(rifs_checksum(ifs_hdr, rifs_info->image_size) != 0) { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("WARNING: Checksum failed on image!\n"); } // Checksum failed - IFS is corrupt status = -1; } } else { if(debug_flag > RIFS_DEBUG_LEVEL) { kprintf("WARNING: Skipped image checksum verification\n"); } } } else { // No IFS or invalid restore data status = -1; } // Restore info is not initialized until after we have checked the old data rifs_init(rifs_info); if((status == -1) && (debug_flag > RIFS_DEBUG_LEVEL)) { kprintf("Restore IFS failed - Reload entire IFS.\n"); } return(status); }
static void load_elf32mmu(paddr32_t addr, Elf32_Ehdr *hdr, Elf32_Phdr *phdr) { int i; for(i = 0; i < hdr->e_phnum; ++i, ++phdr) { switch(phdr->p_type) { case PT_LOAD: { size_t memsz = phdr->p_memsz + (phdr->p_vaddr & PAGEBITS); size_t filesz = phdr->p_filesz + (phdr->p_vaddr & PAGEBITS); uintptr_t vaddr = phdr->p_vaddr & ~PAGEBITS; paddr32_t paddr = phdr->p_paddr & ~PAGEBITS; paddr32_t daddr; if((boot_vaddr_base == 0u) || (boot_vaddr_base > vaddr)){ boot_vaddr_base = vaddr; } if(boot_vaddr_end < (vaddr + memsz)){ boot_vaddr_end = vaddr + memsz; } if((phdr->p_flags & PF_W) == 0 && memsz == filesz) { filesz = memsz = ROUNDPG(filesz); } if(phdr->p_paddr != 0) { if (phdr->p_memsz == phdr->p_filesz) { // mkifs has padded out the data/bss section filesz = memsz = ROUNDPG(filesz); } elf_map(vaddr, paddr, filesz & ~PAGEBITS, phdr->p_flags); memsz = ROUNDPG(memsz - (filesz & ~PAGEBITS)); if(memsz) { daddr = calloc_ram(memsz, __PAGESIZE); copy_memory(daddr, (paddr + (filesz & ~PAGEBITS)), filesz & PAGEBITS); elf_map(vaddr + (filesz & ~PAGEBITS), daddr, memsz, phdr->p_flags); } } else { #ifndef BOOTSTRAPS_RUN_ONE_TO_ONE /* * We need to do different things depending on whether the bootstrap * executables a run in a physical <-> virtual one to one mapping * area (MIPS, SH, PPC) or if they use the normal virtual address * mapping gear (X86, ARM). Basically, is startup or procnto * enabling the MMU on the CPU. */ #error BOOTSTRAPS_RUN_ONE_TO_ONE must be defined #endif #if BOOTSTRAPS_RUN_ONE_TO_ONE daddr = alloc_ram(vaddr - shdr->paddr_bias, ROUNDPG(memsz), __PAGESIZE); if(daddr != vaddr - shdr->paddr_bias) { crash("Error: can not allocate RAM for proc in XIP.\n"); } memmove((void *)phdr->p_vaddr, MAKE_1TO1_PTR(addr + phdr->p_offset), phdr->p_filesz); memset((void *)(phdr->p_vaddr + phdr->p_filesz), 0, (phdr->p_memsz - phdr->p_filesz)); #else daddr = calloc_ram(ROUNDPG(memsz), __PAGESIZE); copy_memory(daddr, (addr + phdr->p_offset) - (phdr->p_vaddr & PAGEBITS), filesz); elf_map(vaddr, daddr, memsz, phdr->p_flags); #endif } } break; } } }