-#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.
-
-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.
-
- 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
-
-#### 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.
-
- 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
-
-#### 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:
-
- ### 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
-2: incw %dx
- outb %al, %dx
- shrl $8, %eax
- loop 2b
-
- ### READ command to command register.
- incw %dx
- movb $0x20, %al
- outb %al, %dx
-
- ### 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 $512 / 4, %ecx
- movl $0x1f0, %edx
- rep insl
-
- ### Next sector.
- incl %ebx
- cmpl $KERNEL_LOAD_PAGES*8 + 1, %ebx
- jnz read_sector
-
-##### 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
- loop 1b
-
-##### Enable paging.
+/* 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. */
- movl %cr0, %eax
- orl $CR0_PG, %eax
- movl %eax, %cr0
- jmp 1f
-1:
-
-##### Jump to kernel entry point.
+# Code runs in real mode, which is a 16-bit segment.
- movl $0xc0007c00, %esp
- movl $0xc0100000, %eax
- jmp *%eax
+.globl start
+start:
+ .code16
-##### GDT
+# Set up segment registers.
+# Stack grows downward starting from us.
-gdt:
- .quad 0x0000000000000000 # null seg
- .quad 0x00cf9a000000ffff # code seg
- .quad 0x00cf92000000ffff # data seg
+ sub ax, ax
+ mov ds, ax
+ mov ss, ax
+ mov sp, 0x7c00
+
+# 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 scan_partitions
+ inc dl
+ jnc 1b
+
+ call panic
+ .asciz "No boot partition"
+
+scan_partitions:
+ # EBX = sector number of partition table
+ # DL = drive number
+ # ES:0000 -> buffer for partition table
+ # Returns CF set if drive exists, CF clear otherwise.
+ call read_sector
+ jnc no_such_drive
+2: cmp word ptr [es:510], 0xaa55
+ jnz no_boot_partition
-gdtdesc:
- .word 0x17 # sizeof (gdt) - 1
- .long gdt # address gdt
+ 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
-##### Arrive here on error
-panic: jmp panic
+ ljmp 0x1000, 0
-##### Memory size in 4 kB pages.
- .org 0x200 - 8
-ram_pages:
- .long 0
+ # 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
+ js read_floppy_sector
+
+read_harddrv_sector:
+ sub eax, eax
+ push eax # LBA sector number [32:63]
+ push ebx # LBA sector number [0:31]
+ mov ax, es
+ shl eax, 4
+ push eax # Buffer linear address
+ 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
+success:
+ 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
+ pusha
+ int 0x13
+ popa
+ jnc success
+
+ # Reset floppy drive motor, try again.
+ sub ah, ah
+ int 0x13
+ popa
+ jmp read_sector
+
+#### The partition table goes here.
+ .org 446
+part_tbl:
-##### Boot-sector signature for BIOS inspection.
- .org 0x200 - 2
+#### Boot-sector signature for BIOS inspection.
+ .org 510
.word 0xaa55