586efb4014e8648e560fb43eee8eea8b09da669b
[grub.git] / grub-core / boot / sparc64 / ieee1275 / boot.S
1 /* -*-Asm-*- */
2 /*
3  *  GRUB  --  GRand Unified Bootloader
4  *  Copyright (C) 2009  Free Software Foundation, Inc.
5  *
6  *  GRUB is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  GRUB is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <grub/machine/boot.h>
21
22         .text
23         .align  4
24         .globl  _start
25 _start:
26         /* OF CIF entry point arrives in %o4 */
27 pic_base:
28         call    boot_continue
29          mov    %o4, CIF_REG
30
31 #ifndef CDBOOT
32         /* The offsets to these locations are defined by the
33          * GRUB_BOOT_MACHINE_foo macros in include/grub/sparc/ieee1275/boot.h,
34          * and grub-setup uses this to patch these next three values as needed.
35          *
36          * The boot_path will be the OF device path of the partition where the
37          * rest of the GRUB kernel image resides.  kernel_sector will be set to
38          * the location of the first block of the GRUB kernel, and
39          * kernel_address is the location where we should load that first block.
40          *
41          * After loading in that block we will execute it by jumping to the
42          * load address plus the size of the prepended A.OUT header (32 bytes).
43          */
44         .org GRUB_BOOT_MACHINE_BOOT_DEVPATH
45 boot_path:
46         .org GRUB_BOOT_MACHINE_KERNEL_BYTE
47 boot_path_end:
48 kernel_byte:            .xword (2 << 9)
49 kernel_address:         .word  GRUB_BOOT_MACHINE_KERNEL_ADDR
50 #else
51 #define boot_path (_start + 512 + SCRATCH_PAD_BOOT_SIZE)
52 #define boot_path_end (_start + 1024)
53 #include <grub/offsets.h>
54
55         .org 8
56 kernel_byte:            .xword (2 << 9)
57 kernel_size:            .word  512
58 kernel_address:         .word  GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS
59 #endif
60
61 prom_finddev_name:      .asciz "finddevice"
62 prom_chosen_path:       .asciz "/chosen"
63 prom_getprop_name:      .asciz "getprop"
64 prom_stdout_name:       .asciz "stdout"
65 prom_write_name:        .asciz "write"
66 prom_bootpath_name:     .asciz "bootpath"
67 prom_open_name:         .asciz "open"
68 prom_seek_name:         .asciz "seek"
69 prom_read_name:         .asciz "read"
70 prom_exit_name:         .asciz "exit"
71 grub_name:              .asciz "GRUB "
72 #define GRUB_NAME_LEN   5
73
74         .align  4
75
76 prom_open_error:
77         GET_ABS(prom_open_name, %o2)
78         call    console_write
79          mov    4, %o3
80         /* fallthru */
81
82 prom_error:
83         GET_ABS(prom_exit_name, %o0)
84         /* fallthru */
85
86         /* %o0: OF call name
87          * %o1: input arg 1
88          */
89 prom_call_1_1_o2:
90         clr     %o2
91         ba      prom_call_x_1
92          mov    1, %g1
93
94 prom_call_getprop:
95         mov     4, %g1
96         stx     %g1, [%l1 + 256]
97         mov     CHOSEN_NODE_REG, %o1
98         ba      prom_call_x_1
99          GET_ABS(prom_getprop_name, %o0)
100
101 prom_call_3_1_o1:
102         ba prom_call_3_1
103          mov    BOOTDEV_REG, %o1
104
105         
106         /* %o2: message string
107          * %o3: message length
108          */
109 console_write:
110         GET_ABS(prom_write_name, %o0)
111         mov     STDOUT_NODE_REG, %o1
112         /* fallthru */
113
114         /* %o0: OF call name
115          * %o1: input arg 1
116          * %o2: input arg 2
117          * %o3: input arg 3
118          */
119 prom_call_3_1:  
120         mov     3, %g1
121 prom_call_x_1:
122         mov     1, %o5
123         /* fallthru */
124
125         /* %o0: OF call name
126          * %g1: num inputs
127          * %o5: num outputs
128          * %o1-%o4: inputs
129          */
130 prom_call:
131         stx     %o0, [%l1 + 0x00]
132         stx     %g1, [%l1 + 0x08]
133         stx     %o5, [%l1 + 0x10]
134         stx     %o1, [%l1 + 0x18]
135         stx     %o2, [%l1 + 0x20]
136         stx     %o3, [%l1 + 0x28]
137         stx     %o4, [%l1 + 0x30]
138         jmpl    CIF_REG, %g0
139          mov    %l1, %o0
140
141 boot_continue:
142         mov     %o7, PIC_REG            /* PIC base */
143 #ifndef CDBOOT
144         sethi   %hi(SCRATCH_PAD_BOOT), %l1      /* OF argument slots */
145 #else
146         GET_ABS(_start + 512, %l1)      /* OF argument slots */
147 #endif
148
149         /* Find the /chosen node so we can fetch the stdout handle,
150          * and thus perform console output.
151          *
152          * chosen_node = prom_finddevice("/chosen")
153          */
154         GET_ABS(prom_finddev_name, %o0)
155         call    prom_call_1_1_o2
156          GET_ABS(prom_chosen_path, %o1)
157
158         ldx     [%l1 + 0x20], CHOSEN_NODE_REG
159         brz     CHOSEN_NODE_REG, prom_error
160
161         /* getprop(chosen_node, "stdout", &buffer, buffer_size) */
162          GET_ABS(prom_stdout_name, %o2)
163         add     %l1, 256, %o3
164         call    prom_call_getprop
165          mov    1024, %o4
166
167         lduw    [%l1 + 256], STDOUT_NODE_REG
168         brz,pn  STDOUT_NODE_REG, prom_error
169
170         /* write(stdout_node, "GRUB ", strlen("GRUB ")) */
171          GET_ABS(grub_name, %o2)
172         call    console_write
173          mov    GRUB_NAME_LEN, %o3
174
175         GET_ABS(boot_path, %o3)
176 #ifndef CDBOOT
177         ldub    [%o3], %o1
178         brnz,pn %o1, bootpath_known
179 #endif
180
181         /* getprop(chosen_node, "bootpath", &buffer, buffer_size) */
182          GET_ABS(prom_bootpath_name, %o2)
183         call    prom_call_getprop
184          mov    (boot_path_end - boot_path), %o4
185
186 bootpath_known: 
187
188         /* Open up the boot_path, and use that handle to read the
189          * first block of the GRUB kernel image.
190          *
191          * bootdev_handle = open(boot_path)
192          */
193         GET_ABS(prom_open_name, %o0)
194         call    prom_call_1_1_o2
195          GET_ABS(boot_path, %o1)
196
197         ldx     [%l1 + 0x20], BOOTDEV_REG
198         brz,pn  BOOTDEV_REG, prom_open_error
199
200         /* Since we have 64-bit cells, the high cell of the seek offset
201          * is zero and the low cell is the entire value.
202          *
203          * seek(bootdev, 0, *kernel_byte)
204          */
205          GET_ABS(prom_seek_name, %o0)
206         clr     %o2
207         call    prom_call_3_1_o1
208          LDX_ABS(kernel_byte, 0x00, %o3)
209
210         /* read(bootdev, *kernel_address, 512) */
211         GET_ABS(prom_read_name, %o0)
212         LDUW_ABS(kernel_address, 0x00, %o2)
213         call    prom_call_3_1_o1
214 #ifdef CDBOOT
215          LDUW_ABS(kernel_size, 0x00, %o3)
216 #else
217          mov    512, %o3
218 #endif
219
220         LDUW_ABS(kernel_address, 0x00, %o2)
221         jmpl    %o2, %o7
222 #ifdef CDBOOT
223          mov    CIF_REG, %o4
224 #else
225          nop
226 #endif
227         .org GRUB_BOOT_MACHINE_CODE_END
228
229 /* the last 4 bytes in the sector 0 contain the signature */
230         .word   GRUB_BOOT_MACHINE_SIGNATURE