⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os-faq-memory.html

📁 教导你怎么样写你自己的操作系统,并且列出来其它操作系统作为举例.
💻 HTML
字号:
<html><head>	<title>Operating Systems FAQ :: Memory</title>	<link rel=stylesheet type="text/css" href="default.css"></head><body><TABLE border="0" width="100%">	<TR>		<TD><H2><A name="what_is_a20">What is the A20 line?</A></H2>		</TD>	</TR>	<TR>		<TD>The A20 line takes a bit of explaining so hang with        me please.<P>When the AT was introduced, it was able to        access up to sixteen megabytes of memory, but in order to        remain compatible with the IBM-XT, due to a quirk in the        XT architecture (memory wraparound) had to be duplicated        in the AT so things would work the same, the 20th address        line on the bus (A20) was turned off so this        &quot;wrap-around&quot; effect worked and software from        the old XT days continued to work (compatibility was a        *B*I*G* issue back then).</P><P>The A20 line is controlled by the keyboard controller        unit. Which is usually a derivative of the 8042 chip.</P>		</TD>	</TR></TABLE><P>&nbsp;</P><TABLE border="0" width="100%">	<TR>		<TD><H2><A name="access_my_memory">Why can't I access all my memory! I have 128mb and can only use 1mb?</A></H2>		</TD>	</TR>	<TR>		<TD>The main reason you can't access all your memory (or        only &quot;odd&quot; megabytes) is because you need to        enable the A20 line on your bus. (For an explanation of        the A20 line, see <A href="#what_is_a20">What is the A20        line?</A>		</TD>	</TR></TABLE><P>&nbsp;</P><TABLE border="0" width="100%">	<TR>		<TD><H2><A name="enable_a20">How do I enable the A20 line?</A></H2>		</TD>	</TR>	<TR>		<TD>To enable the A20 line, you have to use some hardware        IO using the Keyboard Controller chip (8042 chip) and        enable it. Good documentation exists for the 8042 chip        but here is my source for enabling the A20 in C code.<P>The        flow chart for this is;</P>			<OL>				<LI>Disable interrupts				<LI>Wait until the keyboard buffer is empty				<LI>Send command to disable the keyboard				<LI>Wait until the keyboard buffer is empty				<LI>Send command to read output port				<LI>Wait until the keyboard buffer is empty				<LI>Save byte from input port				<LI>Wait until the keyboard buffer is empty				<LI>Send command Write output port				<LI>Wait until the keyboard buffer is empty				<LI>Send saved byte OR by 2 (GATE A20 to                 ON)				<LI>Wait until the keyboard buffer is empty				<LI>Enable the keyboard				<LI>Enable interrupts</LI>			</OL><P>Here is my C source;</P>		<PRE>/* Init the A20 by Dark Fiber */void init_A20(void){	UCHAR	a;	disable_ints();	kyb_wait_until_done();	kyb_send_command(0xAD);		// disable keyboard	kyb_wait_until_done();	kyb_send_command(0xD0);		// Read from input	kyb_wait_until_done();	a=kyb_get_data();	kyb_wait_until_done();	kyb_send_command(0xD1);		// Write to output	kyb_wait_until_done();	kyb_send_data(a|2);	kyb_wait_until_done();	kyb_send_command(0xAE);		// enable keyboard	enable_ints();}        </PRE>		<p>Or in ASM if you wish		<pre>;;;; NASM 32bit assembler;;[bits 32][section .text]enable_A20:	cli	call    a20wait	mov     al,0xAD	out     0x64,al	call    a20wait	mov     al,0xD0	out     0x64,al	call    a20wait2	in      al,0x60	push    eax	call    a20wait	mov     al,0xD1	out     0x64,al	call    a20wait	pop     eax	or      al,2	out     0x60,al        call    a20wait	mov     al,0xAE	out     0x64,al	call    a20wait	reta20wait:.l0:	mov     ecx,65536.l1:	in      al,0x64	test    al,2	jz      .l2	loop    .l1	jmp     .l0.l2:	reta20wait2:.l0:	mov     ecx,65536.l1:	in      al,0x64	test    al,1	jnz     .l2        loop    .l1	jmp     .l0.l2:	ret		</pre>		</TD>	</TR></TABLE><P>&nbsp;</P><TABLE border="0" width="100%">	<TR>		<TD><H2><A name="determine_memory">How do I determine RAM size?</A></H2>		</TD>	</TR>	<TR>		<TD>Determining how much memory you have is one of the        first things that most people implement in their kernel.        In the &quot;old&quot; days of operating systems this was        very easy as few people had more than 64mb of memory.<P>Why        did I mention 64mb of memory? Because that's all the CMOS        can hold up to 99mb values. When you encounter machines        with 128mb what are you going to do? There are some        functions in the BIOS for memory handling. The first set        of calls supported by all BIOS only returns what is in        the CMOS, thus making it irrelevant. There is some more        advanced calls but are not guaranteed to be in every BIOS        you encounter, and since not every machine supports it,        means its also not what we want. Two other methods people        use are directly probing memory, and using your        motherboard chipset registers to determine memory. The        only drawback with the later methos is you must know what        kind of chipset the user has on his motherboard....</P><P>I prefer to directly probe memory at every 1mb        interval and test for memory that way.</P><P>Something to note, not that you may need to know, is        that on old machines (maybe even new ones), it is        possible to have less than 640kb base memory and still        have extended memory beyond the 1mb mark. But in today's        machines where most people have single 64mb DIMM's, you        wont come across this.</P>		</TD>	</TR></TABLE><P>&nbsp;</P><TABLE border="0" width="100%">	<TR>		<TD><H2><A name="determine_memory_bios">How do I determine RAM size with BIOS?</A></H2>		</TD>	</TR>	<TR>		<TD>You can determine RAM size with the BIOS via two	        different calls.<P>The first call is built in nearly        every BIOS, the later call is only contained within newer        BIOS's</P>		<PRE>(from Ralf Brown's Interrupt Listing)--------B-1588-------------------------------INT 15 - SYSTEM - GET EXTENDED MEMORY SIZE (286+)  AH = 88h  Return: CF clear if successful    AX = number of contiguous KB starting at absolute address 100000h    CF set on error  AH = status    80h invalid command (PC,PCjr)    86h unsupported function (XT,PS30)        </PRE><P>Notes: TSRs which wish to allocate extended memory to        themselves often hook this call, and return a reduced        memory size. They are then free to use the memory between        the new and old sizes at will.</P><P>the standard BIOS only returns memory between 1MB and        16MB; use AH=C7h for memory beyond 16MB not all BIOSes        correctly return the carry flag, making this call        unreliable unless one first checks whether it is        supported through a mechanism other than calling the        function and testing        CF</P><P>SeeAlso:AH=87h,AH=8Ah&quot;Phoenix&quot;,AH=C7h,AX=DA88h,AX=E801h,AX=E820h</P>		<PRE>--------b-15E820-----------------------------INT 15 - newer BIOSes - GET SYSTEM MEMORY MAP  AX = E820h  EAX = 0000E820h  EDX = 534D4150h ('SMAP')  EBX = continuation value or 00000000h to start at beginning of map  ECX = size of buffer for result, in bytes (should be &gt;= 20 bytes)  ES:DI -&gt; buffer for result (see #00560)  Return: CF clear if successful    EAX = 534D4150h ('SMAP')    ES:DI buffer filled    EBX = next offset from which to copy or 00000000h if all done    ECX = actual length returned in bytes    CF set on error      AH = error code (86h) (see #00475 at INT 15/AH=80h)			</PRE><P>Notes: originally introduced with the Phoenix BIOS        v4.0, this function is now supported by most newer        BIOSes, since various versions of Windows call it to find        out about the system memory a maximum of 20 bytes will be        transferred at one time, even if ECX is higher; some        BIOSes (e.g. Award Modular BIOS v4.50PG) ignore the value        of ECX on entry, and always copy 20 bytes some BIOSes        expect the high word of EAX to be clear on entry, I.e.        EAX=0000E820h</P><P>if this function is not supported, an application        should fall back to AX=E802h, AX=E801h, and then AH=                         88h the BIOS is permitted to return a nonzero continuation value        in EBX and indicate that the end of the list has        already been reached by returning with CF set        on the next iteration this function will return        base memory and ISA/PCI memory contiguous with        base memory as normal memory ranges; it will indicate        chipset-defined address holes which are not in use and        motherboard memory-mapped devices, and all occurrences of the system             BIOSasreserved;standardPCaddressrangeswillnotbereported</P><P>SeeAlso:AH=C7h,AX=E801h&quot;Phoenix&quot;,AX=E881h,MEM             xxxxh:xxx0h&quot;ACPI&quot;</P>		<PRE>Format of Phoenix BIOS system memory map address range descriptor:Offset	Size	Description	(Table 00559) 00h	QWORD	base address 08h	QWORD	length in bytes 10h	DWORD	type of address range (see #00560)(Table 00560)Values for System Memory Map address type:  01h	memory, available to OS  02h	reserved, not available (e.g. system ROM, memory-mapped device)  03h	ACPI Reclaim Memory (useable by OS after reading ACPI tables)  04h	ACPI NVS Memory (OS is required to save this memory between NVS       	  sessions) other	not defined yet -- treat as Reserved SeeAlso: #00559        </PRE>		</TD>	</TR></TABLE><P>&nbsp;</P><TABLE border="0" width="100%">	<TR>		<TD><H2><A name="determine_memory_probe">How do I determine RAM size with direct probing?</A></H2>		</TD>	</TR>	<TR>		<TD>Directly probing memory, being a method that does not        rely on the BIOS makes it more portable than one that        does rely on the BIOS. Depending on how its coded, may or        may not take into account holes in system memory (15/16mb        mark ala OS/2) or memory mapped devices like frame        buffering SVGA cards, etc. 				<PRE>		/* * void count_memory (void) * * probes memory above 1mb * * last mod : 05sep98 - stuart george *            08dec98 - &quot;&quot;     &quot;&quot; *            21feb99 - removed dummy calls * */void count_memory(void){	register ULONG *mem;	ULONG	mem_count, a;	USHORT	memkb;	UCHAR	irq1, irq2;	ULONG	cr0;	/* save IRQ's */	irq1=inb(0x21);	irq2=inb(0xA1);	/* kill all irq's */	outb(0x21, 0xFF);	outb(0xA1, 0xFF);	mem_count=0;	memkb=0;	// store a copy of CR0	__asm__ __volatile(&quot;movl %%cr0, %%eax&quot;:&quot;=a&quot;(cr0))::&quot;eax&quot;);	// invalidate the cache	// write-back and invalidate the cache	__asm__ __volatile__ (&quot;wbinvd&quot;);	// plug cr0 with just PE/CD/NW	// cache disable(486+), no-writeback(486+), 32bit mode(386+)	__asm__ __volatile__(&quot;movl %%eax, %%cr0&quot;, :: &quot;a&quot; (cr0 | 0x00000001 | 0x40000000 | 0x20000000) : &quot;eax&quot;);	do	{		memkb++;		mem_count+=1024*1024;		mem=(ULONG*)mem_count;		a=*mem;		*mem=0x55AA55AA;				// the empty asm calls tell gcc not to rely on whats in its registers		// as saved variables (this gets us around GCC optimisations)		asm(&quot;&quot;:::&quot;memory&quot;);		if(*mem!=0x55AA55AA)			mem_count=0;		else		{			*mem=0xAA55AA55;			asm(&quot;&quot;:::&quot;memory&quot;);			if(*mem!=0xAA55AA55)				mem_count=0;		}		asm(&quot;&quot;:::&quot;memory&quot;);		*mem=a;	}while(memkb&lt;4096 &amp;&amp; mem_count!=0);	__asm__ __volatile__(&quot;movl %%eax, %%cr0&quot;, :: &quot;a&quot; (cr0) : &quot;eax&quot;);	mem_end=memkb&lt;&lt;20;	mem=(ULONG*)0x413;	bse_end=((*mem)&amp;0xFFFF)&lt;&lt;6;	outb(0x21, irq1);	outb(0xA1, irq2);}		</PRE>		</TD>	</TR></TABLE></body></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -