Leisner.Henr@xerox.com (Marty) (03/09/89)
I haven't been diligent in responding to people about my protected mode implementation of Minix. I'm going to summarize my development status and give a quick history. I stopped hacking Minix in May when I ordered my Sun386i (I wanted to rehost it onto a 32 bit 80386 system and work with that). My Sun just came in (yesterday). I generally found Minix did not handle the 80286 segmentation in a way where what good features the processor architecture provided could be mapped into minix (i.e. more complicated memory models). I do have a protected mode version of V1.1 running (cross compiled on Aztec C) which: 1) uses hardware task switch (via TSS) [modified proc structure]. 2) each task gets TSS and LDT 3) processes throughout 16 Mbytes address space (the memory manager starts with 2 blocks of memory to fill -- lo and hi) [ no ram disk]. 4) Exception handlers (i.e. illegal opcode trap, protection violations, etc.). This was very handy -- any exceptions in user level code could potentially cause catastrophic failures in non-protected systems. It's interesting how often undebugged code generated protection violations (especially when running with < 64k memory for data). 5) Designed support dynamic growth of stack segment (never implemented). 6) Kernel runs at level 0. MM and FS runs at level 1. User tasks run at level 3. 7) kernel, mm and fs use GDT descriptors. Users tasks work in LDT descriptors. This allows kernel/mm and fs to map in user space into their own address space and do virtual address (currently awkward on Minix without passing around real virtual addresses). 8) Changed memory manager/kernel interface to use call gates instead of system task messages. This system ran reliably but didn't always handle exceptions gracefully. I'm not sure if I still core dump to disk. I also had a math problem I never resolved for segments with a limit of 0xffff [I maxed out my segment size at 0xff00]. Oh well. Some enabling steps to allow the above: 1) had to define macros for the 80286 opcodes in the assembler 2) defined primitive functions to access special 80286 opcodes 3) used 80286 opcode to move interrupt table inside kernel (available real and protected modes) 4) Made kernel relocatable so I could boot off dos disks (it seems it was too hard to make Minix disks from DOS -- hard to format each time). 5) Tried to break out what I wanted to change into separate files. 6) The syslib.c was a single module -- this became a pain to change certain interfaces between mm and kernel one at a time. 7) Got start address off a.out header (default was 0). This allowed me to put the C runtime startup code in the library. 8) Had to convert all the assembler to Aztec format (something like masm?) 9) There is a certain cavalier attitude towards memory (getutil.s went bye-bye). I have system task messages (now callgates) to get the amount of low memory and extended memory from the kernel. 10) all peek/pokes were removed and a read_physical_memory() call was instituted. I suppose the peeks and pokes could be synthesized on the fly, but this seemed cleaner and more generic. I eventually got the specs out for the Western Digital board and pretty much rewrote the winchester driver. I took a good hard look at the specs and the code and rewrote substantial pieces of it. I'm not sure I agree with all the code in the current winchester driver but it works much better then the initial one. I'll have to take a closer look at it. I moved my development platform to Aztec C 3.4x on Ms/Dos (since I used this compiler at work). I still have problems with the Minix C compiler since there is a lot of code I pull off usenet which looked innocent enough wouldn't compile on Minix but it compiled on a large variety of other C compiles. Some changes I made to the kernel (which have nothing to do with protected mode). 1) I didn't like the port_in(int port, char *result). I found the aztec functions inportb/inportw with a syntax which looked like: result = inportb(port) to have much better feel. I still don't see why port_in would not just return a value... 2) I started using disable/restore [Andy also began to use it somewhere along the line with lock/restore]. 3) I added a kernel_movblock(src_offset, src_selector, dst_offset, dst_selector, unsigned size). This replaced the mechanism: srcphys = umap(...) destphys = umap(...) phys_copy(). I really wanted it to work with virtual addresses. I felt the D/S/C segments are a mistake on the Intel architecture and it would be better to use virtual addresses everywhere. 4) I read the time off the battery backed up Cmos clock on bootup (I think this is a must)! 5) I moved some of the assembler code into C ( build_sig. Maybe some other stuff?). 6) I started to support 4 console devices so I could switch windows with alt[hjkl]. This is buggy. Someone else did something like this, but I had protected mode issues to resolve also. 7) I rewrote the winchester driver. My distribution disks wouldn't run on a genuine PC AT (both 6 and 8 meg). I never really agreed with what the winchester driver did (not sure about the newest one). I really don't like the MAX_WIN_RETRY == 10000 -- I'm using 10 with no problem... 8) I never was totally comfortable with the vir_clicks, vir_bytes, phys_clicks, phys_bytes stuff. When I changed some code, I generally trampled these concepts [I tried to work with real virtual addresses, which isn't really support here]. I also found changing the typedefs to what I really wanted to do would cause to much grief since I'm generally an incremental developer and didn't want to audit the entire package for the problems this would entail (this is the same type of problem to add far pointers as addresses in messages. 9) Since my memory management is non-contiguous, I do fork copying a little differently (copy regions, at most 64k at a time, text is shared ). I could also set things up to do copy on write for more complicated memory models very easily. I rewrote substantial pieces of the memory manager. I ended up sharing text on exec, allocating text and data in non-contiguous memory. I added region management (influenced by Bach's book). I changed the click size to 256 bytes (so 16 bits would span 16 megabytes for protected mode) -- this was surprisingly difficult. I also rewrote substantial portions of the code to give it more modularity. I didn't like the way bss got cleared -- there's room for a big gain by doing it in assembler -- I currently clear the entire region -- (using a subroutine called far_memset(far *region, char c, unsigned size)). I think instead of running the ram disk for speed, a bigger buffer cache would be a good idea. A 40k buffer cache doesn't unless you're running trivial programs. This pretty much summarizes what I did. I haven't spent much time on figuring out how to incorporate these modifications into v1.4a. I'm planning on moving distributions of v1.1, 1.4 onto the sun386 and getting a feel for how much I changed (the changes become substantial). If there's interest I could post what I did. This would entail a pretty much intact kernel [minus printer driver (never touched)], parts memory manager and some very minor diffs to the file system. I think the 80286 specific stuff is interesting (don't expect it to run without a lot of work onto the Minix C compiler). I'm going to play with the sun and gnu gcc and see about a 386 protected mode system (which may be much easier). marty ARPA: leisner.henr@xerox.com GV: leisner.henr NS: martin leisner:wbst139:xerox UUCP: hplabs!arisia!leisner
darrylo@hpsrli.HP.COM (Darryl Okahata) (03/11/89)
In comp.os.minix, Leisner.Henr@xerox.com (Marty) writes: > I haven't been diligent in responding to people about my protected mode > implementation of Minix. I'm going to summarize my development status and > give a quick history. Is there any way you could make it available via anonymous ftp? I'd like to get a copy, and I am sure that there are many others. -- Darryl Okahata Internet: darrylo%hpnmd@hpcea.HP.COM