X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Floader.S;h=aeb58bc9fd55b572d670fe5087fbd5bdbdb96c06;hb=0550d2e705c042d659a7fab480431c62cb26213d;hp=d1e8309c5f194ec47ca996cf7c7c00fae1e96013;hpb=a929199f73fce9d810c633dff21e2ed7b03bc16c;p=pintos-anon diff --git a/src/threads/loader.S b/src/threads/loader.S index d1e8309..aeb58bc 100644 --- a/src/threads/loader.S +++ b/src/threads/loader.S @@ -1,328 +1,207 @@ -/* 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" + .intel_syntax noprefix + #### 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. - -/* 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. */ +# Runs in real mode, which is a 16-bit segment. + .code16 -# Code runs in real mode, which is a 16-bit segment. +# Set up segment registers. +# Stack grows downward starting from us. .globl start start: - .code16 - -# Disable interrupts. -# String instructions go upward. - - cli + sub ax, ax + mov ds, ax + mov ss, ax + mov sp, 0x7c00 cld -# Set up data segments and stack. - - subw %ax, %ax - movw %ax, %es - movw %ax, %ds - -# Stack grows downward starting from us. -# We don't ever use the stack so this is strictly speaking -# unnecessary. - - movw %ax, %ss - movw $0x7c00, %sp + mov ax, 0x00e3 + sub dx, dx + int 0x14 + +# Scan floppy disks. + + sub dl, dl + sub ebx, ebx + mov eax, 0x7e00 + mov es, ax +1: call scan_partitions + inc dl + jnc 1b + +# Scan hard disks. + mov dl, 0x80 +1: call outw + call scan_partitions + inc dl + jnc 1b + +1: jmp 1b + +scan_partitions: + # EBX = sector number of partition table + # DL = drive number + # ES:0000 -> buffer for partition table + # Returns CF set if drive does not exist, CF clear otherwise. + call read_sector + jc no_such_drive -#### Enable A20. Address line 20 is tied to low when the machine -#### boots, which prevents addressing memory about 1 MB. This code -#### fixes it. +2: pusha + mov edx, [es:508] + call outw + popa -# Poll status register while busy. - -1: inb $0x64, %al - testb $0x2, %al - jnz 1b - -# Send command for writing output port. - - movb $0xd1, %al - outb %al, $0x64 - -# Poll status register while busy. - -1: inb $0x64, %al - testb $0x2, %al - jnz 1b - -# Enable A20 line. - - movb $0xdf, %al - outb %al, $0x60 - -#### 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. We cap memory at 64 MB because that's all we -#### prepare page tables for, below. + cmp word ptr [es:510], 0xaa55 + jnz no_boot_partition - movb $0x88, %ah - int $0x15 - jc panic - addl $1024, %eax # Total kB memory - cmp $0x10000, %eax # Cap at 64 MB - jbe 1f - mov $0x10000, %eax -1: shrl $2, %eax # Total 4 kB pages - movl %eax, ram_pages - -#### Create temporary page directory and page table and set page -#### directory base register. - -# Create page directory at 64 kB and fill with zeroes. - mov $0x1000, %ax - mov %ax, %es - subl %eax, %eax - subl %edi, %edi - movl $0x400, %ecx - rep stosl - -# 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. - - movl $0x11007, %eax - movl $0x11, %ecx - subl %edi, %edi -1: movl %eax, %es:(%di) - movl %eax, %es:LOADER_PHYS_BASE >> 20(%di) - addw $4, %di - addl $0x1000, %eax + mov si, 446 +1: mov al, [es:si+4] + cmp al, 0x20 + jz found_boot_partition + cmp al, 0x05 + jz found_extended_partition + cmp al, 0x0f + jz found_extended_partition + cmp al, 0x85 + jz found_extended_partition + cmp al, 0xc5 + jz found_extended_partition +next_parttbl_entry: + add si, 16 + cmp si, 510 + jb 1b + +no_boot_partition: + clc + ret +no_such_drive: + stc + ret + +found_extended_partition: + # DL = drive number. + # ES:SI -> partition table entry for extended partition. + # Recursively examine it. + pusha + mov ebx, es:[si+8] + mov ax, es + add ax, 0x20 + mov es, ax + call scan_partitions + popa + jmp next_parttbl_entry + +found_boot_partition: + mov ebx, [es:si+8] # EBX = first sector + mov cx, [es:si+12] # CX = number of sectors + mov ax, 0x1000 # ES:0000 -> load address + mov es, ax +1: call read_sector + add ax, 0x20 + mov es, ax 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. - - movw $0x1100, %ax - movw %ax, %es - movl $0x7, %eax - movl $0x4000, %ecx - subl %edi, %edi -1: movl %eax, %es:(%di) - addw $4, %di - addl $0x1000, %eax - loop 1b + ljmp 0x1000, 0 -# Set page directory base register. - - movl $0x10000, %eax - movl %eax, %cr3 - -#### Switch to protected mode. - -# First we turn off interrupts because we don't set up an IDT. - - cli - -# 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 %cr0, %eax - orl $CR0_PE | CR0_PG | CR0_WP | CR0_EM, %eax - movl %eax, %cr0 + # ebx: sector number + # dl: drive number + # es:0000: destination buffer + # returns error flag in CF +read_sector: + pusha + or dl, dl # Floppy drives: DL >= 0 + jns read_floppy_sector + +read_harddrv_sector: + sub eax, eax + push eax # LBA sector number [32:63] + push ebx # LBA sector number [0:31] + push es + push 0 + push 1 # Transfer one sector + push 16 # Packet size + mov ah, 0x42 # Extended read + mov si, sp # DS:SI -> packet + int 0x13 # Error code in CF + lahf + add sp, 16 + sahf +read_sector_done: + popa + ret # Error code in CF + +read_floppy_sector: + #define HEADS 2 + #define SECTORS 36 + + # In: BX = LBA sector number, DL = drive. + # Out: BL = drive, DX = cylinder, AL = head, AH = sector. + sub ax, ax + xchg dx, bx # DX = LBA sector number, BL = drive + mov cx, HEADS * SECTORS + div cx # AX = cyl, DX = hd + (sec-1) * SECTORS + xchg ax, dx # DX = cyl, AX = hd + (sec-1) * SECTORS + mov cl, SECTORS + div cl # AL = head, AH = sector - 1 + inc ah + + # Read sector. + mov ch, dl # CH = cylinder + mov cl, ah # CL = sector + mov dh, al # DH = head + mov dl, bl # DL = drive + mov ax, 0x0201 # AH = function, AL = sectors to read + sub bx, bx # ES:BX -> buffer + mov di, 3 # Number of tries left. -# 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 +try_read_floppy: + pusha + int 0x13 + popa + jnc read_sector_done + dec di + jnz 1f + stc + jmp read_sector_done + +1: # Reset floppy drive motor, try again. + pusha + sub ah, ah + int 0x13 + popa + jmp try_read_floppy + +outw: pushf + pusha -# 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: movw $SEL_KDSEG, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - movw %ax, %ss - movl $LOADER_PHYS_BASE + 0x30000, %esp - -#### Load kernel starting at physical address LOADER_KERN_BASE by -#### frobbing the IDE controller directly. - - movl $1, %ebx - movl $LOADER_KERN_BASE + LOADER_PHYS_BASE, %edi -read_sector: - -# Poll status register while controller busy. - - movl $0x1f7, %edx -1: inb %dx, %al - testb $0x80, %al - jnz 1b - -# Read a single sector. - - movl $0x1f2, %edx - movb $1, %al - outb %al, %dx - -# Sector number to write in low 28 bits. -# LBA mode, device 0 in top 4 bits. - - movl %ebx, %eax - andl $0x0fffffff, %eax - orl $0xe0000000, %eax - -# Dump %eax to ports 0x1f3...0x1f6. - - movl $4, %ecx -1: incw %dx - outb %al, %dx - shrl $8, %eax + mov cx, 8 + mov ebx, edx + mov dx, 0xe9 +1: rol ebx, 4 + mov al, bl + and al, 15 + add al, '0' + cmp al, '9' + jbe 2f + add al, 'a' - '0' - 10 +2: out dx, al loop 1b -# READ command to command register. - - incw %dx - movb $0x20, %al - outb %al, %dx + mov al, '\n' + out dx, al -# Poll status register while controller busy. - -1: inb %dx, %al - testb $0x80, %al - jnz 1b - -# Poll status register until data ready. - -1: inb %dx, %al - testb $0x08, %al - jz 1b - -# Transfer sector. - - movl $256, %ecx - movl $0x1f0, %edx - rep insw - -# Next sector. - - incl %ebx - cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx - jnz read_sector - -#### Jump to kernel entry point. - - movl $LOADER_PHYS_BASE + LOADER_KERN_BASE, %eax - call *%eax - jmp panic - -#### GDT - -gdt: - .quad 0x0000000000000000 # null seg - .quad 0x00cf9a000000ffff # code seg - .quad 0x00cf92000000ffff # data seg + popa + popf + ret + +#### The partition table goes here. + .org 446 +part_tbl: -gdtdesc: - .word 0x17 # sizeof (gdt) - 1 - .long gdt + LOADER_PHYS_BASE # address gdt - -#### Fatal error. -#### Print panicmsg (with help from the BIOS) and spin. - -panic: .code16 # We only panic in real mode. - movw $panicmsg, %si - movb $0xe, %ah - subb %bh, %bh -1: lodsb - test %al, %al -2: jz 2b # Spin. - int $0x10 - jmp 1b - -panicmsg: - .ascii "Loader panic!\r\n" - .byte 0 - -#### Memory size in 4 kB pages. - .org LOADER_RAM_PAGES - LOADER_BASE -ram_pages: - .long 0 - -#### Command-line arguments inserted by another utility. -#### The loader doesn't use these, but we note their -#### location here for easy reference. - .org LOADER_CMD_LINE - LOADER_BASE -cmd_line: - .fill 0x80, 1, 0 #### Boot-sector signature for BIOS inspection. - .org LOADER_BIOS_SIG - LOADER_BASE + .org 510 .word 0xaa55