Dlaczego pierwsza instrukcja BIOS znajduje się pod 0xFFFFFFF0 („góra” pamięci RAM)?

51

Wiem, że BIOS ładuje swoją pierwszą instrukcję z 0xFFFFFFF0, ale dlaczego ten konkretny adres? Mam mnóstwo pytań i mam nadzieję, że przynajmniej w niektórych przypadkach możesz mi pomóc.

Moje pytania:

  • Dlaczego pierwsza instrukcja BIOS znajduje się na „górze” 4 GB pamięci RAM?
  • Co by się stało, gdyby mój komputer miał tylko 1 GB pamięci RAM?
  • Co z systemami z więcej niż 4 GB pamięci RAM (na przykład 8 GB, 16 GB itp.)?
  • Dlaczego stos jest inicjowany z pewną wartością (w tym przypadku wartością znajdującą się pod 0xFFFFFFF0)?

Przeczytałem o tym dziś po południu i nadal nie rozumiem.

Fernando Paladini
źródło
28
Poproszę jedno pytanie na pytanie.
Lekkość ściga się z Moniką
4
Podoba mi się, że w przyjętej odpowiedzi w ogóle nie wspomina się o pamięci segmentowej ani trybach adresowania, a jedynym miejscem, w którym dotknięta jest linia A20, są komentarze.
imallett,
AVR Atmel rozpoczyna wykonywanie od adresu 0, podczas gdy Freescale HCS08 zaczyna od 0xFFFE, iirc. Każda rodzina procesorów ma swoje własne cechy.
Nick T
2
@imallett Podoba mi się sposób, w jaki decydujesz się narzekać tutaj, zamiast prosić plakat o zaktualizowanie odpowiedzi o dodatkowe informacje. Podoba mi się również, jak myślisz, że ta wiedza, którą OP byłby w stanie dostrzec, nawet jeśli celem pytania jest zdobycie wiedzy na temat rzeczy, które można teraz w pełni zrozumieć.
MonkeyZeus,
2
@MonkeyZeus do tej pory, 9 innych komentujących już to zrobiło i nadal się nie zmieniło. Mój komentarz, choć sarkastyczny, nie był próżny; jest to ostrzeżenie dla przyszłych internautów, a także dla PO.
imallett,

Odpowiedzi:

57

0xFFFFFFF0to miejsce, w którym procesor zgodny z x86 rozpoczyna wykonywanie instrukcji po włączeniu. Jest to sztywny, niezmienny (bez dodatkowego sprzętu) aspekt procesora, a różne typy procesorów zachowują się inaczej.

Dlaczego pierwsza instrukcja BIOS znajduje się na „górze” 4 GB pamięci RAM?

Znajduje się na „szczycie” 4 GB przestrzeni adresowej - i po włączeniu BIOS lub ROM UEFI ROM jest ustawiony na reagowanie na odczyt tych adresów.

Moja teoria, dlaczego to jest:

Prawie wszystko w programowaniu działa lepiej z sąsiadującymi adresami. Projektant procesora nie wie, co konstruktor systemu będzie chciał zrobić z procesorem, dlatego złym pomysłem jest, aby procesor wymagał różnych adresów na środku przestrzeni do różnych celów. Lepiej trzymać to „na uboczu” na górze lub na dole przestrzeni adresowej. Oczywiście należy pamiętać, że ta decyzja została podjęta, gdy 8086 był nowy, który nie miał MMU .

W 8086 wektory przerwania istniały w miejscu pamięci 0 i powyżej. Wektory przerwań muszą znajdować się pod znanymi adresami i wymagały elastyczności w pamięci RAM - jednak projektant procesora nie mógł wiedzieć, ile pamięci RAM będzie w systemie. Więc zaczynając od 0 i praca nad nimi ma sens (ponieważ żaden system w 1978 roku, kiedy wynaleziono 8086, nie miałby 4 GB pamięci RAM - więc oczekiwanie RAM na 0xFFFFFFF0 nie było dobrym pomysłem), a następnie ROM musiałby być na górnej granicy.

Oczywiście, zaczynając od co najmniej 80286, wektory przerwań można przenieść do innej lokalizacji początkowej innej niż 0, ale współczesne 64-bitowe procesory x86 nadal uruchamiają się w trybie 8086, więc wszystko nadal działa po staremu w celu zachowania zgodności (jest to śmieszne jak się wydaje w 2015 roku, aby nadal potrzebować procesora x86, aby móc uruchomić DOS).

Ponieważ wektory przerwań zaczynają się od 0 i pracują w górę, ROM musiałby zaczynać od góry i pracować w dół.

Co by się stało, gdyby mój komputer miał tylko 1 GB pamięci RAM?

32-bitowy procesor ma 4 294 967 296 adresów, ponumerowanych od 0 (0x00000000) do 4294967295 (0xFFFFFFFF). ROM może żyć pod niektórymi adresami, a RAM może żyć pod innymi. Dzięki MMU procesora można to nawet przełączać na bieżąco. Pamięć RAM nie musi istnieć pod wszystkimi adresami.

Mając tylko 1 GB pamięci RAM, niektóre adresy nie będą reagować, gdy zostaną odczytane lub zapisane. Może to spowodować odczytanie nieprawidłowych danych podczas uzyskiwania dostępu do takich adresów lub blokowania systemu.

Co z systemami z więcej niż 4 GB pamięci RAM (np. 8 GB, 16 GB itp.)?

Upraszczając nieco: 64-bitowe procesory mają więcej adresów (co jest jedną z rzeczy, które sprawiają, że są 64-bitowe - na przykład 0x0000000000000000 do 0xFFFFFFFFFFFFFFFFFF), więc dodatkowa pamięć RAM „pasuje”. Zakładając, że procesor jest w trybie długim . Do tego czasu pamięć RAM jest dostępna, ale nie można jej adresować.

Dlaczego stos jest inicjowany z pewną wartością (w tym przypadku wartością znajdującą się pod 0xFFFFFFF0)?

Nie mogę natychmiast znaleźć niczego na temat tego, co x86 przypisuje wskaźnik stosu przy włączaniu, ale w końcu musiałoby to zostać ponownie przypisane przez procedurę inicjalizacji, gdy tylko dowie się, ile pamięci RAM jest w systemie. (@Eric Towers w komentarzach poniżej informuje, że jest ustawiony na zero po włączeniu).

LawrenceC
źródło
7
Najlepiej jest myśleć o przestrzeni adresowej jako dużej przestrzeni, w której sprzęt może być przypisany. Gdy procesor odczytuje / zapisuje pamięć, faktycznie komunikuje się przez magistralę, a sprzęt może upewnić się, że pamięć RAM lub ROM reaguje na określone zakresy adresów. Taki sprzęt musiałby więc upewnić się, że ROM reaguje na 0xFFFFFFF0 po zresetowaniu procesora. Nie ma nieodłącznego obowiązku, aby pamięć ROM pojawiała się zaraz po pamięci RAM. Może pojawić się wszędzie tam, gdzie mówi to sprzęt, w zależności od możliwości takiego sprzętu.
LawrenceC
4
Możliwe są „dziury” lub nieprzypisane spacje, które nie są używane przez ROM, RAM itp. - zazwyczaj dostęp do nich spowoduje zablokowanie systemu.
LawrenceC
16
Ta odpowiedź zakłada, że ​​procesor może używać 32 bitów adresu w trybie 16-bitowym. Ale w trybie 16-bitowym może używać tylko 20 bitów adresu. Adres 0xFFFFFFF0jest nieosiągalny, dopóki CPU nie zostanie przełączony w tryb 32-bitowy. Ostatnim razem, gdy przyjrzałem się kodowi BIOS, punkt wejścia był 0xFFFF0.
kasperd
6
@ MichaelKjörling Twoje obliczenia są nieprawidłowe. Przesunięty segment i przesunięcie nie są ORed, są dodawane. Zatem logiczny FFFF: FFF0 jest fizyczny (1) 0FFE0 (gdzie wiodący 1 jest obecny, jeśli A20 jest włączony).
Ruslan
9
@kasperd Jest hack - menedżer pamięci ustawia wysokie 12 bitów na 1, aż do pierwszego skoku w dal. Tak więc, logicznie, pracujesz 0xFFFF0, ale w rzeczywistości jest to odwzorowane 0xFFFFFFF0. Spodziewam się, że zostało to zrobione w celu zapewnienia zgodności z 8086 - wydaje się, że zarówno on, jak i bardziej nowoczesne procesory wydają się używać 0xFFFF0, ale 32-bitowe procesory faktycznie uzyskują dostęp 0xFFFFFFF0(mapowane na BIOS ROM).
Luaan,
26

Nie znajduje się na górze pamięci RAM; znajduje się w pamięci ROM, której adres znajduje się na górze przestrzeni adresowej pamięci, wraz z dowolną pamięcią na kartach rozszerzeń, takich jak kontrolery Ethernet. Jest tak, aby nie powodował konfliktu z pamięcią RAM, przynajmniej do momentu zainstalowania 4 GB. Systemy, które mają 4 GB lub więcej pamięci RAM, mogą zrobić dwie rzeczy, aby rozwiązać konflikt. Tanie płyty główne po prostu ignorują te części pamięci RAM, które są w konflikcie z miejscem, w którym znajduje się ROM. Przyzwoici mapują tę pamięć RAM, aby miała adres powyżej znaku 4 GB.

Nie jestem pewien, o co pytasz o stos. Z pewnością nie jest inicjowany w ROM. Kiedy procesor resetuje się, początkowo znajduje się w „trybie rzeczywistym”, w którym działa tak jak oryginalny 8086 i wykorzystuje 16-bitowe segmentowane adresowanie, pozwalając mu na dostęp tylko 1 MB pamięci. Kod BIOS znajduje się na górze tego 1 MB. BIOS wybiera gdzieś w pamięci RAM, aby ustawić stos, ładuje i wykonuje pierwszy sektor pierwszego dysku rozruchowego. Od systemu operacyjnego zależy przejście do trybu 32- lub 64-bitowego po przejęciu i skonfigurowaniu własnych stosów (po jednym na zadanie / wątek).

psusi
źródło
1
Bardzo dziękuję za odpowiedź, ale @LawrenceC podał więcej szczegółów na temat swojej odpowiedzi i pomógł mi, jak to wszystko działa. Mimo wszystko dziękuję! Daję ci głos: 3
Fernando Paladini
13

Po pierwsze, to naprawdę nie ma nic wspólnego z pamięcią RAM. Mówimy tutaj o przestrzeni adresowej - nawet jeśli masz tylko 16 MiB pamięci, nadal masz pełne 32 bity przestrzeni adresowej na 32-bitowym procesorze.

Odpowiada to już na twoje pierwsze pytanie, naprawdę - w czasie, gdy było to zaprojektowane, rzeczywiste komputery nie miały prawie 4 GB pamięci; były bardziej w zakresie 1-16 MiB pamięci. Przestrzeń adresowa była pod każdym względem wolna.

Dlaczego właśnie 0xFFFFFFF0? Procesor nie wie, ile jest BIOS-u. Niektóre BIOSy mogą zająć tylko kilka kilobajtów, podczas gdy inne mogą zajmować pełne megabajty pamięci - a ja nawet nie wchodzę w różne opcjonalne pamięci RAM. Procesor musi być podłączony do jakiegoś adresu, aby rozpocząć - nie ma potrzeby konfigurowania procesora. Ale to tylko mapowanie przestrzeni adresowej - adres jest mapowany bezpośrednio do układu BIOS ROM (tak, oznacza to, że nie masz dostępu do pełnych 4 GiB pamięci RAM w tym momencie, jeśli masz ich tyle - ale to nie jest nic specjalnego, wiele urządzeń wymaga własnego zasięgu w przestrzeni adresowej). W 32-bitowym CPU ten adres daje pełne 16 bajtów na bardzo podstawową inicjalizację - co wystarcza, aby skonfigurować segmenty i, w razie potrzeby, tryb adresu (pamiętaj,prawdziwy boot „procedura”. W tym momencie w ogóle nie używasz pamięci RAM - to tylko zmapowana pamięć ROM. W rzeczywistości pamięć RAM nie jest jeszcze gotowa do użycia w tym momencie - to jedno z zadań BIOS POST! Być może zastanawiasz się - w jaki sposób 16-bitowy tryb rzeczywisty uzyskuje dostęp do adresu 0xFFFFFFF0? Jasne, istnieją segmenty, więc masz 20-bitową przestrzeń adresową, ale to wciąż nie wystarczy. Cóż, jest w tym pewien sposób - 12 wysokich bitów adresu jest ustawianych, aż wykonasz swój pierwszy skok w dal, dając ci dostęp do wysokiej przestrzeni adresowej (jednocześnie odrzucając dostęp do czegoś niższego niż 0xFFF00000 - aż do wykonania skoku w dal) .

Wszystko to są w większości ukryte przed programistami (nie wspominając o użytkownikach) w nowoczesnych systemach operacyjnych. Zwykle nie masz dostępu do niczego tak niskiego poziomu - niektóre rzeczy są już poza odzyskiem (nie możesz przełączać trybów procesora nie chcąc nie chcąc), niektóre są obsługiwane wyłącznie przez jądro systemu operacyjnego.

Więc ładniejszy widok pochodzi z oldschoolowego kodowania w MS DOS. Innym typowym przykładem bezpośredniego mapowania pamięci urządzenia na przestrzeń adresową jest bezpośredni dostęp do pamięci wideo. Na przykład, jeśli chcesz szybko napisać tekst na wyświetlaczu, piszesz bezpośrednio na adres B800:0000(plus offset - w trybie tekstowym 80x25, oznacza to, że (y * 80 + x) * 2jeśli moja pamięć służy mi poprawnie - dwa bajty na znak, wiersz po wierszu). Jeśli chcesz rysować piksel po pikselu, użyłeś trybu graficznego i adresu początkowego A000:0000(zwykle 320 x 200 przy 8 bitach na piksel). Robienie czegokolwiek o wysokiej wydajności zwykle oznaczało zanurzenie się w instrukcjach obsługi urządzeń, aby dowiedzieć się, jak uzyskać do nich bezpośredni dostęp.

To przetrwa do dziś - jest po prostu ukryte. W systemie Windows możesz zobaczyć adresy pamięci mapowane na urządzenia w Menedżerze urządzeń - po prostu otwórz właściwości czegoś takiego jak karta sieciowa, przejdź do karty Zasoby - wszystkie elementy zakresu pamięci są mapowaniami z pamięci urządzenia do głównej przestrzeni adresowej. W wersji 32-bitowej zobaczysz, że większość tych urządzeń jest odwzorowana powyżej znaku 2 GiB (później 3 GiB) - ponownie, aby zminimalizować konflikty z pamięcią użyteczną dla użytkownika, chociaż tak naprawdę nie jest to problem z pamięcią wirtualną ( aplikacje nie znajdują się w pobliżu rzeczywistej, sprzętowej przestrzeni adresowej - mają własną zwirtualizowaną pamięć, która może być na przykład zmapowana na RAM, ROM, urządzenia lub plik stronicowania).

Jeśli chodzi o stos, to powinno pomóc zrozumieć, że domyślnie stos rośnie od góry. Więc jeśli to zrobisz push, nowy wskaźnik stosu będzie na 0xFFFFFEC- innymi słowy, nie będziesz próbował pisać na adres inicjujący BIOS :) Co oczywiście oznacza, że ​​procedury inicjujące BIOS mogą bezpiecznie używać stosu przed jego odwzorowaniem gdzieś bardziej przydatny. W oldschoolowym programowaniu, zanim stronicowanie stało się de facto domyślnym, stos zwykle zaczynał się na końcu pamięci RAM, a „przepełnienie stosu” miało miejsce, gdy zacząłeś nadpisywać pamięć aplikacji. Ochrona pamięci bardzo to zmieniła, ale ogólnie zachowuje jak największą zgodność wsteczną - zwróć uwagę, że nawet najnowocześniejszy procesor x86-64 może nadal uruchomić MS DOS 5 - lub jak Windows może nadal uruchamiać wiele aplikacji DOS, które nie mają pojęcia o stronicowaniu.

Luaan
źródło
3
Doskonała odpowiedź, wystarczy rozwinąć i powiedzieć, że nowoczesne procesory zaczynają upuszczać hacki, takie jak maskowanie linii A20 , więc umiera obsługa starszych skrzynek.
Podstawowy
2
Do ostatniego akapitu: BIOS nie może używać stosu „swobodnie”: nie może zapisywać na ROM (do którego 0xFFFFFFECzostanie zamapowany). Oznacza to nie tylko nie, pushale na przykład nie call. Muszą poczekać, aż pamięć RAM będzie gotowa.
The Vee
7

Oprócz innych wymienionych punktów, może być pomocne w zrozumieniu tego, co adres jest . Podczas gdy nowsze architektury komplikują rzeczy, historycznie maszyna w każdym cyklu pamięci generowałaby pożądany adres na 20 do 32 przewodach (w zależności od architektury, z pewnymi specjalnymi sztuczkami, aby zauważyć, czy potrzebuje pary lub czterech bajtów jednocześnie); różne części systemu pamięci sprawdzałyby stan tych drutów i same się aktywowały, gdy zobaczyły określone kombinacje wysokich i niskich wartości.

Jeśli maszyna z 32 przewodami adresowymi potrzebowała tylko 1 MB pamięci RAM i 64 KB pamięci ROM (całkiem możliwe w przypadku niektórych wbudowanych kontrolerów), może aktywować pamięć RAM dla wszystkich adresów, w których górny drut adresowy był niski, i ROM dla wszystkich adresów, w których był wysoki. Dolne 20 przewodów adresowych zostanie następnie przywiązanych do pamięci RAM, aby wybrać jeden z 1 048 576 bajtów, a dolne 16 również zostanie podłączone do pamięci ROM, aby wybrać jeden z 65 536 bajtów. Pozostałe 11 przewodów adresowych po prostu nie byłoby do niczego podłączonych.

Na takim komputerze dostęp do adresów 0x00100000-0x001FFFFF byłby równoważny dostępowi do adresów RAM 0x00000000-0x000FFFFF. Podobnie z adresami 0x000200000-0x0002FFFFF lub 0x7FF00000-0x7FFFFFFFF. Adresy powyżej 0x80000000 wszystkie czytałyby ROM, a wzorzec 64K powtarzałby się w całej przestrzeni.

Mimo że procesor ma 4 294 967 296 bajtów przestrzeni adresowej, sprzęt nie musi rozpoznawać tak wielu różnych adresów. Umieszczenie wektora resetowania w górnej części przestrzeni adresowej to projekt, który będzie działał dobrze bez względu na to, ile pamięci RAM i ROM ma system, i pozwala uniknąć konieczności pełnego dekodowania przestrzeni adresowej.

supercat
źródło
Dobra uwaga - nie znajdziesz żadnego 64-bitowego sprzętu, który obsługiwałby cokolwiek zbliżonego do adresowalnej 64-bitowej przestrzeni pamięci (lub nawet 1x10 ^ -12).
Podstawowy
3

Moja teoria polega na tym, że używamy logiki ujemnej, cyfrowa (1) w ogóle nie ma napięcia (O wolty) Musimy tylko naciągnąć ostatnie 4 bity przy inicjalizacji, więc licznik programu (lub wskaźnik instrukcji) jest na 1111 1111 1111 1111 1111 1111 1111 0000. Nie musimy adresować górnych 28 bitów, ponieważ większość (starych) procesorów ma 16 bitów, a dolne skubania mogą być adresowane za pomocą jednego układu adresu w dawnych czasach. Teraz, ponieważ mamy 64 bity z kompatybilnością z 32 bitami i od 32 bitów do 16 bitów, poprawka sprzętowa została ulepszona, ale metoda pozostaje. Również biozy nie zawsze są zaprogramowane na 64 bity lub 32 bity. Uważam też, że wspomnienia nie zawsze są takie same, biografie muszą znajdować się w tym samym pierwszym segmencie. To, w jaki sposób widzimy adresowane bios, nie jest przez cały czas prawdziwym adresem. Tylko mnie nauczył ...

Agguro
źródło
2

po RESETIE procesor zgodny z 8088/8086 wykonuje instrukcje przy 0FFFF0, czyli 16 bajtów poniżej limitu 1 megabajta. normalnie ROM w tym miejscu (w implementacjach na PC) byłby BIOSem, więc pod koniec ROM BIOS-u następuje skok do początku ROM BIOS-u.

pokazano tutaj: wektor startowy i podpis „data” za nim, IBM 5150 PC 8KB eprom zrzut bios data: 19.10.1981

00001FEE  FF                db 0xff
00001FEF  FF                db 0xff
00001FF0  EA5BE000F0        jmp word 0xf000:0xe05b
00001FF5  3130              xor [bx+si],si
00001FF7  2F                das
00001FF8  3139              xor [bx+di],di

zwróć uwagę, że adresowanie to ROM o wartości 8 KB 2000 USD, który umieszcza adres początkowy (absolutnie daleko JMP, w dowolnym innym miejscu, w tym przypadku w samym ROMie 8 KB, chociaż nie jest to najniższy możliwy adres w tym ROMie) na $ FFFF: Segment 0 $ lub liniowy $ FFFF0.

co do kompatybilności: jeśli jakiś „przyszły” lub obecny procesor „spodziewa się”, że będzie miał o wiele więcej liter F przed adresem, to nie ma znaczenia. w celu zapewnienia zgodności nowszego procesora w starszych systemach dodatkowe linie adresowe pozostają niepołączone, dlatego dane na magistrali danych są dokładnie takie same. tak długo, jak najmniej znaczące bity pozostają FFFF0.

(w systemie z zaledwie 1 MB pamięci RAM i romem umieszczonym na końcu tego pamięci RAM i niczym innym, z radością „pomyśli”, że rozmawia z wyższym adresem, ale otrzymuje dokładnie te same dane, ponieważ te implementacje nigdy nie słyszały o linie adresowe wyższe niż A19)

zwróć uwagę, że świat to nie tylko „komputery”… IBM PC był „wypadkiem”, procesory te nigdy nie zostały zaprojektowane specjalnie dla „komputerów” i obejmują znacznie więcej rzeczy niż tylko komputery (takie jak satelity, systemy broni itp.). Tryby chronione w wersji 32- i 64-bitowej są zwykle niepożądane. (tryb wirtualny 8086 jest o wiele bardziej interesujący jako powód, dla którego wybierz na przykład nowszą (386+) wersję). dlatego „kompatybilność wsteczna” to coś więcej niż tylko „uruchomi dos”.

HRH Sven Olaf von CyberBunker
źródło
1

Płyta główna zapewnia, że ​​instrukcja w wektorze resetowania jest skokiem do lokalizacji pamięci zmapowanej do punktu wejścia systemu BIOS. Ten skok domyślnie usuwa ukryty adres bazowy obecny przy włączaniu. Wszystkie te lokalizacje pamięci mają odpowiednią zawartość potrzebną procesorowi dzięki mapie pamięci przechowywanej przez mikroukład. Wszystkie są mapowane do pamięci flash zawierającej BIOS, ponieważ w tym momencie moduły RAM mają w sobie losowe badziewie.

Viktorkh
źródło