The most complex Hello World I'd ever encountered
The most complex Hello World I'd ever encountered
Today I reached a milestone on my hobby OS project - I have my hello world application
Invested countless sleepless night, however the feeling is great. It's like give birth to a new born baby.
The Getting_Started is so true that, There is nothing like the feeling of accomplishment. When you, finally, after hours of struggling finally solve the problem.
The wiki & forum provided so much useful information and insights that helped me a lot, thanks everyone.
Attached an image of my baby:
Invested countless sleepless night, however the feeling is great. It's like give birth to a new born baby.
The Getting_Started is so true that, There is nothing like the feeling of accomplishment. When you, finally, after hours of struggling finally solve the problem.
The wiki & forum provided so much useful information and insights that helped me a lot, thanks everyone.
Attached an image of my baby:
Re: The most complex Hello World I'd ever encountered
Congratulations. That's an operating system! Tell us about the design.
If a trainstation is where trains stop, what is a workstation ?
Re: The most complex Hello World I'd ever encountered
There is actually not much design, as for first attempt I aimed to make a working OS without special consideration on features nor optimizations.
The OS boots from my own boot loader, which load the kernel and initrd into a suitable address, and put boot parameters into a pre-defined memory location. The kernel then use that boot parameters to initialize things like PMM.
On memory layout, I put the kernel, kernel heap and global resources (like initrd) locates at higher-half, so that new processes duplicate the upper bytes of the page directory, last bytes point to process's CR3, and has all lower address for process's local resources.
The VFS is implemented with simplest method, a list of mount point and device:
For example, a call to VFS_open("/initrd/test") found a mount point at "/initrd/", and pass "test" into the drive's open() function.
I also separate the FS parser and underlying IO. Currently I have a ramdisk storage device, and tablefs, which is a read-only filesystem that store files and meta data in a table at end of disk.
I also write a tool to pack files into an initrd with that filesystem.
Drivers are built as DSO, it's loaded and linked with kernel at load-time.
it interact with kernel by directly calling exported kernel functions, or with syscalls.
For process management, I used round-robin scheduling driven by PIT, unless yield() is called the process shall not be preempted, which is not good but it works.
Upon process creation, a mini stack and process context is created with stub function, and the stub function loads the binary, perform runtime linking/relocation, expands the heap, with it's own time-slice and pagedir, and perform clean-up when the program ret.
A sleep queue is implemented so that a process can be removed from scheduling, waiting for signal or sleep - this way I can have many sleeping process without impacting the performance.
User-land application links with newlib and interact with the kernel via INT80 syscall.
The OS boots from my own boot loader, which load the kernel and initrd into a suitable address, and put boot parameters into a pre-defined memory location. The kernel then use that boot parameters to initialize things like PMM.
On memory layout, I put the kernel, kernel heap and global resources (like initrd) locates at higher-half, so that new processes duplicate the upper bytes of the page directory, last bytes point to process's CR3, and has all lower address for process's local resources.
The VFS is implemented with simplest method, a list of mount point and device:
Code: Select all
typedef struct {
char * path;
size_t path_len; // strlen(path)
dev_t dev; // the "drive handler"
} MOUNTPOINT;
I also separate the FS parser and underlying IO. Currently I have a ramdisk storage device, and tablefs, which is a read-only filesystem that store files and meta data in a table at end of disk.
I also write a tool to pack files into an initrd with that filesystem.
Drivers are built as DSO, it's loaded and linked with kernel at load-time.
it interact with kernel by directly calling exported kernel functions, or with syscalls.
For process management, I used round-robin scheduling driven by PIT, unless yield() is called the process shall not be preempted, which is not good but it works.
Upon process creation, a mini stack and process context is created with stub function, and the stub function loads the binary, perform runtime linking/relocation, expands the heap, with it's own time-slice and pagedir, and perform clean-up when the program ret.
A sleep queue is implemented so that a process can be removed from scheduling, waiting for signal or sleep - this way I can have many sleeping process without impacting the performance.
User-land application links with newlib and interact with the kernel via INT80 syscall.
- thepowersgang
- Member
- Posts: 734
- Joined: Tue Dec 25, 2007 6:03 am
- Libera.chat IRC: thePowersGang
- Location: Perth, Western Australia
- Contact:
Re: The most complex Hello World I'd ever encountered
Congratulations I remember when I first got my OS running user apps, I felt so happy. I used a similar structure to that too. But I do wonder why everyone uses Int 0x80 for their syscalls, try something different for once. (I use 0xAC because my OS is called "Acess")
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Re: The most complex Hello World I'd ever encountered
For instant, INT 80 is higher half of the IDT
I reserved lower half for hardware-related interrupts.
I reserved lower half for hardware-related interrupts.
Re: The most complex Hello World I'd ever encountered
I use Int 32. All the hardware interrupts are mapped through starting vector 40.bluemoon wrote:For instant, INT 80 is higher half of the IDT
I reserved lower half for hardware-related interrupts.
Programming is not about using a language to solve a problem, it's about using logic to find a solution !
Re: The most complex Hello World I'd ever encountered
I plan to use interrupt 0x69 for this purpose because I like the idea of perverting my code. Does it count ?thepowersgang wrote:Congratulations I remember when I first got my OS running user apps, I felt so happy. I used a similar structure to that too. But I do wonder why everyone uses Int 0x80 for their syscalls, try something different for once. (I use 0xAC because my OS is called "Acess")
- thepowersgang
- Member
- Posts: 734
- Joined: Tue Dec 25, 2007 6:03 am
- Libera.chat IRC: thePowersGang
- Location: Perth, Western Australia
- Contact:
Re: The most complex Hello World I'd ever encountered
Yes, +1 on that
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
-
- Member
- Posts: 595
- Joined: Mon Jul 05, 2010 4:15 pm
Re: The most complex Hello World I'd ever encountered
Congratulations!
Yes, making an full rich OS to the point where you have a hello world application is probably the most complicated hello world you can do.
Yes, making an full rich OS to the point where you have a hello world application is probably the most complicated hello world you can do.
Re: The most complex Hello World I'd ever encountered
It's 2011 and the x86 still doesn't support "int 0xdeadbeef"!Neolander wrote:I plan to use interrupt 0x69 for this purpose because I like the idea of perverting my code. Does it count ?
And congratulations from me too!
Re: The most complex Hello World I'd ever encountered
I decided to change my syscall to int 0bah so to differentiate my product