Esempio n. 1
0
// Called by _start. Physical addressing is in effect, but this code is
// linked assuming virtual addresses: only PC-relative references actually
// work. A small stack is available.
void boot_start()
{
  // Clear some bootdata values
  bootdata->initrd_size = 0;

  // Work out phys->virt offset
  bootdata->phys_to_virt = (uint32_t)&_start - bootdata->rom_base;

  // Print all the info we received from the assembly entry point
  DBGSTR("Pycorn bootstrap entered\n");
  DBGINT("rom base: ", bootdata->rom_base);
  DBGINT("machine type: ", bootdata->machtype);
  DBGINT("taglist ptr: ", bootdata->taglist_ptr);
  DBGINT("phys->virt: ", bootdata->phys_to_virt);

  // Work out section sizes
  uint32_t text_size = &__text_end__ - &__text_start__;
  uint32_t data_size = &__data_end__ - &__data_start__;
  uint32_t bss_size = &__bss_end__ - &__bss_start__;
  uint32_t heap_size = &__heap_end__ - &__heap_start__;
  uint32_t stack_size = &__stack_end__ - &__stack_start__;
  uint32_t img_size = text_size + data_size;

  // Parse atags
  int r = parse_atags();
  DBGINT("parse_atags returned ", r);
  (void)r;

  // Work out where the first free page after the image is.
  // We will use this as the starting location to allocate pages, so there
  // had better be some megabytes of memory here. This will change later to
  // a less stupid allocator.
  bootdata->next_free_page = bootdata->rom_base + img_size;
  DBGINT("first free page: ", bootdata->next_free_page);

  // Allocate page directory
  DBGSTR("Allocate page directory\n");
  bootdata->page_directory = alloc_pages_zero(PAGEDIR_SIZE, PAGEDIR_SIZE);
  DBGINT("page directory: ", bootdata->page_directory);
  
  // Set MMU base address
  DBGSTR("Set MMU base address\n");
  mmu_set_base(bootdata->page_directory);

  // Allocate and map page table mappings
  // Page tables are placed linearly at a fixed location to make
  // it possible to find them again later without having to remember
  // where they are.
  // This is kinda scary as we are bootstrapping :)
  DBGSTR("Allocate and map page table mappings\n");
  int ptbl_section = (virtaddr)(&__page_tbl_start__) >> SECTION_SHIFT;
  physaddr ptbl_map = get_page_table(ptbl_section, 1);
  virtaddr ptbl_address = (virtaddr)(&__page_tbl_start__)
      + (ptbl_section * PAGETABLE_SIZE);
  map_pages(ptbl_address, ptbl_address + (PAGE_SIZE * PTBLS_PER_PAGE),
      ptbl_map | PTB_RW | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Map page directory
  DBGSTR("Map page directory\n");
  map_pages((virtaddr)&__page_dir_virt__,
      (virtaddr)(&__page_dir_virt__ + PAGEDIR_SIZE),
      bootdata->page_directory | PTB_RW | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Map text section of image
  DBGSTR("Map text section\n");
  map_pages((virtaddr)&__text_start__, (virtaddr)&__text_end__,
      bootdata->rom_base | PTB_ROM | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Map data section of image
  DBGSTR("Map data section\n");
  physaddr data_phys = bootdata->rom_base + text_size;
  map_pages((virtaddr)&__data_start__, (virtaddr)&__data_end__,
      data_phys | PTB_RW | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Allocate and map bss section
  DBGSTR("Allocate and map bss\n");
  physaddr bss_phys = alloc_pages_zero(bss_size, PAGE_SIZE);
  map_pages((virtaddr)&__bss_start__, (virtaddr)&__bss_end__,
      bss_phys | PTB_RW | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Allocate and map heap section
  DBGSTR("Allocate and map heap\n");
  physaddr heap_phys = alloc_pages_zero(heap_size, PAGE_SIZE);
  map_pages((virtaddr)&__heap_start__, (virtaddr)&__heap_end__,
      heap_phys | PTB_RW | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Allocate and map stack section
  DBGSTR("Allocate and map stack\n");
  physaddr stack_phys = alloc_pages_zero(stack_size, PAGE_SIZE);
  map_pages((virtaddr)&__stack_start__, (virtaddr)&__stack_end__,
      stack_phys | PTB_RW | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Map debug UART - we assume no more than a page is needed
  DBGSTR("Mapping debug UART\n");
  map_pages((virtaddr)&__dbg_serial_virt__, 
      (virtaddr)(&__dbg_serial_virt__ + PAGE_SIZE),
      (physaddr)&__dbg_serial_phys__ | PTB_RW | PTB_EXT);

  // Map boot data page
  DBGSTR("Mapping boot data\n");
  map_pages((virtaddr)&__bootdata_virt__,
      (virtaddr)(&__bootdata_virt__ + PAGE_SIZE),
      (physaddr)bootdata | PTB_RW | PTB_CACHE | PTB_BUFF | PTB_EXT);

  // Map the initrd if there was one
  if (bootdata->initrd_size)
  {
    // The initrd address may not be a page multiple as u-boot has
    // its own header on the file, so we need to align it.
    physaddr map_start = PAGEALIGN_DOWN(bootdata->initrd_phys);
    uint32_t map_len = PAGEALIGN_UP(bootdata->initrd_phys +
        bootdata->initrd_size) - map_start;
    // We also need to calculate the offset and offset the virtual
    // address by the matching amount.
    uint32_t offset = bootdata->initrd_phys - map_start;
    bootdata->initrd_virt = (virtaddr)&__initrd_map_start__ + offset;

    DBGSTR("Map initrd\n");
    map_pages((virtaddr)&__initrd_map_start__,
        (virtaddr)(&__initrd_map_start__ + map_len),
        map_start | PTB_ROM | PTB_CACHE | PTB_BUFF | PTB_EXT);
  }

  // Self-map MMU enabling code
  // The page which contains the MMU enable function must be mapped
  // with phys==virt address, otherwise bad stuff happens. We do this
  // by stuffing in a 1MB section mapping for this address, which may
  // overwrite an actual page table mapping (it's saved and restored
  // later on).
  DBGSTR("Self-map MMU enabling code\n");
  mmu_enable_func mmu_enable_phys = &mmu_enable - bootdata->phys_to_virt;
  physaddr selfmap_addr = (physaddr)mmu_enable_phys;
  int selfmap_index = selfmap_addr >> SECTION_SHIFT;
  selfmap_addr = selfmap_index << SECTION_SHIFT;
  uint32_t *pgd = (uint32_t *)bootdata->page_directory;
  uint32_t old_pde = pgd[selfmap_index];
  pgd[selfmap_index] = selfmap_addr | PGD_ROM | PGD_SECTION;

  // Enable MMU. This doesn't return, it goes to boot_after_mmu.
  DBGSTR("Enable MMU\n");
  mmu_enable_phys(selfmap_index, old_pde, &boot_after_mmu);
}
Esempio n. 2
0
void kernel_main(uint32_t boot_dev, uint32_t arm_m_type, uint32_t atags)
{
	atag_cmd_line = (void *)0;
	_atags = atags;
	_arm_m_type = arm_m_type;
	UNUSED(boot_dev);

	// First use the serial console
	stdout_putc = uart_putc;
	stderr_putc = uart_putc;
	stream_putc = def_stream_putc;	

	// Dump ATAGS
	parse_atags(atags, atag_cb);

	int result = fb_init();
	if(result == 0)
		puts("Successfully set up frame buffer");
	else
	{
		puts("Error setting up framebuffer:");
		puthex(result);
	}

	// Switch to the framebuffer for output
	stdout_putc = split_putc;

	printf("Welcome to Rpi bootloader\n");
	printf("ARM system type is %x\n", arm_m_type);
	if(atag_cmd_line != (void *)0)
		printf("Command line: %s\n", atag_cmd_line);

	struct usb_hcd *usb_hcd;
	dwc_usb_init(&usb_hcd, DWC_USB_BASE);
	
	struct block_device *sd_dev;

	if(sd_card_init(&sd_dev) == 0)
		read_mbr(sd_dev, (void*)0, (void*)0);

	// List devices
	printf("MAIN: device list: ");
	char **devs = vfs_get_device_list();
	while(*devs)
		printf("%s ", *devs++);
	printf("\n");

	// Look for a boot configuration file, starting with the default device,
	// then iterating through all devices
	
	FILE *f = (void*)0;
	
	// Default device
	char **fname = boot_cfg_names;
	char *found_cfg;
	while(*fname)
	{
		f = fopen(*fname, "r");
		if(f)
		{
			found_cfg = *fname;
			break;
		}

		fname++;
	}

	if(!f)
	{
		// Try other devices
		char **dev = vfs_get_device_list();
		while(*dev)
		{
			int dev_len = strlen(*dev);
			
			fname = boot_cfg_names;
			while(*fname)
			{
				int fname_len = strlen(*fname);
				char *new_str = (char *)malloc(dev_len + fname_len + 3);
				new_str[0] = 0;
				strcat(new_str, "(");
				strcat(new_str, *dev);
				strcat(new_str, ")");
				strcat(new_str, *fname);

				f = fopen(new_str, "r");

				if(f)
				{
					found_cfg = new_str;					
					break;
				}

				free(new_str);
				fname++;
			}

			if(f)
				break;

			dev++;
		}
	}

	if(!f)
	{
		printf("MAIN: No bootloader configuration file found\n");
	}
	else
	{	
		printf("MAIN: Found bootloader configuration: %s\n", found_cfg);
		char *buf = (char *)malloc(f->len + 1);
		buf[f->len] = 0;		// null terminate
		fread(buf, 1, f->len, f);
		fclose(f);
		cfg_parse(buf);
	}
}