~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to boot/i386/pc/diskboot.S

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 1999,2000,2001,2002   Free Software Foundation, Inc.
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
 */
 
19
 
 
20
#include <grub/machine/boot.h>
 
21
        
 
22
/*
 
23
 *  defines for the code go here
 
24
 */
 
25
 
 
26
        /* Absolute addresses
 
27
           This makes the assembler generate the address without support
 
28
           from the linker. (ELF can't relocate 16-bit addresses!) */
 
29
#define ABS(x) (x-_start+GRUB_BOOT_MACHINE_KERNEL_ADDR)
 
30
        
 
31
        /* Print message string */
 
32
#define MSG(x)  movw $ABS(x), %si; call message
 
33
 
 
34
        .file   "diskboot.S"
 
35
 
 
36
        .text
 
37
 
 
38
        /* Tell GAS to generate 16-bit instructions so that this code works
 
39
           in real mode. */
 
40
        .code16
 
41
 
 
42
        .globl  start, _start
 
43
start:
 
44
_start: 
 
45
        /*
 
46
         * _start is loaded at 0x2000 and is jumped to with
 
47
         * CS:IP 0:0x2000 in kernel.
 
48
         */
 
49
 
 
50
        /* 
 
51
         * we continue to use the stack for boot.img and assume that
 
52
         * some registers are set to correct values. See boot.S
 
53
         * for more information.
 
54
         */
 
55
        
 
56
        /* save drive reference first thing! */
 
57
        pushw   %dx
 
58
 
 
59
        /* print a notification message on the screen */
 
60
        pushw   %si
 
61
        MSG(notification_string)
 
62
        popw    %si
 
63
        
 
64
        /* this sets up for the first run through "bootloop" */
 
65
        movw    $ABS(firstlist - GRUB_BOOT_MACHINE_LIST_SIZE), %di
 
66
 
 
67
        /* save the sector number of the second sector in %ebp */
 
68
        movl    (%di), %ebp
 
69
 
 
70
        /* this is the loop for reading the rest of the kernel in */
 
71
bootloop:
 
72
 
 
73
        /* check the number of sectors to read */
 
74
        cmpw    $0, 4(%di)
 
75
 
 
76
        /* if zero, go to the start function */
 
77
        je      bootit
 
78
 
 
79
setup_sectors:  
 
80
        /* check if we use LBA or CHS */
 
81
        cmpb    $0, -1(%si)
 
82
 
 
83
        /* jump to chs_mode if zero */
 
84
        je      chs_mode
 
85
 
 
86
lba_mode:       
 
87
        /* load logical sector start */
 
88
        movl    (%di), %ebx
 
89
 
 
90
        /* the maximum is limited to 0x7f because of Phoenix EDD */
 
91
        xorl    %eax, %eax
 
92
        movb    $0x7f, %al
 
93
 
 
94
        /* how many do we really want to read? */
 
95
        cmpw    %ax, 4(%di)     /* compare against total number of sectors */
 
96
 
 
97
        /* which is greater? */
 
98
        jg      1f
 
99
 
 
100
        /* if less than, set to total */
 
101
        movw    4(%di), %ax
 
102
 
 
103
1:      
 
104
        /* subtract from total */
 
105
        subw    %ax, 4(%di)
 
106
 
 
107
        /* add into logical sector start */
 
108
        addl    %eax, (%di)
 
109
 
 
110
        /* set up disk address packet */
 
111
 
 
112
        /* the size and the reserved byte */
 
113
        movw    $0x0010, (%si)
 
114
 
 
115
        /* the number of sectors */
 
116
        movw    %ax, 2(%si)
 
117
 
 
118
        /* the absolute address (low 32 bits) */
 
119
        movl    %ebx, 8(%si)
 
120
 
 
121
        /* the segment of buffer address */
 
122
        movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)
 
123
 
 
124
        /* save %ax from destruction! */
 
125
        pushw   %ax
 
126
 
 
127
        /* zero %eax */
 
128
        xorl    %eax, %eax
 
129
 
 
130
        /* the offset of buffer address */
 
131
        movw    %ax, 4(%si)
 
132
 
 
133
        /* the absolute address (high 32 bits) */
 
134
        movl    %eax, 12(%si)
 
135
 
 
136
 
 
137
/*
 
138
 * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
 
139
 *      Call with       %ah = 0x42
 
140
 *                      %dl = drive number
 
141
 *                      %ds:%si = segment:offset of disk address packet
 
142
 *      Return:
 
143
 *                      %al = 0x0 on success; err code on failure
 
144
 */
 
145
 
 
146
        movb    $0x42, %ah
 
147
        int     $0x13
 
148
 
 
149
        jc      read_error
 
150
 
 
151
        movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
 
152
        jmp     copy_buffer
 
153
                        
 
154
chs_mode:       
 
155
        /* load logical sector start (bottom half) */
 
156
        movl    (%di), %eax
 
157
 
 
158
        /* zero %edx */
 
159
        xorl    %edx, %edx
 
160
 
 
161
        /* divide by number of sectors */
 
162
        divl    (%si)
 
163
 
 
164
        /* save sector start */
 
165
        movb    %dl, 10(%si)
 
166
 
 
167
        xorl    %edx, %edx      /* zero %edx */
 
168
        divl    4(%si)          /* divide by number of heads */
 
169
 
 
170
        /* save head start */
 
171
        movb    %dl, 11(%si)
 
172
 
 
173
        /* save cylinder start */
 
174
        movw    %ax, 12(%si)
 
175
 
 
176
        /* do we need too many cylinders? */
 
177
        cmpw    8(%si), %ax
 
178
        jge     geometry_error
 
179
 
 
180
        /* determine the maximum sector length of this read */
 
181
        movw    (%si), %ax      /* get number of sectors per track/head */
 
182
 
 
183
        /* subtract sector start */
 
184
        subb    10(%si), %al
 
185
 
 
186
        /* how many do we really want to read? */
 
187
        cmpw    %ax, 4(%di)     /* compare against total number of sectors */
 
188
 
 
189
 
 
190
        /* which is greater? */
 
191
        jg      2f
 
192
 
 
193
        /* if less than, set to total */
 
194
        movw    4(%di), %ax
 
195
 
 
196
2:      
 
197
        /* subtract from total */
 
198
        subw    %ax, 4(%di)
 
199
 
 
200
        /* add into logical sector start */
 
201
        addl    %eax, (%di)
 
202
 
 
203
/*
 
204
 *  This is the loop for taking care of BIOS geometry translation (ugh!)
 
205
 */
 
206
 
 
207
        /* get high bits of cylinder */
 
208
        movb    13(%si), %dl
 
209
 
 
210
        shlb    $6, %dl         /* shift left by 6 bits */
 
211
        movb    10(%si), %cl    /* get sector */
 
212
 
 
213
        incb    %cl             /* normalize sector (sectors go
 
214
                                        from 1-N, not 0-(N-1) ) */
 
215
        orb     %dl, %cl        /* composite together */
 
216
        movb    12(%si), %ch    /* sector+hcyl in cl, cylinder in ch */
 
217
 
 
218
        /* restore %dx */
 
219
        popw    %dx
 
220
        pushw   %dx
 
221
 
 
222
        /* head number */
 
223
        movb    11(%si), %dh
 
224
 
 
225
        pushw   %ax     /* save %ax from destruction! */
 
226
 
 
227
/*
 
228
 * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
 
229
 *      Call with       %ah = 0x2
 
230
 *                      %al = number of sectors
 
231
 *                      %ch = cylinder
 
232
 *                      %cl = sector (bits 6-7 are high bits of "cylinder")
 
233
 *                      %dh = head
 
234
 *                      %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
 
235
 *                      %es:%bx = segment:offset of buffer
 
236
 *      Return:
 
237
 *                      %al = 0x0 on success; err code on failure
 
238
 */
 
239
 
 
240
        movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
 
241
        movw    %bx, %es        /* load %es segment with disk buffer */
 
242
 
 
243
        xorw    %bx, %bx        /* %bx = 0, put it at 0 in the segment */
 
244
        movb    $0x2, %ah       /* function 2 */
 
245
        int     $0x13
 
246
 
 
247
        jc      read_error
 
248
 
 
249
        /* save source segment */
 
250
        movw    %es, %bx
 
251
        
 
252
copy_buffer:    
 
253
 
 
254
        /* load addresses for copy from disk buffer to destination */
 
255
        movw    6(%di), %es     /* load destination segment */
 
256
 
 
257
        /* restore %ax */
 
258
        popw    %ax
 
259
 
 
260
        /* determine the next possible destination address (presuming
 
261
                512 byte sectors!) */
 
262
        shlw    $5, %ax         /* shift %ax five bits to the left */
 
263
        addw    %ax, 6(%di)     /* add the corrected value to the destination
 
264
                                   address for next time */
 
265
 
 
266
        /* save addressing regs */
 
267
        pusha
 
268
        pushw   %ds
 
269
 
 
270
        /* get the copy length */
 
271
        shlw    $3, %ax
 
272
        movw    %ax, %cx
 
273
 
 
274
        xorw    %di, %di        /* zero offset of destination addresses */
 
275
        xorw    %si, %si        /* zero offset of source addresses */
 
276
        movw    %bx, %ds        /* restore the source segment */
 
277
 
 
278
        cld             /* sets the copy direction to forward */
 
279
 
 
280
        /* perform copy */
 
281
        rep             /* sets a repeat */
 
282
        movsw           /* this runs the actual copy */
 
283
 
 
284
        /* restore addressing regs and print a dot with correct DS 
 
285
           (MSG modifies SI, which is saved, and unused AX and BX) */
 
286
        popw    %ds
 
287
        MSG(notification_step)
 
288
        popa
 
289
 
 
290
        /* check if finished with this dataset */
 
291
        cmpw    $0, 4(%di)
 
292
        jne     setup_sectors
 
293
 
 
294
        /* update position to load from */
 
295
        subw    $GRUB_BOOT_MACHINE_LIST_SIZE, %di
 
296
 
 
297
        /* jump to bootloop */
 
298
        jmp     bootloop
 
299
 
 
300
/* END OF MAIN LOOP */
 
301
 
 
302
bootit:
 
303
        /* print a newline */
 
304
        MSG(notification_done)
 
305
        popw    %dx     /* this makes sure %dl is our "boot" drive */
 
306
        ljmp    $0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
 
307
 
 
308
 
 
309
/*
 
310
 * BIOS Geometry translation error (past the end of the disk geometry!).
 
311
 */
 
312
geometry_error:
 
313
        MSG(geometry_error_string)
 
314
        jmp     general_error
 
315
 
 
316
/*
 
317
 * Read error on the disk.
 
318
 */
 
319
read_error:
 
320
        MSG(read_error_string)
 
321
 
 
322
general_error:
 
323
        MSG(general_error_string)
 
324
 
 
325
/* go here when you need to stop the machine hard after an error condition */
 
326
stop:   jmp     stop
 
327
 
 
328
notification_string:    .string "Loading kernel"
 
329
 
 
330
notification_step:      .string "."
 
331
notification_done:      .string "\r\n"
 
332
        
 
333
geometry_error_string:  .string "Geom"
 
334
read_error_string:      .string "Read"
 
335
general_error_string:   .string " Error"
 
336
 
 
337
/*
 
338
 * message: write the string pointed to by %si
 
339
 *
 
340
 *   WARNING: trashes %si, %ax, and %bx
 
341
 */
 
342
 
 
343
        /*
 
344
         * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
 
345
         *      %ah = 0xe       %al = character
 
346
         *      %bh = page      %bl = foreground color (graphics modes)
 
347
         */
 
348
1:
 
349
        movw    $0x0001, %bx
 
350
        movb    $0xe, %ah
 
351
        int     $0x10           /* display a byte */
 
352
 
 
353
        incw    %si
 
354
message:
 
355
        movb    (%si), %al
 
356
        cmpb    $0, %al
 
357
        jne     1b      /* if not end of string, jmp to display */
 
358
        ret
 
359
lastlist:
 
360
 
 
361
/*
 
362
 *  This area is an empty space between the main body of code below which
 
363
 *  grows up (fixed after compilation, but between releases it may change
 
364
 *  in size easily), and the lists of sectors to read, which grows down
 
365
 *  from a fixed top location.
 
366
 */
 
367
 
 
368
        .word 0
 
369
        .word 0
 
370
 
 
371
        . = _start + 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE
 
372
        
 
373
        /* fill the first data listing with the default */
 
374
blocklist_default_start:
 
375
        /* this is the sector start parameter, in logical sectors from
 
376
           the start of the disk, sector 0 */
 
377
        .long 2
 
378
blocklist_default_len:
 
379
        /* this is the number of sectors to read the command "install"
 
380
           will fill this up */
 
381
        .word 0
 
382
blocklist_default_seg:
 
383
        /* this is the segment of the starting address to load the data into */
 
384
        .word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20)
 
385
        
 
386
firstlist:      /* this label has to be after the list data!!! */