-
Notifications
You must be signed in to change notification settings - Fork 0
/
diskboot.S.txt
341 lines (246 loc) · 8.5 KB
/
diskboot.S.txt
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
从grub-install过程可知list结构为
struct grub_boot_blocklist{
grub_uint64_t start;起始扇区
grub_uint32_t len;此块对应的扇区数
}
#include <grub/symbol.h>
#include <grub/machine/boot.h>
#ifdef QUIET_BOOT
#include <grub/machine/memory.h>
#endif
/*
* defines for the code go here
*/
#define MSG(x) movw $x, %si; call LOCAL(message)
#ifdef QUIET_BOOT
#define SILENT(x) call LOCAL(check_silent); jz LOCAL(x)
#else
#define SILENT(x)
#endif
.file "diskboot.S"
.text
/* Tell GAS to generate 16-bit instructions so that this code works
in real mode. */
.code16
.globl start, _start
start:
_start:
/*
* _start is loaded at 0x2000 and is jumped to with
* CS:IP 0:0x2000 in kernel.
*/
/*
* we continue to use the stack for boot.img and assume that
* some registers are set to correct values. See boot.S
* for more information.
*/
/* save drive reference first thing! 由于依旧使用的是boot.img环境,dl存的是设备号*/
pushw %dx
SILENT(after_notification_string)
/* print a notification message on the screen,打印消息会使用到si寄存器所以保存一下 */
pushw %si
MSG(notification_string)
popw %si
LOCAL(after_notification_string):
/* this sets up for the first run through "bootloop" firstlist也就是grub-install写入的快设备链表*/
/*
0x200是512,GRUB_BOOT_MACHINE_LIST_SIZE是12,也就是LOCAL(firstlist)是末尾的最后一项,从grub-install可知快设备号存储是从512-12递减存储的,也就是第一个块在500,第二个块在488。。。
*/
.word 0
.word 0
.org 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE
LOCAL(firstlist): /* this label has to be before the first list entry!!! */
/* fill the first data listing with the default */
blocklist_default_start:
/* this is the sector start parameter, in logical sectors from
the start of the disk, sector 0 */
.long 2, 0
blocklist_default_len:
/* this is the number of sectors to read. grub-mkimage
will fill this up */
.word 0
blocklist_default_seg:
/* this is the segment of the starting address to load the data into */
.word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20)
movw $LOCAL(firstlist), %di
/* save the sector number of the second sector in %ebp */
movl (%di), %ebp
/* this is the loop for reading the rest of the kernel in */
LOCAL(bootloop):
/* check the number of sectors to read ,测试此块存在多少扇区*/
cmpw $0, 8(%di)
/* if zero, go to the start function ,读完了,因为最后一个扇区会被设置为全0*/
je LOCAL(bootit)
LOCAL(setup_sectors):
/* 在boot.img中si-1是模式的地址0是chs,1是lba*/
cmpb $0, -1(%si)
/* use CHS if zero, LBA otherwise */
je LOCAL(chs_mode)
/* load logical sector start */
movl (%di), %ebx
movl 4(%di), %ecx
/* the maximum is limited to 0x7f because of Phoenix EDD */
xorl %eax, %eax
movb $0x7f, %al
/* how many do we really want to read? */
cmpw %ax, 8(%di) /* compare against total number of sectors */
/* which is greater? 如果firstlist保存的扇区数大于则跳转,否则就是实际剩余未拷贝扇区小余0x7f */
jg 1f
/* if less than, set to total */
movw 8(%di), %ax
1:
/* subtract from total ,第一项总数中减去此次将要拷贝扇区数*/
subw %ax, 8(%di)
/* add into logical sector start ,adc会加进位,重新计算下一次的起始扇区*/
addl %eax, (%di)
adcl $0, 4(%di)
/* set up disk address packet */
/*secoter低两个字节设置为0x0010,表示数据块大小。si指向disk_address_packet*/
movw $0x0010, (%si)
/* the number of sectors ,secoter高两个字节设置为ax,表示传输的扇区数*/
movw %ax, 2(%si)
/* the absolute address ,设置读取起始扇区,这两个值一起决定了起始扇区*/
movl %ebx, 8(%si)
movl %ecx, 12(%si)
/* the segment of buffer address 。ds:si 0x7000*/
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)
/* save %ax from destruction! */
pushw %ax
/* the offset of buffer address */
movw $0, 4(%si)
/*
* BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
* Call with %ah = 0x42
* %dl = drive number
* %ds:%si = segment:offset of disk address packet
* Return:
* %al = 0x0 on success; err code on failure
*/
movb $0x42, %ah
int $0x13
jc LOCAL(read_error)
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
jmp LOCAL(copy_buffer)
LOCAL(chs_mode):
/* load logical sector start (top half) */
movl 4(%di), %eax
orl %eax, %eax
jnz LOCAL(geometry_error)
/* load logical sector start (bottom half) */
movl (%di), %eax
/* zero %edx */
xorl %edx, %edx
/* divide by number of sectors ,计算磁道上的扇区位置*/
divl (%si)
/* save sector start */
movb %dl, 10(%si)
xorl %edx, %edx /* zero %edx */
divl 4(%si) /* divide by number of heads 商->eax 余数->edx,表示哪个柱面,商是起始柱面,余数是起始磁头 */
/* save head start */
movb %dl, 11(%si)
/* save cylinder start */
movw %ax, 12(%si)
/* do we need too many cylinders? 验证大小,大于一个磁头上保存的柱面则报错*/
cmpw 8(%si), %ax
jge LOCAL(geometry_error)
/* determine the maximum sector length of this read */
movw (%si), %ax /* get number of sectors per track/head ,获取一个磁道上的总扇区数*/
/* subtract sector start ax保存的是整个磁道扇区数,需要减去起始扇区也就是这个磁道剩余待读取扇区*/
subb 10(%si), %al
/* how many do we really want to read? */
cmpw %ax, 8(%di) /* compare against total number of sectors */
/* which is greater? */
jg 2f
/* if less than, set to total */
movw 8(%di), %ax
2:
/* subtract from total */
subw %ax, 8(%di)
/* add into logical sector start */
addl %eax, (%di)
adcl $0, 4(%di)
/*
* This is the loop for taking care of BIOS geometry translation (ugh!)
*/
/* get high bits of cylinder */
movb 13(%si), %dl
shlb $6, %dl /* shift left by 6 bits 保留6-7两位*/
movb 10(%si), %cl /* get sector */
incb %cl /* normalize sector (sectors go
from 1-N, not 0-(N-1) ) */
orb %dl, %cl /* composite together 将dl的6-7位高位写入cl*/
movb 12(%si), %ch /* sector+hcyl in cl, cylinder in ch ,读取柱面低8位*/
/* restore %dx */
popw %dx
pushw %dx
/* head number */
movb 11(%si), %dh
pushw %ax /* save %ax from destruction! */
/*通过中断读取扇区
* BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
* Call with %ah = 0x2
* %al = number of sectors
* %ch = cylinder
* %cl = sector (bits 6-7 are high bits of "cylinder")
* %dh = head
* %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
* %es:%bx = segment:offset of buffer
* Return:
* %al = 0x0 on success; err code on failure
*/
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
movw %bx, %es /* load %es segment with disk buffer */
xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */
movb $0x2, %ah /* function 2 */
int $0x13
jc LOCAL(read_error)
/* save source segment */
movw %es, %bx
LOCAL(copy_buffer):
/* load addresses for copy from disk buffer to destination di指向firstlist
设置es为GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20*/
movw 10(%di), %es /* load destination segment */
/* restore %ax */
popw %ax
/* determine the next possible destination address (presuming
512 byte sectors!) */
shlw $5, %ax /* shift %ax five bits to the left ,段地址会再偏移4位,所以此左移5位也就是设置下次段地址*/
addw %ax, 10(%di) /* add the corrected value to the destination
address for next time */
/* save addressing regs */
pusha
pushw %ds
/* get the copy length */
shlw $3, %ax /*左移3位表示是字数*/
movw %ax, %cx
xorw %di, %di /* zero offset of destination addresses */
xorw %si, %si /* zero offset of source addresses */
movw %bx, %ds /* restore the source segment */
/*
* src ds:si dst es:di
*
*
*/
cld /* sets the copy direction to forward */
/* perform copy */
rep /* sets a repeat */
movsw /* this runs the actual copy */
/* restore addressing regs and print a dot with correct DS
(MSG modifies SI, which is saved, and unused AX and BX) */
popw %ds
SILENT(after_notification_step)
MSG(notification_step)
LOCAL(after_notification_step):
popa
/* check if finished with this dataset ,第一个块扇区是不是读完,如果没有再次循环,*/
cmpw $0, 8(%di)
jne LOCAL(setup_sectors)
/* update position to load from ,firstlist-12,下一个块*/
subw $GRUB_BOOT_MACHINE_LIST_SIZE, %di
/* jump to bootloop */
jmp LOCAL(bootloop)
/* END OF MAIN LOOP */
LOCAL(bootit):
SILENT(after_notification_done)
/* print a newline */
MSG(notification_done)