We need to maintain the reference Python simulator, which also lacks proper userspace ABI support. The ABI support is essential for running real userspace applications. -- * https://github.com/qemu/qemu/blob/master/linux-user/syscall.c
Reassigning this bug to me (with Shriya cc'd so she can study along). From my understanding of the task, the actual work would require: - In ISACaller, parse the 'sc' (system call) PowerISA instruction and extract the system call number argument. - Import relevant library into Python which allows to make system calls. - Look up PowerISA ABI, to see which system call arguments correspond to open()/read)()/write() (the system calls chosen for the scope of this task). - Extend the ISACaller (with if-elif-else type of block) which will make the relevant system call depending on the 'sc' instruction argument. The hardest part of the task seems to me to be understanding where to modify the ISACaller simulator, so I'll begin by making sure I can run example programs with it (and make a modified binary which includes a system call instruction).
note that the list of actual syscalls that are needed to run a simple program are a bit different: I tested the following program on ppc64le: gcc -x c - -static <<'EOF' #include <stdio.h> int main() { FILE *f; f = fopen("/proc/cmdline", "r"); if(!f) return 1; while(1) { int ch = fgetc(f); if(ch == EOF) break; putchar(ch); } int err = ferror(f); fclose(f); return err ? 1 : 0; } EOF actual syscalls (ignore the initial execve): strace ./a.out execve("./a.out", ["./a.out"], 0x7fffed38eae0 /* 18 vars */) = 0 brk(NULL) = 0x1000c670000 brk(0x1000c670fe4) = 0x1000c670fe4 uname({sysname="Linux", nodename="75-224-155-23", ...}) = 0 readlink("/proc/self/exe", "/home/jacob/a.out", 4096) = 17 brk(0x1000c6a0fe4) = 0x1000c6a0fe4 brk(0x1000c6b0000) = 0x1000c6b0000 openat(AT_FDCWD, "/proc/cmdline", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 read(3, "root=UUID=0ff31a9e-7434-4c47-b03"..., 1024) = 86 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0 write(1, "root=UUID=0ff31a9e-7434-4c47-b03"..., 86root=UUID=0ff31a9e-7434-4c47-b030-502a14729112 ro quiet disable_radix init=/sbin/init ) = 86 read(3, "", 1024) = 0 close(3) = 0 exit_group(0) = ? +++ exited with 0 +++ so, the list that needs is: brk uname readlink openat fstat read write close exit_group
note that this doesn't need to change the list of syscalls you've chosen to implement, just that they aren't all necessarily the most useful ones. (In reply to Jacob Lifshay from comment #2) > so, the list that needs is: > brk for dynamic memory allocation and/or dynamic linking, mmap and munmap are also useful. > uname if you implement uname, it will need to return results you'd expect on a ppc64le system, not whatever the python script is running on. > readlink > openat > fstat > read > write > close > exit_group this needs to *not* call the exit syscall, but instead just stop the simulator.
(In reply to Jacob Lifshay from comment #2) > note that the list of actual syscalls that are needed to run a simple > program are a bit different: > I tested the following program on ppc64le: > gcc -x c - -static <<'EOF' > #include <stdio.h> > int main() { > FILE *f; > f = fopen("/proc/cmdline", "r"); it's very important to avoid fopen at the early phase, and just do read open write and close. ("man 2 open") check the size of the binary (static compile, stripped) and it will be obvious why, immediately. fopen pulls in vast quantities of libc6 including threads locking spinlocks mutexes, it's a whole stack of shit that massively raises the initial starting-point to an overwhelming barrier, *and* you end up running hundreds of thousands of unnecessary instructions to even initilise all that shit. you don't need the hassle. cut the bullshit, make life easy, do the other syscalls later. btw there is a *REAL* simple way to get this entire thing done *REAL* fast: https://stackoverflow.com/questions/37032203/make-syscall-in-python if you trap malloc realloc and free and emulate them (there are plenty of "replacement" libraries which do exactly this) then this entire job is done in about... ooo... a week? on that: i don't want to hear anyone say "But Security" or "But Guest interference with Host???" - this is not qemu, this is an expedient simulator trick, deployed by cavatools to achieve 500 to 1,000 times the speed of e.g. risc-v-spike simulator.
(In reply to Andrey Miroshnikov from comment #1) > Reassigning this bug to me (with Shriya cc'd so she can study along). > > From my understanding of the task, the actual work would require: > > - In ISACaller, parse the 'sc' (system call) PowerISA instruction and > extract the system call number argument. r3 i think you'll find. check the disasm on a simple binary using open() write() and close(). > - Import relevant library into Python which allows to make system calls. which you may need to write. > - Look up PowerISA ABI, to see which system call arguments correspond to > open()/read)()/write() (the system calls chosen for the scope of this task). been in the media/ directory for 3 years now, and how syscalls work i think i found links online. basically they are exactly the same as a function (set up regs) but instead of "branch to address" you do "sc". https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=media/calling-conv;hb=HEAD > - Extend the ISACaller (with if-elif-else type of block) which will make the > relevant system call depending on the 'sc' instruction argument. just write a unit test that calls one instruction: "sc". then see what happens. > The hardest part of the task seems to me to be understanding where to modify > the ISACaller simulator, so I'll begin by making sure I can run example > programs with it (and make a modified binary which includes a system call > instruction). no: just write *one* unit test with *one* instruction in it (sc). do not attempt to use pypowersim on the initial phase. that comes later once *even one* system call has been verifed by at least one unit test (each). you know the drill, you know how python projects work (unit tests, unit tests, unit tests), you know how that online "word game" works ("what tiny steps get me from Word ABCD to word XYZW"). going directly to pypowersim is *clearly* too much with zero intermediary steps that will utterly overwhelm you, when you know next to nothing about the details involved, so why even attempt it? therefore logically it is your responsibility to work out the tiny intermediary steps. can i please not be put into a position of having to remind you of this again given that i have repeated it so many times already? i will assume that i do not need to say this again.
(In reply to Luke Kenneth Casson Leighton from comment #4) > (In reply to Jacob Lifshay from comment #2) > > note that the list of actual syscalls that are needed to run a simple > > program are a bit different: > > I tested the following program on ppc64le: > > gcc -x c - -static <<'EOF' > > #include <stdio.h> > > int main() { > > FILE *f; > > f = fopen("/proc/cmdline", "r"); > > it's very important to avoid fopen at the early phase, and just do > read open write and close. ("man 2 open") that doesn't help much: strace ./a.out > out.txt execve("./a.out", ["./a.out"], 0x7fffed669f60 /* 18 vars */) = 0 brk(NULL) = 0x1001a000000 brk(0x1001a000fe4) = 0x1001a000fe4 uname({sysname="Linux", nodename="75-224-155-23", ...}) = 0 readlink("/proc/self/exe", "/home/jacob/a.out", 4096) = 17 brk(0x1001a030fe4) = 0x1001a030fe4 brk(0x1001a040000) = 0x1001a040000 openat(AT_FDCWD, "/proc/cmdline", O_RDONLY|O_CLOEXEC) = 3 read(3, "root=UUID=0ff31a9e-7434-4c47-b03"..., 4096) = 86 write(1, "root=UUID=0ff31a9e-7434-4c47-b03"..., 86) = 86 read(3, "", 4096) = 0 exit_group(0) = ? +++ exited with 0 +++ I used this program: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #define BUFSZ 4096 #define RETRY_SYSCALL(retval, call) \ do { \ retval = (call); \ } while(retval == -1 && errno == EINTR) int main() { unsigned char buf[BUFSZ]; int fd; RETRY_SYSCALL(fd, open("/proc/cmdline", O_RDONLY | O_CLOEXEC)); if(fd == -1) return 1; while(1) { ssize_t read_count; RETRY_SYSCALL(read_count, read(fd, buf, sizeof(buf))); if(read_count == -1) return 1; if(read_count == 0) break; ssize_t pos = 0; while(pos < read_count) { ssize_t write_count, left = read_count - pos; RETRY_SYSCALL(write_count, write(STDOUT_FILENO, &buf[pos], left)); if(write_count == -1) return 1; pos += write_count; } } // close(fd); return 0; }
(In reply to Jacob Lifshay from comment #6) still too complex. > #define RETRY_SYSCALL(retval, call) \ > do { \ > retval = (call); \ > } while(retval == -1 && errno == EINTR) cut this > int main() { > unsigned char buf[BUFSZ]; > int fd; > RETRY_SYSCALL(fd, open("/proc/cmdline", O_RDONLY | O_CLOEXEC)); cut macro. > if(fd == -1) > return 1; cut. assume success. > while(1) { cut loop > ssize_t read_count; > RETRY_SYSCALL(read_count, read(fd, buf, sizeof(buf))); cut macro > ssize_t pos = 0; > while(pos < read_count) { cut loop > ssize_t write_count, left = read_count - pos; > RETRY_SYSCALL(write_count, write(STDOUT_FILENO, &buf[pos], > left)); cut macro > if(write_count == -1) > return 1; cut. assume success > pos += write_count; cut. assume write amount is same as read amount now that's down to a manageable easy program that when disassembled is blindingly-obvious, and could easily fit into a VERY SHORT test_caller_sc_***.py unit test. do learn to stop making "perfect" the enemy of "good enough". your experience and preference for rust is hampering delivery and costing you (and the team) money that they could earn far quicker. a *second* unit test - under pypowersim - would be to run the program that you wrote, as a way to test expected error conditions, but that is *optional*... after everything else has been done, and likely there are some libc6 unit tests that could drop in here (cross-ref to NGI Search Grant) bug #1106 bug #1109
(In reply to Luke Kenneth Casson Leighton from comment #7) > (In reply to Jacob Lifshay from comment #6) > > still too complex. my point is that the actual syscalls strace reports don't match the functions I'm calling. Ignore the C program complexity, it's just a short demo.
(In reply to Jacob Lifshay from comment #8) > (In reply to Luke Kenneth Casson Leighton from comment #7) > > (In reply to Jacob Lifshay from comment #6) > > > > still too complex. > > my point is that the actual syscalls strace reports don't match the > functions I'm calling. Ignore the C program complexity, it's just a short > demo. oh, and also that there are a bunch of syscalls called by glibc's init code before main -- the brk and uname and readlink calls
(In reply to Jacob Lifshay from comment #8) > my point is that the actual syscalls strace reports don't match the > functions I'm calling. Ignore the C program complexity, it's just a short > demo. ah - ok i get it. use strace -ff -o xxxx.out, it separates each process by PID. openat instead of open is a new one on me. exit_group is likely bash. -ff will get you *only* what the a.out actually does, in its own xxxx.out.PID file
(In reply to Luke Kenneth Casson Leighton from comment #10) > (In reply to Jacob Lifshay from comment #8) > > > my point is that the actual syscalls strace reports don't match the > > functions I'm calling. Ignore the C program complexity, it's just a short > > demo. > > ah - ok i get it. use strace -ff -o xxxx.out, it separates each > process by PID. afaict that is all only a.out, bash is not included. > > openat instead of open is a new one on me. > > exit_group is likely bash. exit_group is caused by returning from main and then the startup code calls exit, which uses the exit_group syscall
(In reply to Jacob Lifshay from comment #11) > (In reply to Luke Kenneth Casson Leighton from comment #10) > > ah - ok i get it. use strace -ff -o xxxx.out, it separates each > > process by PID. ok, tried: strace -ff -o out.txt ./a.out out.txt.71212: execve("./a.out", ["./a.out"], 0x7fffeb4d7bb8 /* 18 vars */) = 0 brk(NULL) = 0x10037460000 brk(0x10037460fe4) = 0x10037460fe4 uname({sysname="Linux", nodename="75-224-155-23", ...}) = 0 readlink("/proc/self/exe", "/home/jacob/a.out", 4096) = 17 brk(0x10037490fe4) = 0x10037490fe4 brk(0x100374a0000) = 0x100374a0000 openat(AT_FDCWD, "/proc/cmdline", O_RDONLY|O_CLOEXEC) = 3 read(3, "root=UUID=0ff31a9e-7434-4c47-b03"..., 4096) = 86 write(1, "root=UUID=0ff31a9e-7434-4c47-b03"..., 86) = 86 read(3, "", 4096) = 0 exit_group(0) = ? +++ exited with 0 +++
(In reply to Jacob Lifshay from comment #12) > (In reply to Jacob Lifshay from comment #11) > > (In reply to Luke Kenneth Casson Leighton from comment #10) > > > ah - ok i get it. use strace -ff -o xxxx.out, it separates each > > > process by PID. > > ok, tried: strace -ff -o out.txt ./a.out intriguing - no change... analysing: > out.txt.71212: > execve("./a.out", ["./a.out"], 0x7fffeb4d7bb8 /* 18 vars */) = 0 request to replace the current process by this one. whyy... ohh you're not running grsecurity or se/linux or anything, are you? > brk(NULL) = 0x10037460000 > brk(0x10037460fe4) = 0x10037460fe4 > uname({sysname="Linux", nodename="75-224-155-23", ...}) = 0 > readlink("/proc/self/exe", "/home/jacob/a.out", 4096) = 17 > brk(0x10037490fe4) = 0x10037490fe4 > brk(0x100374a0000) = 0x100374a0000 hmmm... yes agreed, likely libc6 initialisation. > openat(AT_FDCWD, "/proc/cmdline", O_RDONLY|O_CLOEXEC) = 3 > read(3, "root=UUID=0ff31a9e-7434-4c47-b03"..., 4096) = 86 > write(1, "root=UUID=0ff31a9e-7434-4c47-b03"..., 86) = 86 > read(3, "", 4096) = 0 expected > exit_group(0) = ? why exit_group - weird. i wonder if it's due to something recent in libc6 and/or threading being enabled for some reason. it'd be good to get down to a minimum program... it's still massive (due to whole unnecessary chunks of libc6 being dragged in, sigh) ---- #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char *argv[] ) { int fd = open("/tmp/x", O_CREAT, S_IRUSR); write(fd, "hello", 5); return 0; } ---- $ history ... 589 powerpc64-linux-gnu-gcc -static -static-libgcc open.c 590 objdump -D a.out > /tmp/x ...
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char *argv[] ) { write(1, "hello\n", 6); return 0; } ==> 0000000010000974 <.main>: 10000974: 7c 08 02 a6 mflr r0 10000978: f8 01 00 10 std r0,16(r1) 1000097c: fb e1 ff f8 std r31,-8(r1) 10000980: f8 21 ff 81 stdu r1,-128(r1) 10000984: 7c 3f 0b 78 mr r31,r1 10000988: 7c 69 1b 78 mr r9,r3 1000098c: f8 9f 00 b8 std r4,184(r31) 10000990: 91 3f 00 b0 stw r9,176(r31) 10000994: 38 a0 00 06 li r5,6 10000998: 3c 82 ff fb addis r4,r2,-5 1000099c: 38 84 76 68 addi r4,r4,30312 100009a0: 38 60 00 01 li r3,1 100009a4: 48 02 16 1d bl 10021fc0 <.__libc_write> 100009a8: 60 00 00 00 nop 100009ac: 39 20 00 00 li r9,0 100009b0: 7d 23 4b 78 mr r3,r9 100009b4: 38 3f 00 80 addi r1,r31,128 100009b8: e8 01 00 10 ld r0,16(r1) 100009bc: 7c 08 03 a6 mtlr r0 100009c0: eb e1 ff f8 ld r31,-8(r1) 100009c4: 4e 80 00 20 blr 100009c8: 00 00 00 00 .long 0x0 100009cc: 00 00 00 01 .long 0x1 100009d0: 80 01 00 01 lwz r0,1(r1) 100009d4: 60 00 00 00 nop 100009d8: 60 00 00 00 nop 100009dc: 60 00 00 00 nop and i bet you if you replace that "bl __libc_write" with "sc" directly in assembler you'll end up with "hello" on the terminal.
okaaaay fiiinallyyy, found one. https://github.com/matja/asm-examples/blob/master/ppc64/hello.ppc64.linux.syscall.gas.asm message: .ascii "Hello world!\n" ._start: li 0, 4 # syscall 4 - write li 3, 1 # arg 0 - fd = 1 (stdout) lis 4, message@highest # arg 1 - buffer ori 4, 4, message@higher rldicr 4, 4, 32, 31 oris 4, 4, message@h ori 4, 4, message@l li 5, message_length # arg 2 - size sc # do syscall li 0, 1 # syscall 1 - exit li 3, 0 # arg 0 - exit code = 0 sc # do syscall
Thanks very much to both of you for your findings. Luke's comments in the IRC log: https://libre-soc.org/irclog/%23libre-soc.2023-09-06.log.html#t2023-09-06T15:01:08 mention how 'write' systemcall can be used with hello world to stdout example (demonstrated on qemu-ppc64le-user). I will replicate this and continue with the task later this week.
(In reply to Andrey Miroshnikov from comment #16) > Thanks very much to both of you for your findings. > > Luke's comments in the IRC log: > https://libre-soc.org/irclog/%23libre-soc.2023-09-06.log.html#t2023-09-06T15: > 01:08 > > mention how 'write' systemcall can be used with hello world to stdout > example comment #15. commands at top of file. prefix with ppc64le-linux-gnu- > (demonstrated on qemu-ppc64le-user). https://wiki.debian.org/QemuUserEmulation very useful. when pypowersim has ELF support it should also work via foreign binfmt.
(In reply to Luke Kenneth Casson Leighton from comment #17) > > https://wiki.debian.org/QemuUserEmulation > > very useful. Thanks, I was able to assemble and run the example (using qemu). Found another hello world assembler example (which actually explained what @highest, @higher, @h, @l meant): https://gist.github.com/sandip4n/09b50786e88968faaecdf42360c85b1b (otherwise the assembler is exactly the same) I created a basic unit test which only calls the system call 'sc' instruction (with reg's preloaded). https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=1be8996cbea4d5bcb96ed9a91c2f0dbfcacf7ee1 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=2c075be04e5603ffb161002a99e4684b41973829 I entered the expected values as per sc instruction definition in PowerISA v3.1b, Book III, Chapter 4, section 4.3.1 System Linkage Instructions: SRR0 <- i_ea CIA + 4 SRR1_33:36 42:47 <- 0 SRR1_0:32 37:41 48:63 <- MSR_0:32 37:41 48:63 MSR <- new_value (see below) NIA <- 0x0000_0000_0000_0C00 The MSR value is defined in Section 7.5 (same book), figure 69. NIA comes from figure 70. The Libre-SOC pseudo-code looks similar: SRR0 <-iea CIA + 4 SRR1[33:36] <- 0 SRR1[42:47] <- 0 SRR1[0:32] <- MSR[0:32] SRR1[37:41] <- MSR[37:41] SRR1[48:63] <- MSR[48:63] MSR <- new_value NIA <- 0x0000_0000_0000_0C00 Running the test_caller_syscall.py causes the following assertions to fail (need to set e.pc to value given by simulator to get other assertion errors): AssertionError: 0x0 != 0x8: SPR.SRR0 mismatch (sim != expected) 'sc' My understanding (based on pseudo-code from PowerISA spec and Libre-SOC page), is that SRR0 will be equal to CIA+4. At the start of the program I defined cia (pc) as 4, so 8 should be the expected value. Is the simulator not setting SRR0 at all? AssertionError: 0x9000000000082903 != 0x9000000000002903: SPR.SRR1 mismatch (sim != expected) 'sc' SRR1 is equal to the MSR before the syscall is made, in this case default value of 0x9000000000002903 was used. Seems like bit 19 is set (where that 8 is). AssertionError: 1792 != 3072 : pc mismatch (sim != expected) 'sc' I picked 3072 (0xC00) as I wasn't sure what it's going to be. However it doesn't make sense where 1792 (0x700) comes from. Not sure how to proceed (other than digging through the internals of ISACaller). Am I making an endian-ness error?
(In reply to Andrey Miroshnikov from comment #18) > At the start of the program I defined cia (pc) as 4, which will attempt to execute the *second* instruction in the list, which of course you don't have. you need to actually look at the trace output closely, and at caller.py searching for log(...) and linking the two in your mind. then you can follow what the simulator is actually doing. you remember i said "you need to be very very patient" and you replied "i don't think i can do that"? sorry to have to repeat it: you need to be very very patient. slow down, pay attention, and think like a simulator. the program unless told otherwise is loaded into "memory" location 0x0000_0000_0000_0000. you *can* specify otherwise, but very few unit tests do that and i haven't used the option to ISACaller in over a year, you'll have to hunt for it yourself.... ... or just don't try setting the start pc to 0x4, it is non-standard for the unit tests anyway. doable but non-standard.
(In reply to Luke Kenneth Casson Leighton from comment #19) > > At the start of the program I defined cia (pc) as 4, > > which will attempt to execute the *second* instruction in the > list, which of course you don't have. For some reason I find this pretty cool. If I didn't copy a test that had several instructions, may not have stumbled upon this so quickly. > > you need to actually look at the trace output closely, and at caller.py > searching for log(...) and linking the two in your mind. > > then you can follow what the simulator is actually doing. Thanks, will do. > the program unless told otherwise is loaded into "memory" location > 0x0000_0000_0000_0000. > > you *can* specify otherwise, but very few unit tests do that and i > haven't used the option to ISACaller in over a year, you'll have to > hunt for it yourself.... > > ... or just don't try setting the start pc to 0x4, it is non-standard > for the unit tests anyway. doable but non-standard. Will keep in mind. Trying the standard way makes sense first.
(In reply to Andrey Miroshnikov from comment #20) > Will keep in mind. Trying the standard way makes sense first. (look at some of the virtual memory tests and the trap tests, they do weird stuff inclucing passing a "stop if PC=0x700" parameter. a LOT has been incrementallyndone in 3 years, it is extremely sophisticated).
Andrey, while I was reading the code you wrote: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/test/syscall/syscall_cases.py;h=2e64315833810a7c38ee9733cba1e9e04e38ceeb;hb=1be8996cbea4d5bcb96ed9a91c2f0dbfcacf7ee1#l38 you need to pass a pointer to the bytes to the write syscall, not put the bytes directly in the register. so, to write data to memory, do: initial_mem = {} base_addr = 0x10000 # arbitrarily selected, must not overlap something else for idx, v in enumerate(the_bytes): # write v as 1 byte at address idx + base_addr initial_mem[idx + base_addr] = v, 1 initial_regs[4] = base_addr # pointer to start of data we just wrote ... self.add_case(self.program, initial_regs, initial_mem=initial_mem, ...) for an example, see: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/test/algorithms/svp64_utf_8_validation.py;h=054fd481dab0040dcb302f0506ab04bc8b52c864;hb=1be8996cbea4d5bcb96ed9a91c2f0dbfcacf7ee1#l352 in the example, note that those *_LUT constants are lists of enums, hence why I used int(v) to convert them before assigning to initial_mem
(In reply to Jacob Lifshay from comment #22) > Andrey, while I was reading the code you wrote: > https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/test/ > syscall/syscall_cases.py;h=2e64315833810a7c38ee9733cba1e9e04e38ceeb; > hb=1be8996cbea4d5bcb96ed9a91c2f0dbfcacf7ee1#l38 > > you need to pass a pointer to the bytes to the write syscall, not put the > bytes directly in the register. yes. this is exactly a function call (just with r0={thesystemcallnumber} therefore, you need to read the man page: https://man7.org/linux/man-pages/man2/write.2.html note that the header is: ssize_t write(int fd, const void buf[.count], size_t count); read the ABI dcument calling convention: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=media/calling-conv;hb=HEAD and set r3=fd (stdout) r4=*ADDRESS* of buf r5=count. can i suggest putting the above links and some explanatory comments into the code so that it can be referred to as a way to help guide people on syscalls? also: every single file *MUST* have: * Copyright notices (including the original if you copied contents of the file from somewhere) * License Header (SPDX) * Thank you to NLnet and the associated EU Grant. all of that is MANDATORY for the project. also in this case put the bug URL to crossref here.
(In reply to Luke Kenneth Casson Leighton from comment #23) > note that the header is: > ssize_t write(int fd, const void buf[.count], size_t count); on my computer that's (imho easier to read since it doesn't use obscure C features): ssize_t write(int fd, const void *buf, size_t count);
(In reply to Jacob Lifshay from comment #24) > (imho please do stop saying "in my HUMBLE opinion": i did say it is irritating and unnecessary in a goal-orientated non-ego-driven team. > easier to read since it doesn't use obscure C > features): > > ssize_t write(int fd, const void *buf, size_t count); i cut/paste what is straight out of the online man page, and yes it is somewhat dismaying to see these "improvements" from doing c since 1989. ultimately though, the "types" get utterly ignored at the low level of regs: all safety-nets (e.g. const) are out the window.
https://github.com/qemu/qemu/blob/master/linux-user/syscall.c this - all twelve THOUSAND lines - is what qemu-user does to emulate systemcalls [safely]. the fact that "memory" is emulated means that when it comes for example to emulate write() it is necessary to extract the contents of sim.mem at the appropriate "address", to place it into a suitable buffer (of size count) and then pass **that** buffer to (either) an actual syscall (or a write function call that ultimately ends up calling that syscall on your behalf).
https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=48ec1783c5 dmitry i love the idea of an autogenerated table, however we have a hard rule (in HDL_workflow wiki page since the inception of the project) that no autogenerated output shall be committed to the repository. can you please remove it and either create it "on-demand" (see python-ply for that trick) or just use/adapt the autogenerator *itself*, or add a Makefile target (similar to "make pywriter") which will then also need adding to devscripts. l.
OK, I made a start on system calls mapping: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=74ea3c42bef943da263395d19c50ad4dba605b9f There's a tool which parses the Linux kernel tree and obtains all system calls available, considering the ABI and other stuff. The only argument is the path to the Linux kernel source code. An example of how its output looks like (beware, huge!): https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=48ec1783c5f7cc64629fba65575db2d3881e8026 I committed this since we're unlikely to take Linux kernel with us. Linux keeps userspace ABI stable (ugly but stable). So the situation we need to generate again is unlikely to happen. Note that this is an exception I committed this artifact: I don't usually do it, it's a bad practice, terrible and even disasterous things can happen. How do you use it? >>> syscall_id = 286 # some deliberate example >>> from openpower.syscalls import tables >>> (name, entries) = tables.SYSNUMS["ppc"]["common"][str(syscall_id)] >>> print(name, entries) openat ['sys_openat', 'compat_sys_openat'] >>> native = int(tables.SYSNUMS["x86-64"]["common"][name]) >>> print(native) 257 >>> print(tables.SYSARGS[name]) {'dfd': 'int', 'filename': 'const char __user *', 'flags': 'int', 'mode': 'umode_t'} I suppose this should be sufficient to start playing with mapping emulated PPC system calls to architecture the simulator runs on. Beware, SYSARGS table, as well as entries upon lookup, are here for a reason: different architectures pass arguments differently (ditto pipe, compat_arg_u64_dual and similar stuff). Linux vaunted userspace ABI is a gory mess. What's missing here? 1. Host architecture detection, including "running 32-bit code on 64-bit architecture" (not sure whether we need it though). 2. Logic for looking into different ABIs (e.g. some system calls might not be in "common" ABI section). 3. The actual call redirection. This is easy enough, because libc already has a shim "syscall". As long as the arguments match each other on two hosts, obviously. Otherwise there must be a bunch of "special cases" and "let's inspect the arguments logic".
(In reply to Luke Kenneth Casson Leighton from comment #27) > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=48ec1783c5 > > dmitry i love the idea of an autogenerated table, however we have a > hard rule (in HDL_workflow wiki page since the inception of the project) > that no autogenerated output shall be committed to the repository. > > can you please remove it and either create it "on-demand" (see python-ply > for that trick) or just use/adapt the autogenerator *itself*, or add > a Makefile target (similar to "make pywriter") which will then also > need adding to devscripts. > > l. You were faster than me. :-) Yes this is a totally ugly practice, I'll drop it. That's for illustrative purposes. What'd be the right place and way to download the Linux kernel? I'm sure we only need --depth=1. I imagine the following approach: 1. In dev-env-setup, clone Linux sources (w/ or w/o --depth=1). 2. In openpower-isa Makefile, invoke the script on the kernel sources.
Yeah, since git (almost) never forgets, I've already dropped the generated file. The link's still actual anyway (I committed a revert), so you might take a look. Andrey, what'd be the right way to split the activities so that I don't step on your toes? I assume the task consists of the following steps: 1. Update dev-env-setup and openpower-isa with the proper Linux kernel clone (easy to handle) and script invocation. 2. Extending openpower.syscalls module with the logic to lookup the PPC system call on the host. 3. Introducing a shim wrapper around syscall, which takes several integers and passes them SOMEHOW into the host registers. The only question I have there relates to resources. Say we had invoked "sc" insn in ISACaller, and we have registers around. However, some of the registers are just pointers, some are descriptors. How'd I copy the memory from these simulated memory cells? As for descriptors, we obviously cannot pass them as is, and we'll kinda end up doing parts of OS job (e.g. introducing a map of sim:host descriptors and vice versa). I assume this needs a trap mechanism by system call identifier in simulator. Am I right?
(In reply to Dmitry Selyutin from comment #30) > Yeah, since git (almost) never forgets, I've already dropped the generated > file. The link's still actual anyway (I committed a revert), so you might > take a look. i did. it's cool. would be nice to know what the function parameters are, from somewhere. or at least the number of arguments, that's the most critical information. is that known? i may have missed it > Say we had invoked "sc" insn in ISACaller, and we have registers around. sim.gpr (or, self.gpr) > However, some of the registers are just pointers, some are descriptors. > How'd I copy the memory from these simulated memory cells? manually. see comment #26. sim.mem (or, self.mem. look in mem.py) > As for > descriptors, we obviously cannot pass them as is, and we'll kinda end up > doing parts of OS job (e.g. introducing a map of sim:host descriptors and > vice versa). siiiigh, yeeeees. i had a think and i don't believe the cavatools trick will work in ISACaller: instead we will have to *literally* implement the syscalls one by one. as in: the implementation of write() would be done *by hand* by: fd = self.gpr(3) buf = self.gpr(4) count = self.gpr(5) actual_buf = bytes() for i in range(count): actual_bytes.append(self.mem.ld(buf+i, 1) # something like that self.gpr(3) = sys.write(fd, actual_bytes) and errno somehow will need to get created/emulated/set, no idea how to do that. > I assume this needs a trap mechanism by system call identifier in simulator. > Am I right? yeeeees - i did describe it somewhere, you need to "spot that a jump to address 0xC00 has been made". normally this would ACTUALLY contain (in a linux kernel) an ACTUAL implementation (binary code) of an ACTUAL systemcall/OS implementation however just like in riscv-spike and cavatools we are going to "hack it", by enabling an option to ISACaller that just goes "if PC == xyz call this special function instead of trying to execute instructions *AT* that address" all quite dreadful but pretty standard - qemu, spike, cavatools - they all do it.
(In reply to Luke Kenneth Casson Leighton from comment #31) > (In reply to Dmitry Selyutin from comment #30) > > Yeah, since git (almost) never forgets, I've already dropped the generated > > file. The link's still actual anyway (I committed a revert), so you might > > take a look. > > i did. it's cool. would be nice to know what the function parameters are, > from somewhere. or at least the number of arguments, that's the most > critical information. is that known? i may have missed it Yep, I implemented it. These are basically useless w/o information on arguments. Check Ctrl+F on this bug page for SYSARGS. :-) > sim.gpr (or, self.gpr) > sim.mem (or, self.mem. look in mem.py) > as in: the implementation of write() would be done *by hand* by: > > fd = self.gpr(3) > buf = self.gpr(4) > count = self.gpr(5) > actual_buf = bytes() > for i in range(count): > actual_bytes.append(self.mem.ld(buf+i, 1) # something like that > self.gpr(3) = sys.write(fd, actual_bytes) Aha, good enough to go. A temporary buffer for passing into the host syscall then. On a per-syscall basis, unfortunately. > siiiigh, yeeeees. i had a think and i don't believe the cavatools trick will > work in ISACaller: instead we will have to *literally* implement the syscalls > one by one. > > and errno somehow will need to get created/emulated/set, no idea how to do > that. Thanks God even as bad OS as Linux doesn't have this idiotic errno concept in kernel. They return a negative result to represent the error. That is, kernel returns -EINTR, and the userspace moves it to errno. "syscall" does the same stuff though, so we'll likely have to pick this from ctypes.get_errno(). > > I assume this needs a trap mechanism by system call identifier in simulator. > > Am I right? > > yeeeees - i did describe it somewhere, you need to "spot that a jump to > address > 0xC00 has been made". normally this would ACTUALLY contain (in a linux > kernel) > an ACTUAL implementation (binary code) of an ACTUAL systemcall/OS > implementation > however just like in riscv-spike and cavatools we are going to "hack it", > by enabling an option to ISACaller that just goes "if PC == xyz call this > special function instead of trying to execute instructions *AT* that address" > > all quite dreadful but pretty standard - qemu, spike, cavatools - they all > do it. Here comes a microkernel in ISACaller, lol. Hard to start, annoying to invent a reusable code, but still pretty doable and straightforward.
(In reply to Dmitry Selyutin from comment #32) > "syscall" does > the same stuff though, so we'll likely have to pick this from > ctypes.get_errno(). Just to clarify, I mean not an instruction but a libc wrapper (man 2 syscall, <unistd.h> and <sys/syscall.h>).
(In reply to Dmitry Selyutin from comment #32) critical information. is that known? i may have missed it > > Yep, I implemented it. i saw. the commit is *tend* of thousands of lines long which is precisely why the hard rule exists, as it is massively overloading both my server and also my tablet. it was 4 minutes to load the diff. > These are basically useless w/o information on > arguments. Check Ctrl+F on this bug page for SYSARGS. :-) ok i see. ok that's auto-parseable. that's great, because autogenerating the actual calls *even if "safed"* like in qemu-user, shouuuld be reasonably straightforward. i don't know how easy it would be to grab the size of data structs for each object out from somewhere? even if it's done by hand (or put into a lookup dictionary). > > > sim.gpr (or, self.gpr) > > sim.mem (or, self.mem. look in mem.py) > > as in: the implementation of write() would be done *by hand* by: > > > > fd = self.gpr(3) > > buf = self.gpr(4) > > count = self.gpr(5) > > actual_buf = bytes() > > for i in range(count): > > actual_bytes.append(self.mem.ld(buf+i, 1) # something like that > > self.gpr(3) = sys.write(fd, actual_bytes) > > Aha, good enough to go. A temporary buffer for passing into the host syscall > then. yes. sigh. > On a per-syscall basis, unfortunately. yes. sigh. but there *might* be enough information to actually autogenerate (dynamic, runtime) everything. > > > siiiigh, yeeeees. i had a think and i don't believe the cavatools trick will > > work in ISACaller: instead we will have to *literally* implement the syscalls > > one by one. > > > > and errno somehow will need to get created/emulated/set, no idea how to do > > that. > > Thanks God even as bad OS as Linux doesn't have this idiotic errno concept > in kernel. They return a negative result to represent the error. That is, > kernel returns -EINTR, and the userspace moves it to errno. "syscall" does > the same stuff though, so we'll likely have to pick this from > ctypes.get_errno(). i hesitate to actually allow the syscall itself, rather than an "explicit emulated" one, but the issue of memory (see below) may force our hand. > Here comes a microkernel in ISACaller, lol. userspace emulation of POSIX, in python... yes! > > Hard to start, annoying to invent a reusable code, but still pretty doable > and straightforward. ohh fer goodness sake. i just realised, any memory allocated (for the syscalls) you can't just discard it, you actually *need* to keep it under a lookup table. so when you get a shared memory lock you absolutely cannot just blithely allocate a new area buffer. ok this is complicated. we *may* need to make a special version of sim.mem that *actually is backed by a mmapped/malloced area of memory*, such that there is a *DIRECT* one-to-one relationship between the addresses of the emulator and when the syscalls take place. this would have the advantage of not needing to map in/out in the syscalls, you just literally pass the pointer-register to the syscall. there is a way to call syscalls... https://stackoverflow.com/questions/37032203/make-syscall-in-python although this looks more complete/comprehensive: https://github.com/ssavvides/execute-syscall i *have* seen something that allows *direct* function calling... oh god https://dev.to/adwaithrajesh/calling-asm-function-from-python-part-maybe-0-46e1
(In reply to Luke Kenneth Casson Leighton from comment #34) > (In reply to Dmitry Selyutin from comment #32) > critical information. is that known? i may have missed it > > > > Yep, I implemented it. > > i saw. the commit is *tend* of thousands of lines long which is > precisely why the hard rule exists, as it is massively overloading > both my server and also my tablet. it was 4 minutes to load the diff. That's why I prefer $(git show), not URL's. :-) Anyway, that's rolled back. > > These are basically useless w/o information on > > arguments. Check Ctrl+F on this bug page for SYSARGS. :-) > > ok i see. ok that's auto-parseable. that's great, because autogenerating > the actual calls *even if "safed"* like in qemu-user, shouuuld be > reasonably straightforward. > > i don't know how easy it would be to grab the size of data structs > for each object out from somewhere? even if it's done by hand > (or put into a lookup dictionary). Let's consider an example of just one system call. Even for `fstat`, there are 3 system calls with three different structures. That's only for i686; I'm not even speaking of compat syscalls. And I don't even mention stat, lstat, fstatat, fstatfs et al. They all have their multiple system calls. Recently they introduced statx, which should finally fix it (again). Newer architectures have less of this nonsense, but still do. PPC has several fstat too: ppc32 supports at least 3 (just fstat), ppc64 has 2 (one of them is compat). There are other issues related to passing 64-bit integers too. That's what happens when you attempt to guarantee userspace ABI but allow users to operate by other means than via libc wrappers. > yes. sigh. but there *might* be enough information to actually > autogenerate (dynamic, runtime) everything. There is, but, unless you pass the same options used to build the kernel and likely build it indeed, it's damn complicated. At the very minimum you have to have the same uAPI files as the kernel generates based on tons of options. The best option is to take from other project; qemu user emulation should've done it. > > Here comes a microkernel in ISACaller, lol. > > userspace emulation of POSIX, in python... yes! No, this is wrong. POSIX has no idea of system calls. That's not their level of abstraction. They operate in terms of API, and it just happens that many OSes choose to implement this API via syscalls. Quite an unfortunate tradition, frankly speaking; I'd prefer simpler building blocks. POSIX is powerful, but not a good candidate for kernel<->userspace cooperation. It serves a different purpose. > > Hard to start, annoying to invent a reusable code, but still pretty doable > > and straightforward. > > ohh fer goodness sake. i just realised, any memory allocated > (for the syscalls) you can't just discard it, you actually *need* > to keep it under a lookup table. > > so when you get a shared memory lock you absolutely cannot just > blithely allocate a new area buffer. > > ok this is complicated. > > we *may* need to make a special version of sim.mem that *actually is > backed by a mmapped/malloced area of memory*, such that there is a > *DIRECT* one-to-one relationship between the addresses of the > emulator and when the syscalls take place. > this would have the advantage of not needing to map in/out in the > syscalls, you just literally pass the pointer-register to the syscall. It makes life easier, indeed. Still there will be mappings for... mmap itself. Basically to make these work you have to invent poor man's MM. > there is a way to call syscalls... > > https://stackoverflow.com/questions/37032203/make-syscall-in-python I already told about it few comments ago. Yes, Linux libc wraps syscalls in syscall(2), converts codes to errno, and this is present in ctypes too (thus ctypes.get_errno() suggestion). On amd64 (and I think on most modern 64 archs) it's as tiny as just changing some of the registers due call/kernel-syscall conventions. > i *have* seen something that allows *direct* function calling... oh god > https://dev.to/adwaithrajesh/calling-asm-function-from-python-part-maybe-0- > 46e1 No need and no point. In addition to complications of passing the parameters, you'll have to support different calling conventions. libc already takes care of that. On the overall in separate comment.
All in all, this task and its future depends on how far you want to go. If you want a proper ABI emulation for another architecture -- you have to invent something like QEMU user mode. Or, better, just directly take it. If we need some fixed number of system calls, or for some reasons want to pass these as is to host OS on our own without intermediate participants like qemu -- that's another story. But that another story has to have some bits depending on which system calls you need: either intermediate copies, or directly shared memory, plus parts of MM, plus parts of fd tree, etc. etc. Basically you'll end up inventing a toy OS inside the interpreter. From comment 2 I assumed the second. That's an interesting thing to try checking out, though I must confess, in my opinion, the budget hardly covers even this experiment. The best I can suggest is preparing an infrastructure which makes this possible and demonstrating some really basic bits: say wrapping some exit(2) variant and maybe write(2) on STDOUT_FILENO and perhaps stuff like sleep and OS detection via say uname(2).
(In reply to Dmitry Selyutin from comment #35) > (In reply to Luke Kenneth Casson Leighton from comment #34) > > this would have the advantage of not needing to map in/out in the > > syscalls, you just literally pass the pointer-register to the syscall. > > It makes life easier, indeed. Still there will be mappings for... mmap > itself. Basically to make these work you have to invent poor man's MM. cavatools cheats, by overriding malloc realloc and free. actually i believe it just makes free() a stub (saves complications) if going down this route (a new sim.mem that *actually* reads/writes to an actual area of malloc/mmao'd userspace memory) it will be necessary to allocate it at a fixed address of a fixed size. some hints lead to mmap with MMAP_FIXED and also mremap https://stackoverflow.com/questions/19945350/allocate-a-memory-chunk-at-a-specified-address-in-linux-kernel https://stackoverflow.com/questions/6446101/how-do-i-choose-a-fixed-address-for-mmap the reason for picking a fixed address is so as to be able to compile static binaries at a pre-arranged address. i would greatly prefer exploring this route first and see how far it gets rather than literally writing every syscall emulated in python. > ctypes.get_errno() suggestion). On amd64 (and I think on most modern 64 > archs) it's as tiny as just changing some of the registers due > call/kernel-syscall conventions. i think we both understand what goes on, you happen to know more details more readily, with more first-hand experience. always a good thing.
(In reply to Dmitry Selyutin from comment #36) > All in all, this task and its future depends on how far you want to go. enough to run "open and read and write some files" such as /dev/ttyUSB0 or other serial console. and enough to say "success!" and justify another grant. > depending on which system calls you need: either intermediate copies, > or directly shared memory, plus parts of MM, plus parts of fd tree, etc. > etc. Basically you'll end up inventing a toy OS inside the interpreter. indeed. > From comment 2 I assumed the second. That's an interesting thing to try > checking out, though I must confess, in my opinion, the budget hardly covers > even this experiment. i know. > The best I can suggest is preparing an infrastructure > which makes this possible and demonstrating some really basic bits: say > wrapping some exit(2) variant and maybe write(2) on STDOUT_FILENO and > perhaps stuff like sleep and OS detection via say uname(2). you can see why cavatools just literally farmed out verbatim guest to host, no security whatsoever, and overrode malloc and free. can we see how far the direct-syscall-with-new-mem.py gets? if it really doesn't work out the fallback is an emulation in python, with a few (very few) syscalls as a start. in theeeoryyy we can borrow the cavatools budget allocated to the same task. see bug #981 oh. https://bugs.libre-soc.org/show_bug.cgi?id=939#c1
(In reply to Luke Kenneth Casson Leighton from comment #37) > if going down this route (a new sim.mem that *actually* reads/writes > to an actual area of malloc/mmao'd userspace memory) it will be > necessary to allocate it at a fixed address of a fixed size. a fixed address is not necessary, all we need is to allocate a memory block and then add the base address of that block to all simulated memory operations. if we bind the allocated block to a python buffer object, python will do that for us, as well as bounds checking. to implement emulated mmap, we can simply pick an unused address in that memory block and use MAP_FIXED on that calculated address. this is exactly what wasm does (with some extra stuff for sandboxing, like fast bounds checking)
(In reply to Jacob Lifshay from comment #39) > a fixed address is not necessary, all we need is to allocate a memory block > and then add the base address of that block to all simulated memory > operations. if we bind the allocated block to a python buffer object, python > will do that for us, as well as bounds checking. e.g.: import mmap mem = mmap.mmap(-1, 1 << 32, mmap.MAP_PRIVATE) # create 4GiB block print(mem[0x12345]) # read byte at 0x12345 mem[0x6789] = 0x12 # write byte at 0x6789 # emulate mmap helper code import ctypes libc = ctypes.CDLL("libc.so.6") off_t = ctypes.c_long # valid on ppc64le and x86_64 afaict libc.mmap.argtypes = [ ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int, ctypes.c_int, ctypes.c_int, off_t] libc.mmap.restype = ctypes.c_void_p MAP_FIXED = 0x10 # emulate mmap addr = pick_free_addr() p = ctypes.c_char.from_buffer(mem, addr) r = libc.mmap(p, MAP_FIXED, ...) if r != p: return make_error_from_errno() return addr
(In reply to Jacob Lifshay from comment #39) > and then add the base address of that block to all simulated memory > operations. this is the bit that (a) requires identifying all memory buffers for all syscalls (which is a stowstopping amount of work for the available budget) and (b) does not work for code that relies on address-offsets *in code*. all *load store* operations executed would need offsetting... *if* they were allocated by a syscall, but not otherwise? this is hopelessly impractical to consider. even (a) is too much work which is why cavatools directly maps the guest program into host memoryspace (one-to-one and onto) then overrides malloc and free.
(In reply to Luke Kenneth Casson Leighton from comment #41) > (In reply to Jacob Lifshay from comment #39) > > > and then add the base address of that block to all simulated memory > > operations. > > this is the bit that (a) requires identifying all memory buffers for > all syscalls (which is a stowstopping amount of work for the > available budget) you're misunderstanding -- there's *one* block used for *all* simulated memory regardless of if we're running a syscall rn or not, read/write syscalls are passed a pointer pointing inside that block. > and (b) does not work for code that relies on > address-offsets *in code*. all *in-code* address offsets are already handled by python for the simulator (well, if we had used a bytesarray instead of a dict for simulated memory, since python adds the index to the bytesarray's base address). the only time when manual offsetting is necessary is when python doesn't do it for you -- when manually calling raw c syscall wrapper functions. > > all *load store* operations executed would need offsetting... *if* they > were allocated by a syscall, but not otherwise? no, they're always offset -- transparently, by python. you just access mem[123] and python accesses byte *(123 + mem.the_buffer_ptr), since that's how array indexing works. > this is hopelessly > impractical to consider. > > even (a) is too much work which is why cavatools directly maps > the guest program into host memoryspace (one-to-one and onto) > then overrides malloc and free. cavatools is written in C/C++ where direct memory read/wrires are just a pointer dereference away. ISACaller is written in python, where indexing into an bytesarray (or other buffer object, in our case, a mmap object) is the default way to access raw memory.
(In reply to Jacob Lifshay from comment #42) > you're misunderstanding -- there's *one* block used for *all* simulated > memory regardless of if we're running a syscall rn or not, read/write > syscalls are passed a pointer pointing inside that block. all the emulated mmap syscall will do is to go behind python's back and replace a piece of that *one* block with MAP_FIXED, python will still keep treating it as *one* block of memory.
(In reply to Jacob Lifshay from comment #42) > all *in-code* address offsets are already handled by python for the > simulator static binaries. non-position-independent (non -fPIC) code. think it through.
(In reply to Luke Kenneth Casson Leighton from comment #44) > (In reply to Jacob Lifshay from comment #42) > > > all *in-code* address offsets are already handled by python for the > > simulator > > static binaries. non-position-independent (non -fPIC) code. > think it through. all insns in those static binaries are simulated by the simulator. so, when the simulator sees lbz r3, 28(r5), it effectively does gprs[3] = mem[28 + gprs[5]] mem.__getitem__ (python builtin) is what adds the offset. so, if the statically linked binary's ELF headers says to load it with .data at 0x40000, then the binary runs an insn to store to .data + 0x10, the simulator will try to write to mem[0x40010], which python's __setitem__ will translate to *(mem.the_base_addr + 0x40010) = the_byte
I chose the cheapest generation approach. No fancy targets, just clone the kernel with --depth=1 upon dev-env-setup/hdl-dev-repos, then launch $(python3 -m openpower.syscalls ../linux) to generate the thing. https://git.libre-soc.org/?p=dev-env-setup.git;a=commitdiff;h=cf35d78fff7db7baa4a69bfb50168e2778e7eb92 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=180638ac02637f38301eb97d15a8590293b3a3a4
(In reply to Jacob Lifshay from comment #45) > so, if the statically linked binary's ELF headers says to load it with .data > at 0x40000, then the binary runs an insn to store to .data + 0x10, the > simulator will try to write to mem[0x40010], which python's __setitem__ will > translate to > *(mem.the_base_addr + 0x40010) = the_byte where is the money coming from to implement that?
(In reply to Luke Kenneth Casson Leighton from comment #47) > (In reply to Jacob Lifshay from comment #45) > > > so, if the statically linked binary's ELF headers says to load it with .data > > at 0x40000, then the binary runs an insn to store to .data + 0x10, the > > simulator will try to write to mem[0x40010], which python's __setitem__ will > > translate to > > *(mem.the_base_addr + 0x40010) = the_byte > > where is the money coming from to implement that? the task we'll make when we want to support emulating mmap and/or loading ELF binaries. all we'd need is to change the Mem class to use that block from mmap.mmap instead of a dict, looking through it, i could do it in a few hours. probably less if nothing reaches into the Mem.mem dict and fiddles with it directly instead of calling the load/store functions. https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/mem.py;h=41d5b0b4df11592f609dfc07c9da57234e8b5626;hb=180638ac02637f38301eb97d15a8590293b3a3a4#l52
Sorry I haven't been responsive chaps in the last few days, I was too tired to work on this. (In reply to Dmitry Selyutin from comment #30) > > Andrey, what'd be the right way to split the activities so that I don't step > on your toes? I assume the task consists of the following steps: > > 1. Update dev-env-setup and openpower-isa with the proper Linux kernel clone > (easy to handle) and script invocation. > 2. Extending openpower.syscalls module with the logic to lookup the PPC > system call on the host. > 3. Introducing a shim wrapper around syscall, which takes several integers > and passes them SOMEHOW into the host registers. The only question I have > there relates to resources. I kind of get the gist of you're suggesting, although this is starting to go way beyond my understanding. The bare minimum I was thinking about, was not even bother with syscalls, and just use bog standard python methods (like write()) to emulate syscall behaviour. With some syscalls (like exit(), we can't even use the linux syscall, because we just want to terminate the program running in ISACaller, not the python script itself). How much actual kernel interaction do you need with ISACaller? Isn't printing to stdout already sufficient for a wide range of applications? On another note, is there a way to reduce the ISACaller printing without SILENCE_LOG? SILENCE_LOG takes away most of it, but normal printing is way too much (don't understand much of it). To me ISACaller is still too much of a monster, and I'm not sure which files are better to approach (where are the GPR's/SPR's memory is, how to start/stop the simulator, etc.)
(In reply to Andrey Miroshnikov from comment #49) > Sorry I haven't been responsive chaps in the last few days, I was too tired > to work on this. Hi Andrey, no problems at all! I hope you got some rest. > I kind of get the gist of you're suggesting, although this is starting to go > way beyond my understanding. > > The bare minimum I was thinking about, was not even bother with syscalls, > and just use bog standard python methods (like write()) to emulate syscall > behaviour. With some syscalls (like exit(), we can't even use the linux > syscall, because we just want to terminate the program running in ISACaller, > not the python script itself). Part of the issue is that you still must detect what exact syscall is being passed (or, well, rather trapped by) ISACaller. So at the very minimum you need guest syscall table. Since we're going to route (at least some of) these to the host, we'll likely need host syscall table. We also need a mechanism to make both cooperate: shared memory, system call ids and arguments translation, fd tree, etc. etc. I've mostly just prepared a ground to dig. :-) > How much actual kernel interaction do you need with ISACaller? Isn't > printing to stdout already sufficient for a wide range of applications? The answer really depends on the overall future of ISACaller and cavatools. If we go till the end of this road, this is basically the same as QEMU user mode (I know, I know, hardly comparable, but partially, in a spirit). For now, however, I want to have some mechanism which provides a basis for doing this. > On another note, is there a way to reduce the ISACaller printing without > SILENCE_LOG? SILENCE_LOG takes away most of it, but normal printing is way > too much (don't understand much of it). To me ISACaller is still too much of > a monster, and I'm not sure which files are better to approach (where are > the GPR's/SPR's memory is, how to start/stop the simulator, etc.) You should ask Luke. :-) I personally think that the idea to debug via print is good as long as this debug is not committed to the repository (in fact, I almost always debug by prints; but almost never commit this debug).
(In reply to Dmitry Selyutin from comment #50) > > Part of the issue is that you still must detect what exact syscall is being > passed (or, well, rather trapped by) ISACaller. So at the very minimum you > need guest syscall table. Since we're going to route (at least some of) > these to the host, we'll likely need host syscall table. You're right, thanks for doing that table btw. > We also need a > mechanism to make both cooperate: shared memory, system call ids and > arguments translation, fd tree, etc. etc. I've mostly just prepared a ground > to dig. :-) Indeed, and again thanks for that. I'll just need to re-read those earlier comments by Luke and Jacob on memory, eventually will sink in :-) > The answer really depends on the overall future of ISACaller and cavatools. > If we go till the end of this road, this is basically the same as QEMU user > mode (I know, I know, hardly comparable, but partially, in a spirit). For > now, however, I want to have some mechanism which provides a basis for doing > this. I guess it's in our interest to (eventually) support a wide range of syscalls. When ISACaller is sufficiently optimised (into C) then running whole applications might actually become viable. And perhaps the efforts of that could work into cavatools. > You should ask Luke. :-) I personally think that the idea to debug via print > is good as long as this debug is not committed to the repository (in fact, I > almost always debug by prints; but almost never commit this debug). Yes, print statements have helped more times than I can count...
Folks, I've played a bit more with these shiny system call tables, and added a simple class which can be used as a basis for ppc/ppc64/i386/amd64 conversion: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=b80670cfb193d148ff0419a14318e0f63900ef76 Usage example: from openpower.syscalls import Dispatcher dispatcher = Dispatcher(guest="ppc", host="amd64", logger=print) print(dispatcher(identifier=20)) print(dispatcher(identifier=207)) print(dispatcher.getpid()) print(dispatcher.gettid()) This works as if somebody arrived to us with system calls 20 and 207 on PPC and attempted to wrap their execution to amd64 (which luckily is the platform I use). Basically it checks guest syscall table by identifier, finds the entry, then finds the backward mapping in host syscall table, then briefly inspects the arguments count (though we might even attempt to validate these). I also added a wrapper to call them by names, not just identifiers. The output is: getpid 20 => 39 15293 getpid 20 => 39 15293 gettid 207 => 186 15293 gettid 207 => 186 1529 Note that these are equal due to obvious reasons (I'm too lazy to fork a thread).
Basically, if we extend this class with memory mapping and fd mapping, this is what we want.
(In reply to Dmitry Selyutin from comment #52) > Folks, I've played a bit more with these shiny system call tables, and added > a simple class which can be used as a basis for ppc/ppc64/i386/amd64 > conversion: > ... > This works as if somebody arrived to us with system calls 20 and 207 on PPC > and attempted to wrap their execution to amd64 (which luckily is the > platform I use). Basically it checks guest syscall table by identifier, > finds the entry, then finds the backward mapping in host syscall table, then > briefly inspects the arguments count (though we might even attempt to > validate these). I also added a wrapper to call them by names, not just > identifiers. The output is: > This is brilliant! Thanks for doing this. During learning I was struggling how to use ctypes, this is so much more capable! I'll give this a spin later.
(In reply to Dmitry Selyutin from comment #52) > Folks, I've played a bit more with these shiny system call tables, and added > a simple class which can be used as a basis for ppc/ppc64/i386/amd64 > conversion: nice! though I wouldn't bother supporting i386... note that some system calls pass in structs and stuff, and those structs often have different layouts between architectures, so they will need more complex translation than just moving registers around.
(In reply to Andrey Miroshnikov from comment #54) > (In reply to Dmitry Selyutin from comment #52) > This is brilliant! Thanks for doing this. During learning I was struggling > how to use ctypes, this is so much more capable! Nah, ctypes are easy and sweet, compared to many CFFI (C foreign function interfaces) or other tools for C interop I saw. At least they are amazing for simple tasks, and here we mostly need to wrap only one function. I'd just extend them to deal with structures and unions in a dataclass-like format, though: the current syntax for this is annoying. > I'll give this a spin later. Sure, no rush! I've updated the code calling convention a bit so that the first argument in __call__ is always expected to be a system call id (as it indeed happens IRL): https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=ad27091ea159b284c1bda2b089f670b83e5681a7 (In reply to Jacob Lifshay from comment #55) > (In reply to Dmitry Selyutin from comment #52) > > Folks, I've played a bit more with these shiny system call tables, and added > > a simple class which can be used as a basis for ppc/ppc64/i386/amd64 > > conversion: > > nice! though I wouldn't bother supporting i386... Naah it was so trivial I could not resist. > note that some system calls pass in structs and stuff, and those structs > often have different layouts between architectures, so they will need more > complex translation than just moving registers around. Yep, I know. That's why we have lookup the exact entry point and why there's a way to override some particular call by its name. :-) I'll extend this mechanism a bit though.
I stepped back and revisited the whole calls hierarchy. From now on, to call by name, we use entry point, not just a syscall "name" (that is, dispatcher.sys_openat or dispatcher.compat_sys_openat, not just dispatcher.openat). https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=5f9944b9de97ed790c34495b32d2cfbd91078a5b The good news is, overriding a custom system call is easy: class CustomDispatcher(syscalls.Dispatcher): def sys_exit(*arguments): raise 42 # not just an exit, but rather a portal!
I suggest that at this point I reserve the rest of the works to Andrey. I think that, with a couple of minor modifications (e.g. extending it with memmap and fdtree arguments), this should be fine to wrap syscalls. Please try not to make it too invasive; the code should not itself depend on ISACaller, just on the interfaces. Luke, what'd be your decision on the budget? I feel that I had to take some budget elsewhere, you suggested 981 IIRC. Would it be fine for me to flag 981 and reserve this task to you and Andrey? Is there something else I should do in scope of this task?
(In reply to Luke Kenneth Casson Leighton from comment #34) > although this looks more complete/comprehensive: > https://github.com/ssavvides/execute-syscall > Before I forget, at least three syscalls (only 'exit' is really in scope of this task) need to be bypassed as they will affect the host python program: exit, pause, vfork: https://github.com/ssavvides/execute-syscall/blob/master/execute_syscall.py#L210
(In reply to Dmitry Selyutin from comment #58) > I suggest that at this point I reserve the rest of the works to Andrey. I > think that, with a couple of minor modifications (e.g. extending it with > memmap and fdtree arguments), this should be fine to wrap syscalls. Please > try not to make it too invasive; the code should not itself depend on > ISACaller, just on the interfaces. Are you saying I should be able to do this without modifying ISACaller source at all? I guess if there's a way to pause ISACaller execution, inspect mem/reg's, then actually I don't need to touch ISACaller at all! > > Luke, what'd be your decision on the budget? I feel that I had to take some > budget elsewhere, you suggested 981 IIRC. Would it be fine for me to flag > 981 and reserve this task to you and Andrey? Is there something else I > should do in scope of this task? If there's not enough budget, I'm happy to split with Dmitry. Although your work on syscalls will eventually come in handy towards cavatools, so raising the budget is probably justified. Of course we'll wait on Luke's response.
(In reply to Andrey Miroshnikov from comment #59) > Before I forget, at least three syscalls (only 'exit' is really in scope of > this task) need to be bypassed as they will affect the host python program: > exit, pause, vfork: > https://github.com/ssavvides/execute-syscall/blob/master/execute_syscall. > py#L210 Almost everything is to be bypassed; other syscalls also make little sense unless they are bypassed. Some can be bypassed in a simpler way, e.g. those which don't have side-effects, like gettid, getpid, gettime, et al.; some need cooperation wrt resources (memory and descriptors) but are doable; some are difficult and I'm not even sure what their semantics would be (e.g. what does it mean to execve, fork or signal inside the emulator?). The three to be bypassed are shown as those which make little sense in the context of the emulation; there is a rationale above the skip list. I wouldn't say exit makes no sense though, that's kinda like simulation stop in our realm. But you should discuss it with Luke. (In reply to Andrey Miroshnikov from comment #60) > (In reply to Dmitry Selyutin from comment #58) > > I suggest that at this point I reserve the rest of the works to Andrey. I > > think that, with a couple of minor modifications (e.g. extending it with > > memmap and fdtree arguments), this should be fine to wrap syscalls. Please > > try not to make it too invasive; the code should not itself depend on > > ISACaller, just on the interfaces. > > Are you saying I should be able to do this without modifying ISACaller > source at all? > I guess if there's a way to pause ISACaller execution, inspect mem/reg's, > then actually I don't need to touch ISACaller at all! Well, some bits are still to be touched. You have to establish the interrupt descriptor table. Basically, when you execute the system call, the processor triggers an interrupt; it happens that the processor is programmed or instructed by OS to jump at some special code section and continue execution there (with the return address and arguments saved, typically on stack or via registers). You can instruct the simulator to behave respectively when it sees this handler, i.e. when sumulator realizes it's on the same instruction counter as where the handler begins. When you found the fact that you're executing the exact place as where the handler belongs, the Python code in simulator can simply be instructed to read self.gpr(XXX) based on the calling convention (just check ISA reference, they should mention "sc" parameters passing). Linux system calls generally don't use stack and never use FPRs, so you don't have to care about stack. Something like this (pseudocode, you have to dig it in ISACaller, I'm a rare guest there; I'm assuming registers 3..10, but you have to check): $ cat sim.py def __init__(self, initial_mem, regs): self.program_msrs_and_interrupts() # should likely be done by PPC assembly upon simulator start def event_loop(self, ...): while True: syscall = syscalls.Dispatcher(guest="ppc", host=YOUR_HOST_AS_PER_PYTHON) pc = self.get_next_insn() if pc == MAGIC_HANDLER: sysnum = self.gpr(3) sysargs = [self.gpr(4), self.gpr(5), self.gpr(6), self.gpr(7), self.gpr(8), self.gpr(9), self.gpr(10)] rv = syscall(sysnum, *sysargs) self.gpr(3) = rv # beware, might be a multi-word; likely you need to set both I'm not aware of PPC architecture enough; I could give you a vague hints on x86 only. I can try and check PPC ISA in this regard, if you want, but it'd be simpler to ask Jacob or Luke or perhaps Konstantinos (I'm not sure whether he dealt with PPC syscalls though). But I see that you alredy do something suspiciously similar in src/openpower/test/syscall/syscall_cases.py. :-) Practically speaking, it's just the same function call, except that you do not jump directly. You interrupt the processor, it switches the context and priviledge level, then jumps to a specific pre-programmed location, then the kernel code serves the request. There's an awful lot of details inbetween these stages, but basically (dramatically simplified) this is it.
Andrey, I think this is not the right budget distribution. :-) Remember, you still have to adjust the ISACaller, install the interrupts/traps/wowever-this-is-called-in-PPC. I'd rather prefer to take a lesser part for this, maybe 1000 or like this, and grab bug #981. Luke, could you, please, check, whether this is fine? I can create some code which converts the stuff to C so that it's better applicable to bug #981.
Andrey, I've edited the budget again and increased yours and Luke's budget, picking only 1K here; I'm expecting that bug #981 can cover all the works I did. I'm thinking about C code generation for bug #981, though, to make it better candidate for cavatools incorporation. Stay tuned.
(In reply to Dmitry Selyutin from comment #62) > Andrey, I think this is not the right budget distribution. :-) i did tell andrey not to edit the budget assignments, but he had already done it. i explained that you are a high-value contributor. they will be restored so that you receive most, but also we may find a way to increase. meeting tonight goes over it.
(In reply to Jacob Lifshay from comment #48) > (In reply to Luke Kenneth Casson Leighton from comment #47) > > where is the money coming from to implement that? > > the task we'll make when we want to support emulating mmap and/or loading > ELF binaries. which has to be *right now* as there is only 4 months left before the EU Assure Programme ENDS. to be discussed tonight. > all we'd need is to change the Mem class to use that block from mmap.mmap > instead of a dict, looking through it, i could do it in a few hours. yes it's real basic. unit test needed as well. > probably less if nothing reaches into the Mem.mem dict and fiddles with it > directly instead of calling the load/store functions. mmmm... no. TestIssuer Test API has to bypass *nmigen* mem interface but not the case with ISACaller as there is the MMU as well and messing with the internals is Bad. no need to support VM/MMU for this userspace-only mode.
(In reply to Luke Kenneth Casson Leighton from comment #64) > meeting tonight goes over it. I'm kinda lost, to be honest. Andrey, do you have time to finish it, or you'll be completely buried under 6 feet of administrative joy? :-) I'm currently concentrated on bug #981, and I assumed that you'll have to handle #982. Please let me know if this is not the case. I don't think #981 will take too long to be finished.
(In reply to Dmitry Selyutin from comment #66) > Practically speaking, it's just the same function call, except that you do > not jump directly. You interrupt the processor, it switches the context and > priviledge level, then jumps to a specific pre-programmed location, then the > kernel code serves the request. There's an awful lot of details inbetween > these stages, but basically (dramatically simplified) this is it. well, imo it would be much easier to just add an `if` to ISACaller that checks if the current insn is `sc` (or, later, `scv`) and if it is, *skips* all privilege transitions and everything, replacing all actions of `sc` with just running the syscall translation code, and then advancing to the next instruction. I'd guess this is exactly what qemu-user does. basically: class ISACaller(...): ... def call(self, name): ... asmop = yield from self.get_assembly_name() log("call", ins_name, asmop) if not self.is_svp64_mode and asmop == "sc" and self.syscall_emulation: yield from self.emulate_syscall() self.update_pc_next() return ...
(In reply to Jacob Lifshay from comment #67) > class ISACaller(...): > ... > def call(self, name): > ... > asmop = yield from self.get_assembly_name() > log("call", ins_name, asmop) > > if not self.is_svp64_mode and asmop == "sc" and self.syscall_emulation: > yield from self.emulate_syscall() > self.update_pc_next() > return > ... def emulate_syscall(self): syscall_num = self.gpr(0) if syscall_num in self.syscall_table: yield from self.syscall_table[syscall_num](self) else: self.cr.crl[0][CRFields.SO] = 1 self.gpr[3] = ENOSYS
(In reply to Dmitry Selyutin from comment #66) > (In reply to Luke Kenneth Casson Leighton from comment #64) > > meeting tonight goes over it. > > I'm kinda lost, to be honest. Andrey, do you have time to finish it, or > you'll be completely buried under 6 feet of administrative joy? :-) I'm > currently concentrated on bug #981, and I assumed that you'll have to handle > #982. Please let me know if this is not the case. I don't think #981 will > take too long to be finished. Sorry for the late response Dmitriy. If you think that you and Jacob can do a much quicker job at this, I'm happy to hand it over to you. Currently I have too much admin work to think about. Given that you seem to be in the zone atm, probably more efficient too.
This is not difficult to handle at least to degree present in cavatools. However, I'd first like to know the fate of #981 which is already done. https://bugs.libre-soc.org/show_bug.cgi?id=981#c13 https://bugs.libre-soc.org/show_bug.cgi?id=981#c14
(In reply to Jacob Lifshay from comment #67) > if not self.is_svp64_mode and asmop == "sc" and > self.syscall_emulation: > yield from self.emulate_syscall() > self.update_pc_next() > return this is the preferred method, where emulate_syscall() is about... 10-15 lines of code covering *every* syscall, because the mmap'd area is in the exact same memory location as where the ELF relocation targetted it. (plus mmap and malloc/free redirect/replacement) (with an option to specify what that is, on the command-line) (In reply to Jacob Lifshay from comment #68) > def emulate_syscall(self): > syscall_num = self.gpr(0) > if syscall_num in self.syscall_table: > yield from self.syscall_table[syscall_num](self) > else: > self.cr.crl[0][CRFields.SO] = 1 > self.gpr[3] = ENOSYS this is the "last resort" method that actually is in some ways "better", because by literally implementing every single POSIX (ok ok i know Dmitry, it's not actually POSIX) call we have no "hacks" - just a hell of a lot of work ahead instead.
(In reply to Dmitry Selyutin from comment #66) > I'm > currently concentrated on bug #981, and I assumed that you'll have to handle > #982. Please let me know if this is not the case. I don't think #981 will > take too long to be finished. ok so from a technical perspective, making any changes or improvements to cavatools is a non-starter at the moment (far too much to do to get everything else for cavatools-ppc64 going: decoder, compiler, everything). cavatools-RISC-V works very well: it is high-performance and if there are syscall mis-matches then that is solved by running *on native hardware*. if any "redirection" tables are added it *actually defeats the objective* of cavatools by slowing down its high performance (50x to 100x faster than qemu). for the exact same reason, *when* we come to doing cavatools-ppc64 (which is not right now, that was what the wednesday meeting was about) then the exact same trick can be done: "if problems on syscall mis-match due to host-guest being different, then run on an IBM POWER9".
(In reply to Luke Kenneth Casson Leighton from comment #71) > (In reply to Jacob Lifshay from comment #68) > > > def emulate_syscall(self): > > syscall_num = self.gpr(0) > > if syscall_num in self.syscall_table: > > yield from self.syscall_table[syscall_num](self) > > else: > > self.cr.crl[0][CRFields.SO] = 1 > > self.gpr[3] = ENOSYS > > this is the "last resort" method that actually is in some > ways "better", because by literally implementing every single > POSIX (ok ok i know Dmitry, it's not actually POSIX) call > we have no "hacks" - just a hell of a lot of work ahead instead. the idea is self.syscall_table has every syscall we implement, not every syscall implemented by the linux kernel.
With few fixes and updates... https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=50160605d50567b43e6918f523646b5f37561814 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=67eaadfa05989ea255159e5f00406ab6488806a3 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=b2bbeec1bad4f579436f7edbb7e1a56dd5d875ff https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=99c290ff878dbdb03ffd8b90964fcc1bd02452d0 ...I've been able to support system calls translation in ISACaller in scemu branch: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=ebbde87d40f606526e846e43e4fc594fb892fec4 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=90ae25eaf809d023b92bd2f2c2a1c038228f9d76 There are some tests: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=c1af87691aaa83838514d3a5ed5ca85f14d86720 If you could help me with what should be the action on exit/exit_group, I could demonstrate how we override the syscall. But, basically, it's this: class SyscallEmulator(openpower.syscalls.Dispatcher): def sys_exit(self, *_): raise StopIteration def sys_exit_group(self, *_): raise StopIteration
We might opt to check more, say flags after sc instruction, but basically this is it. Note that I pass isacaller instance; we might find it handy for cases when we need to deal with the memory.
(In reply to Dmitry Selyutin from comment #74) > If you could help me with what should be the action on exit/exit_group, I > could demonstrate how we override the syscall. But, basically, it's this: > > class SyscallEmulator(openpower.syscalls.Dispatcher): > def sys_exit(self, *_): > raise StopIteration > > def sys_exit_group(self, *_): > raise StopIteration because most of ISACaller's methods are generators, StopIteration interferes with that, so imo we need a new exception class that the main loop catches and exits.
(In reply to Jacob Lifshay from comment #76) > because most of ISACaller's methods are generators, StopIteration interferes > with that, so imo we need a new exception class that the main loop catches > and exits. Nah that was just a wild guess, I didn't really know what to do. But I saw that this is a generator, so I decided to raise it as an exit method. Appears that this guess was correct, just another exception should'be been used?
(In reply to Dmitry Selyutin from comment #74) > There are some tests: > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=c1af87691aaa83838514d3a5ed5ca85f14d86720 that should be in a different file: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/test/syscall/syscall_cases.py;hb=c1af87691aaa83838514d3a5ed5ca85f14d86720 or as a new unittest class in: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/test_caller_syscall.py;h=b6f57a753e7c186de7d8b395cff5bb8b3a7d5139;hb=c1af87691aaa83838514d3a5ed5ca85f14d86720 (don't modify the existing class there)
(In reply to Jacob Lifshay from comment #76) > because most of ISACaller's methods are generators, StopIteration interferes > with that, so imo we need a new exception class that the main loop catches > and exits. don't do massive indents of large swathes of code though. put the try/except in one of the small functions... ah! execute_one. perfect. it already is the main execution funtion and has a mem-exception catch. don't put it anywhere else.
(In reply to Jacob Lifshay from comment #73) > the idea is self.syscall_table has every syscall we implement, not every > syscall implemented by the linux kernel. this is the fallback position. it is a hell of a lot of work.
(In reply to Luke Kenneth Casson Leighton from comment #79) > don't do massive indents of large swathes of code though. put the > try/except in one of the small functions... ah! execute_one. perfect. > it already is the main execution funtion and has a mem-exception catch. > > don't put it anywhere else. actually, imo it's better to put it here: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/test_runner.py;h=b84354cc099cfba908629b9c17b903990fc79388;hb=c1af87691aaa83838514d3a5ed5ca85f14d86720#l79 just wrap the execute_one call in a try-except-break like is done for setup_one a few lines above
(In reply to Dmitry Selyutin from comment #74) > ...I've been able to support system calls translation in ISACaller in scemu > branch: note that sc is kinda weird...on errors it sets CR0.SO and returns the error code in r3 as a *positive* integer. scv is closer to linux's standard convention of small negative results means errors.
(In reply to Dmitry Selyutin from comment #74) > With few fixes and updates... > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=50160605d50567b43e6918f523646b5f37561814 > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=67eaadfa05989ea255159e5f00406ab6488806a3 > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=b2bbeec1bad4f579436f7edbb7e1a56dd5d875ff > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=99c290ff878dbdb03ffd8b90964fcc1bd02452d0 > > ...I've been able to support system calls translation in ISACaller in scemu > branch: briiilliant, i love it. *this* (the integration into ISACaller) is what i meant by "working *towards* ISACaller" under bug #981. *this* is the work that justifies receiving bug #981 budget. this comment should have been posted under bug #981, with suitable explanation that we are using bug #981 to *research working towards* cavatools-ppc64, for a future grant. see how that works? leave it though, i will explain it to NLnet. or, explain it to Andrey and he can (on preparing what to write) explain it to them. welcome to the massive hidden burden of Administrative Project Management, Andrey.
(In reply to Jacob Lifshay from comment #81) > just wrap the execute_one call in a try-except-break like is done for > setup_one a few lines above why do you think i said "do not do anything other than that function"? because i know it is called directly by some of the Test API. please listen, don't force me to explain things i do not want to spend time explaining. please permanently break this habit. except when what i ask is clearly stupid :)
(In reply to Jacob Lifshay from comment #81) > actually, imo it's better to put it here: > https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/ > decoder/isa/test_runner.py;h=b84354cc099cfba908629b9c17b903990fc79388; > hb=c1af87691aaa83838514d3a5ed5ca85f14d86720#l79 no because it's not the only place it's called. keep it inside ISACaller please.
(In reply to Luke Kenneth Casson Leighton from comment #84) > (In reply to Jacob Lifshay from comment #81) > > just wrap the execute_one call in a try-except-break like is done for > > setup_one a few lines above > > why do you think i said "do not do anything other than that function"? well, that doesn't work because it won't make the loop exit without signalling that it's done somehow...so, you can put the try-except in execute_one but it needs to return False or something that the caller can use so it knows to stop. all callers need to be modified to detect that and stop looping (unless they don't call execute_one in a loop)
(In reply to Jacob Lifshay from comment #86) > well, that doesn't work because it won't make the loop exit without > signalling that it's done somehow...so, you can put the try-except in > execute_one but it needs to return False or something that the caller can > use so it knows to stop. set a boolean flag instead. have setup_one throw KeyError. document it and link here as part of the comments. i don't want time wasted hunting down a change to the existing API. > all callers need to be modified to detect that and stop looping (unless they > don't call execute_one in a loop) no. throw KeyError right at the start of setup_one. documented. 65 while index < len(instructions): 66 print("instr pc", pc) 67 try: 68 yield from simulator.setup_one() 69 except KeyError: # instruction not in imem: stop 70 break 71 yield Settle()
I created a MemMMap class which can be used to get a raw ctypes.c_ubyte * N array that can be passed to read/write/etc. enabling it for ISACaller: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=9437aa56d550b9a66772068cf685b06e2d7d263f testing reading/writing through the ctypes array returned by MemMMap.get_ctypes (method naming suggestions appreciated): https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/test_mem.py;h=e57d199148a86de07f67645bb009075005e9f2f3;hb=50cb080ba742df15e33422000b82a015c211aa5b#l97
(In reply to Jacob Lifshay from comment #88) > I created a MemMMap class which can be used to get a raw > ctypes.c_ubyte * N array that can be passed to read/write/etc. > > enabling it for ISACaller: > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=9437aa56d550b9a66772068cf685b06e2d7d263f remember bug #1174 can you please put a # TODO on that to explain, so it is not lost. i will crossref here > testing reading/writing through the ctypes array returned by > MemMMap.get_ctypes (method naming suggestions appreciated): looks good > https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/ > decoder/isa/test_mem.py;h=e57d199148a86de07f67645bb009075005e9f2f3; > hb=50cb080ba742df15e33422000b82a015c211aa5b#l97 renember to add yourself 2023 to the copyright header.
Folks, could you, please, take a look at scemu branch and summarize what's missing or needs to be improved before we can close this task? Just look at top 7 commits, ignore anything before. https://git.libre-soc.org/?p=openpower-isa.git;a=shortlog;h=refs/heads/scemu
Andrey, please discuss the budget with Luke and Jacob and sync it as you feel appropriate, OK? If there's something which can be allocated here based on amount of my works, that'd be great, but I feel that Jacob's works might end up unappreciated.
(In reply to Dmitry Selyutin from comment #91) > Andrey, please discuss the budget with Luke and Jacob and sync it as you > feel appropriate, OK? If there's something which can be allocated here based > on amount of my works, that'd be great, but I feel that Jacob's works might > end up unappreciated. well, bug #1169 and bug #1173 are listed as blocking bug #983 since I think that's where they should get their funding from. if we decide that they shouldn't be under bug #983 because the ELF support should be in a new grant, then I think bug #1173 should probably get its funding from this bug.
(In reply to Dmitry Selyutin from comment #90) > Folks, could you, please, take a look at scemu branch and summarize what's > missing or needs to be improved before we can close this task? Just look at > top 7 commits, ignore anything before. > > https://git.libre-soc.org/?p=openpower-isa.git;a=shortlog;h=refs/heads/scemu v quick. 2am. + if not self.is_svp64_mode and asmop in ("sc", "scv"): + identifier = self.gpr(0) 1. it is impossible to have svp64 on sc and scv. sv.sc or sv.scv will NEVER happen. 2. redirecting ALL sc and scv calls as i said on the call today destroys unit tests on sc and scv (equivalent to qemu-system) 3. running in user mode *must* be made optional just as jacob described in the chat logs of today's call (equivalent to qemu-user) + with Program(lst, bigendian=False) as program: + sim = self.run_tst_program(program, initial_regs, >>>>usermode_emu_sc=True<<<<) 4. enabling usermode_emu_sc *must* enable the mmap memory mode as well.
(please ignore this for now, will edit and correct) --- a/src/openpower/decoder/power_enums.py +++ b/src/openpower/decoder/power_enums.py @@ -811,6 +811,7 @@ _insns = [ + "sc", "scv", that's odd. i must have not added sc/scv unit tests to ISACaller. these should be added (into trap_cases.py) as it is important to verify the pseudocode when in equivalent of qemu-system mode (the default only option up until this bugreport) https://libre-soc.org/openpower/isa/system/ hmmm actually only the sc one. scv i expect to fail with an undefined variable "vectored" (sigh) the unit test will be like this: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/test/trap/trap_cases.py;h=1501b8ab#l62 except there must be a stop/check when PC=0xC00.
https://git.libre-soc.org/?p=soc.git;a=blob;f=src/soc/fu/trap/main_stage.py;h=8127e226#l375 364 with m.Case(MicrOp.OP_SC): 374 # jump to the trap address, return at cia+4 375 self.trap(m, 0xc00, cia_i+4) 376 self.msr_exception(m, 0xc00) ok this is the HDL implementation of sc, which needs the unit test i started attempting to describe in comment #94. HDL testing through the TestAPI *needs* ISACaller to compare against and make sure that the MSR and PC are correct. therefore we *cannot* have an unconditional redirection of sc instruction (if asmop == "sc") because otherwise how can we test the HDL? therefore... that flag (user_emu_syscall or whatever) is necessary and ultimately must be propagated through to pypowersim command-line, *exactly* as how you execute qemu-user vs qemu-system.
I had to jiggle the commits somewhat due to addition of the arguments, and also I decided that it's better for syscall tests to be decoupled. 1. Redundant check for SVP64 is dropped: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=ba551ab85cb1dd7a0fd283b9fe3f70781429fc9c 2. use_syscall_emu parameter is now supported in test_runner, caller and runner modules: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=91d8332a0ea5fa54ebdfe070a4ef383f1189dc64 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=1776e7690367a5f24f32722283a322560d345f55 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=434cdd300e70fcb307f8d00b0553ec19ea67952a 3. Host-backed memory is now activated with some croaking around: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=c35dd70d41b1ccea51319071d80b18b723692f13 4. Tests are decoupled, the commit which poked test_caller.py is dropped: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=e69f8bfcc7c7c04459c408cdc5c06e3680ebc926 Is there anything else to be added considering the description and the title of the task?
(In reply to Dmitry Selyutin from comment #96) > I had to jiggle the commits somewhat due to addition of the arguments, and > also I decided that it's better for syscall tests to be decoupled. > > 1. Redundant check for SVP64 is dropped: great > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=ba551ab85cb1dd7a0fd283b9fe3f70781429fc9c > > 2. use_syscall_emu parameter is now supported in test_runner, caller and > runner modules: exxxcellent. the enabling mmap is good. otherwise it all goes horribly awry... > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=91d8332a0ea5fa54ebdfe070a4ef383f1189dc64 > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=1776e7690367a5f24f32722283a322560d345f55 > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=434cdd300e70fcb307f8d00b0553ec19ea67952a > > 3. Host-backed memory is now activated with some croaking around: yehh no surpriiise but a good way to do it > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=c35dd70d41b1ccea51319071d80b18b723692f13 > > 4. Tests are decoupled, the commit which poked test_caller.py is dropped: gooood. > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=e69f8bfcc7c7c04459c408cdc5c06e3680ebc926 > > Is there anything else to be added considering the description and the title > of the task? ok there is a unit test needed in trap_cases.py (see comment #94) which will demonstrate why the following is not correct to do: 1952 # TODO, asmregs is from the spec, e.g. add RT,RA,RB 1953 # see http://bugs.libre-riscv.org/show_bug.cgi?id=282 1954 asmop = yield from self.get_assembly_name() 1955 log("call", ins_name, asmop, 1956 kind=LogKind.InstrInOuts) 1957 (put a comment here please, "in user mode emulate syscalls" or something) 1958 if asmop in ("sc", "scv"): 1959 if self.syscall is not None: 1960 identifier = self.gpr(0) 1961 arguments = map(self.gpr, range(3, 9)) 1962 result = self.syscall(identifier, *arguments) 1963 self.gpr.write(3, result, False, self.namespace["XLEN"]) 1964 self.update_pc_next() 1965 return 1966 >>> else: <<<< 1967 >>>> self.call_trap(0x700, PIb.ILLEG) <<<< 1968 >>> return <<<< what lines 1966 to 1968 are doing is making "sc" *ILLEGAL* to even execute. if scemu is not active (equivalent of qemu-user) you *MUST* let sc's pseudocode be executed just like any other instruction: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=openpower/isa/system.mdwn;h=74f06c50#l13 7 # System Call 8 9 SC-Form 10 11 * sc LEV 12 13 Pseudo-code: 14 15 SRR0 <-iea CIA + 4 16 SRR1[33:36] <- 0 17 SRR1[42:47] <- 0 18 SRR1[0:32] <- MSR[0:32] 19 SRR1[37:41] <- MSR[37:41] 20 SRR1[48:63] <- MSR[48:63] 21 MSR <- new_value 22 NIA <- 0x0000_0000_0000_0C00 23 24 Special Registers Altered: 25 26 SRR0 SRR1 MSR so those three lines must go, as they prohibit us from running the "sc" instruction when the simulator is in the same type of mode as "qemu-system". i will write an sc unit test and commit it so that you can run it, and see what i mean ok?
(In reply to Luke Kenneth Casson Leighton from comment #97) > (In reply to Dmitry Selyutin from comment #96) > what lines 1966 to 1968 are doing is making "sc" *ILLEGAL* to > even execute. Ah OK, I begin to understand what you mean. The emulator just routes the execution to a well-known address, saving the registers and parts of context, right? And we basically emulate the whole world, kinda like regular qemu, and it'll be up to OS run in the emulator to establish the code at that address where we jump, is it what you mean? > > so those three lines must go, as they prohibit us from running > the "sc" instruction when the simulator is in the same type > of mode as "qemu-system". Not like that we were able to do it before. :-) I kinda had an impression from comment #2 that the point of this task was to enable userspace syscall emulation. OK, if we still have some work to do, it'd be great to adjust the budget: even the works I already completed were somewhat bigger to fit into 1000 I have as of now. :-) > i will write an sc unit test and commit it so that you can run it, > and see what i mean ok? Sure, that'd be great! Thank you!
(In reply to Luke Kenneth Casson Leighton from comment #97) > (put a comment here please, "in user mode emulate syscalls" > or something) Sorry, I missed this part. I'll handle it when I'll deal with the emulator. Before that point, that was already obvious, based on `call_trap` in else branch and `if use_syscall_emu` in its counterpart. :-)
(In reply to Dmitry Selyutin from comment #98) > Ah OK, I begin to understand what you mean. The emulator just routes the > execution to a well-known address, saving the registers and parts of > context, right? saving registers no, swapping MSR->SRR1 and PC->SRR0, and then setting up MSR to a "known good state suitable for a kernel"... yes. i just sorted that out - it was a bit of a mess > And we basically emulate the whole world, kinda like regular > qemu, aka qemu-system, yeeees > and it'll be up to OS run in the emulator to establish the code at > that address where we jump, is it what you mean? by running the pseudocode for sc (after compiling to python) just like any other pseudocode instruction... which i've just had to modify to get the damn thing to work... yes. https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=c91aa3ee > > > > so those three lines must go, as they prohibit us from running > > the "sc" instruction when the simulator is in the same type > > of mode as "qemu-system". > > Not like that we were able to do it before. :-) in TestIssuer (the HDL) yes. ISACaller no, because the Power ISA spec says, in the pseudocode, "assign MSR to new_value" MSR <- new_value then takes you on a stupid stupid wild goose chase "go to this page" which then says "go to this other page" > I kinda had an impression > from comment #2 that the point of this task was to enable userspace syscall > emulation. yeees... but not in the process making it impossible to do the equivalent of qemu-system! i was not expecting to have to sort out the sc pseudocode "on-the-fly" but it was important to do so, so that when we come to doing HDL-vs-ISACaller tests of "sc", ISACaller-in-qemusystem-mode actually works. gaah. https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/test/trap/trap_cases.py;h=32b20125f#l54 you can see, after the sc instruction executes, what the expected value of MSR, PC, SRR0 and SRR1 should be 59 # expected results: PC should be at 0xc00 (sc address) 60 e = ExpectedState(pc=0xc00) 61 e.intregs[1] = 1 62 e.sprs['SRR0'] = 4 # PC to return to: CIA+4 63 e.sprs['SRR1'] = 0x9000000000022903 # MSR to restore after sc return 64 e.msr = 0x9000000000000001 # MSR changed to this by sc/trap > OK, if we still have some work to do, it'd be great to adjust the > budget: even the works I already completed were somewhat bigger to fit into > 1000 I have as of now. :-) yes i know. one for tomorrow. > > i will write an sc unit test and commit it so that you can run it, > > and see what i mean ok? > > Sure, that'd be great! Thank you! done, but i had to revert some code that jacob had added. you'll need to re-run pywriter and pyfnwriter jacob can you please take a look as i have absolutely no clue why copy_assign_rhs was added, it really should not have been, there are ways to write the pseudocode such that it is not necessary to do (variable <- [0]*64 is the usual one)
(In reply to Jacob Lifshay from comment #92) > (In reply to Dmitry Selyutin from comment #91) > > Andrey, please discuss the budget <snip> I feel that Jacob's works might > > end up unappreciated. > > well, bug #1169 and bug #1173 are listed as blocking bug #983 since I think > that's where they should get their funding from. <snip> https://bugs.libre-soc.org/show_bug.cgi?id=1066#c5 Luke says I should get paid some for bug #1066, I think EUR 200-500 from this bug for my suggestions here and work on #1066 is a good amount based on how much time I spent. This is assuming bug #1069 and bug #1173 get paid from bug #983 instead of here.
I've updated the code logic so that it executes in a common way, except that we can use emulation if this was desired: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=c215d24e6a3983e9da525ea04bc710abb605c256 I also checked that sc test from trap_cases works. I tried to adopt the SRR1 and MSR checks there, but the values I got are different, no idea why. SRR0 check works though. https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=a31c1b972039ff28c0d4e289e759c93e22bf65ff Ideas on SRR1/MSR checks are highly appreciated.
(In reply to Jacob Lifshay from comment #101) > https://bugs.libre-soc.org/show_bug.cgi?id=1066#c5 > Luke says I should get paid some for bug #1066, I think EUR 200-500 from > this bug for my suggestions here and work on #1066 is a good amount based on > how much time I spent. This is assuming bug #1069 and bug #1173 get paid > from bug #983 instead of here. Sure. I'll let Andrey and Luke handle this. (In reply to Luke Kenneth Casson Leighton from comment #100) > (In reply to Dmitry Selyutin from comment #98) > > OK, if we still have some work to do, it'd be great to adjust the > > budget: even the works I already completed were somewhat bigger to fit into > > 1000 I have as of now. :-) > > yes i know. one for tomorrow.
(In reply to Dmitry Selyutin from comment #102) > I've updated the code logic so that it executes in a common way, except that > we can use emulation if this was desired: > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=c215d24e6a3983e9da525ea04bc710abb605c256 briilliant. so yes, if self.syscalls is not set up, that's perfect. errr hang on though, you forgot these: - self.update_pc_next() - return the actual sequence *to be emulated* is (i left out MSR): PC=0x00000 addi r0,r0,N # syscall number PC=0x00004 sc LEV=0 # syscall which causes saving to SRR1/SRR0 PC=0x00C00 .... # OS starts doing context-switch here PC=0x00C70 .... # OS starts doing actual syscall about here PC=0x00Ce0 .... # OS starts RESTORING context here PC=0x00Ce4 rfid # rfid *RESTORES* SRR1/SRR0 into MSR/PC... PC=0x00008 usercode # ... aaand we are back to after the syscall therefore hmmm what must be done by the emulator is: PC=0x00000 addi r0,r0,N # syscall number PC=0x00004 sc LEV=0 # syscall *and effect of sc and rfid* EMULATED PC=0x00008 usercode # ... aaand we are back to after the syscall strictly speaking some bits of MSR must be set to zero, it must be as if sc is called then rfid called. > I also checked that sc test from trap_cases works. > I tried to adopt the SRR1 and MSR checks there, but the values I got are > different, no idea why. ah. right. ok. the clue is the modifications to SRR1 and MSR made by the back-to-back sc and rfid. BUT... to properly check this you have to have a program that does both an sc and an rfid, hmmm.... but for now you are missing the "updatepcnext" and the return, but this is still *not* quite correct, see below > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=a31c1b972039ff28c0d4e289e759c93e22bf65ff > > Ideas on SRR1/MSR checks are highly appreciated. ok i know what to do. 1943 def call(self, name, CHEAT=False): 2056 # Usermode system call emulation 2057 if asmop in ("sc", "scv") and self.syscall is not None AND NOT CHEAT: # must emulate the effect of sc followed by rfid. self.call(asmop, CHEAT=True) # now do the emulated syscall... 2058 identifier = self.gpr(0) 2059 arguments = map(self.gpr, range(3, 9)) 2060 result = self.syscall(identifier, *arguments) 2061 self.gpr.write(3, result, False, self.namespace["XLEN"]) # now emulate "return from interrupt" self.call("rfid") # and we are done here. above, rfid updates pc already return see what's happening there? the sc is performed on a "cheat", which *runs the sc pseudocode*, then you emulate the syscall, then pretend that there was an OS that swapped all the context back and as the last thing, does rfid which we can emulate by *running the rfid pseudocode* worst most elegant hack i can think of that gets the job done fast. otherwise you have to analyse the effect of the sc and rfid pseudocode back-to-back: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=openpower/isa/system.mdwn;h=958502d3#l48 to be absolutely honest there's no point when you can just do self.call("sc") and self.call("rfid") what i suggest is just to set MSR=0xfffffffffffffff and see what value it gets set to afterwards. then use that to work out the "masking" effect. test_syscall.py: + initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678} + sim = run_tst(prog, initial_regs, + initial_sprs=initial_sprs, initial_msr=0xffffffffffffffff, + use_syscall_emu=True)
i'm updating the budget to reflect quite a lot of related work by jacob, and the shenanigens for me doing trap unt tests. i have another one to write which is a bit sophisticated, using the "offset" location to start at a non-standard location (normally all programs start at 0x0000) this will allow verifying what happens on a back-to-back sc+rfid
(In reply to Luke Kenneth Casson Leighton from comment #104) > (In reply to Dmitry Selyutin from comment #102) > > I've updated the code logic so that it executes in a common way, except that > > we can use emulation if this was desired: > > > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > h=c215d24e6a3983e9da525ea04bc710abb605c256 > > briilliant. so yes, if self.syscalls is not set up, that's perfect. > > errr hang on though, you forgot these: > > - self.update_pc_next() > - return https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/test_syscall.py;h=74b336839ae677be9f25e66a8f3f422d7ef18718;hb=a31c1b972039ff28c0d4e289e759c93e22bf65ff#l19 This is explicitly checked here. The trick is that some code later already does it. Also, if we return, we won't execute the pseudocode, which is something we want to do. > the actual sequence *to be emulated* is (i left out MSR): > > PC=0x00000 addi r0,r0,N # syscall number > PC=0x00004 sc LEV=0 # syscall which causes saving to SRR1/SRR0 > PC=0x00C00 .... # OS starts doing context-switch here > PC=0x00C70 .... # OS starts doing actual syscall about here > PC=0x00Ce0 .... # OS starts RESTORING context here > PC=0x00Ce4 rfid # rfid *RESTORES* SRR1/SRR0 into MSR/PC... > PC=0x00008 usercode # ... aaand we are back to after the syscall > > therefore hmmm what must be done by the emulator is: > > PC=0x00000 addi r0,r0,N # syscall number > PC=0x00004 sc LEV=0 # syscall *and effect of sc and rfid* EMULATED > PC=0x00008 usercode # ... aaand we are back to after the syscall Is rfid handled by the kernel? Kinda like sysret/sysexit in x86? > strictly speaking some bits of MSR must be set to zero, > it must be as if sc is called then rfid called. > > > I also checked that sc test from trap_cases works. > > I tried to adopt the SRR1 and MSR checks there, but the values I got are > > different, no idea why. > > ah. right. ok. the clue is the modifications to SRR1 and MSR made > by the back-to-back sc and rfid. > > BUT... to properly check this you have to have a program that > does both an sc and an rfid, hmmm.... I don't quite get how trap_cases do it. They have separate tests for rfid, that's true. But I don't see rfid in the sc test case itself... > but for now you are missing the "updatepcnext" and the return, See above. > but this is still *not* quite correct, see below > > > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > h=a31c1b972039ff28c0d4e289e759c93e22bf65ff > > > > Ideas on SRR1/MSR checks are highly appreciated. > > ok i know what to do. > > 1943 def call(self, name, CHEAT=False): > > 2056 # Usermode system call emulation > 2057 if asmop in ("sc", "scv") and self.syscall is not None > AND NOT CHEAT: > # must emulate the effect of sc followed by rfid. > self.call(asmop, CHEAT=True) > # now do the emulated syscall... > 2058 identifier = self.gpr(0) > 2059 arguments = map(self.gpr, range(3, 9)) > 2060 result = self.syscall(identifier, *arguments) > 2061 self.gpr.write(3, result, False, self.namespace["XLEN"]) > # now emulate "return from interrupt" > self.call("rfid") > # and we are done here. above, rfid updates pc already > return This seems to update PC twice, if I'm not mistaken. > to be absolutely honest there's no point when you can just do > self.call("sc") and self.call("rfid") Yes, mine impression is the same. After all, emulating system calls is not the only thing we have to support in order to emulate user mode; however, I feel that the rest is outside of the scope of the changes we initially discussed. > what i suggest is just to set MSR=0xfffffffffffffff and see what value > it gets set to afterwards. then use that to work out the "masking" > effect. > > test_syscall.py: > > + initial_sprs = {'SRR0': 0x12345678, 'SRR1': 0x5678} > + sim = run_tst(prog, initial_regs, > + initial_sprs=initial_sprs, > initial_msr=0xffffffffffffffff, > + use_syscall_emu=True) Sorry, I didn't get it. Do you suggest to check that MSR just got changed from that initial value (assertNotEqual)?
(In reply to Dmitry Selyutin from comment #106) > Is rfid handled by the kernel? Kinda like sysret/sysexit in x86? Ah OK. I'm an idiot, that's just iret.
Hm hm hm. Luke, if my statements on PC are correct, we might do something like this (also brutal but perhaps more obvious than CHEAT): def do_outregs_nia(self, asmop, ins_name, info, outs, ca_en, rc_en, ffirst_hit, ew_dst, rfid=False): # snip if nia_update and not rfid: self.update_pc_next() def call(self, name, rfid=False): # snip if asmop in ("sc", "scv") and self.syscall is not None: identifier = self.gpr(0) arguments = map(self.gpr, range(3, 9)) result = self.syscall(identifier, *arguments) self.gpr.write(3, result, False, self.namespace["XLEN"]) # snip # any modified return results? yield from self.do_outregs_nia(asmop, ins_name, info, outs, carry_en, rc_en, ffirst_hit, ew_dst, rfid=rfid) if asmop in ("sc", "scv") and self.syscall is not None: return self.call("rfid") An alternative is: def call(self, name): # snip scemu = (asmop in ("sc", "scv") and self.syscall is not None) yield from self.do_outregs_nia(asmop, ins_name, info, outs, carry_en, rc_en, ffirst_hit, ew_dst, update_pc=not scemu) if scemu: self.call("rfid", update_pc=False)
Sorry, typo. Yes, I really like this: def do_outregs_nia(self, asmop, ins_name, info, outs, ca_en, rc_en, ffirst_hit, ew_dst, update_pc=True): # snip if nia_update and update_pc: self.update_pc_next() def call(self, name): # snip scemu = (asmop in ("sc", "scv") and self.syscall is not None) yield from self.do_outregs_nia(asmop, ins_name, info, outs, carry_en, rc_en, ffirst_hit, ew_dst, update_pc=not scemu) if scemu: self.call("rfid")
(In reply to Dmitry Selyutin from comment #106) > (In reply to Luke Kenneth Casson Leighton from comment #104) > > (In reply to Dmitry Selyutin from comment #102) > > > I've updated the code logic so that it executes in a common way, except that > > > we can use emulation if this was desired: > > > > > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > > h=c215d24e6a3983e9da525ea04bc710abb605c256 > > > > briilliant. so yes, if self.syscalls is not set up, that's perfect. > > > > errr hang on though, you forgot these: > > > > - self.update_pc_next() > > - return > > https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/ > decoder/isa/test_syscall.py;h=74b336839ae677be9f25e66a8f3f422d7ef18718; > hb=a31c1b972039ff28c0d4e289e759c93e22bf65ff#l19 > > This is explicitly checked here. The trick is that some code later already > does it. Also, if we return, we won't execute the pseudocode, which is > something we want to do. > > > the actual sequence *to be emulated* is (i left out MSR): > > > > PC=0x00000 addi r0,r0,N # syscall number > > PC=0x00004 sc LEV=0 # syscall which causes saving to SRR1/SRR0 > > PC=0x00C00 .... # OS starts doing context-switch here > > PC=0x00C70 .... # OS starts doing actual syscall about here > > PC=0x00Ce0 .... # OS starts RESTORING context here > > PC=0x00Ce4 rfid # rfid *RESTORES* SRR1/SRR0 into MSR/PC... > > PC=0x00008 usercode # ... aaand we are back to after the syscall > Is rfid handled by the kernel? Kinda like sysret/sysexit in x86? kernel - as in: the above sequence when PC is between 0xc00 and 0xce4... yes. PC=0x000 USER PC=0x004 USER PC=0xc00 KERNEL ... PC=0xce4 KERNEL PC=0x008 USER > I don't quite get how trap_cases do it. They have separate tests for rfid, > that's true. But I don't see rfid in the sc test case itself... that's because i have only just written it. https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=9605c45 > > but for now you are missing the "updatepcnext" and the return, > > See above. you have misunderstood. > This seems to update PC twice, if I'm not mistaken. not "seems" - *DOES*. please use that sequence (also include the comments). > > to be absolutely honest there's no point when you can just do > > self.call("sc") and self.call("rfid") > > Yes, mine impression is the same. After all, emulating system calls is not > the only thing we have to support in order to emulate user mode; however, I > feel that the rest is outside of the scope of the changes we initially > discussed. no it is not. the scope (goal) has not changed in any way. however i had not predicted that the *implementation* would *require* the simulator to not only run the full pseudocode of sc but also run the full pseudocode of rfid *after* the emulated-syscall as a way to *meet* that goal. > Sorry, I didn't get it. Do you suggest to check that MSR just got changed > from that initial value (assertNotEqual)? run the unit test that i have just written, you will then understand what is required (which is written out in comment #114).
(In reply to Luke Kenneth Casson Leighton from comment #110) > > I don't quite get how trap_cases do it. They have separate tests for rfid, > > that's true. But I don't see rfid in the sc test case itself... > > that's because i have only just written it. > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=9605c45 OK, will check. > > > > but for now you are missing the "updatepcnext" and the return, > > > > See above. > > you have misunderstood. Then, please, explain _what_ is misunderstood. If I do not return prematurely then I still get an incremented PC, which is shown by the test. I want the code to follow the same logic everywhere and avoid custom cases. > > This seems to update PC twice, if I'm not mistaken. > > not "seems" - *DOES*. please use that sequence (also include the comments). I see one issue with the sequence you suggest. Even if we're fine with updating PC twice (and it seems we are, because we have to do rfid anyway), we have a completely custom sequence, and I don't see a good rationale to have it customized there. > no it is not. the scope (goal) has not changed in any way. however i > had not predicted that the *implementation* would *require* the simulator > to not only run the full pseudocode of sc but also run the full pseudocode > of rfid *after* the emulated-syscall as a way to *meet* that goal. OK, this wording makes it clearer. > > Sorry, I didn't get it. Do you suggest to check that MSR just got changed > > from that initial value (assertNotEqual)? > > run the unit test that i have just written, you will then understand what > is required (which is written out in comment #114). Ack.
OK, considering that PC is incremented twice, why have CHEAT at all? def call(self, name): # snip header scemu = (asmop in ("sc", "scv") and self.syscall is not None) if scemu: identifier = self.gpr(0) arguments = map(self.gpr, range(3, 9)) result = self.syscall(identifier, *arguments) self.gpr.write(3, result, False, self.namespace["XLEN"]) # snip middle # footer if scemu: self.call("rfid")
(In reply to Dmitry Selyutin from comment #112) > OK, considering that PC is incremented twice, why have CHEAT at all? because you have to run the emulated-sc *before* running the emulated-syscall, and what if the syscall *needs the PC*? reminder: speed is not important, at all. > # snip middle ... which is HUNDREDS of lines. no. the code is complex enough as it is. keep the group together.
https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=eee2cb24e2f added in extra comments so it is clear the return result from the syscall is in r3. also crossref'd to the discussion here
(In reply to Luke Kenneth Casson Leighton from comment #113) > ... which is HUNDREDS of lines. > > no. > > the code is complex enough as it is. keep the group together. Perfect, this is a totally acceptable argument, exactly what I needed. You've convinced me.
(In reply to Dmitry Selyutin from comment #115) > Perfect, this is a totally acceptable argument, exactly what I needed. > You've convinced me. it's... 3 years incremental addition, as a Finite State Machine. adding Vertical-First and PACK/UNPACK (swapping of VL/SUBVL loop ordering *on source and destination individually!!!*) simultaneously introduced a special room in Hell, reserved just for me :)
I still had to make it somewhat more complex, because self.call will not do anything, only `yield from self.call` will. Also, since basically our insn flow is unchanged, but we have to "inject" rfid instruction, I had to be somewhat creative. https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=cea6b00e0cfb2acca2098794ad70c04d0d53cb29 I also had to introduce a way to pass initial_msr parameter into test_runner. https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=e25fca65a5a0faecdd9040689b5fe1f44b9a64a7 One this is done, almost everything works, except MSR check: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=dfec8c6456adfd3690d5d8da5a78fe3aa6c96b66
If I understand correctly, we must introduce some code residing at 0xc00, but I cannot think of a good way to handle it yet. We must either modify the Program so that every program has an additional code but this totally breaks the principle of least astonishment. FTR, here's what I get for MSR mismatch: File "./src/openpower/decoder/isa/test_syscall.py", line 23, in run_tst_program self.assertEqual(sim.msr, 0xffffffffffffffff) # MSR changed to this by sc/trap SelectableInt(value=0xfbfffffefd7f10c5, bits=64) != 18446744073709551615
(edited to correct comment #90 to comment #97) (In reply to Dmitry Selyutin from comment #117) > I still had to make it somewhat more complex, because self.call will not do > anything, only `yield from self.call` will. Also, since basically our insn > flow is unchanged, but we have to "inject" rfid instruction, I had to be > somewhat creative. > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=cea6b00e0cfb2acca2098794ad70c04d0d53cb29 ok you notice how in comment #97 i did *not* pass in the "cheat" argument? that was deliberate. it means that the straight rfid pseudocode gets called, as-is. redirecting hrfid to rfid will break hrfid when it is implemented, that should definitely not be done. > I also had to introduce a way to pass initial_msr parameter into test_runner. ah this is not a surprise > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=e25fca65a5a0faecdd9040689b5fe1f44b9a64a7 pass in "None" instead and do "if initial_msr is None: initial_msr=0x9000000000001" (MSR.LE | MSR.SF) > One this is done, almost everything works, except MSR check: > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=dfec8c6456adfd3690d5d8da5a78fe3aa6c96b66 aaawesome. okaay so now that value 0xfffffeeeablahblah that can be the expected e.msr! and with the removal of the redirection of hrfid we are done! (In reply to Dmitry Selyutin from comment #118) > If I understand correctly, we must introduce some code residing at 0xc00, noo: the call to self.syscall *is* the [kernel/OS] code at 0xc00! (and yes that kernel/OS code as its last instruction includes an rfid, hence why we have to explicitly call both sc and rfid) > FTR, here's what I get for MSR mismatch: > File "./src/openpower/decoder/isa/test_syscall.py", line 23, in > run_tst_program > self.assertEqual(sim.msr, 0xffffffffffffffff) # MSR changed to > this by sc/trap > SelectableInt(value=0xfbfffffefd7f10c5, bits=64) != 18446744073709551615 great! see comment #97 again (2nd from last paragraph). set e.msr = 0xfbfffffefd7f10c5 and we are pretty much done.
(In reply to Luke Kenneth Casson Leighton from comment #119) > ok you notice how in comment #90 i did *not* pass in the "cheat" > argument? that was deliberate. it means that the straight rfid > pseudocode gets called, as-is. It still is, even with passing syscall_emu_active parameter. :-) I just needed something to check to make asmop be the same as ins_name; otherwise the code thinks we met an illegal instruction. illegal = ins_name != asmop > redirecting hrfid to rfid will break hrfid when it is implemented, > that should definitely not be done. IIRC I did it since both evaluate to OP_RFID. But yes, this should be dropped. > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > h=e25fca65a5a0faecdd9040689b5fe1f44b9a64a7 > > pass in "None" instead and do "if initial_msr is None: > initial_msr=0x9000000000001" (MSR.LE | MSR.SF) You mean ISACaller.__init__, right? > > One this is done, almost everything works, except MSR check: > > > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > h=dfec8c6456adfd3690d5d8da5a78fe3aa6c96b66 > > aaawesome. > > okaay so now that value 0xfffffeeeablahblah that can be the expected > e.msr! So you mean that we actually got the correct value, it's just that my expectations were incorrect? > great! see comment #90 again (2nd from last paragraph). > set e.msr = 0xfbfffffefd7f10c5 and we are pretty much done. I'm confused. Comment #90 is my comment... :-) You probably meant something else?
(In reply to Luke Kenneth Casson Leighton from comment #119) > (In reply to Dmitry Selyutin from comment #117) > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > h=e25fca65a5a0faecdd9040689b5fe1f44b9a64a7 > > pass in "None" instead and do "if initial_msr is None: > initial_msr=0x9000000000001" (MSR.LE | MSR.SF) please use DEFAULT_MSR instead, since it includes the bits needed for fp to work, or, if you need it to be in Problem state, please create a DEFAULT_USER_MSR that's just DEFAULT_MSR with PR set.
(In reply to Dmitry Selyutin from comment #120) > (In reply to Luke Kenneth Casson Leighton from comment #119) > > ok you notice how in comment #90 i did *not* pass in the "cheat" > > argument? that was deliberate. it means that the straight rfid > > pseudocode gets called, as-is. > > It still is, even with passing syscall_emu_active parameter. :-) I just > needed something to check to make asmop be the same as ins_name; otherwise > the code thinks we met an illegal instruction. > > illegal = ins_name != asmop ah errr that shouldn't happen. ohhh hang on yes i think i know what is going on, the pc is pointing to 0xc00, of course there is no instruction *at* 0xc00 so it gets a NULL op, which is "illegal", and it all goes to shit from there. so yes sigh "cheat" mode is necessary. sigh. or we split out ISACaller.call() into yet anoooother function. let me handle that ok? > IIRC I did it since both evaluate to OP_RFID. OP_xxxx is only relevant for the HDL. ISACaller uses the insndb dictionary. see all.py the HDL does *further MANUAL explicit decoding* whenever an OP_xxxx is shared like that. OP_ADD is an extreme example, check the CSV files, you will see there are something like *THIRTY* different OP_ADD entries, all with completely different insndb parameters. > > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > > h=e25fca65a5a0faecdd9040689b5fe1f44b9a64a7 > > > > pass in "None" instead and do "if initial_msr is None: > > initial_msr=0x9000000000001" (MSR.LE | MSR.SF) > > You mean ISACaller.__init__, right? *no*, under no circumstances change that. if you run all the unit tests all hell will break loose. when i said test_runner.py (implicitly by replying to the commit-diff) i meant test_runner.py and not anything else. > So you mean that we actually got the correct value, it's just that my > expectations were incorrect? correct. > > great! see comment #90 again (2nd from last paragraph). > > set e.msr = 0xfbfffffefd7f10c5 and we are pretty much done. > > I'm confused. Comment #90 is my comment... :-) You probably meant something > else? yes. comment #97. sorry. was on a train. (In reply to Jacob Lifshay from comment #121) > please use DEFAULT_MSR instead, since it includes the bits needed for fp to > work, good call jacob. yes the whole default MSR thing really needs to be a global setting at some point so that the entire test suite can be run in BE mode. or 32-bit mode. but this is a frickin lot of work and i still after 3 years cannot think of a good solution to that. hmmm... now that i think about it, really jacob you should be using a DEFAULT_MSR_FP to ensure that FP is *not* enabled by default *except* for actual FP unit tests. (i e. DEFAULT_MSR needs to be set to MSR.LE|MSR.SF)
Folks, these MSR and SRR1 drive me nuts. Could you check, please, what goes wrong? There are two commits: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=b3a3b220fc8815c8d679c7aec48e90002bcd587c https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=6faf325b3f4368a5a93e6944590461c94f404251 Reproducer is: SILENCELOG=true python3 ./src/openpower/decoder/isa/test_syscall.py | grep SYSCALL You can see here the values I expected vs actual ones. SYSCALL SRR1 0x9000000000002903 0x9000000000022903 SYSCALL MSR 0x9000000000002903 0x9000000000000001 SRR1 gets its bit 17 set, but I'm struggling to find this bit anywhere. This is not present in DEFAULT_MSR, and, as it seems, is not even present as MSR field. MSR gets several bits disabled. Bits 1, 8, 11 and 17 are not present as fields in MSRb. I tried following "4.3.1 System Linkage Instructions" and "7.5.14 System Call Interrupt" but apparently did something wrong. Any clue?
two things: * rfid doesn't write all MSR bits * function default arguments generally should not be mutable values, since if it's modified in the function, that modified value is used as the new default for all function calls def run_tst_program(self, prog, initial_regs=[0] * 32): idk if this will fix your bug, but it might help...
(In reply to Luke Kenneth Casson Leighton from comment #122) > (In reply to Dmitry Selyutin from comment #120) > ah errr that shouldn't happen. ohhh hang on yes i think i know what is > going on, the pc is pointing to 0xc00, of course there is no > instruction *at* 0xc00 so it gets a NULL op, which is "illegal", > and it all goes to shit from there. Nope, by that point it doesn't point to 0xc00. It still points to 0x0, sc. And then it compares sc vs rfid. So I have to replace the instruction temporarily. > so yes sigh "cheat" mode is necessary. sigh. or we split out > ISACaller.call() into yet anoooother function. let me handle > that ok? Sure, np. I couldn't come up with a better way to handle it other than temporarily overriding instruction. > > > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > > > > h=e25fca65a5a0faecdd9040689b5fe1f44b9a64a7 > > > > > > pass in "None" instead and do "if initial_msr is None: > > > initial_msr=0x9000000000001" (MSR.LE | MSR.SF) > > > > You mean ISACaller.__init__, right? > > *no*, under no circumstances change that. if you run all the > unit tests all hell will break loose. when i said test_runner.py > (implicitly by replying to the commit-diff) i meant test_runner.py > and not anything else. Yeah already done. > > So you mean that we actually got the correct value, it's just that my > > expectations were incorrect? > > correct. I still have different expectations. :-) See comment #123.
(In reply to Jacob Lifshay from comment #124) > two things: > * rfid doesn't write all MSR bits > * function default arguments generally should not be mutable values, since > if it's modified in the function, that modified value is used as the new > default for all function calls > > def run_tst_program(self, prog, > initial_regs=[0] * 32): > > idk if this will fix your bug, but it might help... Likely the first one should be the reason. As for the second one, this should be fixed as well, though my troubles start even on the first test.
Nope, it doesn't help, even if I literally copy&paste sc and rfid generated code. I'm looking at ISACaller.TRAP code and find this comment somewhat suspicios: # set exception bits. TODO: this should, based on the address # in figure 66 p1065 V3.0B and the table figure 65 p1063 set these # bits appropriately. however it turns out that *for now* in all # cases (all trap_addrs) the exact same thing is needed. self.msr[MSRb.IR] = 0 self.msr[MSRb.DR] = 0 self.msr[MSRb.FE0] = 0 self.msr[MSRb.FE1] = 0 self.msr[MSRb.EE] = 0 self.msr[MSRb.RI] = 0 self.msr[MSRb.SF] = 1 self.msr[MSRb.TM] = 0 self.msr[MSRb.VEC] = 0 self.msr[MSRb.VSX] = 0 self.msr[MSRb.PR] = 0 self.msr[MSRb.FP] = 0 self.msr[MSRb.PMM] = 0 self.msr[MSRb.TEs] = 0 self.msr[MSRb.TEe] = 0 self.msr[MSRb.UND] = 0 self.msr[MSRb.LE] = 1
(In reply to Dmitry Selyutin from comment #123) > SRR1 gets its bit 17 set, but I'm struggling to find this bit anywhere. Seems it's caused by this line: self.spr['SRR1'][trap_bit] = 1 # change *copy* of MSR in SRR1 trap_bit is PIb.TRAP, which is 46, which is (64 - 17 - 1).
OK, enabling this bit fixes the SRR1: SRR1[PIb.TRAP] = 1 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=75887d596e2d067931382d20b2885d93be86c878 Still no glue about MSR, it has several bits inactive after the code gets executed.
(In reply to Dmitry Selyutin from comment #129) > OK, enabling this bit fixes the SRR1: > > SRR1[PIb.TRAP] = 1 hmmm that should *not* be necessary. it is handled by self.TRAP(0xc00) which is in the system.mdwn pseudocode for sc. > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=75887d596e2d067931382d20b2885d93be86c878 > > Still no glue about MSR, it has several bits inactive after the code gets > executed. yes. that is correct behaviour. i will have a look at this tomorrow ok?
(In reply to Luke Kenneth Casson Leighton from comment #130) > (In reply to Dmitry Selyutin from comment #129) > > OK, enabling this bit fixes the SRR1: > > > > SRR1[PIb.TRAP] = 1 > > hmmm that should *not* be necessary. it is handled by self.TRAP(0xc00) > which is in the system.mdwn pseudocode for sc. i think you misunderstood, luke. dmitry added that to his test case, which tries to reproduce the SRR1 to see if the simulator is correct. he didn't change that part of the simulator
(In reply to Jacob Lifshay from comment #131) > i think you misunderstood, luke. dmitry added that to his test case, which > tries to reproduce the SRR1 to see if the simulator is correct. ahh ok. > he didn't change that part of the simulator rright, i missed that (not able to look closely, just got back from travelling today). yes... it's complicated. sorting this for the HDL (copying microwatt rather than Power ISA spec) LITERALLY tool over 2 years to EVENTUALLY get right. only by running microwatt's binary unit tests *and the linux kernel* under verilator which took at least two months doing nothing else was i able to finally get MSR interrupt and sc/rfid compatibility with microwatt.
dmitry just so you know (i will look at this tomorrow): 11 * sc LEV 12 13 Pseudo-code: 14 15 SRR0 <-iea CIA + 4 16 SRR1[33:36] <- 0 17 SRR1[42:47] <- 0 18 SRR1[0:32] <- MSR[0:32] 19 SRR1[37:41] <- MSR[37:41] 20 SRR1[48:63] <- MSR[48:63] 21 TRAP(0xC00) <<<<--- this ACTUALLY calls ISACaller.TRAP(0xc00) which you will find at... errr.... here: 1318 def TRAP(self, trap_addr=0x700, trap_bit=PIb.TRAP): 1319 """TRAP> saves PC, MSR (and TODO SVSTATE), and updates MSR 1320 ... ... .... 1339 self.spr['SRR1'][trap_bit] = 1 # change *copy* of MSR in SRR1 so yes, this is why you should find that SRR1[PIb.TRAP] has been set to 1 because that's what ISACaller.TRAP() does. whether that is the right thing to do, if you *really* want to look at Power ISA spec around page 1070 the interrupt tables and behaviours please feel free but no bonus points given for doing so :)
(In reply to Luke Kenneth Casson Leighton from comment #133) > dmitry just so you know (i will look at this tomorrow): > > 11 * sc LEV > 12 > 13 Pseudo-code: > 14 > 15 SRR0 <-iea CIA + 4 > 16 SRR1[33:36] <- 0 > 17 SRR1[42:47] <- 0 > 18 SRR1[0:32] <- MSR[0:32] > 19 SRR1[37:41] <- MSR[37:41] > 20 SRR1[48:63] <- MSR[48:63] > 21 TRAP(0xC00) <<<<--- this ACTUALLY calls ISACaller.TRAP(0xc00) > > which you will find at... errr.... here: > > 1318 def TRAP(self, trap_addr=0x700, trap_bit=PIb.TRAP): > 1319 """TRAP> saves PC, MSR (and TODO SVSTATE), and updates MSR > 1320 ... > ... > .... > 1339 self.spr['SRR1'][trap_bit] = 1 # change *copy* of MSR in SRR1 > > so yes, this is why you should find that SRR1[PIb.TRAP] has been set to 1 > because that's what ISACaller.TRAP() does. Luke, I obviously found it (comment #128). I'd have expected this to be cleared after return from interrupt, though; but that's just a logical expectation. > but no bonus > points given for doing so :) I wrote the syscall generator, all the logic for emulation, several tests and spent an awful lot of time debugging all parts of this. And for all this I got 1800 EUR. Thank you, I know there're no bonus points, there's no need to state the obvious. I'm hardcodimg the expected MSR in test. Not a single damn minute on this task anymore.
(In reply to Luke Kenneth Casson Leighton from comment #105) > i'm updating the budget to reflect quite a lot of related work > by jacob, and the shenanigens for me doing trap unt tests. I'm expecting to get paid for bug #1173 as part of bug #983. So, assuming that isn't part of this bug's budget, I don't think I did EUR 1000 worth of work, so can you give EUR 500 of it to Dmitry, leaving EUR 500 for me?
No Jacob, I object. You earned these. So did everybody. My point is that the whole task was underestimated considering the efforts.
(In reply to Dmitry Selyutin from comment #134) > I'm hardcodimg the expected MSR in test. Not a single damn minute on this > task anymore. https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=2d0ad46d3d674b8ab03da7ff325de04ce555c619 I'll wait for CI to be completed and then will merge the whole branch into master.
(In reply to Dmitry Selyutin from comment #137) > (In reply to Dmitry Selyutin from comment #134) > > I'm hardcodimg the expected MSR in test. Not a single damn minute on this > > task anymore. > > https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff; > h=2d0ad46d3d674b8ab03da7ff325de04ce555c619 > > I'll wait for CI to be completed and then will merge the whole branch into > master. CI will not automatically start since git mirroring is currently disabled, and Luke has not given me permission to have it automatically run on any shorter period than 24hr: https://bugs.libre-soc.org/show_bug.cgi?id=1162 That said, I will manually push your commits to the mirrors so CI can run this time
(In reply to Jacob Lifshay from comment #138) > That said, I will manually push your commits to the mirrors so CI can run > this time https://salsa.debian.org/Kazan-team/mirrors/openpower-isa/-/jobs/4841167
Thank you Jacob! Do we have current master results nearby? I'd like to skip tests which already fail (if any).
(In reply to Dmitry Selyutin from comment #140) > Thank you Jacob! Do we have current master results nearby? I'd like to skip > tests which already fail (if any). https://salsa.debian.org/Kazan-team/mirrors/openpower-isa/-/jobs/4841214
(In reply to Dmitry Selyutin from comment #140) > Thank you Jacob! Do we have current master results nearby? I'd like to skip > tests which already fail (if any). because programmerjake/readd-rhs-copy (bug #1066) hasn't been merged yet, a lot of tests fail, enough that CI isn't useful since it stops at 10 failures. Testing on my computer: master branch at eee2cb24e2f1185b2a47cb56e94c94d3d51efcdb: > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestFMvFCvt5::test > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestFMvFCvt1::test > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestFMvFCvt6::test > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestFMvFCvt2::test > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestFMvFCvt3::test > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestFMvFCvt4::test > FAILED src/openpower/decoder/isa/test_caller_svp64_fptrans.py::TestSVP64FPTrans::test > FAILED src/openpower/decoder/isa/test_caller_fptrans.py::TestFPTrans::test - ... > FAILED src/openpower/decoder/isa/test_caller_fminmax.py::TestFMinMax::test - ... > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestFMvFCvt0::test > FAILED src/openpower/decoder/isa/test_caller_fmv_fcvt.py::TestSVP64FMvFCvtCases::test > FAILED src/openpower/decoder/isa/test_caller_bitmanip_av.py::TestAV::test - A... > FAILED src/openpower/decoder/isa/test_caller_syscall.py::TestSysCall::test - ... > FAILED src/openpower/decoder/isa/test_caller_trap.py::TrapTest::test - Assert... > FAILED src/openpower/sv/trans/test_pysvp64dis.py::SVSTATETestCase::test_20_cmp > FAILED src/openpower/sv/trans/test_pysvp64dis.py::SVSTATETestCase::test_36_extras_rldimi > FAILED src/openpower/sv/trans/test_pysvp64dis.py::SVSTATETestCase::test_36_extras_rldimi_ > FAILED src/openpower/sv/trans/test_pysvp64dis.py::SVSTATETestCase::test_37_extras_rldimi > = 18 failed, 440 passed, 75 skipped, 19 xfailed, 819 warnings in 411.65s (0:06:51) = scemu branch at 2d0ad46d3d674b8ab03da7ff325de04ce555c619: > FAILED src/openpower/decoder/isa/test_caller_bcd_full.py::BCDFullTestCase::test_cbcdtd_3 > FAILED src/openpower/decoder/isa/test_caller_bcd_full.py::BCDFullTestCase::test_cbcdtd_7 > FAILED src/openpower/decoder/isa/test_caller_bcd_full.py::BCDFullTestCase::test_addg6s_7 > FAILED src/openpower/decoder/isa/test_caller.py::DecoderTestCase::test_branch_ctr > FAILED src/openpower/decoder/isa/test_caller.py::DecoderTestCase::test_cmp - ... > FAILED src/openpower/decoder/isa/test_caller.py::DecoderTestCase::test_rlwimi > FAILED src/openpower/decoder/isa/test_caller.py::DecoderTestCase::test_mtcrf > FAILED src/openpower/decoder/isa/test_caller_fp.py::DecoderTestCase::test_fpload > FAILED src/openpower/decoder/isa/test_caller_bcd_full.py::BCDFullTestCase::test_cdtbcd_3 > FAILED src/openpower/decoder/isa/test_caller_bcd_full.py::BCDFullTestCase::test_addg6s_3 > FAILED src/openpower/decoder/isa/test_caller.py::DecoderTestCase::test_addi > <snip> > = 216 failed, 245 passed, 75 skipped, 19 xfailed, 4857 warnings in 370.82s (0:06:10) =
my guess of the issue is: if initial_msr is None and use_syscall_emu: initial_msr = DEFAULT_MSR initial_msr needs to be changed to not be None even when use_syscall_emu isn't set, since None isn't a valid value.
OK, initial_msr of None got passed to ISACaller from test_runner. I updated it so that it's changed from None to DEFAULT_MSR. However, ISACaller has initial_msr as 0, so more problems can be expected. I'll not make it DEFAULT_MSR, and instead will pass DEFAULT_MSR from the test; test_runner will by default use 0, as ISACaller does. I've quickly rebased and squashed the commits. Jacob, could you, please, relauch it?
(In reply to Jacob Lifshay from comment #143) > my guess of the issue is: > if initial_msr is None and use_syscall_emu: > initial_msr = DEFAULT_MSR > > initial_msr needs to be changed to not be None even when use_syscall_emu > isn't set, since None isn't a valid value. Yep, exactly. However, I changed it, now I pass DEFAULT_MSR from the test and use 0 by default (exactly as ISACaller has).
(In reply to Jacob Lifshay from comment #142) > because programmerjake/readd-rhs-copy (bug #1066) hasn't been merged yet, do it if they pass on the branch. (In reply to Dmitry Selyutin from comment #145) > Yep, exactly. However, I changed it, now I pass DEFAULT_MSR from the test > and use 0 by default (exactly as ISACaller has). gooood. this is the best approach. changing default behaviour for thousands of unit tests is ennnnntiiirely inappropriate without a full review!!!
(In reply to Dmitry Selyutin from comment #134) > Luke, I obviously found it (comment #128). i am tracking this remotely, from memory of working with the code over *two years* ago, without being able to run it. please be patient, it is not obvious to me asi cannot remember. > I'd have expected this to be cleared after return from interrupt, > though; but that's just a logical expectation. no, that is "rfid"'s job to clear it because that is the "return from interrupt" instruction. (or, more to the point, to copy the bit from SRR1 as you could have nested interrupts) if the test had also run rfid not just "sc 0" then yes you would expect to see it cleared. but because the test only runs "sc 0" the test is *still inside the kernel/OS* (emulated)
(In reply to Dmitry Selyutin from comment #144) > OK, initial_msr of None got passed to ISACaller from test_runner. I updated > it so that it's changed from None to DEFAULT_MSR. However, ISACaller has > initial_msr as 0, so more problems can be expected. I'll not make it > DEFAULT_MSR, and instead will pass DEFAULT_MSR from the test; test_runner > will by default use 0, as ISACaller does. > > I've quickly rebased and squashed the commits. Jacob, could you, please, > relauch it? I ran all the tests, only to realize I didn't generate the syscalls json, so I figured out how to run the script for generating json (that needs to be part of the Makefile, though imo you don't have to do it as part of this bug) and tried it on /usr/src/linux-headers-5.15.0-... which didn't work, so I git cloned Linux 6.5.8 and regenerated the json and reran the tests: > = 18 failed, 443 passed, 75 skipped, 19 xfailed, 822 warnings in 400.52s (0:06:40) = exactly the same tests as master, so, unless you wanted to fix the below test first, feel free to merge: src/openpower/decoder/isa/test_caller_syscall.py::TestSysCall::test I'm going to sleep very soon, so you'll have to run tests yourself or ask someone else if you need more testing.
I will mention that I noticed there's a rfscv instruction that looks like it pairs with scv instead of rfid.
(In reply to Jacob Lifshay from comment #149) > I will mention that I noticed there's a rfscv out of scope. i would have defined the task as "implement syscalls including vectored ones"
(In reply to Jacob Lifshay from comment #148) > exactly the same tests as master, so, unless you wanted to fix the below > test first, feel free to merge: > src/openpower/decoder/isa/test_caller_syscall.py::TestSysCall::test Not at all. First, it checks mostly the same as other tests (registers, MSR, PC). Second, if we need to check memory interaction, these changes are for you in scope of another task. :-) I rebased atop of scemu branch and pushed to master based on the fact that everything works.
(In reply to Jacob Lifshay from comment #148) > (In reply to Dmitry Selyutin from comment #144) > I ran all the tests, only to realize I didn't generate the syscalls json https://git.libre-soc.org/?p=dev-env-setup.git;a=blob;f=hdl-dev-repos;h=14a13c8b4874fd4a8512de24baf0b0792d39f054;hb=HEAD#l83
Anything else needed here, or I can write a summary?
(In reply to Dmitry Selyutin from comment #153) > Anything else needed here, let us check it works (and do a final review) > or I can write a summary? reminder again what michiel wrote: there is no need to write summaries. writing summaries wastes your time because everyone here knows what was done. i.e.: if you want to spend the time writing a summary feel free but you will not get more money for doing so! (In reply to Jacob Lifshay from comment #135) > I'm expecting to get paid for bug #1173 as part of bug #983. So, assuming > that isn't part of this bug's budget, I don't think I did EUR 1000 worth of > work, so can you give EUR 500 of it to Dmitry, leaving EUR 500 for me? no jacob because as Project Lead i am authorizing payment from THIS budget for work done on OTHER (related *and unrelated*) bugs we have done this many times in 5 years. as long as we work together on many tasks even unrelated ones NLnet is quite flexible about who gets paid and for what. i am however going to give dmitry more money from *my* budget, and also from andrey's (because he is subcontracted by RED) reminder dmitry that you only need express the value of what you are doing. we can always find another bugreport to allocate additional funds, or reduce the scope down to "working *TOWARDS* the original Milestone". NLnet does *not* expect any of us to go into debt to complete pure Research.
(In reply to Luke Kenneth Casson Leighton from comment #154) > (In reply to Dmitry Selyutin from comment #153) > > Anything else needed here, > > let us check it works (and do a final review) Sure. > > or I can write a summary? > > reminder again what michiel wrote: there is no need to write summaries. > writing summaries wastes your time because everyone here knows what > was done. I actually assumed from bug #981 that we need to write this kind of documentation as the ultimate comment. > i.e.: if you want to spend the time writing a summary Not at all. > (In reply to Jacob Lifshay from comment #135) > > > I'm expecting to get paid for bug #1173 as part of bug #983. So, assuming > > that isn't part of this bug's budget, I don't think I did EUR 1000 worth of > > work, so can you give EUR 500 of it to Dmitry, leaving EUR 500 for me? > > no jacob because as Project Lead i am authorizing payment from THIS > budget for work done on OTHER (related *and unrelated*) bugs > > we have done this many times in 5 years. > > as long as we work together on many tasks even unrelated ones NLnet > is quite flexible about who gets paid and for what. > > i am however going to give dmitry more money from *my* budget, and also > from andrey's (because he is subcontracted by RED) > > reminder dmitry that you only need express the value of what you are > doing. we can always find another bugreport to allocate additional > funds, or reduce the scope down to "working *TOWARDS* the original > Milestone". > > NLnet does *not* expect any of us to go into debt to complete pure Research. Well, as I mentioned, my comments are related to the fact that this exact task ended up being underrated. I'd say all of us earned it well, it's just that cumulative we should've earned more. But OK, up to you.
(In reply to Dmitry Selyutin from comment #155) > I actually assumed from bug #981 that we need to write this kind of > documentation as the ultimate comment. iirc that's only needed if we think the auditor could be suspicious about the amount paid for the apparent amount of work done.
dmitry i'm running on an armv8l host (kindle tablet, due to circumstances) the default is hardcoded to amd64 in openpower.syscalls?
(In reply to Luke Kenneth Casson Leighton from comment #157) > dmitry i'm running on an armv8l host (kindle tablet, due to circumstances) > the default is hardcoded to amd64 in openpower.syscalls? afaict it's not, it falls back to uname.machine, but probably needs a new entry to convert armv8l to aarch64 (on my phone uname.machine is aarch64): https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/caller.py;hb=6d56fed8edcd256b9264bac81cf897a596b58e53#l1140 actually, it just has no entries for aarch64: https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/syscalls/__init__.py;h=5b349ea9e00e646419a3e80e0867bc55967e17f5;hb=6d56fed8edcd256b9264bac81cf897a596b58e53#l117 117 "i386": i386, 118 "amd64": amd64, 119 "ppc": ppc, 120 "ppc64": ppc64, 121 "riscv32": riscv32, 122 "riscv64": riscv64,
Ah yes, sorry, I only used it with amd64 and ppc. Let me handle that.
(In reply to Luke Kenneth Casson Leighton from comment #157) > dmitry i'm running on an armv8l host (kindle tablet, due to circumstances) > the default is hardcoded to amd64 in openpower.syscalls? luke, can you run `uname -m` and tell us if it says aarch64 or something else?
I've added arm and aarch64, also a couple of aliases: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=e7be3e9e898c04532a3e7fb1bfc49df63d32a4c0 https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=3402776765e36c2058389aa6ea4b0d19b166d2cf I'll check dev scripts.
(In reply to Dmitry Selyutin from comment #161) > I'll check dev scripts. Ah right, we generate JSON for all architectures I found as syscall.tbl, it's just that not all of these architectures are supported in Dispatcher. Luke, could you try now, please? Things should work; if not -- follow the commits from comment #161 and also post the uname().machine in Python.
(In reply to Jacob Lifshay from comment #156) > (In reply to Dmitry Selyutin from comment #155) > > I actually assumed from bug #981 that we need to write this kind of > > documentation as the ultimate comment. > > iirc that's only needed if we think the auditor could be suspicious about > the amount paid for the apparent amount of work done. That's damn unfortunate they aren't as suspicious in an opposite scenario... :-)
(In reply to Dmitry Selyutin from comment #155) > I actually assumed from bug #981 that we need to write this kind of > documentation as the ultimate comment. no, you missed that it was an anomaly, that i am required as Project Team Lead and Signatory to the Memorandum of Understanding to check anything that i think potentially could be red-flagged by an Auditor. when i have a satisfactory answer, it goes in the bugreport, and we move on. done. (NLnet has raised queries and requested additional comments approximately *eight* times in 5 years. they read every single bugreport as part of Due-Diligence, and sometimes it is just not clear. i do not tell people about this, because they email me directly as Project Team Lead) > > i.e.: if you want to spend the time writing a summary > > Not at all. good! :) > task ended up being underrated. I'd say all of us earned it well, it's just > that cumulative we should've earned more. under other bugreports. already taken care of. you very much need to stop thinking in terms of "the task is the task: do it exactly... or else". it is far more flexible than that, being fundamentaly based on trust. (In reply to Jacob Lifshay from comment #156) > iirc that's only needed if we think the auditor could be suspicious about > the amount paid for the apparent amount of work done. correction: if *I as Project Team Lead and Signatory to the MOU*, or NLnet themselves (eight times in 5 years) do not have an answer ready *if* the Auditor is suspicious. hence why NLnet read literally every bugreport. you are not the Signatory to the MoU jacob so you do not have the direct responsibility, although it is all our responsibility.
+from . import ARCH from . import Dispatcher from . import UnknownSyscall oh, sorry Dmitry: the Project Coding Standards prohibit relative imports. please convert these to full-path imports.
jacob see #1066 reduce the mem block down to 1<<29 please dmitry the return result is "-1" but is coming out at 0xffffffffff... this is *possibly* due to using termux (proot). which would be a pisser. i will have to fire up the laptop tomorrow (amd64). ERROR: test_sc_dup (__main__.SyscallTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/libresoc/src/openpower-isa/src/openpower/decoder/isa/test_syscall.py", line 107, in test_sc_dup st1 = os.fstat(fd1) OverflowError: Python int too large to convert to C int ====================================================================== FAIL: test_sc_getpid (__main__.SyscallTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/libresoc/src/openpower-isa/src/openpower/decoder/isa/test_syscall.py", line 82, in test_sc_getpid self.assertEqual(sim.gpr(3), os.getpid()) AssertionError: SelectableInt(value=0xffffffffffffffff, bits=64) != 26211 ====================================================================== FAIL: test_sc_getuid (__main__.SyscallTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/libresoc/src/openpower-isa/src/openpower/decoder/isa/test_syscall.py", line 90, in test_sc_getuid self.assertEqual(sim.gpr(3), os.getuid()) AssertionError: SelectableInt(value=0xffffffffffffffff, bits=64) != 1000 ---------------------------------------------------------------------- Ran 3 tests in 41.027s
(In reply to Luke Kenneth Casson Leighton from comment #166) > jacob see #1066 reduce the mem block down to 1<<29 please I'm assuming you meant bug #1173. > > dmitry the return result is "-1" but is coming out at 0xffffffffff... I would guess the issue is that uname is being used, but what you actually need is the arch of the user-space executable, not the kernel, since Luke seems to have a armhf user-space and aarch64 kernel. after some experimentation, it looks like you can use: python3 -c 'import sysconfig; print(sysconfig.get_config_var("HOST_GNU_TYPE"))' for armhf: armv8l-unknown-linux-gnueabihf for arm64: aarch64-unknown-linux-gnu for i386: i686-pc-linux-gnu for x86_64: x86_64-pc-linux-gnu for ppc64el: powerpc64le-unknown-linux-gnu
(In reply to Jacob Lifshay from comment #167) > for armhf: > armv8l-unknown-linux-gnueabihf > for arm64: > aarch64-unknown-linux-gnu > for i386: > i686-pc-linux-gnu > for x86_64: > x86_64-pc-linux-gnu > for ppc64el: > powerpc64le-unknown-linux-gnu for riscv64: riscv64-unknown-linux-gnu
(In reply to Jacob Lifshay from comment #168) > (In reply to Jacob Lifshay from comment #167) > > for armhf: > > armv8l-unknown-linux-gnueabihf this is the value I get for armhf on multiarch with an emulated arm64 kernel. and yes, armv8l really is armv7, not aarch64. https://bugs.launchpad.net/ubuntu/+source/clang/+bug/1827175 ^ links to: https://stackoverflow.com/q/27121199/608639 for armhf with a 32-bit emulated kernel, I get: armv7l-unknown-linux-gnueabihf
Folks, I don't have any suitable arm or aarch64 device which I could sacrifice for running our env, so you'll have to find it out. I'd say that arm/aarch64 support is not something I expected.
(In reply to Jacob Lifshay from comment #167) > (In reply to Luke Kenneth Casson Leighton from comment #166) > > jacob see #1066 reduce the mem block down to 1<<29 please > > I'm assuming you meant bug #1173. > > > > dmitry the return result is "-1" but is coming out at 0xffffffffff... ...which is exactly the expected result when unsigned integer is used. I think the result can just use long instead of ulong. > > I would guess the issue is that uname is being used, but what you actually > need is the arch of the user-space executable, not the kernel, since Luke > seems to have a armhf user-space and aarch64 kernel. after some > experimentation, it looks like you can use: > python3 -c 'import sysconfig; > print(sysconfig.get_config_var("HOST_GNU_TYPE"))' I'd take a look at this: platform.architecture()[0] sys.maxsize > 2**32
(In reply to Dmitry Selyutin from comment #171) > > I would guess the issue is that uname is being used, but what you actually > > need is the arch of the user-space executable, not the kernel, since Luke > > seems to have a armhf user-space and aarch64 kernel. after some > > experimentation, it looks like you can use: > > python3 -c 'import sysconfig; > > print(sysconfig.get_config_var("HOST_GNU_TYPE"))' > > I'd take a look at this: > platform.architecture()[0] > sys.maxsize > 2**32 platform.architecture() on my phone returns: ('64bit', 'ELF') which has no mention of arm. so imo not very useful. presumably aarch64 systems can have both armhf and armel multiarch. x86_64 likewise can have both i686 and x32.
(In reply to Dmitry Selyutin from comment #170) > Folks, I don't have any suitable arm or aarch64 device which I could > sacrifice for running our env, so you'll have to find it out. I'd say that > arm/aarch64 support is not something I expected. I think it's fine to say we're not supporting arm as part of this bug, luke will just have to use his laptop. that said, it would be nice to support arm at some point.
(In reply to Jacob Lifshay from comment #172) > (In reply to Dmitry Selyutin from comment #171) > > > I would guess the issue is that uname is being used, but what you actually > > > need is the arch of the user-space executable, not the kernel, since Luke > > > seems to have a armhf user-space and aarch64 kernel. after some > > > experimentation, it looks like you can use: > > > python3 -c 'import sysconfig; > > > print(sysconfig.get_config_var("HOST_GNU_TYPE"))' > > > > I'd take a look at this: > > platform.architecture()[0] > > sys.maxsize > 2**32 > > platform.architecture() on my phone returns: > ('64bit', 'ELF') > which has no mention of arm. so imo not very useful. > > presumably aarch64 systems can have both armhf and armel multiarch. x86_64 > likewise can have both i686 and x32. Yes I know. You have to check both arch and some Python executable information simultaneously. That's why you need to check not only platform.platform() but also sys.maxsize (as a cheap way).
(In reply to Dmitry Selyutin from comment #174) > > > > python3 -c 'import sysconfig; > > > > print(sysconfig.get_config_var("HOST_GNU_TYPE"))' > Yes I know. You have to check both arch and some Python executable > information simultaneously. That's why you need to check not only > platform.platform() but also sys.maxsize (as a cheap way). but checking platform.platform() just uses uname (see source code), and combining that with sys.maxsize can't distinguish between armhf/armel or i686/x32 afaict...i know i686 and x32 have different syscall ABIs and maybe armhf/armel too, so it is information you need to know to get it right. the method I suggested using python's sysconfig module gets its info from autotools (config.guess/config.sub) via python's config.h and makefiles, so should contain enough to know the exact ABI.
(In reply to Jacob Lifshay from comment #175) > but checking platform.platform() just uses uname (see source code), https://github.com/python/cpython/blob/v3.7.17/Lib/platform.py#L1334
The idea is that with uname report of 64 bit OS and 32-bit userspace you can switch appropriately.
(In reply to Dmitry Selyutin from comment #177) > The idea is that with uname report of 64 bit OS and 32-bit userspace you can > switch appropriately. yes, I'm saying there may be *multiple* 32-bit userspace ABIs each with a separate syscall ABI. just knowing that user-space is 32-bit doesn't necessarily tell you how to decide which ABI you need.
No, it doesn't affect ABI of syscalls. The only ABI in Linux syscalls we have is OABI, which I don't think modern ARM should use. Same for x86: you don't have different ABIs except for x86/x86_64/x32 (IIRC the latter is dead already as well).
The only ABI => the only additional ARM ABI
(In reply to Dmitry Selyutin from comment #179) > No, it doesn't affect ABI of syscalls. The only ABI in Linux syscalls we > have is OABI, which I don't think modern ARM should use. Same for x86: you > don't have different ABIs except for x86/x86_64/x32 (IIRC the latter is dead > already as well). ok. there's also big-endian arm, but i think we can ignore that.
(In reply to Jacob Lifshay from comment #173) > I think it's fine to say we're not supporting arm as part of this bug, luke > will just have to use his laptop. i'm right here dmitry, please do try to avoid referring to people in 3rd person, it is normally considered rude? i do appreciate you are discussing with jacob and not expecting me to be awake at 7am UK > that said, it would be nice to support arm > at some point. indeed. annoying as it is to have a standard hardware and software platform that decision was made for exactly this reason: to keep the scope of work down to what NLnet can afford.
(In reply to Luke Kenneth Casson Leighton from comment #182) > (In reply to Jacob Lifshay from comment #173) > > > I think it's fine to say we're not supporting arm as part of this bug, luke > > will just have to use his laptop. I hope you're ok with that. > i'm right here dmitry, I think you mean jacob? you're replying to me... > please do try to avoid referring to people > in 3rd person, it is normally considered rude? it depends? I was replying to Dmitry, so since I wasn't directly talking to you, imo 3rd person is appropriate (like how i just referred to Dmitry in the 3rd person).
(In reply to Jacob Lifshay from comment #183) > > I think you mean jacob? you're replying to me... click. yes. sorry for the confusion (dmitry) > > please do try to avoid referring to people > > in 3rd person, it is normally considered rude? > > it depends? I was replying to Dmitry, so since I wasn't directly talking to > you, imo 3rd person is appropriate (like how i just referred to Dmitry in > the 3rd person). the usual way is to say in advance, "i am aware you are there and participating, i am about to dscuss you in the 3rd person, please do not take offense" which is so long it is only worthwhile for detailed discussuon, rather than just simply assume (on a delay) that it is a normal conversation
I kinda lost with the recent comments. Luke, I do not get what you try to tell me, and have no idea what seemed to be rude with my words (especially that you were replying to Jacob's comment).
(In reply to Dmitry Selyutin from comment #185) > I kinda lost with the recent comments. Luke, I do not get what you try to > tell me, nothing! > and have no idea what seemed to be rude with my words you weren't > (especially that you were replying to Jacob's comment). ... and not realising it. yes, sorry for the miscommunication.
Guys, I've pinned the Linux kernel source. https://git.libre-soc.org/?p=dev-env-setup.git;a=commitdiff;h=db25adc0c551626a9d2a4ddfa05f3ca9c8ca0bef This is done as a single command so that we clone at depth 1 of a specific tag.
Why is 1173 listed as blocker for this task? It is not. In fact, the relationship is different.
s/different/opposite/
After some thought, they don't even have blocker relationship. Transparent memory mapping translation just enables some system calls; however, this mechanism is not mandatory for doing system calls. I see no reason for that task to be a blocker.
(In reply to Dmitry Selyutin from comment #188) > Why is 1173 listed as blocker for this task? because the original plan was to support `read`/`write`, which need a pointer to memory. MemMMap.get_ctypes provides that pointer. https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/mem.py;h=cad3d052a38252ebf0e1cf3b8b41deac813e269e;hb=49cd5029f5aa997d80bfcdd5dbaaa873913f8b93#l383
(In reply to Dmitry Selyutin from comment #187) > Guys, I've pinned the Linux kernel source. > > https://git.libre-soc.org/?p=dev-env-setup.git;a=commitdiff; > h=db25adc0c551626a9d2a4ddfa05f3ca9c8ca0bef > > This is done as a single command so that we clone at depth 1 of a specific > tag. fantastic. (In reply to Dmitry Selyutin from comment #188) > Why is 1173 listed as blocker for this task? It is not. In fact, the > relationship is different. ignore it. i do need you to do comment #165 though. the project coding standards require absolute (full) import paths. relative paths are prohibited.
(In reply to Jacob Lifshay from comment #191) > (In reply to Dmitry Selyutin from comment #188) > > Why is 1173 listed as blocker for this task? > > because the original plan was to support `read`/`write`, which need a > pointer to memory. MemMMap.get_ctypes provides that pointer. happy for that to be a "nice to have" although i am genuinely curious to see if it works, i will authorize payment when comment #165 is dealt with.
(In reply to Luke Kenneth Casson Leighton from comment #193) > happy for that to be a "nice to have" although i am genuinely > curious to see if it works, i will authorize payment when > comment #165 is dealt with. MemMMap.get_ctypes does work, I have tests for it. it has not been integrated into the syscall framework yet (probably part of a later task) https://git.libre-soc.org/?p=openpower-isa.git;a=blob;f=src/openpower/decoder/isa/test_mem.py;h=e57d199148a86de07f67645bb009075005e9f2f3;hb=a5d50b0759a5c9196ae0b10441905a5bbecaabce#l82
https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=066fe2eae8514911ee8ff882ab7a8c98642662a7 Introduced an architecture detection, this should perform better on multilib configurations. From now on, the Dispatcher class expects a sanitized architecture name; to be sure, use architecture() function. Changed imports.
brilliant work everyone, we're definitely done here. mmap syscall perhaps under bug #983 jacob? RFP time...
(In reply to Luke Kenneth Casson Leighton from comment #196) > brilliant work everyone, we're definitely done here. mmap syscall > perhaps under bug #983 jacob? yup, that's the plan! (busy trying to recover luks keys from a corrupted ceph-mon database, I may be busy for a while)
def add_case(self, prog, initial_regs=None, initial_sprs=None, initial_cr=0, initial_msr=DEFAULT_MSR, initial_mem=None, sorry i missed this. this *has* to be initial_msr=None followed in ISACaller "if initial_msr is None: initial_msr=DEFAULT_MSR" it is *not* ok to change the initial_msr to something that cannot be overridden. jacob can you remember the bugreport where this was discussed?
(In reply to Luke Kenneth Casson Leighton from comment #198) > def add_case(self, prog, initial_regs=None, initial_sprs=None, > initial_cr=0, initial_msr=DEFAULT_MSR, > initial_mem=None, > > sorry i missed this. this *has* to be initial_msr=None > followed in ISACaller "if initial_msr is None: initial_msr=DEFAULT_MSR" > > it is *not* ok to change the initial_msr to something that cannot > be overridden. jacob can you remember the bugreport where this was > discussed? Jacob, I think this should be handled by you. First, it seems you're better familiar with the rationale (I saw none; all I see is that default value is 0, and nothing really expects None anywhere). Second, I don't even use add_case at all, I haven't touched this place. Third, I pass initial MSR value from the test directly.
(In reply to Jacob Lifshay from comment #197) > yup, that's the plan! (busy trying to recover luks keys from a corrupted > ceph-mon database, I may be busy for a while) Finally got ceph up and working again after writing a python script to try to extract data from a corrupted rocksdb. took me like 20hr of work. I now backed up all my ceph stuff and added keys I know to my luks partitions. (In reply to Luke Kenneth Casson Leighton from comment #198) > sorry i missed this. this *has* to be initial_msr=None > followed in ISACaller "if initial_msr is None: initial_msr=DEFAULT_MSR" ok, I can do that. > it is *not* ok to change the initial_msr to something that cannot > be overridden. I don't see how that's any easier or harder to override...if you need a different MSR for everything, just change DEFAULT_MSR. > jacob can you remember the bugreport where this was > discussed? some searching led to: https://bugs.libre-soc.org/show_bug.cgi?id=1072
(In reply to Jacob Lifshay from comment #200) > (In reply to Luke Kenneth Casson Leighton from comment #198) > > sorry i missed this. this *has* to be initial_msr=None > > followed in ISACaller "if initial_msr is None: initial_msr=DEFAULT_MSR" > > ok, I can do that. done: https://git.libre-soc.org/?p=openpower-isa.git;a=commitdiff;h=21f95f5bb243c937aed9f9ef28605f20b33b7b0e
(In reply to Jacob Lifshay from comment #200) > Finally got ceph up and working again after writing a python script to try > to extract data from a corrupted rocksdb. now you know never to use rocksdb ever again. good idea to pay attention to howard chu's advice here. > (In reply to Luke Kenneth Casson Leighton from comment #198) > I don't see how that's any easier or harder to override...if you need a > different MSR for everything, just change DEFAULT_MSR. ...via and *only* via the mechanism of bug #1173 (not 1072)