summaryrefslogtreecommitdiff
path: root/arch/sparc/lib/bootm.c
blob: c62cf57d80b25584187c777c09d595d342714b25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/* SPARC code for booting linux 2.6
 *
 * (C) Copyright 2007
 * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#include <command.h>
#include <asm/byteorder.h>
#include <asm/prom.h>
#include <asm/cache.h>
#include <image.h>

#define PRINT_KERNEL_HEADER

extern image_header_t header;
extern void srmmu_init_cpu(unsigned int entry);
extern void prepare_bootargs(char *bootargs);

#ifdef CONFIG_USB_UHCI
extern int usb_lowlevel_stop(void);
#endif

/* sparc kernel argument (the ROM vector) */
struct linux_romvec *kernel_arg_promvec;

/* page szie is 4k */
#define PAGE_SIZE 0x1000
#define RAMDISK_IMAGE_START_MASK	0x07FF
#define RAMDISK_PROMPT_FLAG		0x8000
#define RAMDISK_LOAD_FLAG		0x4000
struct __attribute__ ((packed)) {
	char traptable[PAGE_SIZE];
	char swapper_pg_dir[PAGE_SIZE];
	char pg0[PAGE_SIZE];
	char pg1[PAGE_SIZE];
	char pg2[PAGE_SIZE];
	char pg3[PAGE_SIZE];
	char empty_bad_page[PAGE_SIZE];
	char empty_bad_page_table[PAGE_SIZE];
	char empty_zero_page[PAGE_SIZE];
	unsigned char hdr[4];	/* ascii "HdrS" */
	/* 00.02.06.0b is for Linux kernel 2.6.11 */
	unsigned char linuxver_mega_major;
	unsigned char linuxver_major;
	unsigned char linuxver_minor;
	unsigned char linuxver_revision;
	/* header version 0x0203 */
	unsigned short hdr_ver;
	union __attribute__ ((packed)) {
		struct __attribute__ ((packed)) {
			unsigned short root_flags;
			unsigned short root_dev;
			unsigned short ram_flags;
			unsigned int sparc_ramdisk_image;
			unsigned int sparc_ramdisk_size;
			unsigned int reboot_command;
			unsigned int resv[3];
			unsigned int end;
		} ver_0203;
	} hdr_input;
} *linux_hdr;

/* temporary initrd image holder */
image_header_t ihdr;

void arch_lmb_reserve(struct lmb *lmb)
{
	/* Reserve the space used by PROM and stack. This is done
	 * to avoid that the RAM image is copied over stack or
	 * PROM.
	 */
	lmb_reserve(lmb, CONFIG_SYS_RELOC_MONITOR_BASE, CONFIG_SYS_RAM_END);
}

/* boot the linux kernel */
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t * images)
{
	char *bootargs;
	ulong initrd_start, initrd_end;
	ulong rd_len;
	unsigned int data, len, checksum;
	unsigned int initrd_addr, kernend;
	void (*kernel) (struct linux_romvec *, void *);
	struct lmb *lmb = &images->lmb;
	int ret;

	if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
		return 1;

	/* Get virtual address of kernel start */
	linux_hdr = (void *)images->os.load;

	/* */
	kernel = (void (*)(struct linux_romvec *, void *))images->ep;

	/* check for a SPARC kernel */
	if ((linux_hdr->hdr[0] != 'H') ||
	    (linux_hdr->hdr[1] != 'd') ||
	    (linux_hdr->hdr[2] != 'r') || (linux_hdr->hdr[3] != 'S')) {
		puts("Error reading header of SPARC Linux kernel, aborting\n");
		goto error;
	}
#ifdef PRINT_KERNEL_HEADER
	printf("## Found SPARC Linux kernel %d.%d.%d ...\n",
	       linux_hdr->linuxver_major,
	       linux_hdr->linuxver_minor, linux_hdr->linuxver_revision);
#endif

#ifdef CONFIG_USB_UHCI
	usb_lowlevel_stop();
#endif

	/* set basic boot params in kernel header now that it has been
	 * extracted and is writeable.
	 */

	/* Calc length of RAM disk, if zero no ramdisk available */
	rd_len = images->rd_end - images->rd_start;

	if (rd_len) {
		ret = boot_ramdisk_high(lmb, images->rd_start, rd_len,
					&initrd_start, &initrd_end);
		if (ret) {
			puts("### Failed to relocate RAM disk\n");
			goto error;
		}

		/* Update SPARC kernel header so that Linux knows
		 * what is going on and where to find RAM disk.
		 *
		 * Set INITRD Image address relative to RAM Start
		 */
		linux_hdr->hdr_input.ver_0203.sparc_ramdisk_image =
		    initrd_start - CONFIG_SYS_RAM_BASE;
		linux_hdr->hdr_input.ver_0203.sparc_ramdisk_size = rd_len;
		/* Clear READ ONLY flag if set to non-zero */
		linux_hdr->hdr_input.ver_0203.root_flags = 1;
		/* Set root device to: Root_RAM0 */
		linux_hdr->hdr_input.ver_0203.root_dev = 0x100;
		linux_hdr->hdr_input.ver_0203.ram_flags = 0;
	} else {
		/* NOT using RAMDISK image, overwriting kernel defaults */
		linux_hdr->hdr_input.ver_0203.sparc_ramdisk_image = 0;
		linux_hdr->hdr_input.ver_0203.sparc_ramdisk_size = 0;
		/* Leave to kernel defaults
		   linux_hdr->hdr_input.ver_0203.root_flags = 1;
		   linux_hdr->hdr_input.ver_0203.root_dev = 0;
		   linux_hdr->hdr_input.ver_0203.ram_flags = 0;
		 */
	}

	/* Copy bootargs from bootargs variable to kernel readable area */
	bootargs = getenv("bootargs");
	prepare_bootargs(bootargs);

	/* turn on mmu & setup context table & page table for process 0 (kernel) */
	srmmu_init_cpu((unsigned int)kernel);

	/* Enter SPARC Linux kernel
	 * From now on the only code in u-boot that will be
	 * executed is the PROM code.
	 */
	kernel(kernel_arg_promvec, (void *)images->ep);

	/* It will never come to this... */
	while (1) ;

      error:
	return 1;
}