]> Devi Nivas Git - cs3210-lab1.git/commitdiff
Forgot to add bootblock...
authorDavid Devecsery <ddevec@gatech.edu>
Mon, 18 May 2020 14:50:56 +0000 (10:50 -0400)
committerDavid Devecsery <ddevec@gatech.edu>
Mon, 18 May 2020 14:50:56 +0000 (10:50 -0400)
bootblock/CMakeLists.txt [new file with mode: 0644]
bootblock/bootasm.S [new file with mode: 0644]
bootblock/bootmain.c [new file with mode: 0644]
bootblock/tools/sign.pl [new file with mode: 0755]

diff --git a/bootblock/CMakeLists.txt b/bootblock/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5e0f66c
--- /dev/null
@@ -0,0 +1,49 @@
+project(bootblock ASM)
+
+include_directories(include)
+
+set(bootblock_SOURCES
+  # NOTE: bootasm.S must go first in this list, to ensure its placed at 0x7c00
+  #   in the bootloader dump
+  bootasm.S
+  bootmain.c)
+
+add_library(bootblockobjs OBJECT
+  ${bootblock_SOURCES})
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -fno-builtin -fno-pic -nostdinc -m32")
+set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m elf_i386")
+
+# Always force -Os for bootblock
+set(CMAKE_C_FLAGS_RELEASE "-Os")
+set(CMAKE_C_FLAGS_DEBUG "-Os -ggdb3")
+
+add_prefix_suffix(bootblock_OBJECTS
+  "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/bootblockobjs.dir/"
+  ".o"
+  ${bootblock_SOURCES})
+
+add_custom_command(
+  OUTPUT bootblock.obj
+  COMMAND ${CMAKE_LINKER} -m elf_i386 -N -e start -Ttext 0x7C00 -o ${CMAKE_CURRENT_BINARY_DIR}/bootblock.obj ${bootblock_OBJECTS}
+  DEPENDS $<TARGET_OBJECTS:bootblockobjs>)
+
+add_custom_command(
+  OUTPUT bootblock
+  COMMAND objcopy -S -O binary -j .text bootblock.obj bootblock
+  COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/sign.pl bootblock
+  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bootblock.obj)
+
+add_custom_command(
+  OUTPUT bootblock.asm 
+  COMMAND objdump -S bootblock.obj > bootblock.asm
+  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bootblock.obj)
+
+add_custom_target(
+  buildboot ALL
+  DEPENDS bootblockobjs bootblock.asm bootblock)
+
+set_property(TARGET bootblockobjs PROPERTY C_STANDARD 11)
+
+
diff --git a/bootblock/bootasm.S b/bootblock/bootasm.S
new file mode 100644 (file)
index 0000000..120296f
--- /dev/null
@@ -0,0 +1,88 @@
+#include "asm/asm.h"
+#include "memlayout.h"
+#include "mmu.h"
+
+# Start the first CPU: switch to 32-bit protected mode, jump into C.
+# The BIOS loads this code from the first sector of the hard disk into
+# memory at physical address 0x7c00 and starts executing in real mode
+# with %cs=0 %ip=7c00.
+
+.code16                       # Assemble for 16-bit mode
+.globl start
+start:
+  cli                         # BIOS enabled interrupts; disable
+
+  # Zero data segment registers DS, ES, and SS.
+  xorw    %ax,%ax             # Set %ax to zero
+  movw    %ax,%ds             # -> Data Segment
+  movw    %ax,%es             # -> Extra Segment
+  movw    %ax,%ss             # -> Stack Segment
+
+  # Physical address line A20 is tied to zero so that the first PCs 
+  # with 2 MB would run software that assumed 1 MB.  Undo that.
+seta20.1:
+  inb     $0x64,%al               # Wait for not busy
+  testb   $0x2,%al
+  jnz     seta20.1
+
+  movb    $0xd1,%al               # 0xd1 -> port 0x64
+  outb    %al,$0x64
+
+seta20.2:
+  inb     $0x64,%al               # Wait for not busy
+  testb   $0x2,%al
+  jnz     seta20.2
+
+  movb    $0xdf,%al               # 0xdf -> port 0x60
+  outb    %al,$0x60
+
+  # Switch from real to protected mode.  Use a bootstrap GDT that makes
+  # virtual addresses map directly to physical addresses so that the
+  # effective memory map doesn't change during the transition.
+  lgdt    gdtdesc
+  movl    %cr0, %eax
+  orl     $CR0_PE, %eax
+  movl    %eax, %cr0
+
+//PAGEBREAK!
+  # Complete the transition to 32-bit protected mode by using a long jmp
+  # to reload %cs and %eip.  The segment descriptors are set up with no
+  # translation, so that the mapping is still the identity mapping.
+  ljmp    $(SEG_KCODE<<3), $start32
+
+.code32  # Tell assembler to generate 32-bit code now.
+start32:
+  # Set up the protected-mode data segment registers
+  movw    $(SEG_KDATA<<3), %ax    # Our data segment selector
+  movw    %ax, %ds                # -> DS: Data Segment
+  movw    %ax, %es                # -> ES: Extra Segment
+  movw    %ax, %ss                # -> SS: Stack Segment
+  movw    $0, %ax                 # Zero segments not ready for use
+  movw    %ax, %fs                # -> FS
+  movw    %ax, %gs                # -> GS
+
+  # Set up the stack pointer and call into C.
+  movl    $start, %esp
+  call    bootmain
+
+  # If bootmain returns (it shouldn't), trigger a Bochs
+  # breakpoint if running under Bochs, then loop.
+  movw    $0x8a00, %ax            # 0x8a00 -> port 0x8a00
+  movw    %ax, %dx
+  outw    %ax, %dx
+  movw    $0x8ae0, %ax            # 0x8ae0 -> port 0x8a00
+  outw    %ax, %dx
+spin:
+  jmp     spin
+
+# Bootstrap GDT
+.p2align 2                                # force 4 byte alignment
+gdt:
+  SEG_NULLASM                             # null seg
+  SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)   # code seg
+  SEG_ASM(STA_W, 0x0, 0xffffffff)         # data seg
+
+gdtdesc:
+  .word   (gdtdesc - gdt - 1)             # sizeof(gdt) - 1
+  .long   gdt                             # address gdt
+
diff --git a/bootblock/bootmain.c b/bootblock/bootmain.c
new file mode 100644 (file)
index 0000000..737fb15
--- /dev/null
@@ -0,0 +1,96 @@
+// Boot loader.
+//
+// Part of the boot block, along with bootasm.S, which calls bootmain().
+// bootasm.S has put the processor into protected 32-bit mode.
+// bootmain() loads an ELF kernel image from the disk starting at
+// sector 1 and then jumps to the kernel entry routine.
+
+#include "asm/x86.h"
+#include "elf.h"
+#include "memlayout.h"
+#include "types.h"
+
+#define SECTSIZE  512
+
+void readseg(uchar*, uint, uint);
+
+void
+bootmain(void)
+{
+  struct elfhdr *elf;
+  struct proghdr *ph, *eph;
+  void (*entry)(void);
+  uchar* pa;
+
+  elf = (struct elfhdr*)0x10000;  // scratch space
+
+  // Read 1st page off disk
+  readseg((uchar*)elf, 4096, 0);
+
+  // Is this an ELF executable?
+  if(elf->magic != ELF_MAGIC)
+    return;  // let bootasm.S handle error
+
+  // Load each program segment (ignores ph flags).
+  ph = (struct proghdr*)((uchar*)elf + elf->phoff);
+  eph = ph + elf->phnum;
+  for(; ph < eph; ph++){
+    pa = (uchar*)ph->paddr;
+    readseg(pa, ph->filesz, ph->off);
+    if(ph->memsz > ph->filesz)
+      stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz);
+  }
+
+  // Call the entry point from the ELF header.
+  // Does not return!
+  entry = (void(*)(void))(elf->entry);
+  entry();
+}
+
+void
+waitdisk(void)
+{
+  // Wait for disk ready.
+  while((inb(0x1F7) & 0xC0) != 0x40)
+    ;
+}
+
+// Read a single sector at offset into dst.
+void
+readsect(void *dst, uint offset)
+{
+  // Issue command.
+  waitdisk();
+  outb(0x1F2, 1);   // count = 1
+  outb(0x1F3, offset);
+  outb(0x1F4, offset >> 8);
+  outb(0x1F5, offset >> 16);
+  outb(0x1F6, (offset >> 24) | 0xE0);
+  outb(0x1F7, 0x20);  // cmd 0x20 - read sectors
+
+  // Read data.
+  waitdisk();
+  insl(0x1F0, dst, SECTSIZE/4);
+}
+
+// Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
+// Might copy more than asked.
+void
+readseg(uchar* pa, uint count, uint offset)
+{
+  uchar* epa;
+
+  epa = pa + count;
+
+  // Round down to sector boundary.
+  pa -= offset % SECTSIZE;
+
+  // Translate from bytes to sectors; kernel starts at sector 1.
+  offset = (offset / SECTSIZE) + 1;
+
+  // If this is too slow, we could read lots of sectors at a time.
+  // We'd write more to memory than asked, but it doesn't matter --
+  // we load in increasing order.
+  for(; pa < epa; pa += SECTSIZE, offset++)
+    readsect(pa, offset);
+}
diff --git a/bootblock/tools/sign.pl b/bootblock/tools/sign.pl
new file mode 100755 (executable)
index 0000000..d793035
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+
+open(SIG, $ARGV[0]) || die "open $ARGV[0]: $!";
+
+$n = sysread(SIG, $buf, 1000);
+
+if($n > 510){
+  print STDERR "boot block too large: $n bytes (max 510)\n";
+  exit 1;
+}
+
+print STDERR "boot block is $n bytes (max 510)\n";
+
+$buf .= "\0" x (510-$n);
+$buf .= "\x55\xAA";
+
+open(SIG, ">$ARGV[0]") || die "open >$ARGV[0]: $!";
+print SIG $buf;
+close SIG;