Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

39KB

Developing Your Own 32-Bit Operating System — Chapter-07: OS Initialization

  • Source: /library/Developing Your Own 32-Bit Operating System/source-file.pdf
  • PDF pages: 121–136
  • Pages without text: 121

OS Initialization

1 100 Part II ■ Architecture and General Theory Initializing an operating system is much more complicated than initializing a single program. In this chapter, we start with loading the operating system, then go through each section of the basic initialization, including hardware, memory, tasks, and important structures. Your operating system's tasking and memory models may differ from MMURTL's, but the basic steps to get your operating system up and running will be very similar. Getting Booted If you have ever done any research on how an operating system is loaded from disk, you know there is no definitive publication you can turn to for all the answers; it's not every day that someone wants to write an operating system, and it's not exacdy easy. The only hardware platform I've researched for the purpose of learning how to boot an oper- ating system is the IBM-PC ISA-compatible system. If you're using another platform, you will have to do some research. I'm going to give you a good idea of what you need to know, which you can apply to most systems in a generic fashion. This information gives you a very good head start on your studies. If you're using a PC ISA-compatible platform, I've done all your homework. Boot ROM When a processor is powered up, it executes from a reset state. Processor designers are very specific about what state they leave the processor in after they accomplish their internal hard- ware reset. You can find this information in the processor hardware manual or in the processor programming manual from the manufacturer. The processor's purpose is to execute instructions. The question is, what instruction does it execute first? The instruction pointer register or instruction counter (whatever they call it for your particular processor) tells the processor which instruction to execute first. (The initial address that is executed is documented in the processor manual.) The operating system writer may not really need to know the processor's initial execution address, because this address is executed by a boot ROM. For this reason, the first executed address usually is somewhere at the high end of physical memory, where boot ROMs usually reside. The boot ROMis read-only memory that contains just enough code to perform a basic system initialization and load (boot) the operating system. When I say “just enough code,” that's ex- actly what I mean. The operating system is located on a disk or other block-oriented device. This device is, no doubt, organized within a file system. Consider that the boot ROM code knows little or nothing about the file system. If this is true, how does it load a file (the operating system)? It generally doesn't — at least not as a file from the file system.

Chapter 7 ■ OS Initialization The Boot Sector The boot ROM code knows only enough to retrieve a sector or two from the disk to some location in RAM, and then execute it. This process amounts to reading a sector into a fixed address in memory, and then jumping to the first address of the sector. In the PC world, this first address is known as the boot sector of the disk. It usually is the first logical sector of the disk. This small amount of boot sector code has to know how to get the operating system loaded and executed. This process can be completed in more than one step if required. In other words, the boot sector code may load another, more complicated, loader program that in turn loads the operating system. This process is known as a multistage boot. To be honest, 512 bytes (a standard hardware sector size on many systems) is not a lot of code. If the operating system you are loading is located in a special place on the disk, such as a fixed track or cylinder, then life is easy. You only need enough hardware and file-system knowledge to read the sectors from disk to the location you want them in RAM. But it gets more compli- cated. When the boot ROM loaded your boot sector, it may have loaded it right where you want to put your operating system. This means that the boot sector code has to relocate itself before it can even load the operating system. This dynamic relocation can eat up more of the precious 512 bytes of code space in the boot sector (unless your boot ROM enables you to load more than one sector, such as a whole track). You should consider these factors when planning how your operating system boots: 1 . Where the boot ROM expects your boot sector or sectors to be on disk. 2. Where this boot sector is loaded and executed. 3. Whether you can leave the boot sector code where the boot ROM loaded it (dynamic relocation may be needed if the boot sector is where your operating system will load). 4. How to find your operating system or first-stage boot program on disk from the boot sector code after it is executed. 5. How the boot sector code will read the operating system or first-stage boot program from disk (the hardware commands or BIOS calls needed to load it into memory, for example). 6. Where your operating system will reside in memory, and whether you have to move it after you load it. 7. Whether there are any additional set-up items to perform before executing the operating system. 8. Where your operating system's first instruction will be, so that you can begin execution. 101

102 [ Part II ■ Architecture and General Theory I don't pretend to know how to boot your system if you're not using the platform I chose. But I'm sure you can gain some insight on what you will have to do if I give a detailed description of what it's like on an IBM PC-AT-compatible system. I will go over each of the eight items on the list to explain how it's handled, and then I'll show you some boot sector code in grueling detail. Explanations of each step follow: 1 . In an ISA system, the boot ROM expects your boot sector at what it considers is logical sector number zero for the first drive it finds it can read. Some systems enable you to change the boot order for drives, but the standard order on ISA systems is drive A, followed by drive C. Keep in mind that the PC ISA systems have a BIOS (Basic Input/Output System) in ROM, and they have some knowledge of the drive geometry from their initialization routines, which they store in a small work area in RAM. 2. A single boot sector (512 bytes) is loaded to address 7C00 hex, which is in the first 64KofRAM. 3. The 7C00 hex address may be fine for your operating system if you intend to load it into high memory. I wanted mine at the very bottom, and it would have overwritten this memory address, so I relocated my boot sector code (I moved it and executed the next instruction at the new address). 4. How you find your operating system on disk depends on the type of file system and where you stored it. If you intend to load from a wide variety of disk types, your OS may not always be in the same place if it's located after variable-sized structures on the first portion of the disk. This was the case with my system, and also with MS-DOS boot schemes. 5. I was lucky with the PC ISA systems, because they provide the BIOS. Each boot sector provides a small table with detailed disk and file system parameters that enable you to update what the BIOS knows about the disk; then you can use the BIOS calls to load the operating system or first-stage boot program. 6. My operating system data and code must start at address 0 (zero), and runs contigu- ously for about 160K. This was a double problem. The boot sector was in the way (at 7C00h), as were the active interrupt vector table and RAM work area for the BIOS. This problem lead to two relocation efforts. First, I moved the boot sector code way up in memory, and then I executed the next instruction at the new address. Second, I read in the operating system above the actively used memory and then relocated it when I didn't need the BIOS anymore. 7. Usually, you should do a few things before you actually execute the operating system. Just what these things are depends on the hardware platform. In my case, I have to turn on a hardware gate to access all the available memory, and I also go into 32-bit protected mode (Intel-specific) before executing the first operating system instruction. 8. I know the address of the first operating system instruction because my design has only two areas (data and code), and the code segment loads at a fixed address. If your

Chapter 7 ■ OS Initialization operating system's first execution address varies each time you build it, you may need to store this offset at a fixed data location and allow your boot sector code to read it so that it knows where to jump. The following code is a boot sector to load an operating system from a floppy on a PC ISA- compatible system. It must be assembled with the Borland assembler (TASM) because the as- sembler I have provided (DASM) doesn't handle 16-bit code or addressing. One thing you will notice right away is that I take over memory like I own it. I stick the stack anywhere I want in the first megabyte of RAM. Why not? I do own it. There's no operating system here now. Examine the following code: .386P ;This boot sector is STUFFed to the gills to do a single ; stage boot of the MMURTL OS which is about 160K stored as ;a loadable image beginning at cluster 2 on the disk. The OS must ;be stored contiguously in each of the following logical sectors. ;The actual number of sectors is stored in the data param nOSSectors. ;The .386P directive is required because I use protected ; instructions. CSEG SEGMENT WORD ‘Code’ USE16 ASSUME CS:CSEG, DS:CSEG, ES: Nothing ORG JMP SHORT Bootup NOP Padding to make it 3 bytes ;This 59-byte structure follows the 3 jump bytes above ;and is found on all MS-DOS FAT -compatible ;disks. This contains additional information about the file system ;on this disk that the operating needs to know. The boot sector code also ; needs some of this information if this is a bootable disk. Herald DB ‘MMURTLvl ' nBytesPerSect DW 0200h jnBytes/Sector ;Sect/Cluster ;Resvd sectors ; nFATs ;Root Dir entries max ;nTotal Sectors (0 = <32Mb) ;media desc. (worthless) ;nSect in FAT ;nSectors/track ;nHeads ;nHidden Sectors (first whole track on HD) ;nTotalSectors if > 32Mb ; Drive boot sector came from ;Used for temp storage of Sector to Read Ext Boot Signature (always 29h) (140 sectors max) Was Volume ID number ;11 bytes for volume name ;8 bytes for FAT name (Type) nSectPerClstr DB 01 h nRsvdSect DW 0001 h nFATS DB 02 nRootDirEnts DW 00E0h nTotalSectors DW 0B40h bMedia DB 0F0h nSectPerFAT DW 0009h nSectPerTrack DW 0012h nHeads DW 0002h nHidden DD 000000 nTotalSect32 DD 000000 bBootDrive DB 00h ResvdByte DB 00h ExtBootSig DB 29h nOSSectors DW 0140h ResvdWord DW 0000h Volname DB ‘RICH FatType DB ‘FAT12

H i q / Part II ■ Architecture and General Theory ;The following are pointers to my IDT and GDT after my OS loads ; and are not part of the above boot sector data structure. IDTptr DW 7FFh ; LIMIT 256 IDT Slots DD 0000h ;BASE (Linear) GDTptr DW 17FFh ; LIMIT 768 slots DD 0800h ;BASE (Linear) ;This is where we jump from those first 3 bytes BootUp: ;This is the Boot block's first instruction from the initial jump ; at the beginning of this code CLI ;Clear interrupts ;Stick the stack at linear 98000h (an arbitrary location) MOV AX, 9000 h MOV SS, AX MOV SP, 8000h ;Move this boot sector UP to 90000h Linear (dynamic relocation) ;Destination segment [Source segment ; Now we “jump” UP to where we moved it. It's pseudo jump ; that I calculated after assembling it once. Push the ; return address, then “return” to it. It works. MOV AX, 09000h ; Segment for new location PUSH AX MOV AX, 6Fh .-Offset to new location (Next PUSH) PUSH AX RETF ; Now set DS equal to ES which is 9000h PUSH ES POP DS ;Now we must update the BIOS drive parameter ; table so it can read the disk for us. ;This is done by finding out where it is and writing ; some of the parameters to it from the boot sector. ;The BIOS left a pointer to it at the 1E hex interrupt ; vector location. MOV CX, nSectPerTrack ;Get this while DS is correct XOR AX, AX MOV DS, AX MOV AX, 0900I MOV ES, AX XOR DI, DI MOV AX, 7C0h MOV DS, AX XOR SI, SI MOV CX, 512 REP MOVSB

Chapter 7 ■ OS Initialization MOV BX, 0078h ;Int 1E FDC Params! LDS SI, DS:[BX] MOV BYTE PTR [SI +4], CL MOV BYTE PTR [SI+9] , 0Fh PUSH ES POP DS PUSH DS STI MOV DL, bBootDrive XOR AX, AX ;Make DS correct again ;Save DS through the reset ;Must set interrupts for BIOS to work ;Required for Disk System Reset INT 13h JC SHORT BadBoot POP DS ;Reset Disk Controller (DL has drive num) ; Reset failed. . . ;The controller is reset. Now let's read some stuff!! ;We are gonna skip checking to see if the first file ; really IS the OS. We need the space for other code. MOV SI, OFFSET MsgLoad CALL PutChars What we do now is calculate our way to the third cluster on the disk and read in the total number of OS sectors in logical sector order. (3rd cluster is really the first allocated cluster because the first 2 are unused) The layout of the Disk is: Hidden Sectors (optional) Boot Sector (at logical sector 0) FATS (1 or more) Additional Reserved sectors (optional) Root Directory (n Sectors long) XOR AX, AX MOV AL, nFATS MUL WORD PTR nSectPerFAT ADD AX, WORD PTR nHidden ; ADC DX, WORD PTR nHidden+2 ADD AX, nRsvdSect MOV CX, AX ;Save in CX ;CX now has a Word that contains the sector of the Root ;Calculate the size of the root directory and skip past it ;to the first allocated sectors (this is where the OS or ; stage 1 of a 2 stage loader should be). MOV AX,0020h ;Size of Dir Entry MUL WORD PTR nRootDirEntS MOV BX, nBytesPerSect DIV BX ADD AX, CX

I
106 Part II ■ Architecture and General Theory ;AX is at sector for cluster 0, but cluster 0 and 1 don't exist ;so we are really at cluster 2 like we want to be. MOV CX, nOSSectors ; Number of OS sectors to read JMP SHORT ContinueBoot ;Bad boot goes here and displays a message then ;waits for a key to reboot (or tries to) via int 19h BadBoot: MOV SI, OFFSET MsgBadDisk CALL PutChars XOR AX, AX INT 16h ;Wait for keystroke INT 19h ;Sys Reboot PutChars LODSB OR AL.AL JZ SHORT Done MOV AH, 0Eh MOV BX,0007 INT 10h JMP SHORT PutChars Done: RETN ContinueBoot: MOV BX, 06000h MOV ES, BX ;This is segment where we load the OS ; before we move it down to 0000h NextSector: PUSH AX PUSH CX PUSH DX PUSH ES ;This is a single sector read loop ; It's slow, but works well. XOR BX, BX ES:BX points to sector read address Read a logical sector to ES:BX AX has Logical Sector Number MOV DIV INC MOV XOR DIV MOV XCHG MOV XCHG SHL OR MOV MOV INT JC SI, nSectPerTrack SI DL ResvdByte, DL DX, DX WORD PTR nHeads DH, bBootDrive DH AX CH ; Divide LogicalSect by nSectPerTrack ;Sector numbering begins at 1 (not 0) ;Sector to read [Logical Track left in AX ; Leaves Head in DL, Cyl in AX Head to DH, Drive to DL Cyl into CX Low 8 bits of Cyl to CH, Hi 2 bits to CL shifted to bits 6 and 7 BYTE PTR ResvdByte ;OR with Sector number 1 ; Number of sectors 2 ;Read ;Tell BIOS to do it! SHORT BadBoot

Chapter 7 H OS Initialization H MOV SI, OFFSET MsgDot CALL PutChars POP ES POP DX POP cx POP AX MOV BX, ES ADD BX, 20h MOV ES, BX INC AX LOOP NextSector I increment ES and leave BX 0 512 bytes for segment BX will be zeroed at top of loop Next Sector ;At this point we have the OS loaded in a contigous section ;from 60000h linear up to about 80000h linear. ;Now we disable interrupts, turn on the A20 line, move ;the OS down to address 0, set protected mode, and JUMP! CLI XOR CX.CX IBEmm0: IN AL,64h TEST AL,02h LOOPNZ IBEmm0 MOV AL,0D1h OUT 64h,AL XOR CX.CX IBEmml : IN AL,64h TEST AL,02h LOOPNZ IBEmml MOV AL,0DFh OUT 60h,AL XOR CX.CX IBEmm2: IN AL,64h TEST AL,02h LOOPNZ IBEmm2 ;A20 line should be ON Now ;So move the OS MOV DX, 8000h ; Move 64K data chunk from linear 60000h to linear 0 MOV BX, 06000h MOV DS, BX XOR SI, SI XOR AX, AX MOV ES.AX XOR DI.DI MOV CX, DX CLD REP MOVSW ;WORD move

I
108 Part II Architecture and General Theory Move first 64K code chunk from linear 70000h to 10000h MOV BX 07000h MOV DS BX XOR SI SI MOV AX 1000h MOV ES AX XOR DI DI MOV CX DX REP MOVSW ; Move last code MOV DS DX XOR SI SI MOV AX 2000h MOV ES AX XOR DI DI MOV CX DX REP MOVSB MOV BX 9000h MOV DS BX ;WORD move (32K) from linear 80000h to 1 ;DX is 8000h anyway ;BYTE move XOR EDX, EDX MOV DL, bBootDrive ;OS can find bootdrive in DL on entry LIDT FWORD PTR IDTptr LGDT FWORD PTR GDTptr iLoad Processor ITD Pointer Load Processor GDT Pointer MOV EAX.CR0 OR AL,1 MOV CR0 , EAX JMP $+5 NOP NOP MOV BX 10h MOV DS BX MOV ES BX MOV FS BX MOV GS BX MOV SS BX ;Control Register ;Set protected mode bit ; Clear CPU prefetch queue with JMP Set up segment registers ;We define a far jump with 48-bit pointer manually ;by defining the bytes that would make the FAR jump ;call JMP FAR 08h:10000h. The segment and code size escape ;bytes (66h and 67h) are required to indicate we are ; referencing a 32-bit segment with a 32-bit instruction. DB 66h DB 67h DB 0EAh DD DW 8h MsgNone DB ' This is actually padding! MsgBadDisk DB 0Dh , 0Ah, ‘Bad Boot Disk!', 00h

Chapter 7 ■ OS Initialization MsgLoad DB 0Dh, 0Ah, ‘Loading MMURTL’, 00h MsgDot DB ' . ' , 00h BootSig DW 0AA5Fh ;MS-DOS used this. I left it in. CSEG ENDS END To assemble and link this into a usable boot sector, use Borland's Turbo Assembler: TASM Bootblok.asm This will make an EXE file exactly 1024 bytes in length. The first 512 bytes are the EXE header. It's worthless. The last 512 bytes are the boot sector binary code and data in a ready-to-use format. As you change and experiment with the boot sector, you need to inspect the actual size of the sector and location of some of the code, such as the dynamic relocation address (if you needed to relocate). To generate a list file from the assembly (Bootblok.lst) and a map file from the link (Bootblok.map), use TASM: TASM Bootblok Bootblok Bootblok You need some additional information in order to experiment with this boot sector if you are on the PC ISA platforms, such as how to write the boot sector to the disk or read a boot sector from the disk and inspect it. Most operating systems provide utilities to make a disk bootable. The systems may do this as they format the disk, or after the fact. Some systems force you to make a decision as to whether the disk will be bootable before you format it if they pre-allocate space on the disk for the operating system. I used the MS-DOS Debug utility to read and write the disk boot sector while experimenting. It's quite easy to do with the Load, Write, and Name commands. To read the boot sector from a disk, find out where Debug's work buffer is by using an Assemble command (just press A while in Debug). This command shows you a segmented address. Press Enter without entering any instructions and use the address shown for the Load command with the drive, logical sector number, and number of sectors following it. The following code loads the boot sector from the disk to address 219F:0000 (or whatever address you were shown): A 219F:0000 -L 21 9F: 0000 0 0 1 Now you can write this sector to another disk as a file with the Name, Register, and Write com- mands: N C:\Bootblok.bin R BX BX:0 R CX CX:200 W 21 9F: 0000 H

110 Part II ■ Architecture and General Theory The boot sector from drive 0 is now in a file named Bootblok.bin in the root directory of drive C. If you want the boot sector from your hard disk, you must use the Load command: -L 219FC0000 2 0 1 The only difference was the drive number that immediately follows the segmented address. Debug refers to the drives numerically from 0 to n. After you assemble your boot sector, you can use Debug to load it as an EXE file and write the single 512 sector directly to the disk. Keep in mind that you should not do this to your active development drive. The results can be disastrous. From the MS-DOS prompt, type Debug, followed by the name of your new executable boot sector. Then write it to the disk. To find where Debug loaded the boot sector, you can use the Dump command to display it: C:>Debug BootBlok.exe -D 219F:0000 EB 3E 90 (etc.) The following code dumps the first 128 bytes and provides the address you need to the Write command: -W 219F:0000 0 0 1 After the boot sector is on the disk, you only need to put the operating system where it expects to find it. The boot sector code expects to find the operating system in a ready-to-run format at the first cluster on the disk and running contiguously in logical sectors until it ends. This is easy to do. Format a disk with MS-DOS 5.0 or higher using the /U (unconditional) option, and without the /s (system) option. Then copy the operating system image to the disk. It will be the first file on the disk and will occupy the correct sectors. After that, you can copy any- thing you want to the disk. The commands follow: C:> Format A: /U C:> Copy OS. IMG A: \ The new boot sector and the operating system are on the disk and ready to go. Good luck. I only had to do it 30 or 40 times to get it right. Hopefully, I've saved you some serious hours of experimentation. If so, I'm happy. Operating System Boot Image Depending on the tools you use to build your operating system, it may not be in a form you can load directly from disk. If your operating system is in an executable format from a linker, there will be a header and possibly fix-up instructions contained in it. You therefore must pro- vide a utility to turn the operating system executable into a directly executable image that can be booted and run by the small amount of code in a boot sector. With MMURTL, I have provided a utility called Makelmg. This reads the MMURTL execut- able and turns it into a single contiguous executable image to be placed on the disk. The data and code are aligned where they would have been had they been loaded with a loader that

Chapter 7 ■ OS Initialization understood my executable format. My Makelmg utility is included on the CD-ROM, and must be built with the Borland C compiler. Instructions are included in the single source file (Makelmg.c) to properly build it. If no address fix-ups are required in your operating system executable, you might be able to avoid a need for a utility like this. I couldn't. Other Boot Options If the operating system you write will be run from another environment, you may face the chore of booting it from another operating system. This is how I run MMURTL most of the time. I have a program (also provided on CD-ROM) that reads, understands, and loads the image into RAM and then executes it. This program is called MMLoader. It has some additional debugging display code that you easily can eliminate if you want. This single source file program (MMLoader.C) also should be built with the Borland C com- piler, because it has imbedded assembly language. This program basically turns MS-DOS into a $79 loader. It does everything that the boot sector code does, along with reading the operat- ing system from its native executable format (a RUN file). $ Basic Hardware Initialization One of the first things the operating system does after it is loaded and the boot code jumps to the first address is to set up a simple environment. This process includes setting up the OS stack. In a segmented processor (such as the Intel series), the boot code already may have set up the segment registers. In a non-segmented processor (such as the 680x0 series) this wouldn't even be necessary. At this point, interrupts usually are disabled because there are no addresses in the interrupt vector table. Your operating system already may have some of the addresses hard-coded in advance, but it is not necessary. Disabling interrupts is one of the chores that my initialization code handles. All the hardware that is resident in the system — such as the programmable interrupt controller unit, the direct memory access hardware, and basic timers — must be initialized before you can set up the rest of the system (the software state). These elements of hardware simply must be initialized to their default states. Chapter 21, “Initialization Code,” contains all the code from MMURTL that is used to set up the operating system from the very first instruction executed, up to the point you jump the monitor program. All this code is contained in the source file Main.asm on the CD-ROM. It should help give you a picture of what's required. Additionally, some of the hardware-related tasks you may have to accomplish are discussed in Chapter 6, “The Hardware Interface.” $

0 Part II ■ Architecture and General Theory Static Tables and Structures How your operating system handles interrupts and memory, and how you designed your basic operating system API and calling conventions determine how many tables and structures you must set up before you can do things like task and memory management. I had to set up the basic interrupt vector table, the array of call gates (how users get to OS calls), and some basic variables. Chapter 21 shows how I go about this. These first tables are all static tables and do not require any memory allocation. You will have to think about which tables are static and which are dynamically allocated, because this determines whether their initialization occurs before or after memory-management initialization. After the basic hardware tables are set up, you may realize that most of this code may never be executed again. This leaves you with a few options — the first of which may be to eliminate the code from the operating system after it is executed so that it doesn't take up memory. Another option is just to forget the code if it doesn't take up too much space. A third option is to make the code reusable by breaking up the code into small segments so that the code can be more generic and used for other things. What you do simply may depend on how much time you want to spend. I just left the code alone. It's not that big. If you want to eliminate the code, you can position it at the end of your code section and simply deallocate the memory for it, or not even initially allocate it with your memory-initialization code. Initialization of Task Management Initialization of task management, setting up for multitasking, is not trivial. The processor you're working with may provide the task management in the form of structures that the processor works with, but you also may be performing your own task management. Either way, you've got your job cut out for you. Chapter 3, “The Tasking Model,” discusses some of your options for a tasking model. In all the cases discussed, you must understand that the code you are executing on startup can be considered your first task. Its job is to set up the hardware and to get things ready to create additional tasks. If you prefer, you can let this first thread of execution just die after you set up a real first task. The option usually is up to you, but also may depend on hardware task management if you use it. With Intel processors, for example, you need to set up a task state segment (TSS) to switch from, as well as one to switch to. Because I used the Intel task- management hardware, I really had no choice. Being a little conservative, I didn't want to waste a perfectly good TSS by just ignoring it. I could have gone back and added code to reuse it, but why not just let it become a real task that can be switched back to? Chapter 21 shows what I have to do using the Intel hardware task management. Additional task-management accomplishments may include setting up linked lists for the execution queue (scheduler) and setting variables to keep track of statistical information.

Chapter 7 ■ OS Initialization s Initialization of Memory During the basic hardware initialization, you may be required to send a few commands to vari- ous pieces of hardware to set up physical addressing the way you need it. This depends on the platform. It may be to turn on or off a range of hardware addresses, or even to set up the physi- cal range of video memory if your system has internal video hardware. One particular item that falls into this category on the PC ISA hardware platform is the A20 address line gate. This is one example to help you understand that there may be intricacies on your platform that will drive you nuts until you find the little piece of obscure documentation that explains it in enough detail to get a handle on it. What is the A20 line gate? It all stems back to IBM's initial PC-AT design. As most of you are aware (if you're programmers), the real mode addresses are 20 bits wide. This is enough to cover a full one megabyte. These address lines are numbered A0 through A19. If you use one more bit, you can address above 1MB. While in real mode, the A20 address line serves no purpose. I suppose that this line even caused some problems because programmers provided a way in hardware to turn it off (always 0). It seems that memory address calculations wrapped around in real mode (from 1MB to 0), and the programmers wanted the same problem to exist in the AT series of processors. I think it's kind of like inheriting baldness from your parents. You learn to live with it. My goal was not to discover why the A20 address line gate existed, but to ensure that it was turned on and left that way. I tried several methods, some of which didn't work on all ma- chines, and ended up sticking with the way it was documented in the original IBM PC-AT documentation. This method seems to work on most machines, although some people still may have problems with the gate. It is controlled through a spare port on the 8042 keyboard controller (actually a dedicated microprocessor). If your machine doesn't support this method, you may have to do some tweaking of the code. Meanwhile, back to the initialization (already in progress). At this stage of the initialization, you have basic tables set up and tasks ready to go, but you aren't cognizant of memory yet. You don't know how much you have, and you cannot manage or allocate it. This is where you call the routine that initializes memory management. This piece of code may have a lot to do. The following list is not all-inclusive, but it gives you a good idea of what you may need to do. Most of the list depends on what memory model you chose for your design. If you went with a simple flat model, you will have a pretty easy job. If you went with a full- blown demand paged system, this could be a fairly large chunk of code. Chapter 19, “Memory Management Code,” shows what I did using the Intel paging hardware. It is explained in a fair amount of detail. You may need to consider the following points: ■ Find out how much physical memory you have. ■ Know where your OS loaded and allocate the memory that it is occupying.

1 1 / Part II ■ Architecture and General Theory ■ Allocate other areas of memory for things such as video or I/O arrays if they are used on your system. ■ Set up the basic linked list structures if you will be using this type of memory manage- ment; otherwise, set up the basic tables that will manage memory. ■ Make a transition to a paged memory environment, if you used paging hardware and your processor doesn't start out that way (Intel processors don't). Something of importance to note about the Intel platform and paged memory-management hardware is that your physical addresses must match your linear addresses when you make the transition into and out of paged memory mode. This is important because it forces you to have a section of code that remains, or is at least loaded, where the address match will occur. I took the easy way out (totally by accident) when I left the entire static portion of my operating sys- tem in the low end of RAM. If you chose not to do this, it may mean forced dynamic reloca- tion of your entire operating system. It's not that much of a headache, but one I'm glad I didn't face. Dynamic Tables and Structures After memory management has been initialized, you can begin to allocate and set up any dy- namic tables and structures required for your operating system. These structures or tables may be allocated linked lists for resources needed for interprocess communications (IPC), memory areas for future tables that cannot be allocated on the fly, or any number of things. The point is, you couldn't allocate memory until memory-management functions were available. After all the dynamic structures are allocated and set up, you're ready to execute a real program (of sorts). This program generally is part of the operating system, and does things like set up the program environments and load device drivers or system services. At this point, you usually load a command-line interpreter, or maybe even load up your windowing environment.

Powered by TurnKey Linux.