X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Floader.S;h=796dca8c3dd101b5ef61f2708eeb6f8c9bebf223;hb=615bf3b3d2a8573ed6fb9ddc0055745e163ac999;hp=f2563bb149af8b64c46a07473b3ec1d80906cd1c;hpb=750d21936d284127e265d050ccbce76fca1ece1a;p=pintos-anon diff --git a/src/threads/loader.S b/src/threads/loader.S index f2563bb..796dca8 100644 --- a/src/threads/loader.S +++ b/src/threads/loader.S @@ -1,151 +1,295 @@ -#include "mmu.h" +/* This file is derived from source code used in MIT's 6.828 + course. The original copyright notice is reproduced in full + below. */ + +/* + * Copyright (C) 1997 Massachusetts Institute of Technology + * + * This software is being provided by the copyright holders under the + * following license. By obtaining, using and/or copying this software, + * you agree that you have read, understood, and will comply with the + * following terms and conditions: + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose and without fee or royalty is + * hereby granted, provided that the full text of this NOTICE appears on + * ALL copies of the software and documentation or portions thereof, + * including modifications, that you make. + * + * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, + * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR + * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR + * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY + * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT + * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR + * DOCUMENTATION. + * + * The name and trademarks of copyright holders may NOT be used in + * advertising or publicity pertaining to the software without specific, + * written prior permission. Title to copyright in this software and any + * associated documentation will at all times remain with copyright + * holders. See the file AUTHORS which should have accompanied this software + * for a list of all copyright holders. + * + * This file may be derived from previously copyrighted software. This + * copyright applies only to those changes made by the copyright + * holders listed in the AUTHORS file. The rest of this file is covered by + * the copyright notices, if any, listed below. + */ + +#include "threads/loader.h" -################################################################################### -# ENTRY POINT -# This code should be stored in the first sector of the hard disk. When the -# BIOS runs, it loads this code at physical address 0x7c00 - 0x7e00 (512 bytes). -# Then jumps to the beginning of it, in real-mode (BIOS runs in real mode). -# -# This code switches into protected mode (32-bit mode) so that all of -# memory can accessed, then calls into C. -################################################################################### + .intel_syntax noprefix -.globl start # Entry point -start: .code16 # This runs in real mode - cli # Disable interrupts - cld # String ops inc - xorw %ax,%ax # Zero - movw %ax,%es # Address - movw %ax,%ds # data - movw %ax,%ss # Set up - movw $start,%sp # stack (grows down) +#### Kernel loader. + +#### This code should be stored in the first sector of the hard disk. +#### When the BIOS runs, it loads this code at physical address +#### 0x7c00-0x7e00 (512 bytes). Then it jumps to the beginning of it, +#### in real mode. This code switches into protected mode (32-bit +#### mode) so that all of memory can accessed, loads the kernel into +#### memory, and jumps to the first byte of the kernel, where start.S +#### is linked. -#### Enable A20: -#### Address line 20 is tied to low when the machine boots, -#### obviously this a bit of a drag, such as when trying to -#### address memory above 1MB. This code undoes this. +/* Flags in control register 0. */ +#define CR0_PE 0x00000001 /* Protection Enable. */ +#define CR0_EM 0x00000004 /* (Floating-point) Emulation. */ +#define CR0_PG 0x80000000 /* Paging. */ +#define CR0_WP 0x00010000 /* Write-Protect enable in kernel mode. */ + +# Code runs in real mode, which is a 16-bit segment. + +.globl start +start: + .code16 + +# Disable interrupts. +# String instructions go upward. + + cli + cld + +# Set up data segments. + + sub ax, ax + mov es, ax + mov ds, ax + +# Set up stack segment. +# Stack grows downward starting from us. +# We don't ever use the stack so this is strictly speaking +# unnecessary. + + mov ss, ax + mov sp, 0x7c00 -1: inb $0x64,%al # Get status - testb $0x2,%al # Busy? - jnz 1b # Yes - movb $0xd1,%al # Command: Write - outb %al,$0x64 # output port -2: inb $0x64,%al # Get status - testb $0x2,%al # Busy? - jnz 2b # Yes - movb $0xdf,%al # Enable - outb %al,$0x60 # A20 - -#### Get memory size, via interrupt 15h function 88h. -#### Returns CF clear if successful, with AX = (kB of physical memory) - 1024. -#### This only works for memory sizes <= 65 MB, which should be fine for our purposes. +#### Enable A20. Address line 20 is tied to low when the machine +#### boots, which prevents addressing memory about 1 MB. This code +#### fixes it. - movb $0x88,%ah - int $0x15 - jc panic # Carry flag set on error - addl $1024,%eax # Total kB - shrl $2,%eax # Total 4 kB pages - movl %eax, ram_pages +# Poll status register while busy. + +1: in al, 0x64 + test al, 0x2 + jnz 1b + +# Send command for writing output port. + + mov al, 0xd1 + outb 0x64, al + +# Poll status register while busy. + +1: in al, 0x64 + test al, 0x2 + jnz 1b + +# Enable A20 line. + + mov al, 0xdf + out 0x60, al + +#### Get memory size, via interrupt 15h function 88h, which returns CF +#### clear if successful, with AX = (kB of physical memory) - 1024. +#### This only works for memory sizes <= 65 MB, which should be fine +#### for our purposes. We cap memory at 64 MB because that's all we +#### prepare page tables for, below. -#### switch from real to protected mode -#### The segments in GDT allow all of physical memory to be accessed. -#### Furthermore, the segments have base addresses of 0, so that the -#### segment translation is a NOP, ie. virtual addresses are identical to -#### their physical addresses. With this setup, it appears to this code -#### that it is running directly on physical memory. + mov ah, 0x88 + int 0x15 + jc panic + cli # BIOS might have enabled interrupts + add eax, 1024 # Total kB memory + cmp eax, 0x10000 # Cap at 64 MB + jbe 1f + mov eax, 0x10000 +1: shr eax, 2 # Total 4 kB pages + mov ram_pgs, eax - cli # Mandatory since we dont set up an IDT - lgdt gdtdesc # load GDT -- mandatory in protected mode - movl %cr0, %eax # turn on protected mode - orl $CR0_PE, %eax # - movl %eax, %cr0 # - ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs - ### Has the effect of just jmp to the next instruction, but simultaneous - ### loads CS with $PROT_MODE_CSEG. - ljmp $SEL_KCSEG, $protcseg +#### Create temporary page directory and page table and set page +#### directory base register. + +# Create page directory at 64 kB and fill with zeroes. + mov ax, 0x1000 + mov es, ax + sub eax, eax + sub edi, edi + mov ecx, 0x400 + rep stosd + +# Add PDEs to point to PTEs for the first 64 MB of RAM. +# Also add identical PDEs starting at LOADER_PHYS_BASE. +# See [IA32-v3] section 3.7.6 for a description of the bits in eax. + +# A bug in some versions of GAS prevents us from using the straightforward +# mov es:[di + LOADER_PHYS_BASE / 1024 / 1024], eax +# so we calculate the displacement in bx instead. + + mov eax, 0x11007 + mov ecx, 0x11 + sub di, di + mov ebx, LOADER_PHYS_BASE + shr ebx, 20 +1: mov es:[di], eax + mov es:[bx + di], eax + add di, 4 + add eax, 0x1000 + loop 1b + +# Set up one-to-map linear to physical map for the first 64 MB of RAM. +# See [IA32-v3] section 3.7.6 for a description of the bits in eax. + + mov ax, 0x1100 + mov es, ax + mov eax, 0x7 + mov cx, 0x4000 + sub di, di +1: mov es:[di], eax + add di, 4 + add eax, 0x1000 + loop 1b + +# Set page directory base register. + + mov eax, 0x10000 + mov cr3, eax -#### We are in protected mode in a 32-bit segment (hence the .code32) -protcseg: - .code32 - movw $SEL_KDSEG, %ax # set up data segment registers - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %ax, %ss - -#### Load kernel at 1 MB by frobbing the IDE controller directly. - - movl $1, %ebx - movl $0x100000, %edi -read_sector: - movl $0x1f7, %edx -1: inb %dx, %al - testb $0x80, %al - jnz 1b +#### Switch to protected mode. + +# Then we point the GDTR to our GDT. Protected mode requires a GDT. +# We need a data32 prefix to ensure that all 32 bits of the GDT +# descriptor are loaded (default is to load only 24 bits). + + data32 lgdt gdtdesc + +# Then we turn on the following bits in CR0: +# PE (Protect Enable): this turns on protected mode. +# PG (Paging): turns on paging. +# WP (Write Protect): if unset, ring 0 code ignores +# write-protect bits in page tables (!). +# EM (Emulation): forces floating-point instructions to trap. +# We don't support floating point. - movl $0x1f2, %edx - movb $1, %al - outb %al, %dx - - movl %ebx, %eax - andl $0x0fffffff, %eax - orl $0xe0000000, %eax - - movl $4, %ecx -2: incl %edx - outb %al, %dx - shrl $8, %eax - loop 2b - - incw %dx - movb $0x20, %al - outb %al, %dx + mov eax, cr0 + or eax, CR0_PE + CR0_PG + CR0_WP + CR0_EM + mov cr0, eax -1: inb %dx, %al - testb $0x80, %al +# We're now in protected mode in a 16-bit segment. The CPU still has +# the real-mode code segment cached in cs's segment descriptor. We +# need to reload cs, and the easiest way is to use a far jump. +# Because we're not in a 32-bit segment the data32 prefix is needed to +# jump to a 32-bit offset. + + data32 ljmp SEL_KCSEG, 1f + LOADER_PHYS_BASE + +# We're now in protected mode in a 32-bit segment. + + .code32 + +# Reload all the other segment registers and the stack pointer to +# point into our new GDT. + +1: mov ax, SEL_KDSEG + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, LOADER_PHYS_BASE + 0x30000 + +#### Load kernel starting at physical address LOADER_KERN_BASE by +#### frobbing the IDE controller directly. + + mov ebx, 1 + mov edi, LOADER_KERN_BASE + LOADER_PHYS_BASE +read_sector: + +# Poll status register while controller busy. + + mov edx, 0x1f7 +1: in al, dx + test al, 0x80 jnz 1b - movl $512 / 4, %ecx - movl $0x1f0, %edx - rep insl +# Read a single sector. - incl %ebx - cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx - jnz read_sector + mov edx, 0x1f2 + mov al, 1 + out dx, al + +# Sector number to write in low 28 bits. +# LBA mode, device 0 in top 4 bits. + + mov eax, ebx + and eax, 0x0fffffff + or eax, 0xe0000000 + +# Dump eax to ports 0x1f3...0x1f6. -##### Create temporary PDE and PTE and set page directory pointer -##### FIXME? We could use a single 4 MB page instead of 1024 4 kB pages. - - movl $0x10000, %edi - movl %edi, %cr3 - subl %eax, %eax - movl $0x400, %ecx - rep stosl - movl $0x11000 | PG_U | PG_W | PG_P, %eax - movl %eax, 0x10000 - movl %eax, 0x10c00 - movl $PG_U | PG_W | PG_P, %eax - movl $0x400, %ecx -1: stosl - addl $0x1000, %eax + mov ecx, 4 +1: inc dx + out dx, al + shr eax, 8 loop 1b -##### Enable paging. +# READ command to command register. - movl %cr0, %eax - orl $CR0_PG, %eax - movl %eax, %cr0 - jmp 1f -1: - -##### Jump to kernel entry point. + inc dx + mov al, 0x20 + out dx, al + +# Poll status register while controller busy. + +1: in al, dx + test al, 0x80 + jnz 1b + +# Poll status register until data ready. + +1: in al, dx + test al, 0x08 + jz 1b + +# Transfer sector. + + mov ecx, 256 + mov edx, 0x1f0 + rep insw - movl $0xc0007c00, %esp - movl $0xc0100000, %eax - jmp *%eax +# Next sector. -##### GDT + inc ebx + cmp ebx, KERNEL_LOAD_PAGES*8 + 1 + jnz read_sector + +#### Jump to kernel entry point. + + mov eax, LOADER_PHYS_BASE + LOADER_KERN_BASE + call eax + jmp panic + +#### GDT gdt: .quad 0x0000000000000000 # null seg @@ -154,16 +298,42 @@ gdt: gdtdesc: .word 0x17 # sizeof (gdt) - 1 - .long gdt # address gdt + .long gdt + LOADER_PHYS_BASE # address gdt -##### Arrive here on error -panic: jmp panic +#### Fatal error. +#### Print panicmsg (with help from the BIOS) and spin. + +panic: .code16 # We only panic in real mode. + mov si, offset panic_message + mov ah, 0xe + sub bh, bh +1: lodsb + test al, al +2: jz 2b # Spin. + int 0x10 + jmp 1b + +panic_message: + .ascii "Panic!" + .byte 0 + +#### Physical memory size in 4 kB pages. +#### This is initialized by the loader and read by the kernel. + .org LOADER_RAM_PGS - LOADER_BASE +ram_pgs: + .long 0 -##### Memory size in 4 kB pages. - .org 0x200 - 8 -ram_pages: +#### Command-line arguments and their count. +#### This is written by the `pintos' utility and read by the kernel. +#### The loader itself does not do anything with the command line. + .org LOADER_ARG_CNT - LOADER_BASE +arg_cnt: .long 0 + .org LOADER_ARGS - LOADER_BASE +args: + .fill 0x80, 1, 0 -##### Boot-sector signature for BIOS inspection. - .org 0x200 - 2 +#### Boot-sector signature. +#### The BIOS checks that this is set properly. + .org LOADER_SIG - LOADER_BASE .word 0xaa55