Commit db1c4ebc authored by James Foster's avatar James Foster

* Ignore VSCode artifacts

* Capture new PID from fork (nice for debugging)
* Start debugger paused so we can debug the startup process
* Reformat GNUmakefile to highlight similarities in the disk images created
* Update README.md to clarify that we build two disk images
* Use `%bl` when notifying BIOS of Long Mode
* Correct filenames in comments
* Add comments to describe boot process
* Add function to test memory mapping size
* Explain that `panic()` will produce a page fault if there is no console
* Debug CHICKADEE_FIRST_PROCESS
* Use spinlock for logging to avoid interleaving output
parent 2e1d8076
......@@ -32,3 +32,4 @@ tags
tags.*
typescript
vgcore*
.vscode*
......@@ -87,10 +87,14 @@ CHICKADEE_FIRST_PROCESS ?= allocator
ifneq ($(strip $(CHICKADEE_FIRST_PROCESS)),$(DEP_CHICKADEE_FIRST_PROCESS))
FIRST_PROCESS_BUILDSTAMP := $(shell echo "DEP_CHICKADEE_FIRST_PROCESS:=$(CHICKADEE_FIRST_PROCESS)" > $(DEPSDIR)/_first_process.d)
$(OBJDIR)/k-firstprocess.h: always
$(OBJDIR)/chickadee.gdb: always
endif
ifeq ($(wildcard $(OBJDIR)/k-firstprocess.h),)
KERNELBUILDSTAMPS += $(OBJDIR)/k-firstprocess.h
endif
ifeq ($(wildcard $(OBJDIR)/chickadee.gdb),)
KERNELBUILDSTAMPS += $(OBJDIR)/chickadee.gdb
endif
# How to make object files
......@@ -128,6 +132,9 @@ $(OBJDIR)/u-asm.h: u-lib.hh lib.hh types.h x86-64.h build/mkkernelasm.awk $(BUIL
$(OBJDIR)/k-firstprocess.h:
$(call run,echo '#ifndef CHICKADEE_FIRST_PROCESS' >$@; echo '#define CHICKADEE_FIRST_PROCESS "$(CHICKADEE_FIRST_PROCESS)"' >>$@; echo '#endif' >>$@,CREATE $@)
$(OBJDIR)/chickadee.gdb:
$(call run,echo 'add-symbol-file obj/p-$(CHICKADEE_FIRST_PROCESS).full 0x100000' >$@,CREATE $@)
$(OBJDIR)/k-initfs.cc: build/mkinitfs.awk \
$(INITFS_CONTENTS) $(INITFS_BUILDSTAMP) $(KERNELBUILDSTAMPS)
$(call run,echo $(INITFS_CONTENTS) $(INITFS_PARAMS) | awk -f build/mkinitfs.awk >,CREATE,$@)
......@@ -190,13 +197,17 @@ $(OBJDIR)/chickadeefsck: $(CHICKADEEFSCK_OBJS) $(BUILDSTAMPS)
# How to make disk images
# If you change the `-f` argument, also change `boot.cc:KERNEL_START_SECTOR`
chickadeeboot.img: $(OBJDIR)/mkchickadeefs $(OBJDIR)/bootsector $(OBJDIR)/kernel
$(call run,$(OBJDIR)/mkchickadeefs -b 4096 -f 16 -s $(OBJDIR)/bootsector $(OBJDIR)/kernel > $@,CREATE $@)
chickadeefs.img: $(OBJDIR)/mkchickadeefs \
$(OBJDIR)/bootsector $(OBJDIR)/kernel $(DISKFS_CONTENTS) \
$(DISKFS_BUILDSTAMP)
$(call run,$(OBJDIR)/mkchickadeefs -b 32768 -f 16 -j 64 -s $(OBJDIR)/bootsector $(OBJDIR)/kernel $(DISKFS_CONTENTS) > $@,CREATE $@)
# The following two sections have been formatted to highlight their similarities
chickadeeboot.img: $(OBJDIR)/mkchickadeefs \
$(OBJDIR)/bootsector $(OBJDIR)/kernel
$(call run,$(OBJDIR)/mkchickadeefs -b 4096 -f 16 -s \
$(OBJDIR)/bootsector $(OBJDIR)/kernel > $@,CREATE $@)
chickadeefs.img: $(OBJDIR)/mkchickadeefs \
$(OBJDIR)/bootsector $(OBJDIR)/kernel \
$(DISKFS_CONTENTS) $(DISKFS_BUILDSTAMP)
$(call run,$(OBJDIR)/mkchickadeefs -b 32768 -f 16 -j 64 -s \
$(OBJDIR)/bootsector $(OBJDIR)/kernel $(DISKFS_CONTENTS) > $@,CREATE $@)
cleanfs:
$(call run,rm -f chickadeefs.img,RM chickadeefs.img)
......@@ -226,11 +237,11 @@ run-monitor: $(QEMUIMAGEFILES) check-qemu
$(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) -monitor stdio $(QEMUIMG),QEMU $<)
run-gdb: run-gdb-$(QEMUDISPLAY)
@:
run-gdb-console: $(QEMUIMAGEFILES) check-qemu-console
$(call run,$(QEMU) $(QEMUOPT) -curses -S -gdb tcp::12949 $(QEMUIMG),QEMU $<)
run-gdb-graphic: $(QEMUIMAGEFILES) check-qemu
$(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) -gdb tcp::12949 $(QEMUIMG) &,QEMU $<)
$(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) -S -gdb tcp::12949 $(QEMUIMG) &,QEMU $<)
$(call run,sleep 0.5; gdb -x build/chickadee.gdb,GDB)
run-gdb-console: $(QEMUIMAGEFILES) check-qemu-console
$(call run,$(QEMU) $(QEMUOPT) -curses -gdb tcp::12949 $(QEMUIMG),QEMU $<)
run-$(RUNSUFFIX): run
run-graphic-$(RUNSUFFIX): run-graphic
......
......@@ -25,7 +25,11 @@ and CPU resets to the standard error. This setting will also cause QEMU to
quit after encountering a [triple fault][] (normally it will reboot).
`make run-PROGRAM` runs `p-PROGRAM.cc` as the first non-init process. The
default is `alloc`.
default is `allocator`. If you choose an alternate first process, note a
couple things:
* An initial process like p-testkalloc.cc calls panic(), but without a console this gives a [page fault](https://github.com/CS161/chickadee/issues/14).
* build/chickadee.gdb is hard-coded to load symbols for p-allocator.cc, so this file must be [modified](https://github.com/CS161/chickadee/issues/13) if you want to debug an alternate process.
`make HALT=1 run-PROGRAM` should make QEMU exit once all processes are done.
......@@ -131,13 +135,14 @@ Source files
Build files
-----------
The main output of the build process is a disk image,
`chickadeeos.img`. QEMU “boots” off this disk image, but the image
could conceivably boot on real hardware! The build process also
The main outputs of the build process are two disk images, `chickadeeboot.img` and
`chickadeefs.img`. QEMU “boots” off a disk image, but the image
could conceivably boot on real hardware! The build process relies on and
produces other files that can be useful to examine.
| File | Description |
| -------------------------- | ------------------------------------ |
| `GNUmakefile` | Instructions on how to build things |
| `obj/kernel.asm` | Kernel assembly (with addresses) |
| `obj/kernel.sym` | Kernel defined symbols |
| `obj/p-PROCESS.asm`, `sym` | Same for process binaries |
......
......@@ -14,7 +14,7 @@
// the boot device (hard drive) into memory at address 0x7C00, and jumps to
// that address.
//
// The boot loader is contained in bootstart.S and boot.c. Control starts
// The boot loader is contained in bootstart.S and boot.cc. Control starts
// in bootstart.S, which initializes the CPU and sets up a stack, then
// transfers here. This code reads in the kernel image and calls the
// kernel.
......
......@@ -47,7 +47,7 @@ notify_bios64:
# Notify the BIOS (the machine's firmware) to optimize itself
# for x86-64 code. https://wiki.osdev.org/X86-64
movw $0xEC00, %ax
movw $2, %dx
mov $2, %bl
int $0x15
init_boot_pagetable:
......@@ -63,37 +63,48 @@ init_boot_pagetable:
# 0x2000: L3 page table; entries 0 and 510 map 1st 1GB of physmem
# This is the minimal page table that maps all of
# low-canonical, high-canonical, and kernel-text addresses to
# the first 1GB of physical memory.
# the first 1GB (?) of physical memory.
# (Not sure about the 1 GB number. Emperical tests show only 128 MB!)
movl $BOOT_PAGETABLE, %edi
leal 0x1000 + PTE_P + PTE_W(%edi), %ecx
leal 0x1000 + PTE_P + PTE_W(%edi), %ecx # combine address with flags
movl %ecx, (%edi)
movl %ecx, 0x800(%edi)
movl %ecx, 0xFF8(%edi)
# the offsets below are adjusted by -3 to remove the flags!
movl $(PTE_P + PTE_W + PTE_PS), -3(%ecx)
movl $(PTE_P + PTE_W + PTE_PS), 0xFED(%ecx)
# Switch from real to protected mode:
# Up until now, there's been no protection, so we've gotten along perfectly
# well without explicitly telling the processor how to translate addresses.
# When we switch to protected mode, this is no longer true!
# Switch from real mode (16-bit) to long mode (64-bit):
# Up until now, we have used direct physical memory addressing (real mode)
# without explicitly telling the processor how to translate addresses.
# When we enable paging, this is no longer true!
# We need at least to set up some "segments" that tell the processor it's
# OK to run code at any address, or write to any address.
# The `gdt` and `gdtdesc` tables below define these segments.
# This code loads them into the processor.
# We need this setup to ensure the transition to protected mode is smooth.
# See https://en.wikipedia.org/wiki/X86-64 for a nice diagram and description of processor modes.
real_to_prot:
real_to_long:
movl %cr4, %eax # enable physical address extensions
orl $(CR4_PSE | CR4_PAE), %eax
orl $(CR4_PAE), %eax # https://en.wikipedia.org/wiki/Physical_Address_Extension
movl %eax, %cr4
movl %edi, %cr3
movl $MSR_IA32_EFER, %ecx # turn on 64-bit mode
rdmsr
movl %edi, %cr3 # set the address of the page table
movl $MSR_IA32_EFER, %ecx # enable long mode (https://wiki.osdev.org/Setting_Up_Long_Mode)
rdmsr # read from the model-specific register into %eax
# IA32_EFER_LME is to enable 64-bit mode
# IA32_EFER_SCE is to enable syscall/sysret
# IA32_EFER_NXE is to allow PTE_XD (eXecute Disabled) in page table entries
orl $(IA32_EFER_LME | IA32_EFER_SCE | IA32_EFER_NXE), %eax
wrmsr
wrmsr # write %eax to the model-specific register
movl %cr0, %eax # turn on protected mode
movl %cr0, %eax # turn on some other features
# CR0_PE sets Protection Enable
# CR0_WP sets Write Protect
# CR0_PG sets CR0_PG
orl $(CR0_PE | CR0_WP | CR0_PG), %eax
movl %eax, %cr0
......
......@@ -2,7 +2,7 @@ set $loaded = 1
set arch i386:x86-64
file obj/kernel.full
add-symbol-file obj/bootsector.full 0x7c00
add-symbol-file obj/p-allocator.full 0x100000
source obj/chickadee.gdb
target remote localhost:12949
source build/functions.gdb
display/5i $pc
......@@ -175,6 +175,8 @@ void ahcistate::handle_error_interrupt() {
pr_->serror = ~0U;
pr_->command |= pcmd_start;
// XXX must `READ LOG EXT` to clear error
// Note that panic() will prouce a page fault if there is no console
// (https://github.com/CS161/chickadee/issues/14)
panic("SATA disk error");
}
......
......@@ -175,7 +175,11 @@ struct log_printer : public printer {
};
}
// things get ugly when multiple processes output at the same time!
static spinlock printLock;
void log_vprintf(const char* format, va_list val) {
spinlock_guard guard(printLock);
log_printer p;
p.vprintf(0, format, val);
}
......@@ -434,6 +438,8 @@ void __cxa_guard_release(long long* arg) {
// __cxa_pure_virtual()
// Used as a placeholder for pure virtual functions.
void __cxa_pure_virtual() {
// Note that panic() will prouce a page fault if there is no console
// (https://github.com/CS161/chickadee/issues/14)
panic("pure virtual function called in kernel!\n");
}
......
......@@ -70,6 +70,8 @@ void proc::init_kernel(pid_t pid, void (*f)()) {
// Called when `k-exception.S` tries to run a non-runnable proc.
void proc::panic_nonrunnable() {
// Note that panic() will prouce a page fault if there is no console
// (https://github.com/CS161/chickadee/issues/14)
panic("Trying to resume proc %d, which is not runnable\n"
"(proc state %d, recent user %%rip %p)",
id_, pstate_.load(), recent_user_rip_);
......
......@@ -34,6 +34,8 @@ void vmiter::down() {
pep_ = &pt->entry[pageindex(va_, level_)];
}
if ((*pep_ & PTE_PAMASK) >= 0x100000000UL) {
// Note that panic() will prouce a page fault if there is no console
// (https://github.com/CS161/chickadee/issues/14)
panic("Page table %p may contain uninitialized memory!\n"
"(Page table contents: %p)\n", pt_, *pep_);
}
......
......@@ -19,6 +19,7 @@ std::atomic<int> kdisplay;
static void tick();
static void boot_process_start(pid_t pid, const char* program_name);
void find_mapped_memory();
// kernel_start(command)
......@@ -26,6 +27,7 @@ static void boot_process_start(pid_t pid, const char* program_name);
// string is an optional string passed from the boot loader.
void kernel_start(const char* command) {
// find_mapped_memory(); // uncomment this to test the boot page table
init_hardware();
console_clear();
......@@ -431,3 +433,37 @@ void tick() {
memshow();
}
}
/* The comment at init_boot_pagetable in bootentry.s says that 1 GB of RAM
* is mapped. It appears that only 128 MB is mapped. That is, when we write
* to one address, can we find the value when we read from the other address?
* Disable optimizations so we can step through this in a debugger.
*/
#pragma GCC push_options
#pragma GCC optimize ("O0")
void find_mapped_memory() {
long lowCanonical = 0x0;
long highCanonical = 0xffff800000000000;
long kernel = 0xffffffff80000000;
char magic = 0x42;
for (long i = 0x7ffffff; i < 0x80000000; ++i) {
char* p1 = (char*) (lowCanonical + i);
char* p2 = ((char*) highCanonical + i);
char* p3 = ((char*) kernel + i);
*p1 = magic;
char c1 = *p1;
char c2 = *p2;
char c3 = *p3;
if (c1 != magic) {
*p2 = magic;
c2 = *p2;
c1 = *p1; // break here!
}
c1 = c2; // avoid compiler warnings
c2 = c3;
c3 = c1;
}
}
#pragma GCC pop_options
......@@ -243,7 +243,6 @@ struct bitset_view {
// System call numbers (passed in `%rax` at `syscall` time)
// Used in pset 1:
#define SYSCALL_GETPID 1
#define SYSCALL_YIELD 2
#define SYSCALL_PAUSE 3
......@@ -251,7 +250,6 @@ struct bitset_view {
#define SYSCALL_PANIC 5
#define SYSCALL_PAGE_ALLOC 6
#define SYSCALL_FORK 7
// Used in later psets:
#define SYSCALL_EXIT 8
#define SYSCALL_READ 9
#define SYSCALL_WRITE 10
......@@ -491,6 +489,8 @@ assert_memeq_fail(const char* file, int line, const char* msg,
// panic(format, ...)
// Print the message determined by `format` and fail.
// Note that panic() will prouce a page fault if there is no console
// (https://github.com/CS161/chickadee/issues/14)
void __attribute__((noinline, noreturn, cold))
panic(const char* format, ...);
......
......@@ -6,12 +6,19 @@ extern uint8_t end[];
uint8_t* heap_top;
uint8_t* stack_bottom;
// turn off optimization to facilitate debugging of forking new copies
#pragma GCC push_options
#pragma GCC optimize ("O0")
void process_main() {
sys_kdisplay(KDISPLAY_MEMVIEWER);
// Fork three new copies. (But ignore failures.)
(void) sys_fork();
(void) sys_fork();
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
pid_t pid1 = sys_fork();
pid_t pid2 = sys_fork();
#pragma GCC diagnostic pop
pid_t p = sys_getpid();
srand(p);
......@@ -48,3 +55,5 @@ void process_main() {
sys_yield();
}
}
#pragma GCC pop_options
......@@ -5,5 +5,7 @@ void process_main() {
// Running `testkalloc` should cause the kernel to run buddy allocator
// tests. How you make this work is up to you.
// Note that panic() will prouce a page fault if there is no console
// (https://github.com/CS161/chickadee/issues/14)
panic("testkalloc not implemented!\n");
}
......@@ -36,6 +36,8 @@ int printf(const char* format, ...) {
// panic, assert_fail
// Call the SYSCALL_PANIC system call so the kernel loops until Control-C.
// Note that panic() will prouce a page fault if there is no console
// (https://github.com/CS161/chickadee/issues/14)
void panic(const char* format, ...) {
va_list val;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment