mit-pdos / xv6-riscv Goto Github PK
View Code? Open in Web Editor NEWXv6 for RISC-V
License: Other
Xv6 for RISC-V
License: Other
xv6 is a re-implementation of Dennis Ritchie's and Ken Thompson's Unix Version 6 (v6). xv6 loosely follows the structure and style of v6, but is implemented for a modern RISC-V multiprocessor using ANSI C. ACKNOWLEDGMENTS xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14, 2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides pointers to on-line resources for v6. The following people have made contributions: Russ Cox (context switching, locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin Clements. We are also grateful for the bug reports and patches contributed by Takahiro Aoyagi, Marcelo Arroyo, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,Wenyang Duan, eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Nider, Hayato Ohhashi, OptimisticSide, phosphagos, Harry Porter, Greg Price, RayAndrew, Jude Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya Shigemitsu, snoire, Taojie, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Alissa Tung, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe, Lucas Wolf, Nicolas Wolovick, wxdao, Grant Wu, x653, Jindong Zhang, Icenowy Zheng, ZhUyU1997, and Zou Chang Wei. The code in the files that constitute xv6 is Copyright 2006-2024 Frans Kaashoek, Robert Morris, and Russ Cox. ERROR REPORTS Please send errors and suggestions to Frans Kaashoek and Robert Morris (kaashoek,[email protected]). The main purpose of xv6 is as a teaching operating system for MIT's 6.1810, so we are more interested in simplifications and clarifications than new features. BUILDING AND RUNNING XV6 You will need a RISC-V "newlib" tool chain from https://github.com/riscv/riscv-gnu-toolchain, and qemu compiled for riscv64-softmmu. Once they are installed, and in your shell search path, you can run "make qemu".
Though has little impact to TUI, generating debug info for assembly files would make IDE debugging less painful.
qemu-system-riscv64 --version
QEMU emulator version 6.1.0
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
make kernel/kernel
qemu-system-riscv64 -M virt -kernel kernel/kernel -bios none -serial stdio -display none
there is no output.through my effort, I find mret exception happens
The issue turned out to be RISC-V's Physical Memory Protection (PMP). QEMU will raise an illegal instruction exception when executing an MRET instruction if no PMP rules have been defined. Adding a PMP entry resolved the issue.
so ,I add setup_pmp function in kernel/start.c
`
void setup_pmp(void)
{
// Set up a PMP to permit access to all of memory.
// Ignore the illegal-instruction trap if PMPs aren't supported.
unsigned long pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
asm volatile ("la t0, 1f\n\t"
"csrrw t0, mtvec, t0\n\t"
"csrw pmpaddr0, %1\n\t"
"csrw pmpcfg0, %0\n\t"
".align 2\n\t"
"1: csrw mtvec, t0"
: : "r" (pmpc), "r" (-1UL) : "t0");
}
// entry.S jumps here in machine mode on stack0.
void
start()
{
setup_pmp();
........
}
`
the error function is :
printf.c -> void printf(char *fmt, ...)
i find printf(char *fmt, ...)
function may drop the character '%' in the end of any string.
Such as printf("i can print last %\n")
can work as expected , but printf("i can print last %")
can't.
The error behavior is reason for
c = fmt[++i] & 0xff; if (c == 0) break;
.
I think it can be changed as
if (c == 0) {
// when string is '\0' , this loop break at 'for' . So it is security using i - 1 in here.
if (fmt[i - 1] == '%') consputc('%');
break;
}
trap.c:100 w_stvec(TRAMPOLINE + (uservec - trampoline)) should read
w_stvec(TRAMPOLINE)
Successfully built the toolchain but failing to run make qemu command on Arch Linux
Output:
riscv64-unknown-elf-gcc -c -o kernel/entry.o kernel/entry.SAssembler messages: Fatal error: invalid -march= option:
rv64imafdc' make: *** [: kernel/entry.o] Error 1`
struct proc::killed
is listed among the variables for which struct proc::lock
should be held when used. However, this lock is almost invariably not held when killed
is read, and it's also not held when written by usertrap
.
As far as I can see, the xv6 book does not discuss this issue. I was wondering whether this is a deliberate choice or an oversight.
I believe, with low confidence, that this is not an issue. As far as I can see, it could only ever be a problem if killed
is read as 1 while it is actually 0. Since the value of killed
is monotonic during a process' lifetime (it only changes from 0 to 1), this seems impossible to happen even if writes to it are not atomic.
Is this assessment correct? If so, I think it would be nice to clarify this both in the source code and in the book.
➜ xv6-labs-2020 git:(syscall) riscv64-unknown-elf-gdb
GNU gdb (GDB) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-unknown-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/.
Find the GDB manual and other documentation resources online at:
http://www.gnu.org/software/gdb/documentation/.
For help, type "help".
Type "apropos word" to search for commands related to "word".
The target architecture is assumed to be riscv:rv64
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x0000000000001000 in ?? ()
(gdb) tui enable
Undefined command: "tui". Try "help".
Hello, when compiling the kernel, the linker (riscv64-elf-ld) issues the following warning:
riscv64-elf-ld: warning: cannot find entry symbol _entry; defaulting to 0000000080000000
The linker can't find the _entry
symbol, so it defaults to an address that just so happens, one can see from reading the comments in the file kernel/entry.S
, to be the location of the _entry
symbol. Everything works, but it's a bit of a kludge.
After troubleshooting, I found that _entry
isn't exported as a global symbol. putting a .global _entry
directive in kernel/entry.S fixes the problem and removes the linker warning.
https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/entry.S#L4
here 0x8000000
should be 0x80000000
After n ticks of cpu time,I set epc's value to the address of handler,so when it return to the user space,it will run handler.
But why it 'll print "test0 pass" after invoke handler ? I think it should just print alarm because sigreturn just return 0,but it still print "test0 pass". which one set pc's value to the value before being interrupted by the clock ?
the output is
I think the output should be
handler return and process will finish
I use brew install RISC-V toolchain on m1 mac os, and make qemu
it prints:
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
then seems like stuck.
In kernel/kalloc.c, I found that kmem.freelist is not initialized. As a general approach, we set NULL to be the end of a list. Why does kmem.freelist not be initialized?
@kaashoek Hi, I think the bug reported by #5 is still a problem. I am trying to explain in detail.
This bug is related to instruction cache (ICache) in hardware.
A
loads its code to a new physical page P0
in xv6-riscv/kernel/exec.c
. We assume that P0
is not in the ICache before loading the code. Note that from the aspect of hardware, loading code is similar to an invocation of memcpy()
. This means that loading code does not cause such code to enter ICache, since it only involves ordinary load and store instructions. For a processor with data cache (DCache), the code may be even located in DCache.A
executes code. Since P0
is not in the ICache, this will cause ICache miss. ICache will get the correct code from DCache or from memory.A
exits, and P0
is reclaimed.B
is loaded, and B
get exactly the same physical page P0
to load its code. Remember that the loaded code is not in the ICache after loading.B
executes code. Now disaster happens. When B
is going to access ICache, it may get a hit since the code of A
is still in the ICache! This causes B
to execute wrong code!The key to avoid such disaster is to update ICache every time new code is loaded. Such update can be performed in either hardware or software.
synchronization
according to the RISC-V manual. In RISC-V, there are three special instructions belong to this type.
SFENCE.VMA
. This instruction is used to update the state of hardware components related to virtual memory, such as TLB. Note that SFENCE.VMA
is NOT guaranteed to update ICache. It depends on the hardware implementation.
SFENCE.VMA
.SFENCE.VMA
. This is because the index field of an address keeps the same after address translation.SFENCE.VMA
. This is because the tag is from virtual address, and the mapping to the physical address may be changed after SFENCE.VMA
.FENCE
. This instruction is used to synchronize the visibility of store instructions before the FENCE
itself. Every load instructions on other CPUs after FENCE
should see the result of store instructions before FENCE
. Note that FENCE
is defined to only guarantee the visibility to load instructions. FENCE
does NOT guarantee the visibility to instruction fetches. Therefore, executing FENCE
will not guarantee to update ICache.FENCE.I
(different from FENCE
). According to the RISC-V manual,Currently, this instruction is the only standard mechanism to ensure that stores visible to a hart will also be visible to its instruction fetches.
Therefore, the solution to the bug above is FENCE.I
. The discussion about memory barrier at the end of section 9.3 in the text book is about FENCE
. This discussion is still irrelevant to such bug, since memory barrier is talking about ordinary load instructions, but not instruction fetches.
We encounter this bug when we are trying to run xv6 on a simple in-order RISC-V processor designed by undergraduates. There are some buffers and caches in the processor. The table below shows the behavior of the three instructions discussed above (F
= flush, K
= keep).
ICache | DCache | TLB | BTB | |
---|---|---|---|---|
SFENCE.VMA | K | K | F | F |
FENCE | K | K | K | K |
FENCE.I | F | K | K | F |
Since TLB and BTB is indexed by virtual address, they should be flushed under SFENCE.VMA
. ICache and DCache are simply implemented as PIPT, so they are not flushed under SFENCE.VMA
. For FENCE.I
, ICache and BTB will be flushed, since they are related to instruction. Note that the processor is in-order, the behavior required by FENCE
is naturally satisfied. Therefore FENCE
can be implemented as nop
and does not flush anything. This processor can successfully boot Linux and Debian, but fails to run xv6 without applying the patch #5 to fix this bug.
The bug is not exposed in QEMU. This is because in QEMU, all buffers and caches related to instruction are virtually indexed. They will be flushed under SFENCE.VMA
. xv6 will always execute SFENCE.VMA
on context switch. At this time, the code cache (a key component to implement JIT) in QEMU will also be flushed. Compared to our simple RISC-V processor, the main difference is that there is a PIPT ICache in the processor, which is not affected by SFENCE.VMA
and FENCE
.
Welcome for further discussion. :)
In Lab2, there listed a reference of kernal/sysinfo.h which cannot be found in code base.
Could you help make that available so that consistent with the lab2 description? Thanks
void
fprintf(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fd, fmt, ap);
// va_end(ap);
}
void
printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(1, fmt, ap);
// va_end(ap);
}
Hi
I want to record every instructions, so i add these to qemu startup "-d cpu,nochain -D cpu.log -singlestep", but i never see the command prompt come up. Please help
Thanks
Peter
It lies in line 391 of user/sh.c sh.c#L391
case '+': // >>
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
break;
When the symbol is '>>', the flag should be O_APPEND | O_WRONLY | O_CREATE instead of O_WRONLY|O_CREATE.
in my zsh, I want to check code
$ make grade
make: *** No rule to make target `grade'. Stop.
should I modify Makefile?
and I can't find the python srcipt grade-lab-util sleep
Hi, I'm using LLVM to build xv6 and when building it, I got this error:
clang -cc1as: fatal error: error in backend: unable to write nop sequence of 1 bytes
This is my make command
make TOOLPREFIX= CC="clang -target riscv64-elf" AS="clang -target riscv64-elf" LD="ld.lld" OBJCOPY="llvm-objcopy" OBJDUMP="llvm-objdump"
I tried to follow the gdb run in the traps & system call lecture and when I tried to print some registers with gdb, it gave 'dwarf2_find_location_expression: Corrupted DWARF expression.'. I'm using a M1 Mac if that helps.
It seems to me that tweaking some options for the compiler might fix the problem but not sure where to change. Not familiar with makefile at all.
In my dual core machine running qemu consumes %75-%90 CPU, is it normal? How can we decrease it?
I'm trying to implement signals support on XV6-riscv version
And in order to d so I defined a sigaction struct
and some signals macros like SIG_IGN
.
The problem is that when I compile it using make clean qemu
I got the following errors:
In file included from mkfs/mkfs.c:9:
./kernel/types.h:12:8: error: redefinition of 'sigaction'
struct sigaction {
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/signal.h:286:9: note: previous definition is here
struct sigaction {
^
In file included from mkfs/mkfs.c:9:
./kernel/types.h:13:12: error: expected ')'
void (*sa_handler) (int);
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/signal.h:295:38: note: expanded from macro 'sa_handler'
#define sa_handler __sigaction_u.__sa_handler
^
./kernel/types.h:13:10: note: to match this '('
void (*sa_handler) (int);
^
In file included from mkfs/mkfs.c:12:
./kernel/param.h:14:9: error: 'SIG_DFL' macro redefined [-Werror,-Wmacro-redefined]
#define SIG_DFL 0 // default signal handling
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/signal.h:131:9: note: previous definition is here
#define SIG_DFL (void (*)(int))0
^
In file included from mkfs/mkfs.c:12:
./kernel/param.h:15:9: error: 'SIG_IGN' macro redefined [-Werror,-Wmacro-redefined]
#define SIG_IGN 1 // ignore signal
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/signal.h:132:9: note: previous definition is here
#define SIG_IGN (void (*)(int))1
^
4 errors generated.
make: *** [mkfs/mkfs] Error 1
From what I understand sys the new definitions I made already exist in the macOS signal.h file and I do not understand why the compiler even checking this file? since it is in no way relevant for the XV6 and how can I fix this?
Any help would be very appreciated!
Hi,
The xv6 port is amazing. I have a doubt.
I want to configure this to run on a single core.
what should I do for this ?
Will you be keeping the x86 version of xv6 up to date with changes that also apply to it? I.e. changes that have nothing to do with the underlying architecture, but are instead operating system specific (for example like fixing a bug in the scheduling algorithm used, or resolving a race condition).
I encounter following issued on my computer, and I have no clue how to solve it or what the problem is.
Here is my environment:
The problem is that, my breakpoint does not work in main
function. I can step to the line asm volatile("mret");
in function start
.
However, the debugger just hangs after this instruction, it does not hit my breakpoint set on main
function. I can send interrupt by press Ctrl+C, it seems that sometimes it will stop in function timervec
.
I think the timer interrupt is worked as expected.
Have no clue what the problem is and how to fix it. Does anyone face same issue?
qemu-system-riscv64 --version
QEMU emulator version 6.1.0
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
make kernel/kernel
qemu-system-riscv64 -M virt -kernel kernel/kernel -bios none -serial stdio -display none
there is no output.through my effort, I find mret exception happens
The issue turned out to be RISC-V's Physical Memory Protection (PMP). QEMU will raise an illegal instruction exception when executing an MRET instruction if no PMP rules have been defined. Adding a PMP entry resolved the issue.
so ,I add setup_pmp function in kernel/start.c
`
void setup_pmp(void)
{
// Set up a PMP to permit access to all of memory.
// Ignore the illegal-instruction trap if PMPs aren't supported.
unsigned long pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
asm volatile ("la t0, 1f\n\t"
"csrrw t0, mtvec, t0\n\t"
"csrw pmpaddr0, %1\n\t"
"csrw pmpcfg0, %0\n\t"
".align 2\n\t"
"1: csrw mtvec, t0"
: : "r" (pmpc), "r" (-1UL) : "t0");
}
// entry.S jumps here in machine mode on stack0.
void
start()
{
setup_pmp();
........
}
`
The output is as below, and ecall's address in sh.asm is 0xdec.
(gdb) show step-mode
Mode of the step operation is off.
(gdb) set step-mode on
(gdb) b *0xdec
Breakpoint 1 at 0xdec
(gdb) c
Continuing.
Thread 1 hit Breakpoint 1, 0x0000000000000dec in ?? ()
=> 0x0000000000000dec: 73 00 00 00 ecall
(gdb) delete 1
(gdb) print $pc
$1 = (void (*)()) 0xdec
(gdb) x/2c $a1
0x3e9f: 36 '$' 48 '0'
(gdb) si
0x0000000000000df0 in ?? ()
=> 0x0000000000000df0: 82 80 ret
(gdb) print $pc
$2 = (void (*)()) 0xdf0
(gdb)
My system is Ubuntu 20.04 in WSL2, and GDB is gdb-multiarch.
Package: gdb-multiarch
Version: 9.2-0ubuntu1~20.04
Priority: optional
Section: universe/devel
Source: gdb
Origin: Ubuntu
Maintainer: Ubuntu Developers <[email protected]>
Original-Maintainer: Héctor Orón Martínez <[email protected]>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 15.2 MB
Depends: gdb (= 9.2-0ubuntu1~20.04), libbabeltrace1 (>= 1.5.4), libc6 (>= 2.29), libexpat1 (>= 2.0.1), libgcc-s1 (>= 3.4), liblzma5 (>= 5.1.1alpha+20110809), libmpfr6 (>= 3.1.3), libncursesw6 (>= 6), libpython3.8 (>= 3.8.2), libreadline8 (>= 8), libstdc++6 (>= 7), libtinfo6 (>= 6), zlib1g (>= 1:1.2.0)
Homepage: http://www.gnu.org/s/gdb/
Download-Size: 3794 kB
APT-Manual-Installed: yes
APT-Sources: http://archive.ubuntu.com/ubuntu focal-updates/universe amd64 Packages
Description: GNU Debugger (with support for multiple architectures)
GDB is a source-level debugger, capable of breaking programs at
any specific line, displaying variable values, and determining
where errors occurred. Currently, gdb supports C, C++, D,
Objective-C, Fortran, Java, OpenCL C, Pascal, assembly, Modula-2,
Go, and Ada. A must-have for any serious programmer.
.
This package contains a version of GDB which supports multiple
target architectures.
Hi
qemu hang, command prompt never come up. Any hints?
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 --trace events=/tmp/events
thanks
Peter
qemu-system-riscv64 --version
QEMU emulator version 6.1.0
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
make kernel/kernel
qemu-system-riscv64 -M virt -kernel kernel/kernel -bios none -serial stdio -display none
there is no output.through my effort, I find mret exception happens
The issue turned out to be RISC-V's Physical Memory Protection (PMP). QEMU will raise an illegal instruction exception when executing an MRET instruction if no PMP rules have been defined. Adding a PMP entry resolved the issue.
so ,I add setup_pmp function in kernel/start.c
void setup_pmp(void)
{
// Set up a PMP to permit access to all of memory.
// Ignore the illegal-instruction trap if PMPs aren't supported.
unsigned long pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
asm volatile ("la t0, 1f\n\t"
"csrrw t0, mtvec, t0\n\t"
"csrw pmpaddr0, %1\n\t"
"csrw pmpcfg0, %0\n\t"
".align 2\n\t"
"1: csrw mtvec, t0"
: : "r" (pmpc), "r" (-1UL) : "t0");
}
// entry.S jumps here in machine mode on stack0.
void
start()
{
setup_pmp();
........
}
I run make grade
, but it said cannot read answers-pgtbl.txt, where is this file?
pte printout: OK (2.1s)
== Test answers-pgtbl.txt == answers-pgtbl.txt: FAIL
Cannot read answers-pgtbl.txt
I think, in sys_read(), log_write() may be called without begin_op(), which may panic due to an assertion: https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/log.c#L223
The function call chain I suspect is: sys_read -> fileread -> readi -> bmap -> balloc -> log_write .
Even though a file is only read, it may need to zero-initialize new blocks.
We added a "halt" command to xv6 for the x86. I was wondering if anyone has done so for the riscv version. Here are our changes for x86.
sysproc.c:
#ifdef PDX_XV6
// shutdown QEMU
int
sys_halt(void)
{
do_shutdown(); // never returns
return 0;
}
#endif // PDX_XV6
console.c:
#ifdef PDX_XV6
void
do_shutdown()
{
cprintf("\nShutting down ...\n");
outw( 0x604, 0x0 | 0x2000); // signal QEMU to shutdown
return; // not reached
}
#endif // PDX_XV6
Else, I will track this down. We didn't add it to the official as it seemed that the authors were comfortable with just using c-a x. Is qemu mapped to the same range of addresses? I hope so.
Hi, I have trouble to execute make qemu
cmd:
vimer@host:~/src/xv6-riscv$ make qemu
riscv64-unknown-elf-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -MD -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie riscv64 -c -o kernel/start.o kernel/start.c
riscv64-unknown-elf-gcc: error: riscv64: No such file or directory
<内置>: recipe for target 'kernel/start.o' failed
make: *** [kernel/start.o] Error 1
=========================================
My riscv64 gcc and qemu as below:
vimer@host:~/src/xv6-riscv$ riscv64-unknown-elf-gcc --version
riscv64-unknown-elf-gcc (GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
vimer@host:~/src/xv6-riscv$ qemu-system-riscv64 --version
QEMU emulator version 5.1.0
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers
Hi
Is risc-v 32 bits toolchain work? or must use 64 bits?
thanks
Peter
I'm learning 6.S081 myself, and when I read the Isolation & system call entry/exit, using riscv64-unknown-elf-gdb
will receive an error:
Could not fetch register "stvec"; remote failure reply 'E14'
My gdb version is:
riscv64-unknown-elf-gdb --version
Python Exception <type 'exceptions.ImportError'> No module named gdb:
riscv64-unknown-elf-gdb: warning:
Could not load the Python gdb module from `/usr/local/Cellar/riscv-gnu-toolchain/gnu/share/gdb/python'.
Limited Python support is available from the _gdb module.
Suggest passing --data-directory=/path/to/gdb/data-directory.
GNU gdb (GDB) 8.3.0.20190516-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
I download the necessary dependencies and type make qemu
in xv6's directory, it seems some troubles happened:
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
qemu-system-riscv64: qemu_mprotect__osdep: mprotect failed: Permission denied
I don't know what does it means and how to solve it. But it seems I have to exit it by ctrl + A + x
rather than ctrl + c
, which indicates that the problem may come from qemu.
My device:
MacBook Pro m1,
macOS 11.4,
qemu 6.0,
riscv64-unknown-elf-gcc (GCC) 10.2.0
I'd like to know what happens when I type make qemu
in my terminal, and how to configure the qemu emulator to run the xv6 os.
sorry
Hello, I'm recently studying the principle of xv6 and benefits a lot from the explicit comments and the textbook. I think that there may be a bug in the logging layer in the file system. I'll describe the details below:
This is the code of install_trans() in /kernel/log.c
:
static void
install_trans(void)
{
int tail;
for (tail = 0; tail < log.lh.n; tail++) {
struct buf *lbuf = bread(log.dev, log.start+tail+1); // read log block
struct buf *dbuf = bread(log.dev, log.lh.block[tail]); // read dst
memmove(dbuf->data, lbuf->data, BSIZE); // copy block to dst
bwrite(dbuf); // write dst to disk
bunpin(dbuf);
brelse(lbuf);
brelse(dbuf);
}
}
the line bunpin(dbuf)
unpins dbuf
in the buffer cache so that this block can be evicted out of the memory after brelse(dbuf)
. The code works correctly if everything goes normally: there is a bpin()
in log_write()
which pins the block in the buffer cache by incrementing its reference count and the bunpin()
here decrements it.
However, if a crash happened during the installation of a transaction, after xv6 reboots, it would call recover_from_log()
in initlog()
and call install_trans
to write logging blocks into their home blocks. At this moment, there isn't a bpin()
before, so the bunpin()
here will decrement the reference count to zero and in brelse()
the reference count will experience an underflow and become UINT_MAX
since the refcnt
is a uint
type variable. As a result, the block will stay in the buffer cache "forever".
We can expose this bug by adding two lines in xv6:
We emulate a crash by adding a panic()
in install_trans()
like this:
brelse(dbuf);
}
+ if (log.lh.n != 0) panic("crash");
}
Here the condition log.lh.n != 0
ensures that the panic()
won't be triggered during the recover procedure.
We add an assertion in brelse()
:
acquire(&bcache.lock);
+ if (b->refcnt == 0) panic("bug");
b->refcnt--;
if (b->refcnt == 0) {
Before decrementing the reference count, b->refcnt >= 1
should always hold.
After we fire up xv6 for the first time, we'll encounter a "crash", and after rebooting, xv6 will panic at panic("bug")
. I made a disk image, fs-bug.img
, which records a crashed xv6 using the first step. If we load this image, we'll directly get a buggy scene (and can be detected by the assertion in brelse()
). The disk image is available here.
A possible solution for this problem is to add a bpin()
in read_head()
so that the bunpin()
during the recover procedure will have corresponding bpin()
.
I hope that my suggestions will be helpful. Welcome for further discussions, thanks!
problem solved
I can't compile on Ubuntu. My procedure was:
git clone ...
sudo apt install pkg-config-riscv64-linux-gnu libstdc++6-7-dbg-riscv64-cross gobjc-riscv64-linux-gnu libgcc-8-dev-riscv64-cross
cd xv6-riscv
make
And I get that gnarly error message.
The next question, if I build, will be how to emulate RISC-V on a lowly x86_64?
Line 54 in a1da53a
It it a mistake?
https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/entry.S#L4
here 0x8000000
should be 0x80000000
I compiled xv6 with -O3
(modified CFLAGS
in Makefile
), and ran usertests
. I expected it runs successfully, but I got kernel panic: balloc: out of blocks
in writebig
.
In kernel/syscall.c, if
checks num > 0, it seems that in xv6, the first system call number is 1,
but how can we call syscalls[0] (fork)?
void
syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num]();
if ((1 << num) & p->trace_mask)
printf("%d: syscall %s -> %d\n", p->pid, sysname[num-1], p->trapframe->a0);
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.