28

I've always wondered how so much functionality and relative luxuries(CMOS Configuration Utilities. See: https://geekprank.com/bios/ for an example) included with most popular x86 BIOSes could be packed into such a tight space. According to Wikipedia some early(1971-199x; the EPROM reference table doesn't have a lot of dates.) EPROMs where quite small in size. I had a hard time finding a good average size in bytes for an x86 CMOS BIOS EPROM chip from the late 80s early 90s but I'm assuming they weren't measured in MBs but in KBs. This Quora post seems to confirm this.

The author writes: "The Phoenix BIOSes I wrote in 1984-1985 never supported the ROM Basic. The PC was 8k and filled completely. The XT was put into a 16k, but was probably about 10k of code. The AT was probably about 16k for the BIOS and maybe another 8k for the setup, and was normally placed in a 32k ROM."

32kbs by today's standards is quite a small amount of storage space. I suppose for a BIOS most of what you're doing doesn't need immense layers of abstraction and other storage complications, but I'd think that programming those CMOS Configuration Utility TUIs would be expensive space wasters. Not to mention BIOSes somewhere along the way they began to be written in C/C++ which probably wastes some space surely. Did these early programmers just use a library similar to ncurses but for BIOS programming? How were these text interfaces engineered? As most UI libs' raw logic(aside from platform specific stuff like windows and rendering), even super simple ones(Buttons, Labels, ect. Bare minimum common widgets.) usually require a decent amount of abstraction/complexity which seems sort of hard in a language like ASM less so if ASM is only used to load the bare minimum before switching to C/C++(which seems to be how it's done today). Am I overthinking this? Was it easier than I'm imagining?

migrated from softwareengineering.stackexchange.com May 26 at 1:27

This question came from our site for professionals, academics, and students working within the systems development life cycle.

  • 36
    The multiuser operating system kernels I used at the time would fit in 32KB, so my question would be "how can they use that much space for just a simple BIOS?" ;-) – another-dave May 26 at 2:11
  • 11
    It may help to remember that the original spreadsheet, VisiCalc, ran fine on systems with 32 KB of RAM holding all code and data. Other "full-screen" applications such as word processors and visual editors ran in even less. – Curt J. Sampson May 26 at 16:26
  • 1
    Cheating slightly, I'm fairly sure that UPX compressed (i.e. with transparent runtime extraction) output from Turbo Pascal was just 4kb for a simple 3d game I wrote way back in the '90s. Which was a very high-level language by the standards of 1981. So it was probably only about 8kb in the first place. – Tommy May 27 at 15:02
  • 4
    The C64 fit an entire BASIC interpreter, as well as MMIO, into a mere 26kB. Check out demoscene stuff - entire 3D engines and procedural texture algorithms crammed into as little as 4kB or 8kB. – J... May 27 at 19:17
  • definitely check out demoscene, amazing 3d visual & audio in 64kb, even by today's standards nevermind when it first came out. My first and fave is pouet.net/prod.php?which=1221 "fr08: the.product" from 2000 – RozzA May 27 at 22:41
34

The architecture of the original IBM PC (and its clones) let the BIOS access the video memory directly.

So making nice text layouts did not require positioning the cursor or making a sequence of calls like you would do with curses: It was sufficient to set the text mode at startup and write at the right place in memory the character (1 byte) and its attributes (1 byte).

For this it was sufficient to do some address calculation and a move instruction. All very easy in assembler with a minimum of instructions.

Nowadays, the video BIOS manages the compatibility with the BIOS and the video card, since these became much more complex.

  • 2
    I didn't even think of video memory or the Video BIOS. Thanks a lot for the helpful and interesting resources! Quite fascinating! – video_error May 25 at 22:45
  • 2
    ssokow's answer described how you can draw a typical BIOS setup screen much more efficiently than what you proposed. – Ross Ridge May 26 at 15:31
  • 3
    @RossRidge: did int 10h calls hand some work off to the hardware, or somehow do wider than 16-bit stores? I thought I'd read that BIOS calls were usually even slower than direct mov [es: di], ax or whatever at least on some classes of systems. Was that just because of the actual int overhead which an internal call from inside the BIOS could bypass? VGA memory would normally be mapped uncacheable, and have to go over an ISA bus (I think) on some old pre-PCI systems, but doesn't the code behind int 10h have to do the same? – Peter Cordes May 26 at 15:55
  • 7
    @PeterCordes I’m thinking along those lines too, I suspect most BIOSs would call the routines implementing the various INT 10h services, rather than write to memory directly; speed isn’t much of an issue here... There’s no magic in the BIOS ;-), even the VGA BIOS. IIRC the overhead comes from INT itself but also a bunch of checks which the INT 10h does for every call, which might be skippable in the BIOS setup code. I don’t think a BIOS setup would even benefit much from 32-bit writes as possible on VLB or PCI. – Stephen Kitt May 26 at 17:00
  • 2
    @RossRidge "It's massively inefficient to write one character at time with a move instruction for each." - Nonsense. This is exactly what a "video BIOS" would do. And assuming that the BIOS and its configuration TUI are somewhat closely interconnected, functionally it doesn't really matter if the BIOS calls "itself" via interrupt or via subroutine call. – JimmyB May 27 at 10:55
28

TUI-drawing code can be pretty compact when you're working in assembly and relying on the IBM video BIOS to do the heavy lifting.

For example:

  • INT 10h/AH=06h and INT 10h/AH=07h can be used either to scroll a rectangular region of the screen or to clear the screen to a specified foreground/background colour combination.
  • INT 10h/AH=09h can be used to tile a character like horizontally, or to fill the screen with a character like before drawing on top of it, both in a single BIOS call.
  • INT 10h/AH=13h (available on the PC AT, New XT, EGA, and beyond) lets you write a string, with or without in-line colour attributes and with or without moving the cursor.

I'm sure that someone crunched down their drawing code using tricks like this drawing order:

  1. Use INT 10h/AH=09h to fill the screen with characters.
  2. Alternate using INT 10h/AH=09hto draw the spans of and the corners and intersection pieces.
  3. Use INT 10h/AH=06h to clear out the remaining characters to produce the content areas of the frames.

That has three advantages:

  1. There's no BIOS routine that I'm aware of to draw a column of but you can efficiently fill the screen with it, then overdraw or erase everywhere it isn't needed.
  2. When you're working in assembly, you can save space by figuring out how to batch up similar int 10h calls so that each operation leaves as many registers as possible already set up for the invocation of the next operation.
  3. If you alternate drawing the horizontal and corner pieces, you can take that a step further when dealing with instructions that don't move the cursor by drawing the spans one character too long and one character too far to the left, then overdrawing them with the left-end corner pieces. (Thus, no need to mov a new target column value between drawing the horizontal border and drawing its left-end corner.)

From what I remember of the TUIs I saw in Phoenix and AMI BIOSes right up into the Pentium era, it'd only be a few bytes to draw all that framing and set the colours, then updating the screen would just be a case of one int 10h call to clear each framed region you want to update, then you draw in the new text.

The BIOS routines you need to expose to the OS anyway would be your abstraction and anything more would be unnecessary code bloat in that sort of situation.

  • To draw a screen-sized frame I would think it would be more compact to do it entirely on your own with memory writes. If you need to draw frames of various sizes then it might make more sense to go through the BIOS. – Loren Pechtel May 28 at 5:16
  • What is the "New XT"? – mschaef May 28 at 10:16
  • @mschaef It's from a chart in Paul Somerson's DOS Power Tools, 2nd Edition, which doesn't clarify. It's most likely that he was referring to 1986's IBM 5162 (A.K.A. the XT 286) but, according to Wikipedia, the 1986 revision to the XT BIOS was also offered on a refresh of the original XT motherboard and could be retrofitted into an XT that came with the 1982 BIOS, so it might just need anything that has the 1986 XT BIOS. I don't have anything that old to test. – ssokolow May 28 at 15:01
  • @LorenPechtel It'd definitely be close. I'll have to admit that, while I have experience pinching bytes on int 10h calls with inline assembly in Open Watcom C/C++, I've never reimplemented the same behaviour using only x86 assembly, so my intuition about how compact one can make those sorts of loops is limited. – ssokolow May 29 at 7:13
  • @ssokolow I've never tried for minimum bytes with x86, I have done it with Z80 (and with certain bytes prohibited, besides! Assembly assist to BASIC programs--I stored the routines in strings within the BASIC program.), it's amazing how much you can pack into a small space. – Loren Pechtel May 30 at 1:42
13

Traditional BIOS setup interfaces had much simpler user interfaces than you're assuming. They were also written in assembly which allowed for much more compact code than you would think based on the size of applications today. They didn't have "full blown TUIs", most used a simple form interface. On the other hand operating systems like GEOS for the Commodore 64 showed how you could implement a full blown GUI in assembly and have it fit in 64K of RAM and still leave room for applications.

The original IBM PC didn't have a BIOS setup interface. It didn't need one: there was no real-time clock to set, no hard drive interface to configure, and no battery-backed CMOS RAM to store any sort configuration values. It wasn't until the IBM PC/AT that the IBM PC architecture gained these things, but even then there was no BIOS setup interface in the BIOS itself. Instead, if you wanted to changed the BIOS settings you needed to run a special program.

Eventually though, IBM PC clone manufacturers started putting the BIOS setup code in the BIOS. However rather than a full-blown text user-interface (TUI), with various widgets, they used a simple form-based interface. There was a bunch of static text, plus various fields where you could set things like the current time or various hard drive parameters. The arrows keys would select which field to edit, and the number keys and/or the plus (+) and minus (-) keys would change the value. Pressing a key like F10 would save the change configuration values and exit.

BIOS Setup Screen from the Asus P4B533 User Manual

Over time BIOSes also got bigger and bigger. The IBM PC/AT reserved 128K space for motherboard ROMs, so BIOSes could easily grow to 128K as necessary. Eventually even that wasn't enough space and BIOSes started using bank switching to allow the BIOS to grow even bigger while still staying inside the 128K (or even 64K) footprint allowed.

However, most of this additional ROM space (now implemented using flash memory) didn't go towards more advanced setup interfaces; mostly it was used to support new features and functionality built into the motherboard. Things like Advanced Power Management, ACPI, USB keyboard and mouse support, more advanced disk interfaces with RAID support, and booting of Ethernet, CD-ROM and various kinds of USB devices all required more and more ROM space. While this meant more options were added to the BIOS setup screens, the basic interface remained the same.

(There was a period where BIOS vendors experimented with crude graphical setup interfaces with mouse support, but this didn't last long. They were basically the old form based interfaces with additional icons, so they weren't really much of an improvement.)

Even though BIOSes got bigger and bigger, they still would've been written mostly in assembly language. Aside from there still being a need to keep the code as small and as efficient as possible, most of this code was run in 16-bit real-mode. By the time BIOSes might have considered using C, 16-bit x86 C compilers were obsolete and no longer being developed. By today's standards they weren't very good code generators and a bit on the buggy side, and they weren't going to get any better.

Since BIOS vendors were just iteratively updating their BIOS implementations, writing everything in assembly wasn't that big a problem. They had a stable base of code, well tested and known to support all the weird quirks that 100% IBM PC compatibility required. Today if you were writing an entire traditional BIOS from scratch, you'd probably use C, but rewriting everything in C would have caused the BIOS vendors more trouble then it would've been worth.

Because of the adoption of UEFI, things are very different today. UEFI-based firmware for PC clones operate mostly in 32-bit (or 64-bit) mode. This has allowed to them to have much more fancy graphical setup interfaces written in C and/or C++ and compiled with modern compilers.

  • 3
    "Instead, if you wanted to changed the BIOS settings you needed to run a special program." This one sentence is the answer to his question, since there was no BIOS setup program in the early ROM BIOSes. – RonJohn May 27 at 5:46
  • No RTC in original IBM PC? I wonder how these PCs were used: there was no NTP to synchronize with after startup, so did the users have to set time&date after every reboot? Or was timekeeping simply not needed? – Ruslan May 27 at 11:52
  • 2
    @ruslan: timekeeping was needed for setting the (modified) date/time field in files. Some still chose not to care; but most people had an AUTOEXEC.BAT file (which ran automatically at boot time) that started with two command at the top: DATE (prompt user for current date) and TIME (same). Yes, it was annoying. – Euro Micelli May 27 at 12:24
  • @RonJohn Well, I'm not sure the original poster was referring exclusively to the original IBM PC models. There were a number of IBM PC/AT clones that had the BIOS setup in the BIOS itself, using only 32K of ROM. You can apparently even use these clone ROMs in an actual IBM PC/AT: minuszerodegrees.net/bios/bios.htm#5170 – Ross Ridge May 27 at 15:13
  • 5
    @Euro ... and if there’s no AUTOEXEC.BAT, DOS will ask the user to enter the date and time anyway. – Stephen Kitt May 27 at 21:02
8

Was it easier than I'm imagining?

Yes, I believe it was.

Did these early programmers just use a library similar to ncurses but for BIOS programming? How were these text interfaces engineered?

To understand this, it's important to keep in mind two things.

  1. The IBM PC of the time was a very simple architecture by today's standards.

  2. You can do a lot of things in very little code, especially when you know that you don't have to worry about anything else (even operating system routines) running at the same time and you can know with 100% certainty the starting state of the system (as you are entering from a known point in the BIOS power-on self test).

IBM, and by extension every clone maker that wanted that coveted 100% IBM compatibility, put the graphics card's memory at a fixed address. For monochrome, the address range for text mode began at (physical) B0000H; for color, B8000H. In each range, two bytes were used per character to be displayed; the first byte (even address) held the character code, and the second (odd address) held the attributes for that one character. Characters were laid out such that the first memory position held the character displayed at row 1, column 1; the second memory position held that displayed at row 1, column 2; the 81st memory position that displayed at row 2, column 1; and so on.

Thus, with only a little bit of math and minimal knowledge of how to work with data at arbitrary memory locations, both of which would be absolute requirements to be anywhere near the BIOS code anyway, it's trivial to fill any rectangular portion of the screen with any combination of character and attribute you want.

Beyond that, you can just move text labels into video memory directly, not unreasonably by simply copying bytes (REP MOVSW would be your friend, and probably both be faster and require less code than calling through an interrupt, which will at a minimum require its own bookkeeping).

Having that, you need a way to keep track of what element the user is interacting with. A trivial state machine will do that, quite likely in very little code - especially if you're willing to be a little clever in how you implement it. To indicate which selection is active, you could just toggle the "high intensity" bit for the appropriate characters, which could be done with a few instructions at most (I'm not sure if you can actually do REP OR or REP AND but even if you can't, it'd be a real tight loop).

I imagine that the hardest part would be where the setup utility needs to accept more advanced user interaction than to simply "increase" or "decrease" a value (whatever exactly that means for the specific value), which already gets you quite far. But even that could be done in very little code and a little bit of RAM.

There would be no need for anything even remotely as complex as ncurses for any of this.

Oh, and many of the exact same techniques were used by non-BIOS programmers as well, simply because they gave far superior performance as well as better control over the output compared to pretty much any alternative approach, not least of which going through the BIOS or OS services via interrupts.

  • You wouldn't use the REP prefix with bit-twiddling instructions like OR or AND. The REP prefixes (including REPE/REPZ and REPNE/REPNZ) are only for the string instructions. The manual says that operation is undefined when REP is used with anything other than a string instruction. Of course, there are weird exceptions. Sometimes REP is used with the RET instruction to create a "fat" RET that avoids performance problems on certain AMD processor generations. And other instructions, like POPCNT, use a "fake" REP prefix in their encoding, as well. – Cody Gray May 28 at 2:47
  • @CodyGray "The REP prefixes (...) are only for the string instructions." You might very well be right. However, part of my point was that even if you couldn't use REP (or, indeed, one of the variants), you don't need much code at all to toggle an attribute (or color, as the case might be) bit for a handful of characters displayed on screen. Which is an easy and cheap way to indicate which user interaction element is active. – a CVn May 28 at 6:46
6

Assembler is the way ... You can do a lot of stuff in 4 KBytes just google 4K demoscene ... I once created a 3D space ship sim game under 4K (gfx included) with 3D polygonal SW rendering with textures.

Text mode (VGA mode 3) menus are really just few Bytes of code look at his:

Printing of text is really just copying data into VRAM so printing routine is just few BYTEs of code and as you can see even Keyboard interrupt handler is not that big.

If you compile similar code in higher level language then the executable is much much bigger because it must contain Engine of the language (handling heap/stack stuff and variables), also the linkage stuff especially if DLLs are used can be quite big in comparison to the usable code itself.

Also modern OSes does not allow direct HW access so even stuff that was easy on the BIOS or MS-DOS side is now much much more complicated and requires a lot of code just to handle APIs.

So the reality of nowadays computing is even if you create some "almost empty window" with some simple functionality that would fit to few KBytes of code the executable grows to ~1MByte or more simply due to interfacing to OS APIs and used Libs ...

3

My answer is anecdotal, not authoritative, but hopefully it illustrates answers to your questions.

In the early-1990s I worked for a SCSI host adapter startup. Part of being feature-complete in that market was to offer two ROM BIOS features: (a) an INT 13h boot loader (which allowed for the PC to boot off of a SCSI drive, as well as present other SCSI drives as though they were IDE) and (b) a ROM BIOS configuration program to configure the host adapter, format SCSI drives, set IRQ and port numbers, and so forth. (If you used Adaptec cards in the 1990s, this was the "Press Ctrl+A for Setup" option you would see at boot time.)

I was tasked with (b) for our card. Although our target market by that time was not 8086 IBM PCs, or even PC/ATs, compatibility was a high concern; no company wanted a lot of phone calls from unhappy users owning some off-brand machine you never heard of. So, although writing directly to the video RAM was tempting, we stuck with INT 10h for compatibility reasons.

Because we were too cheap to license an existing box-drawing library -- they flourished in the 1990s, and some were small enough for ROM work -- I rolled my own "mini-library" that we wound up using in some simple DOS apps as well. All it offered was box-drawing routines, color selection/highlighting, and a crude form-construction system to move a cursor between menu items (to traverse a tree of menus, a la Gopher) and select/deselect radio buttons and checkboxes. There was no need for free-form text input so the number of controls was quite limited.

Believe it or not, this was mostly written in C with inline assembly stubs for the INT 10h code and to talk with the host adapter (mostly INP/OUTP). The entire ROM BIOS configuration was less than 10K as I recall, well under the 16K onboard ROM I was allocated. (Some of the space was due to the text labels; I considered compressing all strings but abandoned that because we were out of time.)

Which was good, because the INT 13h ROM code (the (a) above) went too big (and it was written in assembly) and had no space for the host adapter microcode (the object code that had to be loaded on the card's microcontroller).

The solution was to use a 32K ROM bank-switched by the host adapter. This meant a portion of the INT 13h code had to be mirrored on my 16K "side" of the ROM so when the switch occurred the CPU continued executing the now-gone ROM code. If the user pressed Ctrl+A the code would jump to my entry point; if the ROM was loading the microcode during its boot routine, it copied the microcode to a block of RAM and bank-switched back to its "side" of the ROM and continued.

Tons of tricks and shortcuts were made to cram a lot of functionality into the ROM BIOS code. C is often pish-poshed as too heavyweight compared to assembly, but it solved a lot of problems for us and cut development time. (Also note my code ran entirely off the stack; a lot of languages simply cannot do that.) It was only two of us writing all of this and we were under time pressure. I don't know we could have fit all of this in a single 16K ROM, but I bet we could've whittled it down further and (perhaps) avoided the need to bank-switch for the microcode.

And remember: While my ROM configuration code was ephemeral (exiting required a reboot), the ROM boot loader hooked INT 13h and remained in memory. This was a trick unto itself; it had zero RAM at its disposal once the system was booted and could only use a limited amount of the stack during interrupts.

It's a miracle all this worked, and yet it did.

2

As noted, assembly can be pretty dense.

You can pack even more code into a small space using a TIL (Threaded Interpreted Language). FORTH is a well known TIL, but it is easy to roll your own. It is easy to have part of your ROM be pure assembly, and part of it be a TIL. What a TIL does is to trade off speed for space: TILs are more compact than native assembly, but slower. So what a programmer can do is to use the TIL in the parts of the program where speed doesn't matter (such as the UI), and stick to native code where speed does matter (floppy disk interface, for example).

I am not saying that any BIOS used a TIL, but it's a well known technique for squeezing more program into a space, one that would come readily to mind if space started to become a problem.

A TIL isn't the only way to trade off speed for space. You can also implement a specialized bytecode interpreter, and write parts of the program in that. For example, the Apple II computers had an interpreted byte-code interpreter called SWEET16, used to do 16-bit arithmetic on the 8-bit processor.

2

Early x86 PCs had no boot configuration program, nor was one needed

Quoting Wikipedia:

The BIOS of the original IBM PC and XT had no interactive user interface. Error codes or messages were displayed on the screen, or coded series of sounds were generated to signal errors when the power-on self-test (POST) had not proceeded to the point of successfully initializing a video display adapter. Options on the IBM PC and XT were set by switches and jumpers on the main board and on expansion cards. Starting around the mid-1990s, it became typical for the BIOS ROM to include a "BIOS configuration utility" (BCU[10]) or "BIOS setup utility", accessed at system power-up by a particular key sequence.

  • As noted in the quote above, many settings were made by adjusting DIP switches and jumpers inside the computer.

  • The boot device was chosen by a fixed scheme. After the power-on self-test and initializing I/O, the BIOS tried to read the boot sector from the A: floppy drive. If that failed, it moved on to the B: floppy, and then the C: hard drive. If the drive itself or its disk were not present, it moved to the next in the sequence. You could always override the hard drive by using a floppy in A:, a security risk that modern BIOSes now allow you to prevent. If there was no viable boot device, it either dropped into ROM BASIC (see below) or gave a retry message.

  • More sophisticated configuration was done by files on the boot volume. This was the whole point of the CONFIG.SYS and AUTOEXEC.BAT files in DOS. Want to reconfigure your system? Just edit the configuration files on the boot volume. No special ROM utility needed.

  • The drivers and configuration files for expansion cards were on the boot device anyway, not stored in ROM. Software on the boot volume could also override the default behavior of calls to ROM BIOS.

  • BIOS literally means basic input/output system. Input was limited to keyboards (and the original ROMs could not even handle 101-key keyboards). Output was text and basic teletype control characters to the screen. ROM BIOS did not even support ANSI escape codes -- that was the whole point of the ANSI.SYS file on the DOS boot volume!

  • Sure, there was ROM BASIC, but...

    • only on IBM brand machines. They licensed BASIC from Microsoft to put into ROM. Part of the agreement was that Microsoft could not sell clone makers the contents of the IBM ROMs. Therefore, clones never had BASIC in ROM.

    • it was only activated if no boot drives (floppies, hard disks) could be found.

    • it was a command-line interpreter, not a fancy menu-driven configuration utility.

    • ROM BASIC could only access files on cassette tape. There were other versions of BASIC that could access files on floppies or the hard drive, but these were DOS programs, not something in the ROM.

    • ROM BASIC could only run BASIC programs, not .COM or .EXE files. So there is no way to transfer control of the system to something else.

    • the cassette port hardware was eliminated in the XT, and BASIC was taken out of the ROM starting with the AT.

  • Sure, there were fancy menu-based programs, but... these were DOS programs loaded from disk, not programs built into ROM.

  • There was no memory to store the settings anyway. EEPROM, battery-backed RAM, and FLASH memory were far more expensive than storing the configuration on the boot device. FLASH chips weren't even available until 1988.

Was it theoretically possible? Yes, and all of the other answers seem to focus on that aspect. However, this is Retrocomputing and should be about what historically happened.

  • Also, there are ridiculously small BASIC interpreters ... 8052 AH BASIC (an interactive(!), serial terminal BASIC designed to run on a 4K ROM, 128 Byte RAM microcontroller...) anyone? :) – rackandboneman May 28 at 23:24
0

The graphics area is small 320x200 with 4 colors on CGA screen or 640x350 2 colors. So a simple chess game can be done in a small area.

For text UIs there's ASCII graphic characters to make boxes and such https://en.wikipedia.org/wiki/Code_page_437

which are still being used today. The color range is also limited to 16 colors.

So basically given a limited palette but "richer" primitives (in the form of ASCII lines from CP437), you don't need as much to do rendering.

Secondly there's less overall memory space so you have an address of 2 bytes to represent something in the 64K space. There's no memory management to deal with because the entire memory space is yours (except for a few reserved areas)

A lot of work can also be done through interrupts specifically Int 10 https://en.wikipedia.org/wiki/BIOS_interrupt_call which gives you a lot of video controls as well.

  • 4
    Note that the text mode resolution(s) don't necessarily match the graphic mode resolution(s), and are completely irrelevant for this question - what the BIOS does is write character codes and attributes to the video RAM in text mode. And the BIOS does implement the interrupt calls itself in the small ROM space. – dirkt May 26 at 4:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy