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 ...@@ -32,3 +32,4 @@ tags
tags.* tags.*
typescript typescript
vgcore* vgcore*
.vscode*
...@@ -87,10 +87,14 @@ CHICKADEE_FIRST_PROCESS ?= allocator ...@@ -87,10 +87,14 @@ CHICKADEE_FIRST_PROCESS ?= allocator
ifneq ($(strip $(CHICKADEE_FIRST_PROCESS)),$(DEP_CHICKADEE_FIRST_PROCESS)) 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) FIRST_PROCESS_BUILDSTAMP := $(shell echo "DEP_CHICKADEE_FIRST_PROCESS:=$(CHICKADEE_FIRST_PROCESS)" > $(DEPSDIR)/_first_process.d)
$(OBJDIR)/k-firstprocess.h: always $(OBJDIR)/k-firstprocess.h: always
$(OBJDIR)/chickadee.gdb: always
endif endif
ifeq ($(wildcard $(OBJDIR)/k-firstprocess.h),) ifeq ($(wildcard $(OBJDIR)/k-firstprocess.h),)
KERNELBUILDSTAMPS += $(OBJDIR)/k-firstprocess.h KERNELBUILDSTAMPS += $(OBJDIR)/k-firstprocess.h
endif endif
ifeq ($(wildcard $(OBJDIR)/chickadee.gdb),)
KERNELBUILDSTAMPS += $(OBJDIR)/chickadee.gdb
endif
# How to make object files # 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 ...@@ -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: $(OBJDIR)/k-firstprocess.h:
$(call run,echo '#ifndef CHICKADEE_FIRST_PROCESS' >$@; echo '#define CHICKADEE_FIRST_PROCESS "$(CHICKADEE_FIRST_PROCESS)"' >>$@; echo '#endif' >>$@,CREATE $@) $(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 \ $(OBJDIR)/k-initfs.cc: build/mkinitfs.awk \
$(INITFS_CONTENTS) $(INITFS_BUILDSTAMP) $(KERNELBUILDSTAMPS) $(INITFS_CONTENTS) $(INITFS_BUILDSTAMP) $(KERNELBUILDSTAMPS)
$(call run,echo $(INITFS_CONTENTS) $(INITFS_PARAMS) | awk -f build/mkinitfs.awk >,CREATE,$@) $(call run,echo $(INITFS_CONTENTS) $(INITFS_PARAMS) | awk -f build/mkinitfs.awk >,CREATE,$@)
...@@ -190,13 +197,17 @@ $(OBJDIR)/chickadeefsck: $(CHICKADEEFSCK_OBJS) $(BUILDSTAMPS) ...@@ -190,13 +197,17 @@ $(OBJDIR)/chickadeefsck: $(CHICKADEEFSCK_OBJS) $(BUILDSTAMPS)
# How to make disk images # How to make disk images
# If you change the `-f` argument, also change `boot.cc:KERNEL_START_SECTOR` # If you change the `-f` argument, also change `boot.cc:KERNEL_START_SECTOR`
chickadeeboot.img: $(OBJDIR)/mkchickadeefs $(OBJDIR)/bootsector $(OBJDIR)/kernel # The following two sections have been formatted to highlight their similarities
$(call run,$(OBJDIR)/mkchickadeefs -b 4096 -f 16 -s $(OBJDIR)/bootsector $(OBJDIR)/kernel > $@,CREATE $@) chickadeeboot.img: $(OBJDIR)/mkchickadeefs \
$(OBJDIR)/bootsector $(OBJDIR)/kernel
chickadeefs.img: $(OBJDIR)/mkchickadeefs \ $(call run,$(OBJDIR)/mkchickadeefs -b 4096 -f 16 -s \
$(OBJDIR)/bootsector $(OBJDIR)/kernel $(DISKFS_CONTENTS) \ $(OBJDIR)/bootsector $(OBJDIR)/kernel > $@,CREATE $@)
$(DISKFS_BUILDSTAMP)
$(call run,$(OBJDIR)/mkchickadeefs -b 32768 -f 16 -j 64 -s $(OBJDIR)/bootsector $(OBJDIR)/kernel $(DISKFS_CONTENTS) > $@,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: cleanfs:
$(call run,rm -f chickadeefs.img,RM chickadeefs.img) $(call run,rm -f chickadeefs.img,RM chickadeefs.img)
...@@ -226,11 +237,11 @@ run-monitor: $(QEMUIMAGEFILES) check-qemu ...@@ -226,11 +237,11 @@ run-monitor: $(QEMUIMAGEFILES) check-qemu
$(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) -monitor stdio $(QEMUIMG),QEMU $<) $(call run,$(QEMU_PRELOAD) $(QEMU) $(QEMUOPT) -monitor stdio $(QEMUIMG),QEMU $<)
run-gdb: run-gdb-$(QEMUDISPLAY) 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 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) $(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-$(RUNSUFFIX): run
run-graphic-$(RUNSUFFIX): run-graphic run-graphic-$(RUNSUFFIX): run-graphic
......
...@@ -25,7 +25,11 @@ and CPU resets to the standard error. This setting will also cause QEMU to ...@@ -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). quit after encountering a [triple fault][] (normally it will reboot).
`make run-PROGRAM` runs `p-PROGRAM.cc` as the first non-init process. The `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. `make HALT=1 run-PROGRAM` should make QEMU exit once all processes are done.
...@@ -131,13 +135,14 @@ Source files ...@@ -131,13 +135,14 @@ Source files
Build files Build files
----------- -----------
The main output of the build process is a disk image, The main outputs of the build process are two disk images, `chickadeeboot.img` and
`chickadeeos.img`. QEMU “boots” off this disk image, but the image `chickadeefs.img`. QEMU “boots” off a disk image, but the image
could conceivably boot on real hardware! The build process also could conceivably boot on real hardware! The build process relies on and
produces other files that can be useful to examine. produces other files that can be useful to examine.
| File | Description | | File | Description |
| -------------------------- | ------------------------------------ | | -------------------------- | ------------------------------------ |
| `GNUmakefile` | Instructions on how to build things |
| `obj/kernel.asm` | Kernel assembly (with addresses) | | `obj/kernel.asm` | Kernel assembly (with addresses) |
| `obj/kernel.sym` | Kernel defined symbols | | `obj/kernel.sym` | Kernel defined symbols |
| `obj/p-PROCESS.asm`, `sym` | Same for process binaries | | `obj/p-PROCESS.asm`, `sym` | Same for process binaries |
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
// the boot device (hard drive) into memory at address 0x7C00, and jumps to // the boot device (hard drive) into memory at address 0x7C00, and jumps to
// that address. // 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 // 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 // transfers here. This code reads in the kernel image and calls the
// kernel. // kernel.
......
...@@ -47,7 +47,7 @@ notify_bios64: ...@@ -47,7 +47,7 @@ notify_bios64:
# Notify the BIOS (the machine's firmware) to optimize itself # Notify the BIOS (the machine's firmware) to optimize itself
# for x86-64 code. https://wiki.osdev.org/X86-64 # for x86-64 code. https://wiki.osdev.org/X86-64
movw $0xEC00, %ax movw $0xEC00, %ax
movw $2, %dx mov $2, %bl
int $0x15 int $0x15
init_boot_pagetable: init_boot_pagetable:
...@@ -63,37 +63,48 @@ init_boot_pagetable: ...@@ -63,37 +63,48 @@ init_boot_pagetable:
# 0x2000: L3 page table; entries 0 and 510 map 1st 1GB of physmem # 0x2000: L3 page table; entries 0 and 510 map 1st 1GB of physmem
# This is the minimal page table that maps all of # This is the minimal page table that maps all of
# low-canonical, high-canonical, and kernel-text addresses to # 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 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, (%edi)
movl %ecx, 0x800(%edi) movl %ecx, 0x800(%edi)
movl %ecx, 0xFF8(%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), -3(%ecx)
movl $(PTE_P + PTE_W + PTE_PS), 0xFED(%ecx) movl $(PTE_P + PTE_W + PTE_PS), 0xFED(%ecx)
# Switch from real to protected mode: # Switch from real mode (16-bit) to long mode (64-bit):
# Up until now, there's been no protection, so we've gotten along perfectly # Up until now, we have used direct physical memory addressing (real mode)
# well without explicitly telling the processor how to translate addresses. # without explicitly telling the processor how to translate addresses.
# When we switch to protected mode, this is no longer true! # When we enable paging, this is no longer true!
# We need at least to set up some "segments" that tell the processor it's # 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. # OK to run code at any address, or write to any address.
# The `gdt` and `gdtdesc` tables below define these segments. # The `gdt` and `gdtdesc` tables below define these segments.
# This code loads them into the processor. # This code loads them into the processor.
# We need this setup to ensure the transition to protected mode is smooth. # 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 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 %eax, %cr4
movl %edi, %cr3
movl $MSR_IA32_EFER, %ecx # turn on 64-bit mode movl %edi, %cr3 # set the address of the page table
rdmsr
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 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 orl $(CR0_PE | CR0_WP | CR0_PG), %eax
movl %eax, %cr0 movl %eax, %cr0
......
...@@ -2,7 +2,7 @@ set $loaded = 1 ...@@ -2,7 +2,7 @@ set $loaded = 1
set arch i386:x86-64 set arch i386:x86-64
file obj/kernel.full file obj/kernel.full
add-symbol-file obj/bootsector.full 0x7c00 add-symbol-file obj/bootsector.full 0x7c00
add-symbol-file obj/p-allocator.full 0x100000 source obj/chickadee.gdb
target remote localhost:12949 target remote localhost:12949
source build/functions.gdb source build/functions.gdb
display/5i $pc display/5i $pc
...@@ -175,6 +175,8 @@ void ahcistate::handle_error_interrupt() { ...@@ -175,6 +175,8 @@ void ahcistate::handle_error_interrupt() {
pr_->serror = ~0U; pr_->serror = ~0U;
pr_->command |= pcmd_start; pr_->command |= pcmd_start;
// XXX must `READ LOG EXT` to clear error // 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"); panic("SATA disk error");
} }
......
...@@ -175,7 +175,11 @@ struct log_printer : public printer { ...@@ -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) { void log_vprintf(const char* format, va_list val) {
spinlock_guard guard(printLock);
log_printer p; log_printer p;
p.vprintf(0, format, val); p.vprintf(0, format, val);
} }
...@@ -434,6 +438,8 @@ void __cxa_guard_release(long long* arg) { ...@@ -434,6 +438,8 @@ void __cxa_guard_release(long long* arg) {
// __cxa_pure_virtual() // __cxa_pure_virtual()
// Used as a placeholder for pure virtual functions. // Used as a placeholder for pure virtual functions.
void __cxa_pure_virtual() { 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"); panic("pure virtual function called in kernel!\n");
} }
......
...@@ -70,6 +70,8 @@ void proc::init_kernel(pid_t pid, void (*f)()) { ...@@ -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. // Called when `k-exception.S` tries to run a non-runnable proc.
void proc::panic_nonrunnable() { 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" panic("Trying to resume proc %d, which is not runnable\n"
"(proc state %d, recent user %%rip %p)", "(proc state %d, recent user %%rip %p)",
id_, pstate_.load(), recent_user_rip_); id_, pstate_.load(), recent_user_rip_);
......
...@@ -34,6 +34,8 @@ void vmiter::down() { ...@@ -34,6 +34,8 @@ void vmiter::down() {
pep_ = &pt->entry[pageindex(va_, level_)]; pep_ = &pt->entry[pageindex(va_, level_)];
} }
if ((*pep_ & PTE_PAMASK) >= 0x100000000UL) { 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" panic("Page table %p may contain uninitialized memory!\n"
"(Page table contents: %p)\n", pt_, *pep_); "(Page table contents: %p)\n", pt_, *pep_);
} }
......
...@@ -19,6 +19,7 @@ std::atomic<int> kdisplay; ...@@ -19,6 +19,7 @@ std::atomic<int> kdisplay;
static void tick(); static void tick();
static void boot_process_start(pid_t pid, const char* program_name); static void boot_process_start(pid_t pid, const char* program_name);
void find_mapped_memory();
// kernel_start(command) // kernel_start(command)
...@@ -26,6 +27,7 @@ static void boot_process_start(pid_t pid, const char* program_name); ...@@ -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. // string is an optional string passed from the boot loader.
void kernel_start(const char* command) { void kernel_start(const char* command) {
// find_mapped_memory(); // uncomment this to test the boot page table
init_hardware(); init_hardware();
console_clear(); console_clear();
...@@ -431,3 +433,37 @@ void tick() { ...@@ -431,3 +433,37 @@ void tick() {
memshow(); 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 { ...@@ -243,7 +243,6 @@ struct bitset_view {
// System call numbers (passed in `%rax` at `syscall` time) // System call numbers (passed in `%rax` at `syscall` time)
// Used in pset 1:
#define SYSCALL_GETPID 1 #define SYSCALL_GETPID 1
#define SYSCALL_YIELD 2 #define SYSCALL_YIELD 2
#define SYSCALL_PAUSE 3 #define SYSCALL_PAUSE 3
...@@ -251,7 +250,6 @@ struct bitset_view { ...@@ -251,7 +250,6 @@ struct bitset_view {
#define SYSCALL_PANIC 5 #define SYSCALL_PANIC 5
#define SYSCALL_PAGE_ALLOC 6 #define SYSCALL_PAGE_ALLOC 6
#define SYSCALL_FORK 7 #define SYSCALL_FORK 7
// Used in later psets:
#define SYSCALL_EXIT 8 #define SYSCALL_EXIT 8
#define SYSCALL_READ 9 #define SYSCALL_READ 9
#define SYSCALL_WRITE 10 #define SYSCALL_WRITE 10
...@@ -491,6 +489,8 @@ assert_memeq_fail(const char* file, int line, const char* msg, ...@@ -491,6 +489,8 @@ assert_memeq_fail(const char* file, int line, const char* msg,
// panic(format, ...) // panic(format, ...)
// Print the message determined by `format` and fail. // 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)) void __attribute__((noinline, noreturn, cold))
panic(const char* format, ...); panic(const char* format, ...);
......
...@@ -6,12 +6,19 @@ extern uint8_t end[]; ...@@ -6,12 +6,19 @@ extern uint8_t end[];
uint8_t* heap_top; uint8_t* heap_top;
uint8_t* stack_bottom; 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() { void process_main() {
sys_kdisplay(KDISPLAY_MEMVIEWER); sys_kdisplay(KDISPLAY_MEMVIEWER);
// Fork three new copies. (But ignore failures.) // Fork three new copies. (But ignore failures.)
(void) sys_fork(); #pragma GCC diagnostic push
(void) sys_fork(); #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(); pid_t p = sys_getpid();
srand(p); srand(p);
...@@ -48,3 +55,5 @@ void process_main() { ...@@ -48,3 +55,5 @@ void process_main() {
sys_yield(); sys_yield();
} }
} }
#pragma GCC pop_options
...@@ -5,5 +5,7 @@ void process_main() { ...@@ -5,5 +5,7 @@ void process_main() {
// Running `testkalloc` should cause the kernel to run buddy allocator // Running `testkalloc` should cause the kernel to run buddy allocator
// tests. How you make this work is up to you. // 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"); panic("testkalloc not implemented!\n");
} }
...@@ -36,6 +36,8 @@ int printf(const char* format, ...) { ...@@ -36,6 +36,8 @@ int printf(const char* format, ...) {
// panic, assert_fail // panic, assert_fail
// Call the SYSCALL_PANIC system call so the kernel loops until Control-C. // 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, ...) { void panic(const char* format, ...) {
va_list val; 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