Linux/boot/head.S

Linux/boot/head.S  

  1 /*

  2  *  linux/boot/head.S

  3  *

  4  *  Copyright (C) 1991, 1992  Linus Torvalds

  5  */

  6

  7 /*

  8  *  head.S contains the 32-bit startup code.

  9  */

 10

 11 .text

 12 .globl _idt,_gdt,

 13 .globl _swapper_pg_dir,_pg0

 14 .globl _empty_bad_page

 15 .globl _empty_bad_page_table

 16 .globl _empty_zero_page

 17 .globl _tmp_floppy_area,_floppy_track_buffer

 18

 19 #include <linux/tasks.h>

 20 #include <linux/segment.h>

 21

 22 #define CL_MAGIC_ADDR   0x90020

 23 #define CL_MAGIC        0xA 33F

 24 #define CL_BASE_ADDR    0x90000

 25 #define CL_OFFSET       0x90022

 26

 27 /*

 28  * swapper_pg_dir is the main page directory, address 0x00001000 (or at

 29  * address 0x00101000 for a compressed boot).

 30  */

 31 startup_32:

 32         cld

 33         movl $(KERNEL_DS),%eax

 34         mov %ax,%ds

 35         mov %ax,%es

 36         mov %ax,%fs

 37         mov %ax,%gs

 38         lss _stack_start,%esp

 39 /*

 40  * Clear BSS first so that there are no surprises...

 41  */

 42         xorl %eax,%eax

 43         movl $__edata,%edi

 44         movl $__end,%ecx

 45         subl %edi,%ecx

 46         cld

 47         rep

 48         stosb

 49 /*

 50  * start system 32-bit setup. We need to re-do some of the things done

 51  * in 16-bit mode for the "real" operations.

 52  */

 53         call setup_idt

 54         xorl %eax,%eax

 55 1:      incl %eax               # check that A20 really IS enabled

 56         movl %eax,0x000000      # loop forever if it isn't

 57         cmpl %eax,0x100000

 58         je 1b

 59 /*

 60  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would

 61  * confuse the debugger if this code is traced.

 62  * XXX - best to initialize before switching to protected mode.

 63  */

 64         pushl $0

 65         popfl

 66 /*

 67  * Copy bootup parameters out of the way. First 2kB of

 68  * _empty_zero_page is for boot parameters, second 2kB

 69  * is for the command line.

 70  */

 71         movl $0x90000,%esi

 72         movl $_empty_zero_page,%edi

 73         movl $512,%ecx

 74         cld

 75         rep

 76         movsl

 77         xorl %eax,%eax

 78         movl $512,%ecx

 79         rep

 80         stosl

 81         cmpw $(CL_MAGIC),CL_MAGIC_ADDR

 82         jne 1f

 83         movl $_empty_zero_page+2048,%edi

 84         movzwl CL_OFFSET,%esi

 85         addl $(CL_BASE_ADDR),%esi

 86         movl $2048,%ecx

 87         rep

 88         movsb

 89 1:

 90 /* check if it is 486 or 386. */

 91 /*

 92  * XXX - this does a lot of unnecessary setup.  Alignment checks don't

 93  * apply at our cpl of 0 and the stack ought to be aligned already, and

 94  * we don't need to preserve eflags.

 95  */

 96         movl %esp,%edi          # save stack pointer

 97         andl $0xfffffffc,%esp   # align stack to avoid AC fault

 98         movl $3,_x86

 99         pushfl                  # push EFLAGS

100         popl %eax               # get EFLAGS

101         movl %eax,%ecx          # save original EFLAGS

102         xorl $0x40000,%eax      # flip AC bit in EFLAGS

103         pushl %eax              # copy to EFLAGS

104         popfl                   # set EFLAGS

105         pushfl                  # get new EFLAGS

106         popl %eax               # put it in eax

107         xorl %ecx,%eax          # change in flags

108         andl $0x40000,%eax      # check if AC bit changed

109         je is386

110         movl $4,_x86

111         movl %ecx,%eax

112         xorl $0x200000,%eax     # check ID flag

113         pushl %eax

114         popfl                   # if we are on a straight 486DX, SX, or

115         pushfl                  # 487SX we can't change it

116         popl %eax

117         xorl %ecx,%eax

118         andl $0x200000,%eax

119         je is486

120 isnew:  pushl %ecx              # restore original EFLAGS

121         popfl

122         movl $1, %eax           # Use the CPUID instruction to

123         .byte 0x 0f , 0xa2        # check the processor type

124         andl $0xf00, %eax       # Set _x86 with the family

125         shrl $8, %eax           # returned.    

126         movl %eax, _x86

127         movl %edi,%esp          # restore esp

128         movl %cr0,%eax          # 486+

129         andl $0x80000011,%eax   # Save PG,PE,ET

130         orl $0x50022,%eax       # set AM, WP, NE and MP

131         jmp 2f

132 is486:  pushl %ecx              # restore original EFLAGS

133         popfl

134         movl %edi,%esp          # restore esp

135         movl %cr0,%eax          # 486

136         andl $0x80000011,%eax   # Save PG,PE,ET

137         orl $0x50022,%eax       # set AM, WP, NE and MP

138         jmp 2f

139 is386:  pushl %ecx              # restore original EFLAGS

140         popfl

141         movl %edi,%esp          # restore esp

142         movl %cr0,%eax          # 386

143         andl $0x80000011,%eax   # Save PG,PE,ET

144         orl $2,%eax             # set MP

145 2:      movl %eax,%cr0

146         call check_x87

147         call setup_paging

148         lgdt gdt_descr

149         lidt idt_descr

150         ljmp $(KERNEL_CS),$ 1f

151 1:      movl $(KERNEL_DS),%eax  # reload all the segment registers

152         mov %ax,%ds             # after changing gdt.

153         mov %ax,%es

154         mov %ax,%fs

155         mov %ax,%gs

156         lss _stack_start,%esp

157         xorl %eax,%eax

158         lldt %ax

159         pushl %eax              # These are the parameters to main :-)

160         pushl %eax

161         pushl %eax

162         cld                     # gcc2 wants the direction flag cleared at all times

163         call _start_kernel

164 L6:

165         jmp L6                  # main should never return here, but

166                                 # just in case, we know what happens.

167

168 /*

169  * We depend on ET to be correct. This checks for 287/387.

170  */

171 check_x87:

172         movl $0,_hard_math

173         clts

174         fninit

175         fstsw %ax

176         cmpb $0,%al

177         je 1f

178         movl %cr0,%eax          /* no coprocessor: have to set bits */

179         xorl $4,%eax            /* set EM */

180         movl %eax,%cr0

181         ret

182 .align 2

183 1:      movl $1,_hard_math

184         .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */

185         ret

186

187 /*

188  *  setup_idt

189  *

190  *  sets up a idt with 256 entries pointing to

191  *  ignore_int, interrupt gates. It doesn't actually load

192  *  idt - that can be done only after paging has been enabled

193  *  and the kernel moved to 0xC0000000. Interrupts

194  *  are enabled elsewhere, when we can be relatively

195  *  sure everything is ok.

196  */

197 setup_idt:

198         lea ignore_int,%edx

199         movl $(KERNEL_CS << 16),%eax

200         movw %dx,%ax            /* selector = 0x0010 = cs */

201         movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */

202

203         lea _idt,%edi

204         mov $256,%ecx

205 rp_sidt:

206         movl %eax,(%edi)

207         movl %edx,4(%edi)

208         addl $8,%edi

209         dec %ecx

210         jne rp_sidt

211         ret

212

213

214 /*

215  * Setup_paging

216  *

217  * This routine sets up paging by setting the page bit

218  * in cr0. The page tables are set up, identity-mapping

219  * the first 4MB.  The rest are initialized later.

220  *

221  * (ref: added support for up to 32mb, 17Apr92)  -- Rik Faith

222  * (ref: update, 25Sept92)  -- [email protected]

223  * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)

224  */

225 .align 2

226 setup_paging:

227         movl $1024*2,%ecx               /* 2 pages - swapper_pg_dir+1 page table */

228         xorl %eax,%eax

229         movl $_swapper_pg_dir,%edi      /* swapper_pg_dir is at 0x1000 */

230         cld;rep;stosl

231 /* Identity-map the kernel in low 4MB memory for ease of transition */

232         movl $_pg0+7,_swapper_pg_dir            /* set present bit/user r/w */

233 /* But the real place is at 0xC0000000 */

234         movl $_pg0+7,_swapper_pg_dir+3072       /* set present bit/user r/w */

235         movl $_pg0+4092,%edi

236         movl $0x03ff007,%eax            /*  4Mb - 4096 + 7 (r/w user,p) */

237         std

238 1:      stosl                   /* fill the page backwards - more efficient :-) */

239         subl $0x1000,%eax

240         jge 1b

241         cld

242         movl $_swapper_pg_dir,%eax

243         movl %eax,%cr3                  /* cr3 - page directory start */

244         movl %cr0,%eax

245         orl $0x80000000,%eax

246         movl %eax,%cr0          /* set paging (PG) bit */

247         ret                     /* this also flushes the prefetch-queue */

248

249 /*

250  * page 0 is made non-existent, so that kernel NULL pointer references get

251  * caught. Thus the swapper page directory has been moved to 0x1000

252  *

253  * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,

254  * with the introduction of the compressed boot code.  Theoretically,

255  * the original design of overlaying the startup code with the swapper

256  * page directory is still possible --- it would reduce the size of the kernel

257  * by 2-3k.  This would be a good thing to do at some point.....

258  */

259 .org 0x1000

260 _swapper_pg_dir:

261 /*

262  * The page tables are initialized to only 4MB here - the final page

263  * tables are set up later depending on memory size.

264  */

265 .org 0x2000

266 _pg0:

267

268 .org 0x3000

269 _empty_bad_page:

270

271 .org 0x4000

272 _empty_bad_page_table:

273

274 .org 0x5000

275 _empty_zero_page:

276

277 .org 0x6000

278 /*

279  * tmp_floppy_area is used by the floppy-driver when DMA cannot

280  * reach to a buffer-block. It needs to be aligned, so that it isn't

281  * on a 64kB border.

282  */

283 _tmp_floppy_area:

284         .fill 1024,1,0

285 /*

286  * floppy_track_buffer is used to buffer one track of floppy data: it

287  * has to be separate from the tmp_floppy area, as otherwise a single-

288  * sector read/write can mess it up. It can contain one full track of

289  * data (18*2*512 bytes).

290  */

291 _floppy_track_buffer:

292         .fill 512*2*18,1,0

293

294 /* This is the default interrupt "handler" :-) */

295 int_msg:

296         .asciz "Unknown interrupt/n"

297 .align 2

298 ignore_int:

299         cld

300         pushl %eax

301         pushl %ecx

302         pushl %edx

303         push %ds

304         push %es

305         push %fs

306         movl $(KERNEL_DS),%eax

307         mov %ax,%ds

308         mov %ax,%es

309         mov %ax,%fs

310         pushl $int_msg

311         call _printk

312         popl %eax

313         pop %fs

314         pop %es

315         pop %ds

316         popl %edx

317         popl %ecx

318         popl %eax

319         iret

320

321 /*

322  * The interrupt descriptor table has room for 256 idt's

323  */

324 .align 4

325 .word 0

326 idt_descr:

327         .word 256*8-1           # idt contains 256 entries

328         .long 0xc0000000+_idt

329

330 .align 4

331 _idt:

332         .fill 256,8,0           # idt is uninitialized

333

334 .align 4

335 .word 0

336 gdt_descr:

337         .word (8+2*NR_TASKS)*8-1

338         .long 0xc0000000+_gdt

339

340 /*

341  * This gdt setup gives the kernel a 1GB address space at virtual

342  * address 0xC0000000 - space enough for expansion, I hope.

343  */

344 .align 4

345 _gdt:

346         .quad 0x0000000000000000        /* NULL descriptor */

347         .quad 0x0000000000000000        /* not used */

348         .quad 0xc 0c 39a 000000ffff        /* 0x10 kernel 1GB code at 0xC0000000 */

349         .quad 0xc 0c 392000000ffff        /* 0x18 kernel 1GB data at 0xC0000000 */

350         .quad 0x00cbfa000000ffff        /* 0x23 user   3GB code at 0x00000000 */

351         .quad 0x00cbf2000000ffff        /* 0x2b user   3GB data at 0x00000000 */

352         .quad 0x0000000000000000        /* not used */

353         .quad 0x0000000000000000        /* not used */

354         .fill 2*NR_TASKS,8,0            /* space for LDT's and TSS's etc */

 

你可能感兴趣的:(table,buffer,Parameters,transition,Descriptor,alignment)