~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/boot/i386/pc/diskboot.S

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

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