ddvk / remarkable2-framebuffer

remarkable2 framebuffer reversing
MIT License
283 stars 22 forks source link

see what it takes to support KOReader #5

Closed raisjn closed 3 years ago

raisjn commented 4 years ago

either through IPC model or using LD_PRELOAD

see https://github.com/koreader/koreader/issues/6792

raisjn commented 4 years ago

for rM2, it seems there is a software thread that acts like the EPDC/TCON (whatever those mean). there's discussion in KOReader and reStream#28 about it a little bit and other places.

the gist seems to be: the framebuffer is now a memory location inside a process (and not /dev/fb, any longer) and there is a software thread that accepts the equivalent commands to update_display(rect, waveform, ...). we are discussing whether to make it possible for each process to instantiate their own SWTCON or if we should have a server that provides an API for interacting with the framebuffer

@niluje: i'm curious if you've seen display drivers that use a software thread for driving the display and what KOReader has done in those cases. specifically: is it reasonable to create a "framebuffer server" that would be required to be running for KOReader to run (and the framebuffer server exposes IPC API for interacting with framebuffer).

NiLuJe commented 4 years ago

Nope, that's entirely new territory for me ;). Would this rely on xochitl in any way? (I'm fairly sure we kill it right now?).

On eInk devices (if you forget about Android, where things are... messy), we generally expect to have full control over the framebuffer device (i.e., either we neuter the stock system (Kindle), we try to play nice with it while still mostly neutering it (PocketBook), or we murder it with fire (Kobo)).

Given the recent discussions about the launcher(s) situation on rM, a centralized server possibly makes more sense if you want to help stuff interoperate. But, technically, both model would work just fine, I think?

NiLuJe commented 4 years ago

On a mildly related note, as far as xochitl is concerned, you might want to take a look at what @pgaskin came up with to avoid having to setup a global LD_PRELOAD and still hook into the Qt5 Kobo app, by piggybacking on the Qt5 image plugin system: https://github.com/pgaskin/NickelHook/

raisjn commented 4 years ago

The server process will rely on using functions from either xochitl or remarkable-shutdown but those processes don't actually run. We use LD_PRELOAD to take over the process, like LD_PRELOAD=rm2fb.so xochitl and then we use our own main() func but call into the APIs we need to 1) start the SWTCON threads and 2) send updates. If we go server model, this only needs to happen once (instead of each application doing this dance)

https://github.com/ddvk/remarkable2-framebuffer/blob/master/src/loader/main.cpp#L100

NickelHook looks interesting, thanks! we will need to read on it and see if we can re-use those ideas.

ddvk commented 4 years ago

all this now is a stopgap solution, until we can drive the framebuffer ourselves (in which case everyone can write their own implementstion) or use the propietary lib from the SDK when/if it is available.

pgaskin commented 4 years ago

If you need help with injection or hooking (both plain C apps, Qt5 apps, and the kernel itself) and other things like that, I can answer any questions you have about my kobo mods and related topics. I'm not very familiar with e-ink fb quirks, though (that's @NiLuJe's area of expertise).


Regarding the client-server idea, I have a few concerns about that approach (I was almost going to take a similar approach with NickelHook et al, but abandoned it after some discussion):

raisjn commented 4 years ago

@pgaskin thanks! one major question is: we know the API of the func we want (and have its current memory address and can find it again by hand in other binaries if we need to), but is there a way to search memory for that func's address so that its more future proof? our first idea is to grab X bytes from the current func and then search for those same bytes in the other binaries.

looking at nickelhook, it seems like plugins are shared libraries that are opened with dlopen/dlsym and invoked? this is something i want to explore here, too (i see you commented on https://github.com/ddvk/remarkable2-framebuffer/issues/3, thank you!)

Handling timing issues between clients (double or triple buffering may help at the expense of CPU).

what is timing issues? the SWTCON does have double buffering, afaict. they have a "vsync and flip thread" which moves data from one area to another

IPC compatibility between versions (the severity of this issue could be reduced by having a dynamic library which abstracts the communication method and exposes a very low-level interface).

agree. if we start by being compatible with the mxcfb_update struct, i think that should mostly cover the update API but not sure if missing stuff since we don't understand SWTCON yet.

pgaskin commented 4 years ago

we know the API of the func we want (and have its current memory address and can find it again by hand in other binaries if we need to), but is there a way to search memory for that func's address so that its more future proof? our first idea is to grab X bytes from the current func and then search for those same bytes in the other binaries.

It depends. Based on what you said, I'm assuming the remarkable binaries have hidden symbols? If so, you'll have to find the function. A few possible ideas on how this can be done:

it seems like plugins are shared libraries that are opened with dlopen/dlsym and invoked

Not for NickelHook. NickelHook plugins are the libraries themselves. Qt's plugin system does all the required dlopening. This should work here too if it's a proper Qt5 application.

My suggestion in #3 is slightly different.

what is timing issues? the SWTCON does have double buffering, afaict. they have a "vsync and flip thread" which moves data from one area to another

In that case, you should be OK in general. I'm not familiar with the reMarkable tablets.

If you end up supporting multiple clients, you'll need to make sure the writes don't end up overlapping accidentally.

... but not sure if missing stuff since we don't understand SWTCON yet.

Yes, you'll need to look into it more before designing the API if you choose to go that direction.

raisjn commented 4 years ago

using LD_PRELOAD shim for clients: https://imgur.com/a/ZSKw0vi

raisjn commented 4 years ago

Circling back on this, there are a few things that need to be done before it feels like KOReader is finished.

i'll need help with all of the above and am going to be unavailable from 11/11 for a week or two, so if anyone wants to pick these up, will be very appreciated! @ddvk can help / give guidance

as it is now: KOReader can be run through ssh and it works.

NiLuJe commented 4 years ago
* inputs: input is wrong on the x axis - needs to invert X (or uninvert, as the case may be). is there a setting for this or is it done in code?

There's probably already something available for that. c.f., the Kobo device module for usage examples.

* ???

The rM device module will also need a simple detection to discriminate the two (e.g., https://github.com/NiLuJe/FBInk/blob/d8a9e81335fa57eaf31c228456e3b5e4c5f1ffb5/fbink_device_id.c#L956-L1005).

And, ideally, with a check for the shim's env var, so we can crash gracefully and point to it if it's not available ;).

raisjn commented 3 years ago

ddvk's work has been merged into koreader and nightly works on rm2 (with rm2fb)