Page 1 of 1
Constructing a C++ framework for complex kernel-mode devices
Posted: Wed Oct 06, 2010 2:17 pm
by rdos
I've this far only used 386-assembler in my kernel & kernel-mode device drivers. However, in the process of integrating with Open Watcom, I've already built a libc and debugger that can be used for applications. This is part of the official 1.9 release. This means I have left BCC for creating applications. I'm also working on porting all kernel code to WASM, and instead of using DOS executable format, I've defined a custom format & added it to the Open Watcom tool-chain.
All current device-drivers (except for the 32-bit DPMI server) uses 16-bit code-segments. Because of the DPMI server, I'll also need a 32-bit device-driver format, which I will implement shortly. With a 32-bit device-driver format, it will become possible to port Open Watcom's clib for kernel mode-code as well, and write device-drivers in C/C++. The compiler supports 48-bit pointers (in 32-bit code), so this should not be impossible to do.
I think the first step would be to define all kernel-APIs in a header-file similar to how I did for applications. Kernel-mode device-drivers can use both the application APIs (extended to 48-bit pointers) and the kernel-mode API. For user mode, I've created a class library that encapsulates the functions in a more easy-to-use format than simple C functions. I think I might do that for kernel as well, and code all device-drivers in C++ rather than C. Most of the complex APIs are well suited for using a object-oriented approach.
For instance, it would be possible to create a base-class for new file systems. It would contain a set of virtual methods called to do different operations. There is already such a table in the assembler-level interface that passes a table of pointers as a new file system is initiated. A particular file system would just override these virtual methods with actual code. Then there could be a set of methods the file system could use to access physical disc space.
I think I like this approach much better than just writing C code, which tends to become as bad as assembler.
Re: Constructing a C++ framework for complex kernel-mode dev
Posted: Wed Oct 06, 2010 2:45 pm
by gerryg400
For instance, it would be possible to create a base-class for new file systems. It would contain a set of virtual methods called to do different operations. There is already such a table in the assembler-level interface that passes a table of pointers as a new file system is initiated. A particular file system would just override these virtual methods with actual code. Then there could be a set of methods the file system could use to access physical disc space.
This seems like a very good approach. I imagine its difficult to design the base-classes at the outset however you have the advantage that your OS already has filesystems to base the design on.
BTW, I am porting newlib to my OS and noticed there is an 'rdos' port. Is that the same rdos that you develop ?
Re: Constructing a C++ framework for complex kernel-mode dev
Posted: Wed Oct 06, 2010 3:06 pm
by JamesM
Hi,
rdos wrote:I've this far only used 386-assembler in my kernel & kernel-mode device drivers. However, in the process of integrating with Open Watcom, I've already built a libc and debugger that can be used for applications. This is part of the official 1.9 release. This means I have left BCC for creating applications. I'm also working on porting all kernel code to WASM, and instead of using DOS executable format, I've defined a custom format & added it to the Open Watcom tool-chain.
All current device-drivers (except for the 32-bit DPMI server) uses 16-bit code-segments. Because of the DPMI server, I'll also need a 32-bit device-driver format, which I will implement shortly. With a 32-bit device-driver format, it will become possible to port Open Watcom's clib for kernel mode-code as well, and write device-drivers in C/C++. The compiler supports 48-bit pointers (in 32-bit code), so this should not be impossible to do.
I think the first step would be to define all kernel-APIs in a header-file similar to how I did for applications. Kernel-mode device-drivers can use both the application APIs (extended to 48-bit pointers) and the kernel-mode API. For user mode, I've created a class library that encapsulates the functions in a more easy-to-use format than simple C functions. I think I might do that for kernel as well, and code all device-drivers in C++ rather than C. Most of the complex APIs are well suited for using a object-oriented approach.
For instance, it would be possible to create a base-class for new file systems. It would contain a set of virtual methods called to do different operations. There is already such a table in the assembler-level interface that passes a table of pointers as a new file system is initiated. A particular file system would just override these virtual methods with actual code. Then there could be a set of methods the file system could use to access physical disc space.
I think I like this approach much better than just writing C code, which tends to become as bad as assembler.
Was there a question? or was it just "general comments"?
The problem with your design is that of vtables. Virtual functions are implemented using vtables, a pointer to which is placed in every object (that uses virtual functions). The vtable for each class is a constant, and will be located wherever the program that created/initialised the object decided to put it.
This means that for user application/driver A, it will be in one place, for the kernel it will be in another place and for user driver B it will be in another place. All of these are in separate, isolated memory areas (else what would be the point of having an API?). Thus, all you're going to get when you perform a virtual call is a GPF.
Unless you only call virtual functions from kernel space (and never from user space), in which case it'll still fall down if you use different address spaces for each driver. I don't know if you're doing that or not (or if everything's in the same address space).
Cheers,
James
Re: Constructing a C++ framework for complex kernel-mode dev
Posted: Wed Oct 06, 2010 7:14 pm
by TylerH
JamesM wrote:
The problem with your design is that of vtables. Virtual functions are implemented using vtables, a pointer to which is placed in every object (that uses virtual functions). The vtable for each class is a constant, and will be located wherever the program that created/initialised the object decided to put it.
This means that for user application/driver A, it will be in one place, for the kernel it will be in another place and for user driver B it will be in another place. All of these are in separate, isolated memory areas (else what would be the point of having an API?). Thus, all you're going to get when you perform a virtual call is a GPF.
Unless you only call virtual functions from kernel space (and never from user space), in which case it'll still fall down if you use different address spaces for each driver. I don't know if you're doing that or not (or if everything's in the same address space).
I think he means he's going to use C++ OOP to simplify calls to the kernel. The object could be anywhere in memory, it would just make system calls anyway. It's like MFC vs Win32 API, the calls go to the same place, one provides a layer of abstraction on top of the other.
Re: Constructing a C++ framework for complex kernel-mode dev
Posted: Wed Oct 06, 2010 10:45 pm
by rdos
TylerAnon wrote:JamesM wrote:
The problem with your design is that of vtables. Virtual functions are implemented using vtables, a pointer to which is placed in every object (that uses virtual functions). The vtable for each class is a constant, and will be located wherever the program that created/initialised the object decided to put it.
This means that for user application/driver A, it will be in one place, for the kernel it will be in another place and for user driver B it will be in another place. All of these are in separate, isolated memory areas (else what would be the point of having an API?). Thus, all you're going to get when you perform a virtual call is a GPF.
Unless you only call virtual functions from kernel space (and never from user space), in which case it'll still fall down if you use different address spaces for each driver. I don't know if you're doing that or not (or if everything's in the same address space).
I think he means he's going to use C++ OOP to simplify calls to the kernel. The object could be anywhere in memory, it would just make system calls anyway. It's like MFC vs Win32 API, the calls go to the same place, one provides a layer of abstraction on top of the other.
Yes. I will not export an OOP API, just create a new kernel-mode API on top of the existing API that can be used for new file system implementations in C++. This will greatly simplify driver development. Today making a new file system driver is a very complex task even if one knows what all structures involved are used for.
As for the vtable, it will be allocated (as a selector) as part of the creation of the file system object (ordinary new operator). It already contains function pointers, but these are 16:16, so these cannot directly be used as vtable in a 32-bit driver. It might be possible to expand these, but I suspect it would be easier to add a "translation" layer (a jmp/call to the virtual function), as the callbacks into the driver are register-based (I might need some other conversions as well, like expanding the object selector to a 16:32 pointer).
Other functions that might benefit are new USB-functions. Here too, there is an OO friendly API with function pointers, and some helper methods for doing USB operations.
Re: Constructing a C++ framework for complex kernel-mode dev
Posted: Wed Oct 06, 2010 10:53 pm
by rdos
gerryg400 wrote:BTW, I am porting newlib to my OS and noticed there is an 'rdos' port. Is that the same rdos that you develop ?
Yes. I did this years ago, but lost interest as it took too long to get the changes into mainline. Especially getting rdos into some of the basic projects needed by GCC seemed to take forever. In the Open Watcom project, I now have access to the code with Perforce, and the compiler is well suited both for flat-mode applications and segmented device-drivers.