VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I notice that the hard drive emulation of UniPCemu goes strange when the following code is executed during LInux 0.01:

static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
unsigned int head,unsigned int cyl,unsigned int cmd,
void (*intr_addr)(void))
{
register int port asm("dx");

if (drive>1 || head>15)
panic("Trying to write bad sector");
if (!controller_ready())
panic("HD controller not ready");
do_hd = intr_addr;
outb(_CTL,HD_CMD);
port=HD_DATA;
outb_p(_WPCOM,++port);
outb_p(nsect,++port);
outb_p(sect,++port);
outb_p(cyl,++port);
outb_p(cyl>>8,++port);
outb_p(0xA0|(drive<<4)|head,++port);
outb(cmd,++port);
}

In UniPCemu's case, the hard disk BIOS leaves it at the primary slave, thus the writes until and including the cylinder number is written to the primary slave, then the head register of the primary master is updated, then the command is sent to the primary master.

Afaik, the registers are drive-specific? The drive you're writing to is the currently selected drive until a controller reset(using port 3F6, writing 1 to it's SRST bit) or a different drive is selected using the drive/head register(writes said value to the drive selected using the DRV bit when it's written)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

There just seems so much wrong with Linux 0.01's source code.
- Firstly, it writes the registers before setting up the correct drive.
- Second, after an invalid command, it seems to write entirely different sector data to the correct drive?
- It then issues a Initialize Device Parameters command.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 2 of 17, by dr_st

User metadata
Rank l33t
Rank
l33t

Gee, 0.01? Isn't it too modern? I suggest you try Linux 0.0.0.0.0.0.0.00000001.

Sorry, couldn't resist.

But anyways, read this and the link therein:
https://superuser.com/questions/290808/runnin … virtual-machine

https://cloakedthargoid.wordpress.com/ - Random content on hardware, software, games and toys

Reply 3 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

That still doesn't resolve the hard disk register write ordering? It's writing the registers in the wrong order. The Drive/Head register needs to be written before all others, as the XT-IDE BIOS leaves it at the primary slave(The DRV bit being set). That causes Linux(which doesn't reset the controller(properly)) to write it's data(cylinder,sector,sectorcount,features register) to the slave, then switch to the master and write it's drive/head register, then the command for the master, which errors out due to an invalid LBA/CHS address past the end of the disk!

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 4 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

So, looking at QEMU's source code, writing to the block registers(those registers that went wrong with UniPCemu) for all registers but the drive/head and command/status registers writes to both master and slave registers, while reading from them only reads from the currently selected drive? That would explain why Linux has said issue. UniPCemu simply routed them to the selected drive only, instead of to both the master and slave drives simultaneously. Only reads are affected, as it needs to report the status and registers of the selected drive only?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 5 of 17, by Stenzek

User metadata
Rank Newbie
Rank
Newbie
superfury wrote:

So, looking at QEMU's source code, writing to the block registers(those registers that went wrong with UniPCemu) for all registers but the drive/head and command/status registers writes to both master and slave registers, while reading from them only reads from the currently selected drive? That would explain why Linux has said issue. UniPCemu simply routed them to the selected drive only, instead of to both the master and slave drives simultaneously. Only reads are affected, as it needs to report the status and registers of the selected drive only?

That's how I have my IDE ports implemented. Writes to cylinder/sector/count/features/drive select go to all attached drives, command/data go to the selected drive. Reads are from the selected drive or 0xFF.

I think I also had to return 0xFF for the error register if there was nothing attached to the selected drive to stop some BIOSes from hanging.

Reply 6 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Having implemented that(all you've said, except the drive/head register and the 0xFF error register), the reads succeed better(until finishing the read).

Then I noticed that UniPCemu was generating an interrupt when the transfer from the hard drive was complete(causing Linux to panic with a "Unexpected hd interrupt"). After fixing the drives to no longer generate one on completed reads(except when reading more or erroring out on reading more), the Linux 0.01 kernel now says: "Partition tables OK.
Kernel Panic: Unable to mount root".

So that's probably because I have the usual MS-DOS disk image mounted as the primary master? Although UniPCemu doesn't support a non-standard disk image structure(when using CHS mode), perhaps(if it's using LBA 24-bit addressing) it will still use it correctly?

Although, the XT-IDE BIOS changes the geometry to be automatic. UniPCemu by default reports it according to it's optimally found size(the size it finds, from large to small) with the most CHS coverage.
Edit: Linux 0.01 still doesn't seem to like it(perhaps the XT-IDE BIOS is applying a different geometry. I don't know, it's set to automatic after all)?

Edit: Just tried the 1.0.9 kernel. It displays the same old LSS issue I had before with the 0.01 kernel due to SPT misallignment.
Edit: That seems to have been the case. The floppy detection code was failing(the code in bootsect.S that determined if to read tracks of 18, 15 or 8 sectors per track.
Since the drive is a 1.44MB/2.88MB one, with the BIOS configured for 720K and a 720K disk image used, it was failing on that one. A simple patch of each "jnc got_sectors" by adding a "stc" line in front of each of them causes the drive to be correctly detected, thus booting continues on (so far checked until the delay loop.

It seems fine so far. It sees the processor honours the WP bit even in Supervisor mode(because it's a Pentium CPU being emulated). Then the floppy drives are both 720K(which is fine as well, as the BIOS doesn't support 1.44MB/2.88MB ones).
Then it says:

Getstatus timed out.
floppy: FDC failed to return version byte.
No coprocessor found and no math emulation present.
Giving up.

So I'll need to enable the math emulation for it to boot. Another step that's required 😒

Edit: Ran "make config" and enabled all options for their defaults, but disabled the sound and network drivers, as they have issues compiling due to missing headers.
Just ran compilation again, once again inserted it to the start of a 720K floppy disk image(still with the modified stc added for proper floppy disk detection). Now booting hopefully will get rid of that pesky math emulation problem.

Edit: After a lot of CD-ROM drivers failing and it aborting, it starts the calibration of the delay loop, then a long, seemingly unfinished list of "HD-controller reset failed: 00" being printed on the screen.
Edit: Luckily, that's an easy fix(those HD reset fail messages themselves): just make the ATA error register become 1 after a reset(any kind of reset, not just SRST).
Edit: Managed to fix that combined with the actual hard disk BIOS by making it set the Error Register to 1 instead of 0 when resetting ONLY when detecting that it's not a CD-ROM RESET DEVICE command and it's a SRST-based reset with the ERROR bit set in the status register.

Although it still managed to hang saying:

Partition check:

Edit: I do see it keep sending a ATA SRST, while keep writing the Drive/Head register, which causes a Drive Select timing to occur(50us), but not properly checking again after selecting it. It only counts down to about 35us left, then writes the drive/head register again?

Edit: Changing the Drive Select delay down to 400ns seems to have fixed it. It now successfully mounts it's (0.01 hdd from version 1.0 floppy) minix filesystem on the harddisk. 😁

It now reports(the linux version name got information about the PC I've compiled it on, just ignore it):

Floppy drive(s): fd0 is 720k, fd1 is 720k
Getstatus times out
floppy: FDC failed to return version byte
Linux version 1.0.9 (mypcname@mypcid) #22 fulldateandtime (note: fill in the blank XD )
Partition check:
hda: hda1
hdb: hdb1
VFS: Mounted root (minix filesystem)

Then it doesn't seem to do anything anymore?

Edit: After looking at the FDC code, I noticed that commands 13h, 14h and 16h(CONFIGURE, LOCK and VERIFY) didn't have their parameter length specified, causing a invalid parameter handling. Also, the VERSION command wasn't immediately being executed, causing problems when used(Linux noticed that fact for me, giving an error message on the VERSION command being executed not giving it's result correctly). Having fixed that, it now properly reports version 0x90(which is a 82077AA controller, which is emulated).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 7 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Well, one good thing is that right now, with the latest bugfixes(some Floppy Disk Controller issues and ATA hard disk emulation issues), it at least doesn't throw ANY errors regarding the harddisk anymore.

Since it says it's mounted the root, it at least seems to have reached line 533 of The Linux 1.0.9's fs/super.c. So it should return from mount_root(kernel mode), it's caller sys_setup(the setup function), then bop down into user mode back to the init process? So it should(if bopping down from kernel mode is successfull), reach line 493 of init/main.c, at the call to sprintf(term,....) ?

Edit: Hmmmm... Just took a little debugger breakpoint on the user-mode task execution(thus CPL=3) on the Linux running within UniPCemu(using a Visual Studio breakpoint on the INT instruction(conditions being: CPU[0].CPL==3 && CPUmode && (immb==0x80) && (CPU[0].registers->EAX!=112). The 112 exclusion is mainly to not get the idle() call of the system idle process(the "idle" task) in my debugging, which seems to happen a lot at said point during booting.

This is what I've found out about those first three processes:

Process 1: CR3:BFB000, Task 0050:c0bfd80c
Idle process: CR3:101000, Task 0040:c018bbb4
Process 2(fork of Init): CR3: BEF000, Task 0060:c0bf180c
Process 3(second fork of Init during the main loop): CR3: BEB000, Task 0060:c0bed80c

That's very illuminating already 😁

- I see the open call happening on Process 1. It's first parameter is 0010c7d8, it's second parameter being 2. So that's the first open("/dev/tty1",2(O_RDWR),0) system call.
- Then, a dup(0) syscall.
- Another dup(0) syscall.
- Then execve("/etc/init"(0010c7e2),argv_init(0018a00c),envp_init(0018a034)).
- Then execve("/bin/init"(0010c7ec),argv_init,envp_init).
- Then execve("/sbin/init"(0010c7f6),argv_init,envp_init).
- Then fork().
- Then, on the Process 1, sys_waitpid(ffffffff,0018cf4c,00000000).
- Then, on the child process(CR3: BEF000, Task 0060:c0bf180c), I see a close(0).
- Then, on the child process, open("/etc/rc"(0010c801),O_RDONLY(00000000),00000000).
- Then, on the child process, _exit(1).
- Then, back on the Init process(PID of 1): once again, fork(), it's the fork at line 514, within Init's main loop.
- Then, the main loop starts waiting on it's child process using wait(-1,0018cf4c,0x00000000)? Perhaps 0018cf4c is the address of the identifier gotten from fork()? It's line 527.
- Then, the child process 3 executes close(0).
- Then it also executes close(1).
- Then, also close(2).
- Then it executes setsid().
- Then it executes open("/dev/tty1"(0010c7d8),O_RDWR(00000002),0).
- Then it executes dup(0).
- Then, another dup(0).
- Then execve("/bin/sh"(0010bcac,argv(0018a070),envp(0018a078)). That's line 524.
- Then exit(-1(ffffffff)).
- Then, Init(PID 1) becomes active again, executing write(fd(00000001),buf(00193b50),cnt(0000001f)). That's probably the printf notifying the user that "\n\rchild %d died with code %04x\n\r".
- Then sync() from the Init(PID 1) process.
- Then fork() again(line 514).

So it seems like it's trying to execute the various programs(including the shell itself), but fails to do so? It also seems to fail writing it's text on the stdout(the parameter of 1 seems to imply that)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 8 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

So, what I can determine is that the fork of the child process seems to work properly, but the exec calls return -1, which is the case for all processes started with execve?

So the Init program is doing exactly what it's supposed to do, but all the execve calls are failing in trying to start the program they're instructed to start? That's the case for all the programs, in order /etc/init, /bin/init, /sbin/init, /bin/sh and finally in a loop all that it's trying to start again and again(failing) /bin/sh.

So that's a kernel issue(the execve kernel call to be exact), the Init process is doing exactly what it's supposed to do?

Btw, this is all with Linux 1.0.9.

Edit: OK. So after restoring the hd_oldlinux.img disk image(marking it as read-only in the emulator settings), Linux doesn't seem to like that it can't write to the disk. So I'll have to retry with disk access being granted normally(not a read-only disk).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 9 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Hmmmm.... This seems to be the very first(and only) actual start of execve("/bin/sh",argv,envp) at init/main.c:524 of Linux 1.0.9:

0023:0010cb2b CD 80 int 80	RealRAM(p):000acb66=89(‰); RAM(p):0010cb66=89(‰); Physical(p):0010cb66=89(‰); Paged(p):0010cb66=89(‰); Normal(p):0010cb66=89(‰); RealRAM(p):000acb67=f9(ù); RAM(p):0010cb67=f9(ù); Physical(p):0010cb67=f9(ù); Paged(p):0010cb67=f9(ù); Normal(p):0010cb67=f9(ù); RealRAM(p):000acb68=31(1); RAM(p):0010cb68=31(1); Physical(p):0010cb68=31(1); Paged(p):0010cb68=31(1); Normal(p):0010cb68=31(1); RealRAM(p):000acb69=d2(Ò); RAM(p):0010cb69=d2(Ò); Physical(p):0010cb69=d2(Ò); Paged(p):0010cb69=d2(Ò); Normal(p):0010cb69=d2(Ò); RealRAM(p):000acb6a=cd(Í); RAM(p):0010cb6a=cd(Í); Physical(p):0010cb6a=cd(Í); Paged(p):0010cb6a=cd(Í); Normal(p):0010cb6a=cd(Í); RealRAM(r):00b8d810=00( ); RAM(r):00bed810=00( ); Physical(r):00bed810=00( ); Paged(r):c0bed810=00( ); Normal(r):00000004=00( ); RealRAM(r):00b8d811=d0(Ð); RAM(r):00bed811=d0(Ð); Physical(r):00bed811=d0(Ð); Paged(r):c0bed811=d0(Ð); Normal(r):00000005=d0(Ð); RealRAM(r):00b8d812=be(¾); RAM(r):00bed812=be(¾); Physical(r):00bed812=be(¾); Paged(r):c0bed812=be(¾); Normal(r):00000006=be(¾); RealRAM(r):00b8d813=00( ); RAM(r):00bed813=00( ); Physical(r):00bed813=00( ); Paged(r):c0bed813=00( ); Normal(r):00000007=00( ); RealRAM(r):00b8d814=18(); RAM(r):00bed814=18(); Physical(r):00bed814=18(); Paged(r):c0bed814=18(); Normal(r):00000008=18(); RealRAM(r):00b8d815=00( ); RAM(r):00bed815=00( ); Physical(r):00bed815=00( ); Paged(r):c0bed815=00( ); Normal(r):00000009=00( ); RealRAM(r):00b8bc0b=00( ); RAM(r):00bebc0b=00( ); Physical(r):00bebc0b=00( ); RealRAM(r):00b8bc0a=1a(); RAM(r):00bebc0a=1a(); Physical(r):00bebc0a=1a(); RealRAM(r):00b8bc09=d0(Ð); RAM(r):00bebc09=d0(Ð); Physical(r):00bebc09=d0(Ð); RealRAM(r):00b8bc08=27('); RAM(r):00bebc08=27('); Physical(r):00bebc08=27('); RealRAM(r):0014dfb3=00( ); RAM(r):001adfb3=00( ); Physical(r):001adfb3=00( ); RealRAM(r):0014dfb2=be(¾); RAM(r):001adfb2=be(¾); Physical(r):001adfb2=be(¾); RealRAM(r):0014dfb1=c0(À); RAM(r):001adfb1=c0(À); Physical(r):001adfb1=c0(À); RealRAM(r):0014dfb0=67(g); RAM(r):001adfb0=67(g); Physical(r):001adfb0=67(g); Normal(w):00becffc=2b(+); Paged(w):c0becffc=2b(+); Physical(w):00becffc=2b(+); RAM(w):00becffc=2b(+); RealRAM(w):00b8cffc=2b(+); Normal(w):00becffd=00( ); Paged(w):c0becffd=00( ); Physical(w):00becffd=00( ); RAM(w):00becffd=00( ); RealRAM(w):00b8cffd=00( ); Normal(w):00becffe=00( ); Paged(w):c0becffe=00( ); Physical(w):00becffe=00( ); RAM(w):00becffe=00( ); RealRAM(w):00b8cffe=00( ); Normal(w):00becfff=00( ); Paged(w):c0becfff=00( ); Physical(w):00becfff=00( ); RAM(w):00becfff=00( ); RealRAM(w):00b8cfff=00( ); Normal(w):00becff8=38(8); Paged(w):c0becff8=38(8); Physical(w):00becff8=38(8); RAM(w):00becff8=38(8); RealRAM(w):00b8cff8=38(8); Normal(w):00becff9=cf(Ï); Paged(w):c0becff9=cf(Ï); Physical(w):00becff9=cf(Ï); RAM(w):00becff9=cf(Ï); RealRAM(w):00b8cff9=cf(Ï); Normal(w):00becffa=18(); Paged(w):c0becffa=18(); Physical(w):00becffa=18(); RAM(w):00becffa=18(); RealRAM(w):00b8cffa=18(); Normal(w):00becffb=00( ); Paged(w):c0becffb=00( ); Physical(w):00becffb=00( ); RAM(w):00becffb=00( ); RealRAM(w):00b8cffb=00( ); Normal(w):00becff4=17(); Paged(w):c0becff4=17(); Physical(w):00becff4=17(); RAM(w):00becff4=17(); RealRAM(w):00b8cff4=17(); Normal(w):00becff5=02(); Paged(w):c0becff5=02(); Physical(w):00becff5=02(); RAM(w):00becff5=02(); RealRAM(w):00b8cff5=02(); Normal(w):00becff6=00( ); Paged(w):c0becff6=00( ); Physical(w):00becff6=00( ); RAM(w):00becff6=00( ); RealRAM(w):00b8cff6=00( ); Normal(w):00becff7=00( ); Paged(w):c0becff7=00( ); Physical(w):00becff7=00( ); RAM(w):00becff7=00( ); RealRAM(w):00b8cff7=00( ); Normal(w):00becff0=23(#); Paged(w):c0becff0=23(#); Physical(w):00becff0=23(#); RAM(w):00becff0=23(#); RealRAM(w):00b8cff0=23(#); Normal(w):00becff1=00( ); Paged(w):c0becff1=00( ); Physical(w):00becff1=00( ); RAM(w):00becff1=00( ); RealRAM(w):00b8cff1=00( ); Normal(w):00becff2=00( ); Paged(w):c0becff2=00( ); Physical(w):00becff2=00( ); RAM(w):00becff2=00( ); RealRAM(w):00b8cff2=00( ); Normal(w):00becff3=00( ); Paged(w):c0becff3=00( ); Physical(w):00becff3=00( ); RAM(w):00becff3=00( ); RealRAM(w):00b8cff3=00( ); Normal(w):00becfec=2d(-); Paged(w):c0becfec=2d(-); Physical(w):00becfec=2d(-); RAM(w):00becfec=2d(-); RealRAM(w):00b8cfec=2d(-); Normal(w):00becfed=cb(Ë); Paged(w):c0becfed=cb(Ë); Physical(w):00becfed=cb(Ë); RAM(w):00becfed=cb(Ë); RealRAM(w):00b8cfed=cb(Ë); Normal(w):00becfee=10(); Paged(w):c0becfee=10(); Physical(w):00becfee=10(); RAM(w):00becfee=10(); RealRAM(w):00b8cfee=10(); Normal(w):00becfef=00( ); Paged(w):c0becfef=00( ); Physical(w):00becfef=00( ); RAM(w):00becfef=00( ); RealRAM(w):00b8cfef=00( )
Registers:
EAX: 0000000b EBX: 0010bcac ECX: 0018a070 EDX: 0018a078
ESP: 0018cf38 EBP: 00000002 ESI: 00000000 EDI: 00000009
CS: 0023 DS: 002b ES: 002b FS: 002b GS: 002b SS: 002b TR: 0060 LDTR: 0068
EIP: 0010cb2b EFLAGS: 00000217
CR0: 8005003f CR1: 00000000 CR2: c0000000 CR3: 00beb000
CR4: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c010b460083f IDTR: 0000c010ac5007ff
FLAGSINFO: 0000000000ipfavr0n00odItsz0A0P1C

That should at least provide a starting point for debugging?

When it returns, EAX and EDI are FFFFFFFE(-2)? Does that tell us anything?

Edit: This is what happens during said syscall:

Filename
debugger_execve_binsh.zip
File size
1.47 MiB
Downloads
38 downloads
File comment
execve("/bin/sh",argv,envp) at init/main.c:524
File license
Fair use/fair dealing exception

Anyone can see what's going wrong? The first hard disk was successfully mounted(the Linux 0.01 harddisk using a Minix filesystem). The second harddisk was rejected(just to make it not error on the harddisks) due to using CHS translation(done by the BIOS on the 512MB WFW 3.11 disk image).

Attachments

  • Filename
    debugger_initexecutingitsfinalfork.zip
    File size
    44.26 KiB
    Downloads
    57 downloads
    File comment
    Init executing it's final fork(0023:0010cb2b being the execve("/bin/sh",argv,envp) at init/main.c:524 )
    File license
    Fair use/fair dealing exception
Last edited by superfury on 2019-06-29, 13:19. Edited 1 time in total.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 10 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Hmmm.... 0010:0010e07d seems to be the call that starts the sys_execve function itself at Supervisor level. So 0010:001230c8 is the execve() function prologue being executed.

Edit: So 0010:0012443c is the start of the getname() function.
Edit: 0010:001230dc is the return from the getname() function. It returns 0(according to EAX). So the function was a success.
Edit: Then, 0010:001230f5 is the call to do_execve().
Edit: Then, within do_execve(), there's at 0010:00122af6 fs/exec.c:553, the call to open_namei(filename,0,0,&bprm.inode,NULL). It's CALLed at 0010:00122b05.
Looking at the result value at 0010:00122b0a, EAX contains -2? So the open_namei call returns -2, so there's something wrong there?
Edit: Looking at include/linux/errno.h, it's return -2, so -ENOENT? So it cannot find the /bin directory or /bin/sh file correctly? Hmmm...
So, the open_namei call starts at 0010:00124a2c...
Edit: So, 0010:00124a76 E8 F1 FC FF FF calld 0012476c is the call to dir_namei(pathname,&namelen,&basename,base,&dir).
Edit: Looking at the result at 0010:00124a7b, it returns -2(so -ENOENT) as well? So dir_namei is failing somehow?
Edit: 0010:0012477f is *res_inode = NULL;
Edit: Base is NULL at 0010:00124785, so !base must be followed, the innet of the IF being at 0010:0012478c.
Edit: It loads current into EAX, then EAX+3D0 into EAX, effectively loading current->pwd into EAX.Then EAX into ESP+28(which is the base parameter).
Edit: Then, it increases i_count using a basic INC instruction.
Edit: It sees the root start(/), at which point it calls iput(base) at 0010:001247a9.
Edit: It returns at 0010:001247ae.
Edit: It loads current->root into base and increases pathname by 1 at 0010:001247bd.
Edit: It increases base->icount at 0010:001247be.
Edit: The infinite loop is entered. Pathname(ESI) is loaded into thisname(EBX).
Edit: It initializes len to 0(0010:001247ca) at [esp+10], for the pathname length check for the current directory(bin) to process.
Edit: I see it reading b, copying it to the c variable, increase and check for NULL-termination, then '/'(2Fh). It then increases len to 1.
Edit: Then the next one, reading i, increase and check for NULL-termination, then '/'(2Fh). It then increases len to 2.
Edit: Then the final path one, reading n, increase and check for NULL termination, then '/'(2Fh).
Edit: Then the path termination, reading '/', increase and check for NULL termination, then '/'(2Fh), which is found. It thus proceeds to 0010:001247eb.
Edit: It then checks for the NULL-terminator at 0010:001247eb to terminate the main loop.
Edit: It then stores EDX with the 'base' parameter's address at 0010:001247ef. It then increases base->icount at 0010:001247f3(fs:namei.c:181 ).
Edit: It then pushes parameters on the stack(len verified being 3 correctly("bin" length) and calls the lookup() function at 0010:00124803.
Edit: It returns -2. Looking at the source code for the lookup function, I see that value being returned right at the start of the function? Hmmm....
Edit: I see the lookup function starting at 0010:001245dc.
Edit: It sets the result to NULL at 0010:001245ef.
Edit: It validates dir to be valid.
Edit: It calls permission(dir,MAY_EXEC(=1)) at 0010:0012460f. It returns 1 at 0010:00124614 and stores it at ESP+18(the perm variable).
Edit: It checks the length for 2(it's 3 in length) at 0010:0012461b, which mismatches, jumping to 0010:0012466c.
Edit: It checks dir->i_op and dir->i_op for zero, finds them non-zero and jumps to 0010:0012469c.
Edit: The perm check succeeds, proceeding to 0010:001246bc for the length check.
Edit: It then calls dir->i_op->lookup(dir,name,len,result) at 0010:001246c0.
Edit: The Minix filesystem lookup(minix_lookup) function is then called at 0010:001246cb, the function existing at 0010:00131868. Said function returns -2 as well, so it's the cause.
Edit: Minix_lookup clears the result at 0010:00131876.
Edit: It proceeds to check for the directory attribute on 0010:00131898 for the root directory.
Edit: Said attribute is 0x41ed.
Edit: It's a directory(0x4000 set), thus proceeds to 0010:001318c8.
Edit: It calls minix_find_entry(dir,name,len,&de) at 0010:001318d8. Said functions returns 0, thus giving the -2 result which fails all.
Edit: It initializes res_dir to 0 at 0010:00131767.
Edit: Dir and dir->i_sb are deemed valid, thus continuing to 0010:00131788.
Edit: It loads namelen into EDX at 0010:0013178e.
Edit: It compares it to 14(0xE), being s->namelen.
Edit: It initializes for the main entry loop at 0010:0013179e.
Edit: The main entry loop then starts at 0010:001317aa.
Edit: It checks EBX(bh) for being 0. It finds it being NULL, thus proceeding to 0010:001317b4.
Edit: It then reads the filesystem using minix_bread(dir(00bf7ee0),block(0),0) at 0010:001317b8. The function existing at 0010:00133874.
Edit: It returns a valid value, thus finding something 😁 The bh pointer now will contain 0xbfed20 at 0010:001317bd.
Edit: It finds the result non-zero, thus continuing on.
Edit: *res_dir is updated with the first entry it found at 0010:001317e2.
Edit: It calls the name compare(minix_match(namelen,name,bh,&offset,info)) function at 0010:001317f5.
OK, at this point, it gets interesting! This function starts to compare the found directory entries to the entry we're searching for(which must be failing)...
Said function starts running at 0010:001316c8.

It loads the len in ebx, then bh into edx, the offset pointer into eax, info into ebp.
Edit: Then, it loads bh->b_data into edx at 0010:001316dc.
It then adds the offset dereferenced pointer to that edx. Thus getting the sum for the de variable.
It then loads info->dirsize(offset 5C), which matches minix_fs_sb.h, into esi at 0010:001316e0. That's 0x10(16).
It then adds the dirsize variable to the offset pointer dereferenced.
It then finds the inode being zeroed at 0010:001316e5 and returns.

It then compares offset to bh->b_size(0x400). Thus CMP b_size(0x400),EAX(10h) at 0010:00131805.
It them compares 0x60 with EAX(0x10) at 0010:00131827.
It notices EAX is below 0x60, thus jumping back to 0010:001317b0.

It restarts the loop, processing the next entry.
It's finding another zeroed inode, thus aborting.

That seems to continue. It only seems to find zeroed inodes?
Edit: The root directory has 6 entries, each being 0x10 bytes long. Looking at the disk image, the bin directory should be having 2 in it's inode. But the memory-resident version has 0 as it's value, thus invalid?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 11 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

It doesn't seem to find any inodes with the required bits set in memory, so perhaps the disk is incorrectly read during boot?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 12 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Thinking about it, are the inodes ever read from disk into memory? As far as I can see in the code, when mounting, only the first 1024 bytes are read from disk? Thus the inodes aren't read? When are they read from disk? During sys_setup?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 13 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Perhaps the bread for the superblock(during minix_read_super) fails? Although mounting succeeds, so at least the superblock is read correctly? That is bread(dev,1,BLOCK_SIZE).

Then, are the inodes etc. properly read from disk after that(s_imap and s_zmap)?
What about the iget(s,MINIX_ROOT_INO) call? Is it messing up it's parsing of the earlier loaded objects?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 14 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Seeing as the filesystem IS successfully mounted, at least the bread for the SuperBlock must be succeeding.

I'll need to look into what happens after that(the maps and the root directory inodes).

The maps should easily be detected, as they're read from the disk in a sequential way.

Then there's the root directory inode, where it gets interesting(as those are incorrect(NULL) when used).

Or perhaps the caches themselves are malfunctioning?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 15 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

So, the syscall starts at 10:10e030.
So, sys_setup is at 0010:1109a4.
So, sector 16h is the superblock?
Hmmm... sector 37c should be read during the initial root directory fetch. 37b should be the final map block read.
Edit: I only see it read a few blocks(about 4), then 37c and 37d? So the initial directory fetch should be fetched?

I see it reading sector *0(boot sector), 1, *16(superblock), 17, 18, 19, 1a, 1b, 1c, 1d, 19,20, 21,22(zeroed block),23,24(zeroed block),25,26(some data),27,*37c(the root directory),37d,2c(some bitmap?),2d,4b9c(containing tty and tty0),4b9d,37e(the bin directory?),37f,3934,3935(various executables inodes),3936,380(Some ELF header),381,38e,38f,*692,693,694,695,696,697,698,699,...

It seems to be actually loading something at least, I just don't know what or where in memory...

Anyone got some advice at what to look for?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 16 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Thus, looking at the log of it running again, I see interesting comparisions at 0010:0013172e. It's the namecompare function's loop that's actually finding directory entries!

Edit: Looking at the disassembly, looking at said location, I DO see /bin/sh being found and matched to a used input!

0010:0013172c 89 D9 mov ecx,ebx	RealRAM(p):000d176a=00( ); RAM(p):0013176a=00( ); Physical(p):0013176a=00( ); Paged(p):c013176a=00( ); Normal(p):0013176a=00( ); RealRAM(p):000d176b=00( ); RAM(p):0013176b=00( ); Physical(p):0013176b=00( ); Paged(p):c013176b=00( ); Normal(p):0013176b=00( )
Registers:
EAX: 00bf4422 EBX: 00000002 ECX: 00000002 EDX: 00bf4420
ESP: 00bebd80 EBP: 001a8408 ESI: 00be8005 EDI: 00bf4422
CS: 0010 DS: 0018 ES: 0018 FS: 002b GS: 002b SS: 0018 TR: 0060 LDTR: 0068
EIP: 0013172c EFLAGS: 00000246
CR0: 8005003f CR1: 00000000 CR2: c0000000 CR3: 00bea000
CR4: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c010b460083f IDTR: 0000c010ac5007ff
FLAGSINFO: 0000000000ipfavr0n00odItsZ0a0P1c
0010:0013172c 89 D9 mov ecx,ebx RealRAM(p):000d176c=00( ); RAM(p):0013176c=00( ); Physical(p):0013176c=00( ); Paged(p):c013176c=00( ); Normal(p):0013176c=00( ); RealRAM(p):000d176d=85(?); RAM(p):0013176d=85(?); Physical(p):0013176d=85(?); Paged(p):c013176d=85(?); Normal(p):0013176d=85(?); RealRAM(r):00b88005=73(s); RAM(r):00be8005=73(s); Physical(r):00be8005=73(s); Paged(r):c0be8005=73(s); RealRAM(r):00b94422=73(s); RAM(r):00bf4422=73(s); Physical(r):00bf4422=73(s); Paged(r):c0bf4422=73(s)
0010:0013172c 89 D9 mov ecx,ebx RealRAM(r):00b88006=68(h); RAM(r):00be8006=68(h); Physical(r):00be8006=68(h); Paged(r):c0be8006=68(h); RealRAM(r):00b94423=68(h); RAM(r):00bf4423=68(h); Physical(r):00bf4423=68(h); Paged(r):c0bf4423=68(h)
0010:0013172e F3 A6 repz cmpsb ds:[esi],es:[edi]
Registers:
EAX: 00bf4422 EBX: 00000002 ECX: 00000002 EDX: 00bf4420
ESP: 00bebd80 EBP: 001a8408 ESI: 00be8005 EDI: 00bf4422
CS: 0010 DS: 0018 ES: 0018 FS: 002b GS: 002b SS: 0018 TR: 0060 LDTR: 0068
EIP: 0013172e EFLAGS: 00000246
CR0: 8005003f CR1: 00000000 CR2: c0000000 CR3: 00bea000
CR4: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c010b460083f IDTR: 0000c010ac5007ff
FLAGSINFO: 0000000000ipfavr0n00odItsZ0a0P1c
0010:00131730 0F 94 C0 setz al RealRAM(p):000d176e=ff(?); RAM(p):0013176e=ff(?); Physical(p):0013176e=ff(?); Paged(p):c013176e=ff(?); Normal(p):0013176e=ff(?); RealRAM(p):000d176f=74(t); RAM(p):0013176f=74(t); Physical(p):0013176f=74(t); Paged(p):c013176f=74(t); Normal(p):0013176f=74(t)
Registers:
EAX: 00bf4422 EBX: 00000002 ECX: 00000000 EDX: 00bf4420
ESP: 00bebd80 EBP: 001a8408 ESI: 00be8007 EDI: 00bf4424
CS: 0010 DS: 0018 ES: 0018 FS: 002b GS: 002b SS: 0018 TR: 0060 LDTR: 0068
EIP: 00131730 EFLAGS: 00000246
CR0: 8005003f CR1: 00000000 CR2: c0000000 CR3: 00bea000
CR4: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c010b460083f IDTR: 0000c010ac5007ff
FLAGSINFO: 0000000000ipfavr0n00odItsZ0a0P1c
0010:00131733 25 FF 00 00 00 and eax,000000ff RealRAM(p):000d1770=06(); RAM(p):00131770=06(); Physical(p):00131770=06(); Paged(p):c0131770=06(); Normal(p):00131770=06(); RealRAM(p):000d1771=83(?); RAM(p):00131771=83(?); Physical(p):00131771=83(?); Paged(p):c0131771=83(?); Normal(p):00131771=83(?); RealRAM(p):000d1772=7f(); RAM(p):00131772=7f(); Physical(p):00131772=7f(); Paged(p):c0131772=7f(); Normal(p):00131772=7f()
Registers:
EAX: 00bf4401 EBX: 00000002 ECX: 00000000 EDX: 00bf4420
ESP: 00bebd80 EBP: 001a8408 ESI: 00be8007 EDI: 00bf4424
CS: 0010 DS: 0018 ES: 0018 FS: 002b GS: 002b SS: 0018 TR: 0060 LDTR: 0068
EIP: 00131733 EFLAGS: 00000246
CR0: 8005003f CR1: 00000000 CR2: c0000000 CR3: 00bea000
CR4: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c010b460083f IDTR: 0000c010ac5007ff
FLAGSINFO: 0000000000ipfavr0n00odItsZ0a0P1c
RealRAM(p):000d1773=38(8); RAM(p):00131773=38(8); Physical(p):00131773=38(8); Paged(p):c0131773=38(8); Normal(p):00131773=38(8); RealRAM(p):000d1774=00( ); RAM(p):00131774=00( ); Physical(p):00131774=00( ); Paged(p):c0131774=00( ); Normal(p):00131774=00( ); RealRAM(p):000d1775=75(u); RAM(p):00131775=75(u); Physical(p):00131775=75(u); Paged(p):c0131775=75(u); Normal(p):00131775=75(u); RealRAM(p):000d1776=11(); RAM(p):00131776=11(); Physical(p):00131776=11(); Paged(p):c0131776=11(); Normal(p):00131776=11(); RealRAM(p):000d1777=31(1); RAM(p):00131777=31(1); Physical(p):00131777=31(1); Paged(p):c0131777=31(1); Normal(p):00131777=31(1)
0010:00131738 5B pop ebx RealRAM(r):00b8bd80=60(`); RAM(r):00bebd80=60(`); Physical(r):00bebd80=60(`); Paged(r):c0bebd80=60(`); RealRAM(r):00b8bd81=ec(?); RAM(r):00bebd81=ec(?); Physical(r):00bebd81=ec(?); Paged(r):c0bebd81=ec(?); RealRAM(r):00b8bd82=bf(?); RAM(r):00bebd82=bf(?); Physical(r):00bebd82=bf(?); Paged(r):c0bebd82=bf(?); RealRAM(r):00b8bd83=00( ); RAM(r):00bebd83=00( ); Physical(r):00bebd83=00( ); Paged(r):c0bebd83=00( )
Registers:
EAX: 00000001 EBX: 00000002 ECX: 00000000 EDX: 00bf4420
ESP: 00bebd80 EBP: 001a8408 ESI: 00be8007 EDI: 00bf4424
CS: 0010 DS: 0018 ES: 0018 FS: 002b GS: 002b SS: 0018 TR: 0060 LDTR: 0068
EIP: 00131738 EFLAGS: 00000202
CR0: 8005003f CR1: 00000000 CR2: c0000000 CR3: 00bea000
CR4: 00000000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
Show last 3 lines
DR6: 00000000 DR7: 00000000
GDTR: 0000c010b460083f IDTR: 0000c010ac5007ff
FLAGSINFO: 0000000000ipfavr0n00odItsz0a0p1c

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 17 of 17, by superfury

User metadata
Rank l33t++
Rank
l33t++

Perhaps the issue with the sys_write function might shine some light on the issue?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io